diff options
author | dim <dim@FreeBSD.org> | 2011-02-20 13:06:31 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-02-20 13:06:31 +0000 |
commit | 39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df (patch) | |
tree | a9243275843fbeaa590afc07ee888e006b8d54ea /lib/Sema | |
parent | 69b4eca4a4255ba43baa5c1d9bbdec3ec17f479e (diff) | |
download | FreeBSD-src-39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df.zip FreeBSD-src-39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df.tar.gz |
Vendor import of clang trunk r126079:
http://llvm.org/svn/llvm-project/cfe/trunk@126079
Diffstat (limited to 'lib/Sema')
35 files changed, 26122 insertions, 11928 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index cfebed6..63f561d 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/SemaInternal.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprObjC.h" @@ -25,6 +26,7 @@ #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/Analyses/ReachableCode.h" +#include "clang/Analysis/Analyses/UninitializedValuesV2.h" #include "llvm/ADT/BitVector.h" #include "llvm/Support/Casting.h" @@ -108,24 +110,41 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { bool HasFakeEdge = false; bool HasPlainEdge = false; bool HasAbnormalEdge = false; - for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), - E = cfg->getExit().pred_end(); - I != E; - ++I) { - CFGBlock& B = **I; + + // Ignore default cases that aren't likely to be reachable because all + // enums in a switch(X) have explicit case statements. + CFGBlock::FilterOptions FO; + FO.IgnoreDefaultsWithCoveredEnums = 1; + + for (CFGBlock::filtered_pred_iterator + I = cfg->getExit().filtered_pred_start_end(FO); I.hasMore(); ++I) { + const CFGBlock& B = **I; if (!live[B.getBlockID()]) continue; - if (B.size() == 0) { + + // Destructors can appear after the 'return' in the CFG. This is + // normal. We need to look pass the destructors for the return + // statement (if it exists). + CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); + for ( ; ri != re ; ++ri) { + CFGElement CE = *ri; + if (isa<CFGStmt>(CE)) + break; + } + + // No more CFGElements in the block? + if (ri == re) { if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { HasAbnormalEdge = true; continue; } - // A labeled empty statement, or the entry block... HasPlainEdge = true; continue; } - Stmt *S = B[B.size()-1]; + + CFGStmt CS = cast<CFGStmt>(*ri); + Stmt *S = CS.getStmt(); if (isa<ReturnStmt>(S)) { HasLiveReturn = true; continue; @@ -169,19 +188,6 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { } } } - // FIXME: Remove this hack once temporaries and their destructors are - // modeled correctly by the CFG. - if (CXXExprWithTemporaries *E = dyn_cast<CXXExprWithTemporaries>(S)) { - for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) { - const FunctionDecl *FD = E->getTemporary(I)->getDestructor(); - if (FD->hasAttr<NoReturnAttr>() || - FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) { - NoReturnEdge = true; - HasFakeEdge = true; - break; - } - } - } // FIXME: Add noreturn message sends. if (NoReturnEdge == false) HasPlainEdge = true; @@ -208,9 +214,11 @@ struct CheckFallThroughDiagnostics { unsigned diag_AlwaysFallThrough_ReturnsNonVoid; unsigned diag_NeverFallThroughOrReturn; bool funMode; + SourceLocation FuncLoc; static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { CheckFallThroughDiagnostics D; + D.FuncLoc = Func->getLocation(); D.diag_MaybeFallThrough_HasNoReturn = diag::warn_falloff_noreturn_function; D.diag_MaybeFallThrough_ReturnsNonVoid = @@ -255,18 +263,22 @@ struct CheckFallThroughDiagnostics { bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, bool HasNoReturn) const { if (funMode) { - return (D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) - == Diagnostic::Ignored || ReturnsVoid) - && (D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) - == Diagnostic::Ignored || !HasNoReturn) - && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) - == Diagnostic::Ignored || !ReturnsVoid); + return (ReturnsVoid || + D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function, + FuncLoc) == Diagnostic::Ignored) + && (!HasNoReturn || + D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr, + FuncLoc) == Diagnostic::Ignored) + && (!ReturnsVoid || + D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc) + == Diagnostic::Ignored); } // For blocks. return ReturnsVoid && !HasNoReturn - && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) - == Diagnostic::Ignored || !ReturnsVoid); + && (!ReturnsVoid || + D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc) + == Diagnostic::Ignored); } }; @@ -343,6 +355,112 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, } //===----------------------------------------------------------------------===// +// -Wuninitialized +//===----------------------------------------------------------------------===// + +namespace { +struct SLocSort { + bool operator()(const Expr *a, const Expr *b) { + SourceLocation aLoc = a->getLocStart(); + SourceLocation bLoc = b->getLocStart(); + return aLoc.getRawEncoding() < bLoc.getRawEncoding(); + } +}; + +class UninitValsDiagReporter : public UninitVariablesHandler { + Sema &S; + typedef llvm::SmallVector<const Expr *, 2> UsesVec; + typedef llvm::DenseMap<const VarDecl *, UsesVec*> UsesMap; + UsesMap *uses; + +public: + UninitValsDiagReporter(Sema &S) : S(S), uses(0) {} + ~UninitValsDiagReporter() { + flushDiagnostics(); + } + + void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd) { + if (!uses) + uses = new UsesMap(); + + UsesVec *&vec = (*uses)[vd]; + if (!vec) + vec = new UsesVec(); + + vec->push_back(ex); + } + + void flushDiagnostics() { + if (!uses) + return; + + for (UsesMap::iterator i = uses->begin(), e = uses->end(); i != e; ++i) { + const VarDecl *vd = i->first; + UsesVec *vec = i->second; + + bool fixitIssued = false; + + // Sort the uses by their SourceLocations. While not strictly + // guaranteed to produce them in line/column order, this will provide + // a stable ordering. + std::sort(vec->begin(), vec->end(), SLocSort()); + + for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; ++vi) + { + if (const DeclRefExpr *dr = dyn_cast<DeclRefExpr>(*vi)) { + S.Diag(dr->getLocStart(), diag::warn_uninit_var) + << vd->getDeclName() << dr->getSourceRange(); + } + else { + const BlockExpr *be = cast<BlockExpr>(*vi); + S.Diag(be->getLocStart(), diag::warn_uninit_var_captured_by_block) + << vd->getDeclName(); + } + + // Report where the variable was declared. + S.Diag(vd->getLocStart(), diag::note_uninit_var_def) + << vd->getDeclName(); + + // Only report the fixit once. + if (fixitIssued) + continue; + + fixitIssued = true; + + // Suggest possible initialization (if any). + const char *initialization = 0; + QualType vdTy = vd->getType().getCanonicalType(); + + if (vdTy->getAs<ObjCObjectPointerType>()) { + // Check if 'nil' is defined. + if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) + initialization = " = nil"; + else + initialization = " = 0"; + } + else if (vdTy->isRealFloatingType()) + initialization = " = 0.0"; + else if (vdTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) + initialization = " = false"; + else if (vdTy->isEnumeralType()) + continue; + else if (vdTy->isScalarType()) + initialization = " = 0"; + + if (initialization) { + SourceLocation loc = S.PP.getLocForEndOfToken(vd->getLocEnd()); + S.Diag(loc, diag::note_var_fixit_add_initialization) + << FixItHint::CreateInsertion(loc, initialization); + } + } + delete vec; + } + delete uses; + } +}; +} + +//===----------------------------------------------------------------------===// // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based // warnings on a function, method, or block. //===----------------------------------------------------------------------===// @@ -355,7 +473,8 @@ clang::sema::AnalysisBasedWarnings::Policy::Policy() { clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { Diagnostic &D = S.getDiagnostics(); DefaultPolicy.enableCheckUnreachable = (unsigned) - (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored); + (D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) != + Diagnostic::Ignored); } void clang::sema:: @@ -390,7 +509,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 // explosion for destrutors that can result and the compile time hit. - AnalysisContext AC(D, 0, false); + AnalysisContext AC(D, 0, /*useUnoptimizedCFG=*/false, /*addehedges=*/false, + /*addImplicitDtors=*/true, /*addInitializers=*/true); // Warning: check missing 'return' if (P.enableCheckFallThrough) { @@ -403,6 +523,32 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Warning: check for unreachable code if (P.enableCheckUnreachable) CheckUnreachable(S, AC); + + if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart()) + != Diagnostic::Ignored) { + ASTContext &ctx = D->getASTContext(); + llvm::OwningPtr<CFG> tmpCFG; + bool useAlternateCFG = false; + if (ctx.getLangOptions().CPlusPlus) { + // Temporary workaround: implicit dtors in the CFG can confuse + // the path-sensitivity in the uninitialized values analysis. + // For now create (if necessary) a separate CFG without implicit dtors. + // FIXME: We should not need to do this, as it results in multiple + // CFGs getting constructed. + CFG::BuildOptions B; + B.AddEHEdges = false; + B.AddImplicitDtors = false; + B.AddInitializers = true; + tmpCFG.reset(CFG::buildCFG(D, AC.getBody(), &ctx, B)); + useAlternateCFG = true; + } + CFG *cfg = useAlternateCFG ? tmpCFG.get() : AC.getCFG(); + if (cfg) { + UninitValsDiagReporter reporter(S); + runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC, + reporter); + } + } } void clang::sema:: diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index 8ccb2ca..c0a3053 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -16,37 +16,26 @@ #include "llvm/ADT/StringSwitch.h" using namespace clang; -AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, +AttributeList::AttributeList(llvm::BumpPtrAllocator &Alloc, + IdentifierInfo *aName, SourceLocation aLoc, IdentifierInfo *sName, SourceLocation sLoc, IdentifierInfo *pName, SourceLocation pLoc, Expr **ExprList, unsigned numArgs, - AttributeList *n, bool declspec, bool cxx0x) - : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc), - ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n), + bool declspec, bool cxx0x) + : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), + ScopeLoc(sLoc), + ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(0), DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) { if (numArgs == 0) Args = 0; else { - Args = new Expr*[numArgs]; + // Allocate the Args array using the BumpPtrAllocator. + Args = Alloc.Allocate<Expr*>(numArgs); memcpy(Args, ExprList, numArgs*sizeof(Args[0])); } } -AttributeList::~AttributeList() { - if (Args) { - // FIXME: before we delete the vector, we need to make sure the Expr's - // have been deleted. Since ActionBase::ExprTy is "void", we are dependent - // on the actions module for actually freeing the memory. The specific - // hooks are ActOnDeclarator, ActOnTypeName, ActOnParamDeclaratorType, - // ParseField, ParseTag. Once these routines have freed the expression, - // they should zero out the Args slot (to indicate the memory has been - // freed). If any element of the vector is non-null, we should assert. - delete [] Args; - } - delete Next; -} - AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { llvm::StringRef AttrName = Name->getName(); @@ -62,17 +51,17 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("used", AT_used) .Case("alias", AT_alias) .Case("align", AT_aligned) - .Case("final", AT_final) .Case("cdecl", AT_cdecl) .Case("const", AT_const) + .Case("__const", AT_const) // some GCC headers do contain this spelling .Case("blocks", AT_blocks) .Case("format", AT_format) - .Case("hiding", AT_hiding) .Case("malloc", AT_malloc) .Case("packed", AT_packed) .Case("unused", AT_unused) .Case("aligned", AT_aligned) .Case("cleanup", AT_cleanup) + .Case("naked", AT_naked) .Case("nodebug", AT_nodebug) .Case("nonnull", AT_nonnull) .Case("nothrow", AT_nothrow) @@ -87,12 +76,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("iboutletcollection", AT_IBOutletCollection) .Case("noreturn", AT_noreturn) .Case("noinline", AT_noinline) - .Case("override", AT_override) .Case("sentinel", AT_sentinel) .Case("NSObject", AT_nsobject) .Case("dllimport", AT_dllimport) .Case("dllexport", AT_dllexport) - .Case("may_alias", IgnoredAttribute) // FIXME: TBAA + .Case("may_alias", AT_may_alias) .Case("base_check", AT_base_check) .Case("deprecated", AT_deprecated) .Case("visibility", AT_visibility) @@ -111,12 +99,18 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("vec_type_hint", IgnoredAttribute) .Case("objc_exception", AT_objc_exception) .Case("ext_vector_type", AT_ext_vector_type) + .Case("neon_vector_type", AT_neon_vector_type) + .Case("neon_polyvector_type", AT_neon_polyvector_type) .Case("transparent_union", AT_transparent_union) .Case("analyzer_noreturn", AT_analyzer_noreturn) .Case("warn_unused_result", AT_warn_unused_result) .Case("carries_dependency", AT_carries_dependency) + .Case("ns_consumed", AT_ns_consumed) + .Case("ns_consumes_self", AT_ns_consumes_self) + .Case("ns_returns_autoreleased", AT_ns_returns_autoreleased) .Case("ns_returns_not_retained", AT_ns_returns_not_retained) .Case("ns_returns_retained", AT_ns_returns_retained) + .Case("cf_consumed", AT_cf_consumed) .Case("cf_returns_not_retained", AT_cf_returns_not_retained) .Case("cf_returns_retained", AT_cf_returns_retained) .Case("ownership_returns", AT_ownership_returns) @@ -126,11 +120,22 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("init_priority", AT_init_priority) .Case("no_instrument_function", AT_no_instrument_function) .Case("thiscall", AT_thiscall) + .Case("bounded", IgnoredAttribute) // OpenBSD .Case("pascal", AT_pascal) .Case("__cdecl", AT_cdecl) .Case("__stdcall", AT_stdcall) .Case("__fastcall", AT_fastcall) .Case("__thiscall", AT_thiscall) .Case("__pascal", AT_pascal) + .Case("constant", AT_constant) + .Case("device", AT_device) + .Case("global", AT_global) + .Case("host", AT_host) + .Case("shared", AT_shared) + .Case("launch_bounds", AT_launch_bounds) + .Case("common", AT_common) + .Case("nocommon", AT_nocommon) + .Case("opencl_kernel_function", AT_opencl_kernel_function) + .Case("uuid", AT_uuid) .Default(UnknownAttribute); } diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index e65bb22..0d66e25 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_NO_RTTI 1) +set(LLVM_USED_LIBS clangBasic clangAST clangLex clangAnalysis) add_clang_library(clangSema AnalysisBasedWarnings.cpp @@ -31,6 +31,7 @@ add_clang_library(clangSema SemaTemplateDeduction.cpp SemaTemplateInstantiate.cpp SemaTemplateInstantiateDecl.cpp + SemaTemplateVariadic.cpp SemaType.cpp TargetAttributesSema.cpp ) diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 58a1627..b7037ce 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -19,6 +19,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang-c/Index.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstring> @@ -28,9 +29,51 @@ using namespace clang; using llvm::StringRef; //===----------------------------------------------------------------------===// +// Code completion context implementation +//===----------------------------------------------------------------------===// + +bool CodeCompletionContext::wantConstructorResults() const { + switch (Kind) { + case CCC_Recovery: + case CCC_Statement: + case CCC_Expression: + case CCC_ObjCMessageReceiver: + case CCC_ParenthesizedExpression: + return true; + + case CCC_TopLevel: + case CCC_ObjCInterface: + case CCC_ObjCImplementation: + case CCC_ObjCIvarList: + case CCC_ClassStructUnion: + case CCC_MemberAccess: + case CCC_EnumTag: + case CCC_UnionTag: + case CCC_ClassOrStructTag: + case CCC_ObjCProtocolName: + case CCC_Namespace: + case CCC_Type: + case CCC_Name: + case CCC_PotentiallyQualifiedName: + case CCC_MacroName: + case CCC_MacroNameUse: + case CCC_PreprocessorExpression: + case CCC_PreprocessorDirective: + case CCC_NaturalLanguage: + case CCC_SelectorName: + case CCC_TypeQualifiers: + case CCC_Other: + case CCC_OtherWithMacros: + return false; + } + + return false; +} + +//===----------------------------------------------------------------------===// // Code completion string implementation //===----------------------------------------------------------------------===// -CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) +CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text) : Kind(Kind), Text("") { switch (Kind) { @@ -39,13 +82,9 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) case CK_Placeholder: case CK_Informative: case CK_ResultType: - case CK_CurrentParameter: { - char *New = new char [Text.size() + 1]; - std::memcpy(New, Text.data(), Text.size()); - New[Text.size()] = '\0'; - this->Text = New; + case CK_CurrentParameter: + this->Text = Text; break; - } case CK_Optional: llvm_unreachable("Optional strings cannot be created from text"); @@ -110,112 +149,48 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateText(StringRef Text) { +CodeCompletionString::Chunk::CreateText(const char *Text) { return Chunk(CK_Text, Text); } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateOptional( - std::auto_ptr<CodeCompletionString> Optional) { +CodeCompletionString::Chunk::CreateOptional(CodeCompletionString *Optional) { Chunk Result; Result.Kind = CK_Optional; - Result.Optional = Optional.release(); + Result.Optional = Optional; return Result; } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreatePlaceholder(StringRef Placeholder) { +CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) { return Chunk(CK_Placeholder, Placeholder); } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateInformative(StringRef Informative) { +CodeCompletionString::Chunk::CreateInformative(const char *Informative) { return Chunk(CK_Informative, Informative); } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateResultType(StringRef ResultType) { +CodeCompletionString::Chunk::CreateResultType(const char *ResultType) { return Chunk(CK_ResultType, ResultType); } CodeCompletionString::Chunk CodeCompletionString::Chunk::CreateCurrentParameter( - StringRef CurrentParameter) { + const char *CurrentParameter) { return Chunk(CK_CurrentParameter, CurrentParameter); } -CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const { - switch (Kind) { - case CK_TypedText: - case CK_Text: - case CK_Placeholder: - case CK_Informative: - case CK_ResultType: - case CK_CurrentParameter: - case CK_LeftParen: - case CK_RightParen: - case CK_LeftBracket: - case CK_RightBracket: - case CK_LeftBrace: - case CK_RightBrace: - case CK_LeftAngle: - case CK_RightAngle: - case CK_Comma: - case CK_Colon: - case CK_SemiColon: - case CK_Equal: - case CK_HorizontalSpace: - case CK_VerticalSpace: - return Chunk(Kind, Text); - - case CK_Optional: { - std::auto_ptr<CodeCompletionString> Opt(Optional->Clone()); - return CreateOptional(Opt); - } - } - - // Silence GCC warning. - return Chunk(); -} - -void -CodeCompletionString::Chunk::Destroy() { - switch (Kind) { - case CK_Optional: - delete Optional; - break; - - case CK_TypedText: - case CK_Text: - case CK_Placeholder: - case CK_Informative: - case CK_ResultType: - case CK_CurrentParameter: - delete [] Text; - break; - - case CK_LeftParen: - case CK_RightParen: - case CK_LeftBracket: - case CK_RightBracket: - case CK_LeftBrace: - case CK_RightBrace: - case CK_LeftAngle: - case CK_RightAngle: - case CK_Comma: - case CK_Colon: - case CK_SemiColon: - case CK_Equal: - case CK_HorizontalSpace: - case CK_VerticalSpace: - break; - } -} - -void CodeCompletionString::clear() { - std::for_each(Chunks.begin(), Chunks.end(), - std::mem_fun_ref(&Chunk::Destroy)); - Chunks.clear(); +CodeCompletionString::CodeCompletionString(const Chunk *Chunks, + unsigned NumChunks, + unsigned Priority, + CXAvailabilityKind Availability) + : NumChunks(NumChunks), Priority(Priority), Availability(Availability) +{ + Chunk *StoredChunks = reinterpret_cast<Chunk *>(this + 1); + for (unsigned I = 0; I != NumChunks; ++I) + StoredChunks[I] = Chunks[I]; } std::string CodeCompletionString::getAsString() const { @@ -247,140 +222,30 @@ const char *CodeCompletionString::getTypedText() const { return 0; } -CodeCompletionString * -CodeCompletionString::Clone(CodeCompletionString *Result) const { - if (!Result) - Result = new CodeCompletionString; - for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) - Result->AddChunk(C->Clone()); - return Result; +const char *CodeCompletionAllocator::CopyString(llvm::StringRef String) { + char *Mem = (char *)Allocate(String.size() + 1, 1); + std::copy(String.begin(), String.end(), Mem); + Mem[String.size()] = 0; + return Mem; } -static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) { - OS.write((const char *)&Value, sizeof(unsigned)); +const char *CodeCompletionAllocator::CopyString(llvm::Twine String) { + // FIXME: It would be more efficient to teach Twine to tell us its size and + // then add a routine there to fill in an allocated char* with the contents + // of the string. + llvm::SmallString<128> Data; + return CopyString(String.toStringRef(Data)); } -static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, - unsigned &Value) { - if (Memory + sizeof(unsigned) > MemoryEnd) - return true; - - memmove(&Value, Memory, sizeof(unsigned)); - Memory += sizeof(unsigned); - return false; -} - -void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { - // Write the number of chunks. - WriteUnsigned(OS, size()); - - for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { - WriteUnsigned(OS, C->Kind); - - switch (C->Kind) { - case CK_TypedText: - case CK_Text: - case CK_Placeholder: - case CK_Informative: - case CK_ResultType: - case CK_CurrentParameter: { - const char *Text = C->Text; - unsigned StrLen = strlen(Text); - WriteUnsigned(OS, StrLen); - OS.write(Text, StrLen); - break; - } - - case CK_Optional: - C->Optional->Serialize(OS); - break; - - case CK_LeftParen: - case CK_RightParen: - case CK_LeftBracket: - case CK_RightBracket: - case CK_LeftBrace: - case CK_RightBrace: - case CK_LeftAngle: - case CK_RightAngle: - case CK_Comma: - case CK_Colon: - case CK_SemiColon: - case CK_Equal: - case CK_HorizontalSpace: - case CK_VerticalSpace: - break; - } - } -} - -bool CodeCompletionString::Deserialize(const char *&Str, const char *StrEnd) { - if (Str == StrEnd || *Str == 0) - return false; - - unsigned NumBlocks; - if (ReadUnsigned(Str, StrEnd, NumBlocks)) - return false; - - for (unsigned I = 0; I != NumBlocks; ++I) { - if (Str + 1 >= StrEnd) - break; - - // Parse the next kind. - unsigned KindValue; - if (ReadUnsigned(Str, StrEnd, KindValue)) - return false; - - switch (ChunkKind Kind = (ChunkKind)KindValue) { - case CK_TypedText: - case CK_Text: - case CK_Placeholder: - case CK_Informative: - case CK_ResultType: - case CK_CurrentParameter: { - unsigned StrLen; - if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd)) - return false; - - AddChunk(Chunk(Kind, StringRef(Str, StrLen))); - Str += StrLen; - break; - } - - case CK_Optional: { - std::auto_ptr<CodeCompletionString> Optional(new CodeCompletionString()); - if (Optional->Deserialize(Str, StrEnd)) - AddOptionalChunk(Optional); - break; - } - - case CK_LeftParen: - case CK_RightParen: - case CK_LeftBracket: - case CK_RightBracket: - case CK_LeftBrace: - case CK_RightBrace: - case CK_LeftAngle: - case CK_RightAngle: - case CK_Comma: - case CK_Colon: - case CK_SemiColon: - case CK_Equal: - case CK_HorizontalSpace: - case CK_VerticalSpace: - AddChunk(Chunk(Kind)); - break; - } - }; - - return true; -} - -void CodeCompletionResult::Destroy() { - if (Kind == RK_Pattern) { - delete Pattern; - Pattern = 0; - } +CodeCompletionString *CodeCompletionBuilder::TakeString() { + void *Mem = Allocator.Allocate( + sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size(), + llvm::alignOf<CodeCompletionString>()); + CodeCompletionString *Result + = new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(), + Priority, Availability); + Chunks.clear(); + return Result; } unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) { @@ -389,8 +254,15 @@ unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) { // Context-based decisions. DeclContext *DC = ND->getDeclContext()->getRedeclContext(); - if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) + if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) { + // _cmd is relatively rare + if (ImplicitParamDecl *ImplicitParam = dyn_cast<ImplicitParamDecl>(ND)) + if (ImplicitParam->getIdentifier() && + ImplicitParam->getIdentifier()->isStr("_cmd")) + return CCP_ObjC_cmd; + return CCP_LocalDeclaration; + } if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) return CCP_MemberDeclaration; @@ -399,6 +271,7 @@ unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) { return CCP_Constant; if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) return CCP_Type; + return CCP_Declaration; } @@ -454,9 +327,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, if (Results[I].Hidden) OS << " (Hidden)"; if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef)) { + = Results[I].CreateCodeCompletionString(SemaRef, Allocator)) { OS << " : " << CCS->getAsString(); - delete CCS; } OS << '\n'; @@ -469,9 +341,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, case CodeCompletionResult::RK_Macro: { OS << Results[I].Macro->getName(); if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef)) { + = Results[I].CreateCodeCompletionString(SemaRef, Allocator)) { OS << " : " << CCS->getAsString(); - delete CCS; } OS << '\n'; break; @@ -493,9 +364,9 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, unsigned NumCandidates) { for (unsigned I = 0; I != NumCandidates; ++I) { if (CodeCompletionString *CCS - = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) { + = Candidates[I].CreateSignatureString(CurrentArg, SemaRef, + Allocator)) { OS << "OVERLOAD: " << CCS->getAsString() << "\n"; - delete CCS; } } } @@ -587,37 +458,3 @@ bool clang::operator<(const CodeCompletionResult &X, return false; } - -void -CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, - CodeCompletionContext Context, - CodeCompletionResult *Results, - unsigned NumResults) { - // Print the results. - for (unsigned I = 0; I != NumResults; ++I) { - WriteUnsigned(OS, Results[I].CursorKind); - WriteUnsigned(OS, Results[I].Priority); - WriteUnsigned(OS, Results[I].Availability); - CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef); - assert(CCS && "No code-completion string?"); - CCS->Serialize(OS); - delete CCS; - } -} - -void -CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, - unsigned CurrentArg, - OverloadCandidate *Candidates, - unsigned NumCandidates) { - for (unsigned I = 0; I != NumCandidates; ++I) { - WriteUnsigned(OS, CXCursor_NotImplemented); - WriteUnsigned(OS, /*Priority=*/I); - WriteUnsigned(OS, /*Availability=*/CXAvailability_Available); - CodeCompletionString *CCS - = Candidates[I].CreateSignatureString(CurrentArg, SemaRef); - assert(CCS && "No code-completion string?"); - CCS->Serialize(OS); - delete CCS; - } -} diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index b46e8af..bc289ec 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -23,8 +23,8 @@ using namespace clang; static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc, - SourceManager &SrcMgr, unsigned DiagID) { - return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID); + unsigned DiagID) { + return D.Report(Loc, DiagID); } @@ -46,11 +46,14 @@ void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) { /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. -DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, +DeclaratorChunk DeclaratorChunk::getFunction(const ParsedAttributes &attrs, + bool hasProto, bool isVariadic, SourceLocation EllipsisLoc, ParamInfo *ArgInfo, unsigned NumArgs, unsigned TypeQuals, + bool RefQualifierIsLvalueRef, + SourceLocation RefQualifierLoc, bool hasExceptionSpec, SourceLocation ThrowLoc, bool hasAnyExceptionSpec, @@ -59,11 +62,13 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, unsigned NumExceptions, SourceLocation LPLoc, SourceLocation RPLoc, - Declarator &TheDeclarator) { + Declarator &TheDeclarator, + ParsedType TrailingReturnType) { DeclaratorChunk I; I.Kind = Function; I.Loc = LPLoc; I.EndLoc = RPLoc; + I.Fun.AttrList = attrs.getList(); I.Fun.hasPrototype = hasProto; I.Fun.isVariadic = isVariadic; I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); @@ -71,11 +76,14 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, I.Fun.TypeQuals = TypeQuals; I.Fun.NumArgs = NumArgs; I.Fun.ArgInfo = 0; + I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef; + I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); I.Fun.hasExceptionSpec = hasExceptionSpec; I.Fun.ThrowLoc = ThrowLoc.getRawEncoding(); I.Fun.hasAnyExceptionSpec = hasAnyExceptionSpec; I.Fun.NumExceptions = NumExceptions; I.Fun.Exceptions = 0; + I.Fun.TrailingReturnType = TrailingReturnType.getAsOpaquePtr(); // new[] an argument array if needed. if (NumArgs) { @@ -218,7 +226,25 @@ const char *DeclSpec::getSpecifierName(TQ T) { bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID) { + unsigned &DiagID, + const LangOptions &Lang) { + // OpenCL prohibits extern, auto, register, and static + // It seems sensible to prohibit private_extern too + if (Lang.OpenCL) { + switch (S) { + case SCS_extern: + case SCS_private_extern: + case SCS_auto: + case SCS_register: + case SCS_static: + DiagID = diag::err_not_opencl_storage_class_specifier; + PrevSpec = getSpecifierName(S); + return true; + default: + break; + } + } + if (StorageClassSpec != SCS_unspecified) { // Changing storage class is allowed only if the previous one // was the 'extern' that is part of a linkage specification and @@ -481,7 +507,7 @@ void DeclSpec::SaveWrittenBuiltinSpecs() { writtenBS.Type = getTypeSpecType(); // Search the list of attributes for the presence of a mode attribute. writtenBS.ModeAttr = false; - AttributeList* attrs = getAttributes(); + AttributeList* attrs = getAttributes().getList(); while (attrs) { if (attrs->getKind() == AttributeList::AT_mode) { writtenBS.ModeAttr = true; @@ -510,28 +536,27 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { SaveStorageSpecifierAsWritten(); // Check the type specifier components first. - SourceManager &SrcMgr = PP.getSourceManager(); // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { if (TypeAltiVecBool) { // Sign specifiers are not allowed with vector bool. (PIM 2.1) if (TypeSpecSign != TSS_unspecified) { - Diag(D, TSSLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) + Diag(D, TSSLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSS)TypeSpecSign); } // Only char/int are valid with vector bool. (PIM 2.1) if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) && (TypeSpecType != TST_int)) || TypeAltiVecPixel) { - Diag(D, TSTLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) + Diag(D, TSTLoc, diag::err_invalid_vector_bool_decl_spec) << (TypeAltiVecPixel ? "__pixel" : getSpecifierName((TST)TypeSpecType)); } // Only 'short' is valid with vector bool. (PIM 2.1) if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short)) - Diag(D, TSWLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) + Diag(D, TSWLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSW)TypeSpecWidth); // Elements of vector bool are interpreted as unsigned. (PIM 2.1) @@ -555,7 +580,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_char && TypeSpecType != TST_wchar) { - Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec) + Diag(D, TSSLoc, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType); // signed double -> double. TypeSpecSign = TSS_unspecified; @@ -570,7 +595,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { - Diag(D, TSWLoc, SrcMgr, + Diag(D, TSWLoc, TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec : diag::err_invalid_longlong_spec) << getSpecifierName((TST)TypeSpecType); @@ -582,7 +607,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { - Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec) + Diag(D, TSWLoc, diag::err_invalid_long_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; TypeSpecOwned = false; @@ -594,16 +619,16 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { - Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex) + Diag(D, TSCLoc, diag::ext_plain_complex) << FixItHint::CreateInsertion( PP.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. - Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex); + Diag(D, TSTLoc, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { - Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec) + Diag(D, TSCLoc, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecComplex = TSC_unspecified; } @@ -619,7 +644,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { SourceLocation SCLoc = getStorageClassSpecLoc(); SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName)); - Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec) + Diag(D, SCLoc, diag::err_friend_storage_spec) << SpecName << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); @@ -665,3 +690,58 @@ void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, EndLocation = SymbolLocations[I]; } } + +bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, + const char *&PrevSpec) { + if (Specifiers & VS) { + PrevSpec = getSpecifierName(VS); + return true; + } + + Specifiers |= VS; + + switch (VS) { + default: assert(0 && "Unknown specifier!"); + case VS_Override: VS_overrideLoc = Loc; break; + case VS_Final: VS_finalLoc = Loc; break; + case VS_New: VS_newLoc = Loc; break; + } + + return false; +} + +const char *VirtSpecifiers::getSpecifierName(Specifier VS) { + switch (VS) { + default: assert(0 && "Unknown specifier"); + case VS_Override: return "override"; + case VS_Final: return "final"; + case VS_New: return "new"; + } +} + +bool ClassVirtSpecifiers::SetSpecifier(Specifier CVS, SourceLocation Loc, + const char *&PrevSpec) { + if (Specifiers & CVS) { + PrevSpec = getSpecifierName(CVS); + return true; + } + + Specifiers |= CVS; + + switch (CVS) { + default: assert(0 && "Unknown specifier!"); + case CVS_Final: CVS_finalLoc = Loc; break; + case CVS_Explicit: CVS_explicitLoc = Loc; break; + } + + return false; +} + +const char *ClassVirtSpecifiers::getSpecifierName(Specifier CVS) { + switch (CVS) { + default: assert(0 && "Unknown specifier"); + case CVS_Final: return "final"; + case CVS_Explicit: return "explicit"; + } +} + diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index b23f615..b73f0e9 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -62,7 +62,7 @@ class JumpScopeChecker { llvm::SmallVector<Stmt*, 16> Jumps; llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps; - llvm::SmallVector<LabelStmt*, 4> IndirectJumpTargets; + llvm::SmallVector<LabelDecl*, 4> IndirectJumpTargets; public: JumpScopeChecker(Stmt *Body, Sema &S); private: @@ -71,7 +71,7 @@ private: void VerifyJumps(); void VerifyIndirectJumps(); void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope, - LabelStmt *Target, unsigned TargetScope); + LabelDecl *Target, unsigned TargetScope); void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, unsigned JumpDiag); @@ -186,6 +186,17 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { break; case Stmt::IndirectGotoStmtClass: + // "goto *&&lbl;" is a special case which we treat as equivalent + // to a normal goto. In addition, we don't calculate scope in the + // operand (to avoid recording the address-of-label use), which + // works only because of the restricted set of expressions which + // we detect as constant targets. + if (cast<IndirectGotoStmt>(S)->getConstantTarget()) { + LabelAndGotoScopes[S] = ParentScope; + Jumps.push_back(S); + return; + } + LabelAndGotoScopes[S] = ParentScope; IndirectJumps.push_back(cast<IndirectGotoStmt>(S)); break; @@ -210,8 +221,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { break; } - for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; - ++CI) { + for (Stmt::child_range CI = S->children(); CI; ++CI) { if (SkipFirstSubStmt) { SkipFirstSubStmt = false; continue; @@ -225,12 +235,12 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // order to avoid blowing out the stack. while (true) { Stmt *Next; - if (isa<CaseStmt>(SubStmt)) - Next = cast<CaseStmt>(SubStmt)->getSubStmt(); - else if (isa<DefaultStmt>(SubStmt)) - Next = cast<DefaultStmt>(SubStmt)->getSubStmt(); - else if (isa<LabelStmt>(SubStmt)) - Next = cast<LabelStmt>(SubStmt)->getSubStmt(); + if (CaseStmt *CS = dyn_cast<CaseStmt>(SubStmt)) + Next = CS->getSubStmt(); + else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SubStmt)) + Next = DS->getSubStmt(); + else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt)) + Next = LS->getSubStmt(); else break; @@ -336,7 +346,15 @@ void JumpScopeChecker::VerifyJumps() { // With a goto, if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { - CheckJump(GS, GS->getLabel(), GS->getGotoLoc(), + CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), + diag::err_goto_into_protected_scope); + continue; + } + + // We only get indirect gotos here when they have a constant target. + if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) { + LabelDecl *Target = IGS->getConstantTarget(); + CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(), diag::err_goto_into_protected_scope); continue; } @@ -406,15 +424,15 @@ void JumpScopeChecker::VerifyIndirectJumps() { // Collect a single representative of every scope containing a // label whose address was taken somewhere in the function. // For most code bases, there will be only one such scope. - llvm::DenseMap<unsigned, LabelStmt*> TargetScopes; - for (llvm::SmallVectorImpl<LabelStmt*>::iterator + llvm::DenseMap<unsigned, LabelDecl*> TargetScopes; + for (llvm::SmallVectorImpl<LabelDecl*>::iterator I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); I != E; ++I) { - LabelStmt *TheLabel = *I; - assert(LabelAndGotoScopes.count(TheLabel) && + LabelDecl *TheLabel = *I; + assert(LabelAndGotoScopes.count(TheLabel->getStmt()) && "Referenced label didn't get added to scopes?"); - unsigned LabelScope = LabelAndGotoScopes[TheLabel]; - LabelStmt *&Target = TargetScopes[LabelScope]; + unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()]; + LabelDecl *&Target = TargetScopes[LabelScope]; if (!Target) Target = TheLabel; } @@ -427,10 +445,10 @@ void JumpScopeChecker::VerifyIndirectJumps() { // entered, then verify that every jump scope can be trivially // exitted to reach a scope in S. llvm::BitVector Reachable(Scopes.size(), false); - for (llvm::DenseMap<unsigned,LabelStmt*>::iterator + for (llvm::DenseMap<unsigned,LabelDecl*>::iterator TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) { unsigned TargetScope = TI->first; - LabelStmt *TargetLabel = TI->second; + LabelDecl *TargetLabel = TI->second; Reachable.reset(); @@ -493,12 +511,12 @@ void JumpScopeChecker::VerifyIndirectJumps() { /// Diagnose an indirect jump which is known to cross scopes. void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, unsigned JumpScope, - LabelStmt *Target, + LabelDecl *Target, unsigned TargetScope) { assert(JumpScope != TargetScope); - S.Diag(Jump->getGotoLoc(), diag::warn_indirect_goto_in_protected_scope); - S.Diag(Target->getIdentLoc(), diag::note_indirect_goto_target); + S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); + S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target); unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 17817d4..23a3c24 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -19,7 +19,9 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/APFloat.h" #include "clang/Sema/CXXFieldCollector.h" +#include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" @@ -29,6 +31,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/AST/StmtCXX.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" @@ -37,15 +40,14 @@ using namespace sema; FunctionScopeInfo::~FunctionScopeInfo() { } -void FunctionScopeInfo::Clear(unsigned NumErrors) { +void FunctionScopeInfo::Clear() { HasBranchProtectedScope = false; HasBranchIntoScope = false; HasIndirectGoto = false; - LabelMap.clear(); SwitchStack.clear(); Returns.clear(); - NumErrorsAtStartOfFunction = NumErrors; + ErrorTrap.reset(); } BlockScopeInfo::~BlockScopeInfo() { } @@ -129,15 +131,18 @@ void Sema::ActOnTranslationUnitScope(Scope *S) { Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, bool CompleteTranslationUnit, CodeCompleteConsumer *CodeCompleter) - : TheTargetAttributesSema(0), + : TheTargetAttributesSema(0), FPFeatures(pp.getLangOptions()), LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), - PackContext(0), VisContext(0), ParsingDeclDepth(0), - IdResolver(pp.getLangOptions()), GlobalNewDeleteDeclared(false), + PackContext(0), VisContext(0), + IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0), + GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), - NumSFINAEErrors(0), SuppressAccessChecking(false), - NonInstantiationEntries(0), CurrentInstantiationScope(0), TyposCorrected(0), + NumSFINAEErrors(0), SuppressAccessChecking(false), + AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), + NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), + CurrentInstantiationScope(0), TyposCorrected(0), AnalysisWarnings(*this) { TUScope = 0; @@ -151,7 +156,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ExprEvalContexts.push_back( ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); - FunctionScopes.push_back(new FunctionScopeInfo(Diags.getNumErrors())); + FunctionScopes.push_back(new FunctionScopeInfo(Diags)); } void Sema::Initialize() { @@ -201,15 +206,6 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, if (ExprTy == TypeTy) return; - if (Expr->getType()->isPointerType() && Ty->isPointerType()) { - QualType ExprBaseType = cast<PointerType>(ExprTy)->getPointeeType(); - QualType BaseType = cast<PointerType>(TypeTy)->getPointeeType(); - if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) { - Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast) - << Expr->getSourceRange(); - } - } - // If this is a derived-to-base cast to a through a virtual base, we // need a vtable. if (Kind == CK_DerivedToBase && @@ -275,32 +271,103 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { return false; } +namespace { + struct UndefinedInternal { + NamedDecl *decl; + FullSourceLoc useLoc; + + UndefinedInternal(NamedDecl *decl, FullSourceLoc useLoc) + : decl(decl), useLoc(useLoc) {} + }; + + bool operator<(const UndefinedInternal &l, const UndefinedInternal &r) { + return l.useLoc.isBeforeInTranslationUnitThan(r.useLoc); + } +} + +/// checkUndefinedInternals - Check for undefined objects with internal linkage. +static void checkUndefinedInternals(Sema &S) { + if (S.UndefinedInternals.empty()) return; + + // Collect all the still-undefined entities with internal linkage. + llvm::SmallVector<UndefinedInternal, 16> undefined; + for (llvm::DenseMap<NamedDecl*,SourceLocation>::iterator + i = S.UndefinedInternals.begin(), e = S.UndefinedInternals.end(); + i != e; ++i) { + NamedDecl *decl = i->first; + + // Ignore attributes that have become invalid. + if (decl->isInvalidDecl()) continue; + + // __attribute__((weakref)) is basically a definition. + if (decl->hasAttr<WeakRefAttr>()) continue; + + if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) { + if (fn->isPure() || fn->hasBody()) + continue; + } else { + if (cast<VarDecl>(decl)->hasDefinition() != VarDecl::DeclarationOnly) + continue; + } + + // We build a FullSourceLoc so that we can sort with array_pod_sort. + FullSourceLoc loc(i->second, S.Context.getSourceManager()); + undefined.push_back(UndefinedInternal(decl, loc)); + } + + if (undefined.empty()) return; + + // Sort (in order of use site) so that we're not (as) dependent on + // the iteration order through an llvm::DenseMap. + llvm::array_pod_sort(undefined.begin(), undefined.end()); + + for (llvm::SmallVectorImpl<UndefinedInternal>::iterator + i = undefined.begin(), e = undefined.end(); i != e; ++i) { + NamedDecl *decl = i->decl; + S.Diag(decl->getLocation(), diag::warn_undefined_internal) + << isa<VarDecl>(decl) << decl; + S.Diag(i->useLoc, diag::note_used_here); + } +} + /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { // At PCH writing, implicit instantiations and VTable handling info are // stored and performed when the PCH is included. - if (CompleteTranslationUnit) - while (1) { - // C++: Perform implicit template instantiations. - // - // FIXME: When we perform these implicit instantiations, we do not - // carefully 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 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. - PerformPendingInstantiations(); - - /// If DefinedUsedVTables ends up marking any virtual member - /// functions it might lead to more pending template - /// instantiations, which is why we need to loop here. - if (!DefineUsedVTables()) - break; + if (CompleteTranslationUnit) { + // If any dynamic classes have their key function defined within + // this translation unit, then those vtables are considered "used" and must + // be emitted. + for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { + assert(!DynamicClasses[I]->isDependentType() && + "Should not see dependent types here!"); + if (const CXXMethodDecl *KeyFunction + = Context.getKeyFunction(DynamicClasses[I])) { + const FunctionDecl *Definition = 0; + if (KeyFunction->hasBody(Definition)) + MarkVTableUsed(Definition->getLocation(), DynamicClasses[I], true); + } } + + // If DefinedUsedVTables ends up marking any virtual member functions it + // might lead to more pending template instantiations, which we then need + // to instantiate. + DefineUsedVTables(); + + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not + // carefully 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 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. + PerformPendingInstantiations(); + } // Remove file scoped decls that turned out to be used. UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(), @@ -371,26 +438,32 @@ void Sema::ActOnEndOfTranslationUnit() { Consumer.CompleteTentativeDefinition(VD); } - - // Output warning for unused file scoped decls. - for (llvm::SmallVectorImpl<const DeclaratorDecl*>::iterator - I = UnusedFileScopedDecls.begin(), - E = UnusedFileScopedDecls.end(); I != E; ++I) { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { - const FunctionDecl *DiagD; - if (!FD->hasBody(DiagD)) - DiagD = FD; - Diag(DiagD->getLocation(), - isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function - : diag::warn_unused_function) - << DiagD->getDeclName(); - } else { - const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition(); - if (!DiagD) - DiagD = cast<VarDecl>(*I); - Diag(DiagD->getLocation(), diag::warn_unused_variable) - << DiagD->getDeclName(); + + // If there were errors, disable 'unused' warnings since they will mostly be + // noise. + if (!Diags.hasErrorOccurred()) { + // Output warning for unused file scoped decls. + for (llvm::SmallVectorImpl<const DeclaratorDecl*>::iterator + I = UnusedFileScopedDecls.begin(), + E = UnusedFileScopedDecls.end(); I != E; ++I) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { + const FunctionDecl *DiagD; + if (!FD->hasBody(DiagD)) + DiagD = FD; + Diag(DiagD->getLocation(), + isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function + : diag::warn_unused_function) + << DiagD->getDeclName(); + } else { + const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition(); + if (!DiagD) + DiagD = cast<VarDecl>(*I); + Diag(DiagD->getLocation(), diag::warn_unused_variable) + << DiagD->getDeclName(); + } } + + checkUndefinedInternals(*this); } TUScope = 0; @@ -431,6 +504,50 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() { } Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { + if (!isActive()) + return; + + if (llvm::Optional<TemplateDeductionInfo*> Info = SemaRef.isSFINAEContext()) { + switch (DiagnosticIDs::getDiagnosticSFINAEResponse(getDiagID())) { + case DiagnosticIDs::SFINAE_Report: + // Fall through; we'll report the diagnostic below. + break; + + case DiagnosticIDs::SFINAE_AccessControl: + // Unless access checking is specifically called out as a SFINAE + // error, report this diagnostic. + if (!SemaRef.AccessCheckingSFINAE) + break; + + case DiagnosticIDs::SFINAE_SubstitutionFailure: + // Count this failure so that we know that template argument deduction + // has failed. + ++SemaRef.NumSFINAEErrors; + SemaRef.Diags.setLastDiagnosticIgnored(); + SemaRef.Diags.Clear(); + Clear(); + return; + + case DiagnosticIDs::SFINAE_Suppress: + // Make a copy of this suppressed diagnostic and store it with the + // template-deduction information; + FlushCounts(); + DiagnosticInfo DiagInfo(&SemaRef.Diags); + + if (*Info) + (*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(), + PartialDiagnostic(DiagInfo, + SemaRef.Context.getDiagAllocator())); + + // Suppress this diagnostic. + SemaRef.Diags.setLastDiagnosticIgnored(); + SemaRef.Diags.Clear(); + Clear(); + return; + } + } + + // Emit the diagnostic. if (!this->Emit()) return; @@ -438,7 +555,7 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { // that is different from the last template instantiation where // we emitted an error, print a template instantiation // backtrace. - if (!SemaRef.Diags.isBuiltinNote(DiagID) && + if (!DiagnosticIDs::isBuiltinNote(DiagID) && !SemaRef.ActiveTemplateInstantiations.empty() && SemaRef.ActiveTemplateInstantiations.back() != SemaRef.LastTemplateInstantiationErrorContext) { @@ -449,26 +566,7 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { } Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID) { - if (isSFINAEContext()) { - switch (Diagnostic::getDiagnosticSFINAEResponse(DiagID)) { - case Diagnostic::SFINAE_Report: - // Fall through; we'll report the diagnostic below. - break; - - case Diagnostic::SFINAE_SubstitutionFailure: - // Count this failure so that we know that template argument deduction - // has failed. - ++NumSFINAEErrors; - // Fall through - - case Diagnostic::SFINAE_Suppress: - // Suppress this diagnostic. - Diags.setLastDiagnosticIgnored(); - return SemaDiagnosticBuilder(*this); - } - } - - DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); + DiagnosticBuilder DB = Diags.Report(Loc, DiagID); return SemaDiagnosticBuilder(DB, *this, DiagID); } @@ -514,17 +612,16 @@ void Sema::PushFunctionScope() { if (FunctionScopes.size() == 1) { // Use the "top" function scope rather than having to allocate // memory for a new scope. - FunctionScopes.back()->Clear(getDiagnostics().getNumErrors()); + FunctionScopes.back()->Clear(); FunctionScopes.push_back(FunctionScopes.back()); return; } - FunctionScopes.push_back( - new FunctionScopeInfo(getDiagnostics().getNumErrors())); + FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics())); } void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) { - FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics().getNumErrors(), + FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics(), BlockScope, Block)); } @@ -538,8 +635,7 @@ void Sema::PopFunctionOrBlockScope() { /// \brief Determine whether any errors occurred within this function/method/ /// block. bool Sema::hasAnyErrorsInThisFunction() const { - return getCurFunction()->NumErrorsAtStartOfFunction - != getDiagnostics().getNumErrors(); + return getCurFunction()->ErrorTrap.hasErrorOccurred(); } BlockScopeInfo *Sema::getCurBlock() { @@ -552,6 +648,11 @@ BlockScopeInfo *Sema::getCurBlock() { // Pin this vtable to this file. ExternalSemaSource::~ExternalSemaSource() {} +std::pair<ObjCMethodList, ObjCMethodList> +ExternalSemaSource::ReadMethodPool(Selector Sel) { + return std::pair<ObjCMethodList, ObjCMethodList>(); +} + void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const { SourceLocation Loc = this->Loc; if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation(); diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index e629f0f..4f9bf1c 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -134,7 +134,7 @@ struct EffectiveContext { bool Dependent; }; -/// Like sema:;AccessedEntity, but kindly lets us scribble all over +/// Like sema::AccessedEntity, but kindly lets us scribble all over /// it. struct AccessTarget : public AccessedEntity { AccessTarget(const AccessedEntity &Entity) @@ -516,6 +516,11 @@ static AccessResult MatchesFriend(Sema &S, static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, FriendDecl *FriendD) { + // Whitelist accesses if there's an invalid or unsupported friend + // declaration. + if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend()) + return AR_accessible; + if (TypeSourceInfo *T = FriendD->getFriendType()) return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); @@ -1003,9 +1008,51 @@ static void DiagnoseAccessPath(Sema &S, TryDiagnoseProtectedAccess(S, EC, Entity)) return; + // Find an original declaration. + while (D->isOutOfLine()) { + NamedDecl *PrevDecl = 0; + if (isa<VarDecl>(D)) + PrevDecl = cast<VarDecl>(D)->getPreviousDeclaration(); + else if (isa<FunctionDecl>(D)) + PrevDecl = cast<FunctionDecl>(D)->getPreviousDeclaration(); + else if (isa<TypedefDecl>(D)) + PrevDecl = cast<TypedefDecl>(D)->getPreviousDeclaration(); + else if (isa<TagDecl>(D)) { + if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName()) + break; + PrevDecl = cast<TagDecl>(D)->getPreviousDeclaration(); + } + if (!PrevDecl) break; + D = PrevDecl; + } + + CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); + Decl *ImmediateChild; + if (D->getDeclContext() == DeclaringClass) + ImmediateChild = D; + else { + DeclContext *DC = D->getDeclContext(); + while (DC->getParent() != DeclaringClass) + DC = DC->getParent(); + ImmediateChild = cast<Decl>(DC); + } + + // Check whether there's an AccessSpecDecl preceding this in the + // chain of the DeclContext. + bool Implicit = true; + for (CXXRecordDecl::decl_iterator + I = DeclaringClass->decls_begin(), E = DeclaringClass->decls_end(); + I != E; ++I) { + if (*I == ImmediateChild) break; + if (isa<AccessSpecDecl>(*I)) { + Implicit = false; + break; + } + } + S.Diag(D->getLocation(), diag::note_access_natural) << (unsigned) (Access == AS_protected) - << /*FIXME: not implicitly*/ 0; + << Implicit; return; } @@ -1213,13 +1260,19 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, if (S.SuppressAccessChecking) return Sema::AR_accessible; - // If we're currently parsing a top-level declaration, delay - // diagnostics. This is the only case where parsing a declaration - // can actually change our effective context for the purposes of - // access control. - if (S.CurContext->isFileContext() && S.ParsingDeclDepth) { - S.DelayedDiagnostics.push_back( - DelayedDiagnostic::makeAccess(Loc, Entity)); + // If we're currently parsing a declaration, we may need to delay + // access control checking, because our effective context might be + // different based on what the declaration comes out as. + // + // For example, we might be parsing a declaration with a scope + // specifier, like this: + // A::private_type A::foo() { ... } + // + // Or we might be parsing something that will turn out to be a friend: + // void foo(A::private_type); + // void B::foo(A::private_type); + if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { + S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity)); return Sema::AR_delayed; } @@ -1233,16 +1286,20 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, return Sema::AR_accessible; } -void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { - // Pretend we did this from the context of the newly-parsed - // declaration. If that declaration itself forms a declaration context, - // include it in the effective context so that parameters and return types of - // befriended functions have that function's access priveledges. - DeclContext *DC = Ctx->getDeclContext(); - if (isa<FunctionDecl>(Ctx)) - DC = cast<DeclContext>(Ctx); - else if (FunctionTemplateDecl *FnTpl = dyn_cast<FunctionTemplateDecl>(Ctx)) - DC = cast<DeclContext>(FnTpl->getTemplatedDecl()); +void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *decl) { + // Access control for names used in the declarations of functions + // and function templates should normally be evaluated in the context + // of the declaration, just in case it's a friend of something. + // However, this does not apply to local extern declarations. + + DeclContext *DC = decl->getDeclContext(); + if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) { + if (!DC->isFunctionOrMethod()) DC = fn; + } else if (FunctionTemplateDecl *fnt = dyn_cast<FunctionTemplateDecl>(decl)) { + // Never a local declaration. + DC = fnt->getTemplatedDecl(); + } + EffectiveContext EC(DC); AccessTarget Target(DD.getAccessData()); diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 0921156..794b0b1 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -263,37 +263,35 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, } } -void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers, - Scope *curScope, - SourceLocation PragmaLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { - - for (unsigned i = 0; i < NumIdentifiers; ++i) { - const Token &Tok = Identifiers[i]; - IdentifierInfo *Name = Tok.getIdentifierInfo(); - LookupResult Lookup(*this, Name, Tok.getLocation(), LookupOrdinaryName); - LookupParsedName(Lookup, curScope, NULL, true); - - if (Lookup.empty()) { - Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var) - << Name << SourceRange(Tok.getLocation()); - continue; - } +void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, + SourceLocation PragmaLoc) { - VarDecl *VD = Lookup.getAsSingle<VarDecl>(); - if (!VD || !VD->hasLocalStorage()) { - Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar) - << Name << SourceRange(Tok.getLocation()); - continue; - } + IdentifierInfo *Name = IdTok.getIdentifierInfo(); + LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName); + LookupParsedName(Lookup, curScope, NULL, true); + + if (Lookup.empty()) { + Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var) + << Name << SourceRange(IdTok.getLocation()); + return; + } - VD->addAttr(::new (Context) UnusedAttr(Tok.getLocation(), Context)); + VarDecl *VD = Lookup.getAsSingle<VarDecl>(); + if (!VD) { + Diag(PragmaLoc, diag::warn_pragma_unused_expected_var_arg) + << Name << SourceRange(IdTok.getLocation()); + return; } + + // Warn if this was used before being marked unused. + if (VD->isUsed()) + Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name; + + VD->addAttr(::new (Context) UnusedAttr(IdTok.getLocation(), Context)); } -typedef std::vector<std::pair<VisibilityAttr::VisibilityType, - SourceLocation> > VisStack; +typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack; +enum { NoVisibility = (unsigned) -1 }; void Sema::AddPushedVisibilityAttribute(Decl *D) { if (!VisContext) @@ -303,7 +301,11 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) { return; VisStack *Stack = static_cast<VisStack*>(VisContext); - VisibilityAttr::VisibilityType type = Stack->back().first; + unsigned rawType = Stack->back().first; + if (rawType == NoVisibility) return; + + VisibilityAttr::VisibilityType type + = (VisibilityAttr::VisibilityType) rawType; SourceLocation loc = Stack->back().second; D->addAttr(::new (Context) VisibilityAttr(loc, Context, type)); @@ -315,8 +317,7 @@ void Sema::FreeVisContext() { VisContext = 0; } -static void PushPragmaVisibility(Sema &S, VisibilityAttr::VisibilityType type, - SourceLocation loc) { +static void PushPragmaVisibility(Sema &S, unsigned type, SourceLocation loc) { // Put visibility on stack. if (!S.VisContext) S.VisContext = new VisStack; @@ -349,8 +350,26 @@ void Sema::ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType, } } -void Sema::PushVisibilityAttr(const VisibilityAttr *Attr) { - PushPragmaVisibility(*this, Attr->getVisibility(), Attr->getLocation()); +void Sema::ActOnPragmaFPContract(tok::OnOffSwitch OOS) { + switch (OOS) { + case tok::OOS_ON: + FPFeatures.fp_contract = 1; + break; + case tok::OOS_OFF: + FPFeatures.fp_contract = 0; + break; + case tok::OOS_DEFAULT: + FPFeatures.fp_contract = getLangOptions().DefaultFPContract; + break; + } +} + +void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr) { + // Visibility calculations will consider the namespace's visibility. + // Here we just want to note that we're in a visibility context + // which overrides any enclosing #pragma context, but doesn't itself + // contribute visibility. + PushPragmaVisibility(*this, NoVisibility, SourceLocation()); } void Sema::PopPragmaVisibility() { diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 21b1a73..506d261 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -21,6 +21,8 @@ #include <set> using namespace clang; + + enum TryCastResult { TC_NotApplicable, ///< The cast method is not applicable. TC_Success, ///< The cast method is appropriate and successful. @@ -37,18 +39,25 @@ enum CastType { CT_Functional ///< Type(expr) }; + + + static void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange); static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange, CastKind &Kind); static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + ExprValueKind &VK, const SourceRange &OpRange, CastKind &Kind, CXXCastPath &BasePath); static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange, CastKind &Kind, @@ -68,7 +77,10 @@ static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); // %1: Source Type // %2: Destination Type static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, - QualType DestType, unsigned &msg); + QualType DestType, bool CStyle, + CastKind &Kind, + CXXCastPath &BasePath, + unsigned &msg); static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, @@ -109,12 +121,24 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, CXXCastPath &BasePath); static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, unsigned &msg); -static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, +static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastKind &Kind); + +static ExprResult +ResolveAndFixSingleFunctionTemplateSpecialization( + Sema &Self, Expr *SrcExpr, + bool DoFunctionPointerConverion = false, + bool Complain = false, + const SourceRange& OpRangeForComplaining = SourceRange(), + QualType DestTypeForComplaining = QualType(), + unsigned DiagIDForComplaining = 0); + + + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. ExprResult Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, @@ -146,51 +170,147 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, // FIXME: should we check this in a more fine-grained manner? bool TypeDependent = DestType->isDependentType() || Ex->isTypeDependent(); + if (Ex->isBoundMemberFunction(Context)) + Diag(Ex->getLocStart(), diag::err_invalid_use_of_bound_member_func) + << Ex->getSourceRange(); + + ExprValueKind VK = VK_RValue; + if (TypeDependent) + VK = Expr::getValueKindForType(DestType); + switch (Kind) { - default: assert(0 && "Unknown C++ cast!"); + default: llvm_unreachable("Unknown C++ cast!"); case tok::kw_const_cast: if (!TypeDependent) - CheckConstCast(*this, Ex, DestType, OpRange, DestRange); + CheckConstCast(*this, Ex, DestType, VK, OpRange, DestRange); return Owned(CXXConstCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - Ex, DestTInfo, OpLoc)); + VK, Ex, DestTInfo, OpLoc, + Parens.getEnd())); case tok::kw_dynamic_cast: { - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Dependent; CXXCastPath BasePath; if (!TypeDependent) - CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind, BasePath); + CheckDynamicCast(*this, Ex, DestType, VK, OpRange, DestRange, + Kind, BasePath); return Owned(CXXDynamicCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - Kind, Ex, &BasePath, DestTInfo, - OpLoc)); + VK, Kind, Ex, &BasePath, DestTInfo, + OpLoc, Parens.getEnd())); } case tok::kw_reinterpret_cast: { - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Dependent; if (!TypeDependent) - CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind); + CheckReinterpretCast(*this, Ex, DestType, VK, OpRange, DestRange, Kind); return Owned(CXXReinterpretCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - Kind, Ex, 0, - DestTInfo, OpLoc)); + VK, Kind, Ex, 0, + DestTInfo, OpLoc, Parens.getEnd())); } case tok::kw_static_cast: { - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Dependent; CXXCastPath BasePath; if (!TypeDependent) - CheckStaticCast(*this, Ex, DestType, OpRange, Kind, BasePath); + CheckStaticCast(*this, Ex, DestType, VK, OpRange, Kind, BasePath); return Owned(CXXStaticCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - Kind, Ex, &BasePath, - DestTInfo, OpLoc)); + VK, Kind, Ex, &BasePath, + DestTInfo, OpLoc, Parens.getEnd())); } } return ExprError(); } +/// Try to diagnose a failed overloaded cast. Returns true if +/// diagnostics were emitted. +static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, + SourceRange range, Expr *src, + QualType destType) { + switch (CT) { + // These cast kinds don't consider user-defined conversions. + case CT_Const: + case CT_Reinterpret: + case CT_Dynamic: + return false; + + // These do. + case CT_Static: + case CT_CStyle: + case CT_Functional: + break; + } + + QualType srcType = src->getType(); + if (!destType->isRecordType() && !srcType->isRecordType()) + return false; + + InitializedEntity entity = InitializedEntity::InitializeTemporary(destType); + InitializationKind initKind + = InitializationKind::CreateCast(/*type range?*/ range, + (CT == CT_CStyle || CT == CT_Functional)); + InitializationSequence sequence(S, entity, initKind, &src, 1); + + assert(sequence.getKind() == InitializationSequence::FailedSequence && + "initialization succeeded on second try?"); + switch (sequence.getFailureKind()) { + default: return false; + + case InitializationSequence::FK_ConstructorOverloadFailed: + case InitializationSequence::FK_UserConversionOverloadFailed: + break; + } + + OverloadCandidateSet &candidates = sequence.getFailedCandidateSet(); + + unsigned msg = 0; + OverloadCandidateDisplayKind howManyCandidates = OCD_AllCandidates; + + switch (sequence.getFailedOverloadResult()) { + case OR_Success: llvm_unreachable("successful failed overload"); + return false; + case OR_No_Viable_Function: + if (candidates.empty()) + msg = diag::err_ovl_no_conversion_in_cast; + else + msg = diag::err_ovl_no_viable_conversion_in_cast; + howManyCandidates = OCD_AllCandidates; + break; + + case OR_Ambiguous: + msg = diag::err_ovl_ambiguous_conversion_in_cast; + howManyCandidates = OCD_ViableCandidates; + break; + + case OR_Deleted: + msg = diag::err_ovl_deleted_conversion_in_cast; + howManyCandidates = OCD_ViableCandidates; + break; + } + + S.Diag(range.getBegin(), msg) + << CT << srcType << destType + << range << src->getSourceRange(); + + candidates.NoteCandidates(S, howManyCandidates, &src, 1); + + return true; +} + +/// Diagnose a failed cast. +static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, + SourceRange opRange, Expr *src, QualType destType) { + if (msg == diag::err_bad_cxx_cast_generic && + tryDiagnoseOverloadedCast(S, castType, opRange, src, destType)) + return; + + S.Diag(opRange.getBegin(), msg) << castType + << src->getType() << destType << opRange << src->getSourceRange(); +} + /// UnwrapDissimilarPointerTypes - Like Sema::UnwrapSimilarPointerTypes, /// this removes one level of indirection from both types, provided that they're /// the same kind of pointer (plain or to-member). Unlike the Sema function, @@ -297,7 +417,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { // Test if they're compatible. return SrcConstruct != DestConstruct && - !Self.IsQualificationConversion(SrcConstruct, DestConstruct); + !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false); } /// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. @@ -305,7 +425,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { /// checked downcasts in class hierarchies. static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, - const SourceRange &OpRange, + ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange, CastKind &Kind, CXXCastPath &BasePath) { QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); @@ -316,11 +436,14 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, QualType DestPointee; const PointerType *DestPointer = DestType->getAs<PointerType>(); - const ReferenceType *DestReference = DestType->getAs<ReferenceType>(); + const ReferenceType *DestReference = 0; if (DestPointer) { DestPointee = DestPointer->getPointeeType(); - } else if (DestReference) { + } else if ((DestReference = DestType->getAs<ReferenceType>())) { DestPointee = DestReference->getPointeeType(); + VK = isa<LValueReferenceType>(DestReference) ? VK_LValue + : isa<RValueReferenceType>(DestReference) ? VK_XValue + : VK_RValue; } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) << OrigDestType << DestRange; @@ -343,10 +466,8 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // 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, - // [...] - + // an lvalue of a complete class type, [...]. If T is an rvalue reference + // type, v shall be an expression having a complete class type, [...] QualType SrcType = Self.Context.getCanonicalType(OrigSrcType); QualType SrcPointee; if (DestPointer) { @@ -358,7 +479,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, return; } } else if (DestReference->isLValueReferenceType()) { - if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { + if (!SrcExpr->isLValue()) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; } @@ -437,9 +558,10 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /// const char *str = "literal"; /// legacy_function(const_cast\<char*\>(str)); void -CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, +CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange) { - if (!DestType->isLValueReferenceType()) + VK = Expr::getValueKindForType(DestType); + if (VK == VK_RValue) Self.DefaultFunctionArrayLvalueConversion(SrcExpr); unsigned msg = diag::err_bad_cxx_cast_generic; @@ -456,17 +578,28 @@ CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /// char *bytes = reinterpret_cast\<char*\>(int_ptr); void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, - const SourceRange &OpRange, const SourceRange &DestRange, - CastKind &Kind) { - if (!DestType->isLValueReferenceType()) + ExprValueKind &VK, const SourceRange &OpRange, + const SourceRange &DestRange, CastKind &Kind) { + VK = Expr::getValueKindForType(DestType); + if (VK == VK_RValue) Self.DefaultFunctionArrayLvalueConversion(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; + { + if (SrcExpr->getType() == Self.Context.OverloadTy) { + //FIXME: &f<int>; is overloaded and resolvable + Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_overload) + << OverloadExpr::find(SrcExpr).Expression->getName() + << DestType << OpRange; + Self.NoteAllOverloadCandidates(SrcExpr); + + } else { + diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr, DestType); + } + } } @@ -475,25 +608,47 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /// implicit conversions explicit and getting rid of data loss warnings. void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, - const SourceRange &OpRange, CastKind &Kind, - CXXCastPath &BasePath) { + ExprValueKind &VK, const SourceRange &OpRange, + CastKind &Kind, CXXCastPath &BasePath) { // 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()) { - Kind = CK_ToVoid; + Self.IgnoredValueConversions(SrcExpr); + if (SrcExpr->getType() == Self.Context.OverloadTy) { + ExprResult SingleFunctionExpression = + ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr, + false, // Decay Function to ptr + true, // Complain + OpRange, DestType, diag::err_bad_static_cast_overload); + if (SingleFunctionExpression.isUsable()) + { + SrcExpr = SingleFunctionExpression.release(); + Kind = CK_ToVoid; + } + } + else + Kind = CK_ToVoid; return; } - if (!DestType->isLValueReferenceType() && !DestType->isRecordType()) + VK = Expr::getValueKindForType(DestType); + if (VK == VK_RValue && !DestType->isRecordType()) Self.DefaultFunctionArrayLvalueConversion(SrcExpr); unsigned msg = diag::err_bad_cxx_cast_generic; if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg, - Kind, BasePath) != TC_Success && msg != 0) - Self.Diag(OpRange.getBegin(), msg) << CT_Static - << SrcExpr->getType() << DestType << OpRange; - else if (Kind == CK_Unknown || Kind == CK_BitCast) + Kind, BasePath) != TC_Success && msg != 0) { + if (SrcExpr->getType() == Self.Context.OverloadTy) { + OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression; + Self.Diag(OpRange.getBegin(), diag::err_bad_static_cast_overload) + << oe->getName() << DestType << OpRange << oe->getQualifierRange(); + Self.NoteAllOverloadCandidates(SrcExpr); + } else { + diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr, DestType); + } + } + else if (Kind == CK_BitCast) Self.CheckCastAlign(SrcExpr, DestType, OpRange); } @@ -530,13 +685,13 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, 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) { - Kind = CK_NoOp; + // C++0x [expr.static.cast]p3: + // A glvalue 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, CStyle, Kind, BasePath, + 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, [...]. @@ -553,10 +708,26 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // 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()); + // C++0x 5.2.9p9: A value of a scoped enumeration type can be explicitly + // converted to an integral type. [...] A value of a scoped enumeration type + // can also be explicitly converted to a floating-point type [...]. + if (const EnumType *Enum = SrcType->getAs<EnumType>()) { + if (Enum->getDecl()->isScoped()) { + if (DestType->isBooleanType()) { + Kind = CK_IntegralToBoolean; + return TC_Success; + } else if (DestType->isIntegralType(Self.Context)) { + Kind = CK_IntegralCast; + return TC_Success; + } else if (DestType->isRealFloatingType()) { + Kind = CK_IntegralToFloating; + return TC_Success; + } + } + } + // Reverse integral promotion/conversion. All such conversions are themselves // again integral promotions or conversions and are thus already handled by // p2 (TryDirectInitialization above). @@ -623,8 +794,10 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, } // Allow arbitray objective-c pointer conversion with static casts. if (SrcType->isObjCObjectPointerType() && - DestType->isObjCObjectPointerType()) + DestType->isObjCObjectPointerType()) { + Kind = CK_BitCast; return TC_Success; + } // We tried everything. Everything! Nothing works! :-( return TC_NotApplicable; @@ -633,14 +806,16 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, /// Tests whether a conversion according to N2844 is valid. TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, + bool CStyle, CastKind &Kind, CXXCastPath &BasePath, 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". + // C++0x [expr.static.cast]p3: + // A glvalue 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) + if (!SrcExpr->isGLValue()) return TC_NotApplicable; // Because we try the reference downcast before this function, from now on @@ -648,16 +823,32 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, // FIXME: Should allow casting away constness if CStyle. bool DerivedToBase; bool ObjCConversion; + QualType FromType = SrcExpr->getType(); + QualType ToType = R->getPointeeType(); + if (CStyle) { + FromType = FromType.getUnqualifiedType(); + ToType = ToType.getUnqualifiedType(); + } + if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(), - SrcExpr->getType(), R->getPointeeType(), + ToType, FromType, DerivedToBase, ObjCConversion) < Sema::Ref_Compatible_With_Added_Qualification) { msg = diag::err_bad_lvalue_to_rvalue_cast; return TC_Failed; } - // FIXME: We should probably have an AST node for lvalue-to-rvalue - // conversions. + if (DerivedToBase) { + Kind = CK_DerivedToBase; + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/true); + if (!Self.IsDerivedFrom(SrcExpr->getType(), R->getPointeeType(), Paths)) + return TC_NotApplicable; + + Self.BuildBasePathArray(Paths, BasePath); + } else + Kind = CK_NoOp; + return TC_Success; } @@ -681,7 +872,7 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_NotApplicable; } bool RValueRef = DestReference->isRValueReferenceType(); - if (!RValueRef && SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { + if (!RValueRef && !SrcExpr->isLValue()) { // 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; @@ -818,12 +1009,20 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, return TC_Failed; } - if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(), - SrcType, DestType, - Paths.front(), + if (!CStyle) { + switch (Self.CheckBaseClassAccess(OpRange.getBegin(), + SrcType, DestType, + Paths.front(), diag::err_downcast_from_inaccessible_base)) { - msg = 0; - return TC_Failed; + case Sema::AR_accessible: + case Sema::AR_delayed: // be optimistic + case Sema::AR_dependent: // be optimistic + break; + + case Sema::AR_inaccessible: + msg = 0; + return TC_Failed; + } } Self.BuildBasePathArray(Paths, BasePath); @@ -887,7 +1086,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, Paths.setRecordingPaths(true); bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths); assert(StillOkay); - StillOkay = StillOkay; + (void)StillOkay; std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths); Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv) << 1 << SrcClass << DestClass << PathDisplayStr << OpRange; @@ -902,12 +1101,22 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, return TC_Failed; } - if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(), - DestClass, SrcClass, - Paths.front(), - diag::err_upcast_to_inaccessible_base)) { - msg = 0; - return TC_Failed; + if (!CStyle) { + switch (Self.CheckBaseClassAccess(OpRange.getBegin(), + DestClass, SrcClass, + Paths.front(), + diag::err_upcast_to_inaccessible_base)) { + case Sema::AR_accessible: + case Sema::AR_delayed: + case Sema::AR_dependent: + // Optimistically assume that the delayed and dependent cases + // will work out. + break; + + case Sema::AR_inaccessible: + msg = 0; + return TC_Failed; + } } if (WasOverloadedFunction) { @@ -951,17 +1160,19 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, } } - // 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. InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType); InitializationKind InitKind - = InitializationKind::CreateCast(/*FIXME:*/OpRange, - CStyle); + = InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle); InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1); + + // At this point of CheckStaticCast, if the destination is a reference, + // or the expression is an overload expression 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. + if (InitSeq.getKind() == InitializationSequence::FailedSequence && - (CStyle || !DestType->isReferenceType())) + (CStyle || !DestType->isReferenceType())) return TC_NotApplicable; ExprResult Result @@ -986,9 +1197,8 @@ 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) { + if (const ReferenceType *DestTypeTmp =DestType->getAs<ReferenceType>()) { + if (DestTypeTmp->isLValueReferenceType() && !SrcExpr->isLValue()) { // 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. @@ -1049,7 +1259,43 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_Success; } -static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, +// A helper function to resolve and fix an overloaded expression that +// can be resolved because it identifies a single function +// template specialization +// Last three arguments should only be supplied if Complain = true +static ExprResult ResolveAndFixSingleFunctionTemplateSpecialization( + Sema &Self, Expr *SrcExpr, + bool DoFunctionPointerConverion, + bool Complain, + const SourceRange& OpRangeForComplaining, + QualType DestTypeForComplaining, + unsigned DiagIDForComplaining) { + assert(SrcExpr->getType() == Self.Context.OverloadTy); + DeclAccessPair Found; + Expr* SingleFunctionExpression = 0; + if (FunctionDecl* Fn = Self.ResolveSingleFunctionTemplateSpecialization( + SrcExpr, false, // false -> Complain + &Found)) { + if (!Self.DiagnoseUseOfDecl(Fn, SrcExpr->getSourceRange().getBegin())) { + // mark the expression as resolved to Fn + SingleFunctionExpression = Self.FixOverloadedFunctionReference(SrcExpr, + Found, Fn); + + if (DoFunctionPointerConverion) + Self.DefaultFunctionArrayLvalueConversion(SingleFunctionExpression); + } + } + if (!SingleFunctionExpression && Complain) { + OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression; + Self.Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining) + << oe->getName() << DestTypeForComplaining << OpRangeForComplaining + << oe->getQualifierRange(); + Self.NoteAllOverloadCandidates(SrcExpr); + } + return SingleFunctionExpression; +} + +static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, @@ -1058,11 +1304,28 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, DestType = Self.Context.getCanonicalType(DestType); QualType SrcType = SrcExpr->getType(); + + // Is the source an overloaded name? (i.e. &foo) + // If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ... + if (SrcType == Self.Context.OverloadTy) { + // ... unless foo<int> resolves to an lvalue unambiguously + ExprResult SingleFunctionExpr = + ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr, + Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr + ); + if (SingleFunctionExpr.isUsable()) { + SrcExpr = SingleFunctionExpr.release(); + SrcType = SrcExpr->getType(); + } + else + return TC_NotApplicable; + } + 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. + if (LValue && !SrcExpr->isLValue()) { + // Cannot cast non-lvalue to lvalue reference type. See the similar + // comment in const_cast. msg = diag::err_bad_cxx_cast_rvalue; return TC_NotApplicable; } @@ -1073,6 +1336,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, // This code does this transformation for the checked types. DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); SrcType = Self.Context.getPointerType(SrcType); + IsLValueCast = true; } @@ -1193,6 +1457,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, 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. + // C++ 5.2.10p9: [Note: ...a null pointer constant of integral type is not + // necessarily converted to a null pointer value.] Kind = CK_IntegralToPointer; return TC_Success; } @@ -1257,26 +1523,54 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, // So we finish by allowing everything that remains - it's got to be two // object pointers. return TC_Success; -} +} bool -Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, - CastKind &Kind, +Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, + Expr *&CastExpr, CastKind &Kind, CXXCastPath &BasePath, bool FunctionalStyle) { + if (CastExpr->isBoundMemberFunction(Context)) + return Diag(CastExpr->getLocStart(), + diag::err_invalid_use_of_bound_member_func) + << CastExpr->getSourceRange(); + // 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()) { - Kind = CK_ToVoid; - return false; + IgnoredValueConversions(CastExpr); + bool ret = false; // false is 'able to convert' + if (CastExpr->getType() == Context.OverloadTy) { + ExprResult SingleFunctionExpr = + ResolveAndFixSingleFunctionTemplateSpecialization(*this, + CastExpr, + /* Decay Function to ptr */ false, + /* Complain */ true, + R, CastTy, diag::err_bad_cstyle_cast_overload); + if (SingleFunctionExpr.isUsable()) { + CastExpr = SingleFunctionExpr.release(); + Kind = CK_ToVoid; + } + else + ret = true; + } + else + Kind = CK_ToVoid; + return ret; } + // Make sure we determine the value kind before we bail out for + // dependent types. + VK = Expr::getValueKindForType(CastTy); + // If the type is dependent, we won't do any other semantic analysis now. - if (CastTy->isDependentType() || CastExpr->isTypeDependent()) + if (CastTy->isDependentType() || CastExpr->isTypeDependent()) { + Kind = CK_Dependent; return false; + } - if (!CastTy->isLValueReferenceType() && !CastTy->isRecordType()) + if (VK == VK_RValue && !CastTy->isRecordType()) DefaultFunctionArrayLvalueConversion(CastExpr); // C++ [expr.cast]p5: The conversions performed by @@ -1307,10 +1601,24 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, } } - if (tcr != TC_Success && msg != 0) - Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle) - << CastExpr->getType() << CastTy << R; - else if (Kind == CK_Unknown || Kind == CK_BitCast) + if (tcr != TC_Success && msg != 0) { + if (CastExpr->getType() == Context.OverloadTy) { + DeclAccessPair Found; + FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(CastExpr, + CastTy, + /* Complain */ true, + Found); + + assert(!Fn + && "cast failed but able to resolve overload expression!!"); + (void)Fn; + + } else { + diagnoseBadCast(*this, msg, (FunctionalStyle ? CT_Functional : CT_CStyle), + R, CastExpr, CastTy); + } + } + else if (Kind == CK_BitCast) CheckCastAlign(CastExpr, CastTy, R); return tcr != TC_Success; diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 631308e..aa0efcd 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -24,14 +24,26 @@ using namespace clang; /// \brief Find the current instantiation that associated with the given type. -static CXXRecordDecl *getCurrentInstantiationOf(QualType T) { +static CXXRecordDecl *getCurrentInstantiationOf(QualType T, + DeclContext *CurContext) { if (T.isNull()) return 0; const Type *Ty = T->getCanonicalTypeInternal().getTypePtr(); - if (isa<RecordType>(Ty)) - return cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); - else if (isa<InjectedClassNameType>(Ty)) + if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (!T->isDependentType()) + return Record; + + // This may be a member of a class template or class template partial + // specialization. If it's part of the current semantic context, then it's + // an injected-class-name; + for (; !CurContext->isFileContext(); CurContext = CurContext->getParent()) + if (CurContext->Equals(Record)) + return Record; + + return 0; + } else if (isa<InjectedClassNameType>(Ty)) return cast<InjectedClassNameType>(Ty)->getDecl(); else return 0; @@ -45,10 +57,11 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType 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(); + if (!T->isDependentType()) + if (const TagType *Tag = T->getAs<TagType>()) + return Tag->getDecl(); - return ::getCurrentInstantiationOf(T); + return ::getCurrentInstantiationOf(T, CurContext); } /// \brief Compute the DeclContext that is associated with the given @@ -174,7 +187,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { return 0; QualType T = QualType(NNS->getAsType(), 0); - return ::getCurrentInstantiationOf(T); + return ::getCurrentInstantiationOf(T, CurContext); } /// \brief Require that the context specified by SS be complete. @@ -518,7 +531,6 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, // a declaration context. if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, - Alias->getNamespace()); QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index a0b4b98..5566654 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -25,82 +25,23 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" -#include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/ConvertUTF.h" #include <limits> using namespace clang; using namespace sema; -/// getLocationOfStringLiteralByte - Return a source location that points to the -/// specified byte of the specified string literal. -/// -/// Strings are amazingly complex. They can be formed from multiple tokens and -/// can have escape sequences in them in addition to the usual trigraph and -/// escaped newline business. This routine handles this complexity. -/// 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. - SourceLocation StrTokSpellingLoc = SourceMgr.getSpellingLoc(StrTokLoc); - - // Re-lex the token to get its length and original spelling. - std::pair<FileID, unsigned> LocInfo = - SourceMgr.getDecomposedLoc(StrTokSpellingLoc); - bool Invalid = false; - llvm::StringRef Buffer = SourceMgr.getBufferData(LocInfo.first, &Invalid); - if (Invalid) - return StrTokSpellingLoc; - - const char *StrData = Buffer.data()+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.begin(), StrData, - Buffer.end()); - Token TheTok; - TheLexer.LexFromRawLexer(TheTok); - - // Use the StringLiteralParser to compute the length of the string in bytes. - StringLiteralParser SLP(&TheTok, 1, PP, /*Complain=*/false); - unsigned TokNumBytes = SLP.GetStringLength(); - - // If the byte is in this token, return the location of the byte. - if (ByteNo < TokNumBytes || - (ByteNo == TokNumBytes && TokNo == SL->getNumConcatenated())) { - unsigned Offset = - StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP, - /*Complain=*/false); - - // Now that we know the offset of the token in the spelling, use the - // preprocessor to get the offset in the original source. - return PP.AdvanceToTokenCharacter(StrTokLoc, Offset); - } - - // Move to the next string token. - ++TokNo; - ByteNo -= TokNumBytes; - } + return SL->getLocationOfByte(ByteNo, PP.getSourceManager(), + PP.getLangOptions(), PP.getTargetInfo()); } + /// CheckablePrintfAttr - does a function call have a "printf" attribute /// and arguments that merit checking? @@ -129,6 +70,24 @@ ExprResult Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { ExprResult TheCallResult(Owned(TheCall)); + // Find out if any arguments are required to be integer constant expressions. + unsigned ICEArguments = 0; + ASTContext::GetBuiltinTypeError Error; + Context.GetBuiltinType(BuiltinID, Error, &ICEArguments); + if (Error != ASTContext::GE_None) + ICEArguments = 0; // Don't diagnose previously diagnosed errors. + + // If any arguments are required to be ICE's, check and diagnose. + for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) { + // Skip arguments not required to be ICE's. + if ((ICEArguments & (1 << ArgNo)) == 0) continue; + + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, ArgNo, Result)) + return true; + ICEArguments &= ~(1 << ArgNo); + } + switch (BuiltinID) { case Builtin::BI__builtin___CFStringMakeConstantString: assert(TheCall->getNumArgs() == 1 && @@ -162,19 +121,6 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (SemaBuiltinFPClassification(TheCall, 1)) return ExprError(); break; - case Builtin::BI__builtin_return_address: - case Builtin::BI__builtin_frame_address: { - llvm::APSInt Result; - if (SemaBuiltinConstantArg(TheCall, 0, Result)) - return ExprError(); - break; - } - case Builtin::BI__builtin_eh_return_data_regno: { - llvm::APSInt Result; - if (SemaBuiltinConstantArg(TheCall, 0, Result)) - 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 @@ -191,6 +137,16 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (SemaBuiltinLongjmp(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_constant_p: + if (TheCall->getNumArgs() == 0) + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 /*function call*/ << 1 << 0 << TheCall->getSourceRange(); + if (TheCall->getNumArgs() > 1) + return Diag(TheCall->getArg(1)->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << 1 << TheCall->getNumArgs() + << TheCall->getArg(1)->getSourceRange(); + break; case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_sub: case Builtin::BI__sync_fetch_and_or: @@ -217,11 +173,6 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; - case llvm::Triple::x86: - case llvm::Triple::x86_64: - if (CheckX86BuiltinFunctionCall(BuiltinID, TheCall)) - return ExprError(); - break; default: break; } @@ -230,19 +181,6 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return move(TheCallResult); } -bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - switch (BuiltinID) { - case X86::BI__builtin_ia32_palignr128: - case X86::BI__builtin_ia32_palignr: { - llvm::APSInt Result; - if (SemaBuiltinConstantArg(TheCall, 2, Result)) - return true; - break; - } - } - return false; -} - // Get the valid immediate range for the specified NEON type code. static unsigned RFT(unsigned t, bool shift = false) { bool quad = t & 0x10; @@ -260,11 +198,9 @@ static unsigned RFT(unsigned t, bool shift = false) { assert(!shift && "cannot shift float types!"); return (2 << (int)quad) - 1; case 5: // poly8 - assert(!shift && "cannot shift polynomial types!"); - return (8 << (int)quad) - 1; + return shift ? 7 : (8 << (int)quad) - 1; case 6: // poly16 - assert(!shift && "cannot shift polynomial types!"); - return (4 << (int)quad) - 1; + return shift ? 15 : (4 << (int)quad) - 1; case 7: // float16 assert(!shift && "cannot shift float types!"); return (4 << (int)quad) - 1; @@ -339,8 +275,12 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { // more efficient. For example, just map function ids to custom // handlers. - // Printf checking. - if (const FormatAttr *Format = FDecl->getAttr<FormatAttr>()) { + // Printf and scanf checking. + for (specific_attr_iterator<FormatAttr> + i = FDecl->specific_attr_begin<FormatAttr>(), + e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) { + + const FormatAttr *Format = *i; const bool b = Format->getType() == "scanf"; if (b || CheckablePrintfAttr(Format, TheCall)) { bool HasVAListArg = Format->getFirstArg() == 0; @@ -351,12 +291,11 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { } } - specific_attr_iterator<NonNullAttr> - i = FDecl->specific_attr_begin<NonNullAttr>(), - e = FDecl->specific_attr_end<NonNullAttr>(); - - for (; i != e; ++i) + for (specific_attr_iterator<NonNullAttr> + i = FDecl->specific_attr_begin<NonNullAttr>(), + e = FDecl->specific_attr_end<NonNullAttr>(); i != e; ++i) { CheckNonNullArguments(*i, TheCall); + } return false; } @@ -422,7 +361,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { QualType ValType = FirstArg->getType()->getAs<PointerType>()->getPointeeType(); - if (!ValType->isIntegerType() && !ValType->isPointerType() && + if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && !ValType->isBlockPointerType()) { Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intptr) << FirstArg->getType() << FirstArg->getSourceRange(); @@ -545,9 +484,10 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // 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. - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Invalid; + ExprValueKind VK = VK_RValue; CXXCastPath BasePath; - if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, BasePath)) + if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, VK, BasePath)) return ExprError(); // Okay, we have something that *can* be converted to the right type. Check @@ -556,7 +496,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // 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, Kind, VK_RValue, &BasePath); + ImpCastExprToType(Arg, ValType, Kind, VK, &BasePath); TheCall->setArg(i+1, Arg); } @@ -581,9 +521,6 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { /// 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 -/// belong to the input codeset UTF-8" /// Note: It might also make sense to do the UTF-16 conversion here (would /// simplify the backend). bool Sema::CheckObjCString(Expr *Arg) { @@ -602,7 +539,21 @@ bool Sema::CheckObjCString(Expr *Arg) { diag::warn_cfstring_literal_contains_nul_character) << Arg->getSourceRange(); } - + if (Literal->containsNonAsciiOrNull()) { + llvm::StringRef String = Literal->getString(); + unsigned NumBytes = String.size(); + llvm::SmallVector<UTF16, 128> ToBuf(NumBytes); + const UTF8 *FromPtr = (UTF8 *)String.data(); + UTF16 *ToPtr = &ToBuf[0]; + + ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, + &ToPtr, ToPtr + NumBytes, + strictConversion); + // Check for conversion failure. + if (Result != conversionOK) + Diag(Arg->getLocStart(), + diag::warn_cfstring_truncated) << Arg->getSourceRange(); + } return false; } @@ -798,7 +749,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { } else if (numElements != numResElements) { QualType eltType = LHSType->getAs<VectorType>()->getElementType(); resType = Context.getVectorType(eltType, numResElements, - VectorType::NotAltiVec); + VectorType::GenericVector); } } @@ -929,31 +880,44 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, bool isPrintf) { - + tryAgain: if (E->isTypeDependent() || E->isValueDependent()) return false; switch (E->getStmtClass()) { + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { - const ConditionalOperator *C = cast<ConditionalOperator>(E); + const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E); return SemaCheckStringLiteral(C->getTrueExpr(), TheCall, HasVAListArg, format_idx, firstDataArg, isPrintf) - && SemaCheckStringLiteral(C->getRHS(), TheCall, HasVAListArg, + && SemaCheckStringLiteral(C->getFalseExpr(), TheCall, HasVAListArg, format_idx, firstDataArg, isPrintf); } + case Stmt::IntegerLiteralClass: + // Technically -Wformat-nonliteral does not warn about this case. + // The behavior of printf and friends in this case is implementation + // dependent. Ideally if the format string cannot be null then + // it should have a 'nonnull' attribute in the function prototype. + return true; + case Stmt::ImplicitCastExprClass: { - const ImplicitCastExpr *Expr = cast<ImplicitCastExpr>(E); - return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg, - format_idx, firstDataArg, isPrintf); + E = cast<ImplicitCastExpr>(E)->getSubExpr(); + goto tryAgain; } case Stmt::ParenExprClass: { - const ParenExpr *Expr = cast<ParenExpr>(E); - return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg, - format_idx, firstDataArg, isPrintf); + E = cast<ParenExpr>(E)->getSubExpr(); + goto tryAgain; } + case Stmt::OpaqueValueExprClass: + if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) { + E = src; + goto tryAgain; + } + return false; + case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast<DeclRefExpr>(E); @@ -1072,12 +1036,16 @@ Sema::CheckPrintfScanfArguments(const CallExpr *TheCall, bool HasVAListArg, // of member functions is counted. However, it doesn't appear in our own // lists, so decrement format_idx in that case. if (isa<CXXMemberCallExpr>(TheCall)) { - // Catch a format attribute mistakenly referring to the object argument. - if (format_idx == 0) - return; - --format_idx; - if(firstDataArg != 0) - --firstDataArg; + const CXXMethodDecl *method_decl = + dyn_cast<CXXMethodDecl>(TheCall->getCalleeDecl()); + if (method_decl && method_decl->isInstance()) { + // Catch a format attribute mistakenly referring to the object argument. + if (format_idx == 0) + return; + --format_idx; + if(firstDataArg != 0) + --firstDataArg; + } } // CHECK: printf/scanf-like function is called with no format string. @@ -1531,6 +1499,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier } // Check each flag does not conflict with any other component. + if (!FS.hasValidThousandsGroupingPrefix()) + HandleFlag(FS, FS.hasThousandsGrouping(), startSpecifier, specifierLen); if (!FS.hasValidLeadingZeros()) HandleFlag(FS, FS.hasLeadingZeros(), startSpecifier, specifierLen); if (!FS.hasValidPlusPrefix()) @@ -1585,9 +1555,12 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier // or 'short' to an 'int'. This is done because printf is a varargs // function. if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex)) - if (ICE->getType() == S.Context.IntTy) - if (ATR.matchesType(S.Context, ICE->getSubExpr()->getType())) + if (ICE->getType() == S.Context.IntTy) { + // All further checking is done on the subexpression. + Ex = ICE->getSubExpr(); + if (ATR.matchesType(S.Context, Ex->getType())) return true; + } // We may be able to offer a FixItHint if it is a supported type. PrintfSpecifier fixedFS = FS; @@ -1794,8 +1767,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, //===--- CHECK: Return Address of Stack Variable --------------------------===// -static DeclRefExpr* EvalVal(Expr *E); -static DeclRefExpr* EvalAddr(Expr* E); +static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars); +static Expr *EvalAddr(Expr* E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars); /// CheckReturnStackAddr - Check if a return statement returns the address /// of a stack variable. @@ -1803,45 +1776,79 @@ 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. - RetValExp = RetValExp->IgnoreParenCasts(); + Expr *stackE = 0; + llvm::SmallVector<DeclRefExpr *, 8> refVars; - if (BlockExpr *C = dyn_cast<BlockExpr>(RetValExp)) - if (C->hasBlockDeclRefExprs()) - Diag(C->getLocStart(), diag::err_ret_local_block) - << C->getSourceRange(); + // Perform checking for returned stack addresses, local blocks, + // label addresses or references to temporaries. + if (lhsType->isPointerType() || lhsType->isBlockPointerType()) { + stackE = EvalAddr(RetValExp, refVars); + } else if (lhsType->isReferenceType()) { + stackE = EvalVal(RetValExp, refVars); + } - if (AddrLabelExpr *ALE = dyn_cast<AddrLabelExpr>(RetValExp)) - Diag(ALE->getLocStart(), diag::warn_ret_addr_label) - << ALE->getSourceRange(); + if (stackE == 0) + return; // Nothing suspicious was found. - } 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) - << DR->getDecl()->getDeclName() << RetValExp->getSourceRange(); + SourceLocation diagLoc; + SourceRange diagRange; + if (refVars.empty()) { + diagLoc = stackE->getLocStart(); + diagRange = stackE->getSourceRange(); + } else { + // We followed through a reference variable. 'stackE' contains the + // problematic expression but we will warn at the return statement pointing + // at the reference variable. We will later display the "trail" of + // reference variables using notes. + diagLoc = refVars[0]->getLocStart(); + diagRange = refVars[0]->getSourceRange(); + } + + if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { //address of local var. + Diag(diagLoc, lhsType->isReferenceType() ? diag::warn_ret_stack_ref + : diag::warn_ret_stack_addr) + << DR->getDecl()->getDeclName() << diagRange; + } else if (isa<BlockExpr>(stackE)) { // local block. + Diag(diagLoc, diag::err_ret_local_block) << diagRange; + } else if (isa<AddrLabelExpr>(stackE)) { // address of label. + Diag(diagLoc, diag::warn_ret_addr_label) << diagRange; + } else { // local temporary. + Diag(diagLoc, lhsType->isReferenceType() ? diag::warn_ret_local_temp_ref + : diag::warn_ret_local_temp_addr) + << diagRange; + } + + // Display the "trail" of reference variables that we followed until we + // found the problematic expression using notes. + for (unsigned i = 0, e = refVars.size(); i != e; ++i) { + VarDecl *VD = cast<VarDecl>(refVars[i]->getDecl()); + // If this var binds to another reference var, show the range of the next + // var, otherwise the var binds to the problematic expression, in which case + // show the range of the expression. + SourceRange range = (i < e-1) ? refVars[i+1]->getSourceRange() + : stackE->getSourceRange(); + Diag(VD->getLocation(), diag::note_ref_var_local_bind) + << VD->getDeclName() << range; } } /// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that /// check if the expression in a return statement evaluates to an address -/// to a location on the stack. The recursion is used to traverse the +/// to a location on the stack, a local block, an address of a label, or a +/// reference to local temporary. The recursion is used to traverse the /// AST of the return expression, with recursion backtracking when we -/// encounter a subexpression that (1) clearly does not lead to the address -/// of a stack variable or (2) is something we cannot determine leads to -/// the address of a stack variable based on such local checking. +/// encounter a subexpression that (1) clearly does not lead to one of the +/// above problematic expressions (2) is something we cannot determine leads to +/// a problematic expression based on such local checking. +/// +/// Both EvalAddr and EvalVal follow through reference variables to evaluate +/// the expression that they point to. Such variables are added to the +/// 'refVars' vector so that we know what the reference variable "trail" was. /// /// 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 -/// the refers to a stack variable. +/// At the base case of the recursion is a check for the above problematic +/// expressions. /// /// This implementation handles: /// @@ -1851,7 +1858,10 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, /// * arbitrary interplay between "&" and "*" operators /// * pointer arithmetic from an address of a stack variable /// * taking the address of an array element where the array is on the stack -static DeclRefExpr* EvalAddr(Expr *E) { +static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { + if (E->isTypeDependent()) + return NULL; + // We should only be called for evaluating pointer expressions. assert((E->getType()->isAnyPointerType() || E->getType()->isBlockPointerType() || @@ -1864,7 +1874,23 @@ static DeclRefExpr* EvalAddr(Expr *E) { switch (E->getStmtClass()) { case Stmt::ParenExprClass: // Ignore parentheses. - return EvalAddr(cast<ParenExpr>(E)->getSubExpr()); + return EvalAddr(cast<ParenExpr>(E)->getSubExpr(), refVars); + + case Stmt::DeclRefExprClass: { + DeclRefExpr *DR = cast<DeclRefExpr>(E); + + if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) + // If this is a reference variable, follow through to the expression that + // it points to. + if (V->hasLocalStorage() && + V->getType()->isReferenceType() && V->hasInit()) { + // Add the reference variable to the "trail". + refVars.push_back(DR); + return EvalAddr(V->getInit(), refVars); + } + + return NULL; + } case Stmt::UnaryOperatorClass: { // The only unary operator that make sense to handle here @@ -1872,7 +1898,7 @@ static DeclRefExpr* EvalAddr(Expr *E) { UnaryOperator *U = cast<UnaryOperator>(E); if (U->getOpcode() == UO_AddrOf) - return EvalVal(U->getSubExpr()); + return EvalVal(U->getSubExpr(), refVars); else return NULL; } @@ -1893,7 +1919,7 @@ static DeclRefExpr* EvalAddr(Expr *E) { if (!Base->getType()->isPointerType()) Base = B->getRHS(); assert (Base->getType()->isPointerType()); - return EvalAddr(Base); + return EvalAddr(Base, refVars); } // For conditional operators we need to see if either the LHS or RHS are @@ -1902,12 +1928,27 @@ static DeclRefExpr* EvalAddr(Expr *E) { ConditionalOperator *C = cast<ConditionalOperator>(E); // Handle the GNU extension for missing LHS. - if (Expr *lhsExpr = C->getLHS()) - if (DeclRefExpr* LHS = EvalAddr(lhsExpr)) - return LHS; + if (Expr *lhsExpr = C->getLHS()) { + // In C++, we can have a throw-expression, which has 'void' type. + if (!lhsExpr->getType()->isVoidType()) + if (Expr* LHS = EvalAddr(lhsExpr, refVars)) + return LHS; + } - return EvalAddr(C->getRHS()); + // In C++, we can have a throw-expression, which has 'void' type. + if (C->getRHS()->getType()->isVoidType()) + return NULL; + + return EvalAddr(C->getRHS(), refVars); } + + case Stmt::BlockExprClass: + if (cast<BlockExpr>(E)->getBlockDecl()->hasCaptures()) + return E; // local block. + return NULL; + + case Stmt::AddrLabelExprClass: + return E; // address of label. // For casts, we need to handle conversions from arrays to // pointer values, and pointer-to-pointer conversions. @@ -1920,9 +1961,9 @@ static DeclRefExpr* EvalAddr(Expr *E) { if (SubExpr->getType()->isPointerType() || SubExpr->getType()->isBlockPointerType() || SubExpr->getType()->isObjCQualifiedIdType()) - return EvalAddr(SubExpr); + return EvalAddr(SubExpr, refVars); else if (T->isArrayType()) - return EvalVal(SubExpr); + return EvalVal(SubExpr, refVars); else return 0; } @@ -1941,7 +1982,7 @@ static DeclRefExpr* EvalAddr(Expr *E) { case Stmt::CXXReinterpretCastExprClass: { Expr *S = cast<CXXNamedCastExpr>(E)->getSubExpr(); if (S->getType()->isPointerType() || S->getType()->isBlockPointerType()) - return EvalAddr(S); + return EvalAddr(S, refVars); else return NULL; } @@ -1955,7 +1996,7 @@ static DeclRefExpr* EvalAddr(Expr *E) { /// EvalVal - This function is complements EvalAddr in the mutual recursion. /// See the comments for EvalAddr for more details. -static DeclRefExpr* EvalVal(Expr *E) { +static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { do { // We should only be called for evaluating non-pointer expressions, or // expressions with a pointer type that are not used as references but instead @@ -1975,13 +2016,24 @@ do { } case Stmt::DeclRefExprClass: { - // 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. + // When we hit a DeclRefExpr we are looking at code that refers to a + // variable's name. If it's not a reference variable 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()) { + if (!V->getType()->isReferenceType()) + return DR; + + // Reference variable, follow through to the expression that + // it points to. + if (V->hasInit()) { + // Add the reference variable to the "trail". + refVars.push_back(DR); + return EvalVal(V->getInit(), refVars); + } + } return NULL; } @@ -1999,7 +2051,7 @@ do { UnaryOperator *U = cast<UnaryOperator>(E); if (U->getOpcode() == UO_Deref) - return EvalAddr(U->getSubExpr()); + return EvalAddr(U->getSubExpr(), refVars); return NULL; } @@ -2008,20 +2060,20 @@ do { // 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()); + return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars); } 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. + // non-NULL Expr's. If one is non-NULL, we return it. ConditionalOperator *C = cast<ConditionalOperator>(E); // Handle the GNU extension for missing LHS. if (Expr *lhsExpr = C->getLHS()) - if (DeclRefExpr *LHS = EvalVal(lhsExpr)) + if (Expr *LHS = EvalVal(lhsExpr, refVars)) return LHS; - return EvalVal(C->getRHS()); + return EvalVal(C->getRHS(), refVars); } // Accesses to members are potential references to data on the stack. @@ -2037,11 +2089,16 @@ do { if (M->getMemberDecl()->getType()->isReferenceType()) return NULL; - return EvalVal(M->getBase()); + return EvalVal(M->getBase(), refVars); } - // Everything else: we simply don't reason about them. default: + // Check that we don't return or take the address of a reference to a + // temporary. This is only useful in C++. + if (!E->isTypeDependent() && E->isRValue()) + return E; + + // Everything else: we simply don't reason about them. return NULL; } } while (true); @@ -2055,8 +2112,8 @@ do { void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { bool EmitWarning = true; - Expr* LeftExprSansParen = lex->IgnoreParens(); - Expr* RightExprSansParen = rex->IgnoreParens(); + Expr* LeftExprSansParen = lex->IgnoreParenImpCasts(); + Expr* RightExprSansParen = rex->IgnoreParenImpCasts(); // Special case: check for x == x (which is OK). // Do not emit warnings for such cases. @@ -2117,19 +2174,19 @@ struct IntRange { : Width(Width), NonNegative(NonNegative) {} - // Returns the range of the bool type. + /// Returns the range of the bool type. static IntRange forBoolType() { return IntRange(1, true); } - // Returns the range of an integral type. - static IntRange forType(ASTContext &C, QualType T) { - return forCanonicalType(C, T->getCanonicalTypeInternal().getTypePtr()); + /// Returns the range of an opaque value of the given integral type. + static IntRange forValueOfType(ASTContext &C, QualType T) { + return forValueOfCanonicalType(C, + T->getCanonicalTypeInternal().getTypePtr()); } - // Returns the range of an integeral type based on its canonical - // representation. - static IntRange forCanonicalType(ASTContext &C, const Type *T) { + /// Returns the range of an opaque value of a canonical integral type. + static IntRange forValueOfCanonicalType(ASTContext &C, const Type *T) { assert(T->isCanonicalUnqualified()); if (const VectorType *VT = dyn_cast<VectorType>(T)) @@ -2137,8 +2194,12 @@ struct IntRange { if (const ComplexType *CT = dyn_cast<ComplexType>(T)) T = CT->getElementType().getTypePtr(); + // For enum types, use the known bit width of the enumerators. if (const EnumType *ET = dyn_cast<EnumType>(T)) { EnumDecl *Enum = ET->getDecl(); + if (!Enum->isDefinition()) + return IntRange(C.getIntWidth(QualType(T, 0)), false); + unsigned NumPositive = Enum->getNumPositiveBits(); unsigned NumNegative = Enum->getNumNegativeBits(); @@ -2151,13 +2212,34 @@ struct IntRange { return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger()); } - // Returns the supremum of two ranges: i.e. their conservative merge. + /// Returns the "target" range of a canonical integral type, i.e. + /// the range of values expressible in the type. + /// + /// This matches forValueOfCanonicalType except that enums have the + /// full range of their type, not the range of their enumerators. + static IntRange forTargetOfCanonicalType(ASTContext &C, const Type *T) { + assert(T->isCanonicalUnqualified()); + + if (const VectorType *VT = dyn_cast<VectorType>(T)) + T = VT->getElementType().getTypePtr(); + if (const ComplexType *CT = dyn_cast<ComplexType>(T)) + T = CT->getElementType().getTypePtr(); + if (const EnumType *ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getIntegerType().getTypePtr(); + + const BuiltinType *BT = cast<BuiltinType>(T); + assert(BT->isInteger()); + + return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger()); + } + + /// Returns the supremum of two ranges: i.e. their conservative merge. static IntRange join(IntRange L, IntRange R) { return IntRange(std::max(L.Width, R.Width), L.NonNegative && R.NonNegative); } - // Returns the infinum of two ranges: i.e. their aggressive merge. + /// Returns the infinum of two ranges: i.e. their aggressive merge. static IntRange meet(IntRange L, IntRange R) { return IntRange(std::min(L.Width, R.Width), L.NonNegative || R.NonNegative); @@ -2169,7 +2251,7 @@ IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { return IntRange(value.getMinSignedBits(), false); if (value.getBitWidth() > MaxWidth) - value.trunc(MaxWidth); + value = value.trunc(MaxWidth); // isNonNegative() just checks the sign bit without considering // signedness. @@ -2224,11 +2306,9 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { if (CE->getCastKind() == CK_NoOp) return GetExprRange(C, CE->getSubExpr(), MaxWidth); - IntRange OutputTypeRange = IntRange::forType(C, CE->getType()); + IntRange OutputTypeRange = IntRange::forValueOfType(C, CE->getType()); bool isIntegerCast = (CE->getCastKind() == CK_IntegralCast); - if (!isIntegerCast && CE->getCastKind() == CK_Unknown) - isIntegerCast = CE->getSubExpr()->getType()->isIntegerType(); // Assume that non-integer casts can span the full range of the type. if (!isIntegerCast) @@ -2283,12 +2363,12 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { case BO_RemAssign: case BO_AddAssign: case BO_SubAssign: - return IntRange::forType(C, E->getType()); + return IntRange::forValueOfType(C, E->getType()); // Operations with opaque sources are black-listed. case BO_PtrMemD: case BO_PtrMemI: - return IntRange::forType(C, E->getType()); + return IntRange::forValueOfType(C, E->getType()); // Bitwise-and uses the *infinum* of the two source ranges. case BO_And: @@ -2303,14 +2383,14 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { if (IntegerLiteral *I = dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) { if (I->getValue() == 1) { - IntRange R = IntRange::forType(C, E->getType()); + IntRange R = IntRange::forValueOfType(C, E->getType()); return IntRange(R.Width, /*NonNegative*/ true); } } // fallthrough case BO_ShlAssign: - return IntRange::forType(C, E->getType()); + return IntRange::forValueOfType(C, E->getType()); // Right shift by a constant can narrow its left argument. case BO_Shr: @@ -2339,7 +2419,7 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { // Black-list pointer subtractions. case BO_Sub: if (BO->getLHS()->getType()->isPointerType()) - return IntRange::forType(C, E->getType()); + return IntRange::forValueOfType(C, E->getType()); // fallthrough default: @@ -2362,7 +2442,7 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { // Operations with opaque sources are black-listed. case UO_Deref: case UO_AddrOf: // should be impossible - return IntRange::forType(C, E->getType()); + return IntRange::forValueOfType(C, E->getType()); default: return GetExprRange(C, UO->getSubExpr(), MaxWidth); @@ -2370,7 +2450,7 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { } if (dyn_cast<OffsetOfExpr>(E)) { - IntRange::forType(C, E->getType()); + IntRange::forValueOfType(C, E->getType()); } FieldDecl *BitField = E->getBitField(); @@ -2381,7 +2461,7 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { return IntRange(BitWidth, BitField->getType()->isUnsignedIntegerType()); } - return IntRange::forType(C, E->getType()); + return IntRange::forValueOfType(C, E->getType()); } IntRange GetExprRange(ASTContext &C, Expr *E) { @@ -2426,30 +2506,55 @@ bool IsSameFloatAfterCast(const APValue &value, IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); } -void AnalyzeImplicitConversions(Sema &S, Expr *E); +void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); + +static bool IsZero(Sema &S, Expr *E) { + // Suppress cases where we are comparing against an enum constant. + if (const DeclRefExpr *DR = + dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) + if (isa<EnumConstantDecl>(DR->getDecl())) + return false; + + // Suppress cases where the '0' value is expanded from a macro. + if (E->getLocStart().isMacroID()) + return false; -bool IsZero(Sema &S, Expr *E) { llvm::APSInt Value; return E->isIntegerConstantExpr(Value, S.Context) && Value == 0; } +static bool HasEnumType(Expr *E) { + // Strip off implicit integral promotions. + while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->getCastKind() != CK_IntegralCast && + ICE->getCastKind() != CK_NoOp) + break; + E = ICE->getSubExpr(); + } + + return E->getType()->isEnumeralType(); +} + void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { BinaryOperatorKind op = E->getOpcode(); + if (E->isValueDependent()) + return; + if (op == BO_LT && IsZero(S, E->getRHS())) { S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) - << "< 0" << "false" + << "< 0" << "false" << HasEnumType(E->getLHS()) << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } else if (op == BO_GE && IsZero(S, E->getRHS())) { S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) - << ">= 0" << "true" + << ">= 0" << "true" << HasEnumType(E->getLHS()) << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } else if (op == BO_GT && IsZero(S, E->getLHS())) { S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) - << "0 >" << "false" + << "0 >" << "false" << HasEnumType(E->getRHS()) << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } else if (op == BO_LE && IsZero(S, E->getLHS())) { S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) - << "0 <=" << "true" + << "0 <=" << "true" << HasEnumType(E->getRHS()) << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } } @@ -2457,8 +2562,8 @@ void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { /// Analyze the operands of the given comparison. Implements the /// fallback case from AnalyzeComparison. void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { - AnalyzeImplicitConversions(S, E->getLHS()); - AnalyzeImplicitConversions(S, E->getRHS()); + AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); + AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); } /// \brief Implements -Wsign-compare. @@ -2476,7 +2581,11 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { // We don't do anything special if this isn't an unsigned integral // comparison: we're only interested in integral comparisons, and // signed comparisons only happen in cases we don't care to warn about. - if (!T->hasUnsignedIntegerRepresentation()) + // + // We also don't care about value-dependent expressions or expressions + // whose result is a constant. + if (!T->hasUnsignedIntegerRepresentation() + || E->isValueDependent() || E->isIntegerConstantExpr(S.Context)) return AnalyzeImpConvsInComparison(S, E); Expr *lex = E->getLHS()->IgnoreParenImpCasts(); @@ -2503,8 +2612,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { // Go ahead and analyze implicit conversions in the operands. Note // that we skip the implicit conversions on both sides. - AnalyzeImplicitConversions(S, lex); - AnalyzeImplicitConversions(S, rex); + AnalyzeImplicitConversions(S, lex, E->getOperatorLoc()); + AnalyzeImplicitConversions(S, rex, E->getOperatorLoc()); // If the signed range is non-negative, -Wsign-compare won't fire, // but we should still check for comparisons which are always true @@ -2533,13 +2642,103 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { << lex->getSourceRange() << rex->getSourceRange(); } +/// Analyzes an attempt to assign the given value to a bitfield. +/// +/// Returns true if there was something fishy about the attempt. +bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, + SourceLocation InitLoc) { + assert(Bitfield->isBitField()); + if (Bitfield->isInvalidDecl()) + return false; + + // White-list bool bitfields. + if (Bitfield->getType()->isBooleanType()) + return false; + + // Ignore value- or type-dependent expressions. + if (Bitfield->getBitWidth()->isValueDependent() || + Bitfield->getBitWidth()->isTypeDependent() || + Init->isValueDependent() || + Init->isTypeDependent()) + return false; + + Expr *OriginalInit = Init->IgnoreParenImpCasts(); + + llvm::APSInt Width(32); + Expr::EvalResult InitValue; + if (!Bitfield->getBitWidth()->isIntegerConstantExpr(Width, S.Context) || + !OriginalInit->Evaluate(InitValue, S.Context) || + !InitValue.Val.isInt()) + return false; + + const llvm::APSInt &Value = InitValue.Val.getInt(); + unsigned OriginalWidth = Value.getBitWidth(); + unsigned FieldWidth = Width.getZExtValue(); + + if (OriginalWidth <= FieldWidth) + return false; + + llvm::APSInt TruncatedValue = Value.trunc(FieldWidth); + + // It's fairly common to write values into signed bitfields + // that, if sign-extended, would end up becoming a different + // value. We don't want to warn about that. + if (Value.isSigned() && Value.isNegative()) + TruncatedValue = TruncatedValue.sext(OriginalWidth); + else + TruncatedValue = TruncatedValue.zext(OriginalWidth); + + if (Value == TruncatedValue) + return false; + + std::string PrettyValue = Value.toString(10); + std::string PrettyTrunc = TruncatedValue.toString(10); + + S.Diag(InitLoc, diag::warn_impcast_bitfield_precision_constant) + << PrettyValue << PrettyTrunc << OriginalInit->getType() + << Init->getSourceRange(); + + return true; +} + +/// Analyze the given simple or compound assignment for warning-worthy +/// operations. +void AnalyzeAssignment(Sema &S, BinaryOperator *E) { + // Just recurse on the LHS. + AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); + + // We want to recurse on the RHS as normal unless we're assigning to + // a bitfield. + if (FieldDecl *Bitfield = E->getLHS()->getBitField()) { + if (AnalyzeBitFieldAssignment(S, Bitfield, E->getRHS(), + E->getOperatorLoc())) { + // Recurse, ignoring any implicit conversions on the RHS. + return AnalyzeImplicitConversions(S, E->getRHS()->IgnoreParenImpCasts(), + E->getOperatorLoc()); + } + } + + AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); +} + /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { - S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange(); +void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext, + unsigned diag) { + S.Diag(E->getExprLoc(), diag) + << E->getType() << T << E->getSourceRange() << SourceRange(CContext); +} + +std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { + if (!Range.Width) return "0"; + + llvm::APSInt ValueInRange = Value; + ValueInRange.setIsSigned(!Range.NonNegative); + ValueInRange = ValueInRange.trunc(Range.Width); + return ValueInRange.toString(10); } void CheckImplicitConversion(Sema &S, Expr *E, QualType T, - bool *ICContext = 0) { + SourceLocation CC, bool *ICContext = 0) { if (E->isTypeDependent() || E->isValueDependent()) return; const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); @@ -2547,6 +2746,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (Source == Target) return; if (Target->isDependentType()) return; + // If the conversion context location is invalid or instantiated + // from a system macro, don't complain. + if (CC.isInvalid() || + (CC.isMacroID() && S.Context.getSourceManager().isInSystemHeader( + S.Context.getSourceManager().getSpellingLoc(CC)))) + return; + // Never diagnose implicit casts to bool. if (Target->isSpecificBuiltinType(BuiltinType::Bool)) return; @@ -2554,7 +2760,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Strip vector types. if (isa<VectorType>(Source)) { if (!isa<VectorType>(Target)) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar); + return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar); Source = cast<VectorType>(Source)->getElementType().getTypePtr(); Target = cast<VectorType>(Target)->getElementType().getTypePtr(); @@ -2563,7 +2769,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Strip complex types. if (isa<ComplexType>(Source)) { if (!isa<ComplexType>(Target)) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar); + return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar); Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); Target = cast<ComplexType>(Target)->getElementType().getTypePtr(); @@ -2591,15 +2797,21 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; } - DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision); + DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision); } return; } // If the target is integral, always warn. - if ((TargetBT && TargetBT->isInteger())) - // TODO: don't warn for integer values? - DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer); + if ((TargetBT && TargetBT->isInteger())) { + Expr *InnerE = E->IgnoreParenImpCasts(); + if (FloatingLiteral *LiteralExpr = dyn_cast<FloatingLiteral>(InnerE)) { + DiagnoseImpCast(S, LiteralExpr, T, CC, + diag::warn_impcast_literal_float_to_integer); + } else { + DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_integer); + } + } return; } @@ -2608,14 +2820,27 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; IntRange SourceRange = GetExprRange(S.Context, E); - IntRange TargetRange = IntRange::forCanonicalType(S.Context, Target); + IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); if (SourceRange.Width > TargetRange.Width) { + // If the source is a constant, use a default-on diagnostic. + // TODO: this should happen for bitfield stores, too. + llvm::APSInt Value(32); + if (E->isIntegerConstantExpr(Value, S.Context)) { + std::string PrettySourceValue = Value.toString(10); + std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); + + S.Diag(E->getExprLoc(), diag::warn_impcast_integer_precision_constant) + << PrettySourceValue << PrettyTargetValue + << E->getType() << T << E->getSourceRange() << clang::SourceRange(CC); + return; + } + // People want to build with -Wshorten-64-to-32 and not -Wconversion // and by god we'll let them. if (SourceRange.Width == 64 && TargetRange.Width == 32) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32); - return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision); + return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32); + return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision); } if ((TargetRange.NonNegative && !SourceRange.NonNegative) || @@ -2633,7 +2858,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, *ICContext = true; } - return DiagnoseImpCast(S, E, T, DiagID); + return DiagnoseImpCast(S, E, T, CC, DiagID); } return; @@ -2642,35 +2867,38 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T); void CheckConditionalOperand(Sema &S, Expr *E, QualType T, - bool &ICContext) { + SourceLocation CC, bool &ICContext) { E = E->IgnoreParenImpCasts(); if (isa<ConditionalOperator>(E)) return CheckConditionalOperator(S, cast<ConditionalOperator>(E), T); - AnalyzeImplicitConversions(S, E); + AnalyzeImplicitConversions(S, E, CC); if (E->getType() != T) - return CheckImplicitConversion(S, E, T, &ICContext); + return CheckImplicitConversion(S, E, T, CC, &ICContext); return; } void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) { - AnalyzeImplicitConversions(S, E->getCond()); + SourceLocation CC = E->getQuestionLoc(); + + AnalyzeImplicitConversions(S, E->getCond(), CC); bool Suspicious = false; - CheckConditionalOperand(S, E->getTrueExpr(), T, Suspicious); - CheckConditionalOperand(S, E->getFalseExpr(), T, Suspicious); + CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious); + CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious); // If -Wconversion would have warned about either of the candidates // for a signedness conversion to the context type... if (!Suspicious) return; // ...but it's currently ignored... - if (S.Diags.getDiagnosticLevel(diag::warn_impcast_integer_sign_conditional)) + if (S.Diags.getDiagnosticLevel(diag::warn_impcast_integer_sign_conditional, + CC)) return; // ...and -Wsign-compare isn't... - if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional)) + if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional, CC)) return; // ...then check whether it would have warned about either of the @@ -2678,10 +2906,10 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) { if (E->getType() != T) { Suspicious = false; CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), - E->getType(), &Suspicious); + E->getType(), CC, &Suspicious); if (!Suspicious) CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), - E->getType(), &Suspicious); + E->getType(), CC, &Suspicious); if (!Suspicious) return; } @@ -2697,7 +2925,7 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) { /// AnalyzeImplicitConversions - Find and report any interesting /// implicit conversions in the given expression. There are a couple /// of competing diagnostics here, -Wconversion and -Wsign-compare. -void AnalyzeImplicitConversions(Sema &S, Expr *OrigE) { +void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { QualType T = OrigE->getType(); Expr *E = OrigE->IgnoreParenImpCasts(); @@ -2713,19 +2941,25 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE) { // The non-canonical typecheck is just an optimization; // CheckImplicitConversion will filter out dead implicit conversions. if (E->getType() != T) - CheckImplicitConversion(S, E, T); + CheckImplicitConversion(S, E, T, CC); // Now continue drilling into this expression. // Skip past explicit casts. if (isa<ExplicitCastExpr>(E)) { E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts(); - return AnalyzeImplicitConversions(S, E); + return AnalyzeImplicitConversions(S, E, CC); } - // Do a somewhat different check with comparison operators. - if (isa<BinaryOperator>(E) && cast<BinaryOperator>(E)->isComparisonOp()) - return AnalyzeComparison(S, cast<BinaryOperator>(E)); + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + // Do a somewhat different check with comparison operators. + if (BO->isComparisonOp()) + return AnalyzeComparison(S, BO); + + // And with assignments and compound assignments. + if (BO->isAssignmentOp()) + return AnalyzeAssignment(S, BO); + } // These break the otherwise-useful invariant below. Fortunately, // we don't really need to recurse into them, because any internal @@ -2737,9 +2971,9 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE) { if (isa<SizeOfAlignOfExpr>(E)) return; // Now just recurse over the expression's children. - for (Stmt::child_iterator I = E->child_begin(), IE = E->child_end(); - I != IE; ++I) - AnalyzeImplicitConversions(S, cast<Expr>(*I)); + CC = E->getExprLoc(); + for (Stmt::child_range I = E->children(); I; ++I) + AnalyzeImplicitConversions(S, cast<Expr>(*I), CC); } } // end anonymous namespace @@ -2747,7 +2981,11 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE) { /// Diagnoses "dangerous" implicit conversions within the given /// expression (which is a full expression). Implements -Wconversion /// and -Wsign-compare. -void Sema::CheckImplicitConversions(Expr *E) { +/// +/// \param CC the "context" location of the implicit conversion, i.e. +/// the most location of the syntactic entity requiring the implicit +/// conversion +void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) { // Don't diagnose in unevaluated contexts. if (ExprEvalContexts.back().Context == Sema::Unevaluated) return; @@ -2756,7 +2994,14 @@ void Sema::CheckImplicitConversions(Expr *E) { if (E->isTypeDependent() || E->isValueDependent()) return; - AnalyzeImplicitConversions(*this, E); + // This is not the right CC for (e.g.) a variable initialization. + AnalyzeImplicitConversions(*this, E, CC); +} + +void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, + FieldDecl *BitField, + Expr *Init) { + (void) AnalyzeBitFieldAssignment(*this, BitField, Init, InitLoc); } /// CheckParmsForFunctionDef - Check that the parameters of the given @@ -2764,11 +3009,12 @@ void Sema::CheckImplicitConversions(Expr *E) { /// takes care of any checks that cannot be performed on the /// declaration itself, e.g., that the types of each of the function /// parameters are complete. -bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { +bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd, + bool CheckParameterNames) { bool HasInvalidParm = false; - for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { - ParmVarDecl *Param = FD->getParamDecl(p); - + for (; P != PEnd; ++P) { + ParmVarDecl *Param = *P; + // C99 6.7.5.3p4: the parameters in a parameter type list in a // function declarator that is part of a function definition of // that function shall not have incomplete type. @@ -2783,7 +3029,8 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { // 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 (CheckParameterNames && + Param->getIdentifier() == 0 && !Param->isImplicit() && !getLangOptions().CPlusPlus) Diag(Param->getLocation(), diag::err_parameter_name_omitted); @@ -2811,7 +3058,8 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { // This is actually a lot of work to potentially be doing on every // cast; don't do it if we're ignoring -Wcast_align (as is the default). - if (getDiagnostics().getDiagnosticLevel(diag::warn_cast_align) + if (getDiagnostics().getDiagnosticLevel(diag::warn_cast_align, + TRange.getBegin()) == Diagnostic::Ignored) return; @@ -2850,3 +3098,47 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { << TRange << Op->getSourceRange(); } +void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) { + const Expr *BaseExpr = E->getBase()->IgnoreParenImpCasts(); + const ConstantArrayType *ArrayTy = + Context.getAsConstantArrayType(BaseExpr->getType()); + if (!ArrayTy) + return; + + const Expr *IndexExpr = E->getIdx(); + if (IndexExpr->isValueDependent()) + return; + llvm::APSInt index; + if (!IndexExpr->isIntegerConstantExpr(index, Context)) + return; + + if (!index.isNegative()) { + llvm::APInt size = ArrayTy->getSize(); + if (!size.isStrictlyPositive()) + return; + if (size.getBitWidth() > index.getBitWidth()) + index = index.sext(size.getBitWidth()); + else if (size.getBitWidth() < index.getBitWidth()) + size = size.sext(index.getBitWidth()); + + if (index.slt(size)) + return; + + Diag(E->getBase()->getLocStart(), diag::warn_array_index_exceeds_bounds) + << index.toString(10, true) << size.toString(10, true) + << IndexExpr->getSourceRange(); + } else { + Diag(E->getBase()->getLocStart(), diag::warn_array_index_precedes_bounds) + << index.toString(10, true) << IndexExpr->getSourceRange(); + } + + const NamedDecl *ND = NULL; + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) + ND = dyn_cast<NamedDecl>(DRE->getDecl()); + if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) + ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); + if (ND) + Diag(ND->getLocStart(), diag::note_array_index_out_of_bounds) + << ND->getDeclName(); +} + diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index f00d1cd..bab665a 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -22,6 +22,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -116,6 +117,9 @@ namespace { /// \brief The semantic analysis object for which results are being /// produced. Sema &SemaRef; + + /// \brief The allocator used to allocate new code-completion strings. + CodeCompletionAllocator &Allocator; /// \brief If non-NULL, a filter function used to remove any code-completion /// results that are not desirable. @@ -146,12 +150,44 @@ namespace { /// \brief The selector that we prefer. Selector PreferredSelector; - void AdjustResultPriorityForPreferredType(Result &R); + /// \brief The completion context in which we are gathering results. + CodeCompletionContext CompletionContext; + + /// \brief If we are in an instance method definition, the @implementation + /// object. + ObjCImplementationDecl *ObjCImplementation; + + void AdjustResultPriorityForDecl(Result &R); + void MaybeAddConstructorResults(Result R); + public: - explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0) - : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false), - HasObjectTypeQualifiers(false) { } + explicit ResultBuilder(Sema &SemaRef, CodeCompletionAllocator &Allocator, + const CodeCompletionContext &CompletionContext, + LookupFilter Filter = 0) + : SemaRef(SemaRef), Allocator(Allocator), Filter(Filter), + AllowNestedNameSpecifiers(false), HasObjectTypeQualifiers(false), + CompletionContext(CompletionContext), + ObjCImplementation(0) + { + // If this is an Objective-C instance method definition, dig out the + // corresponding implementation. + switch (CompletionContext.getKind()) { + case CodeCompletionContext::CCC_Expression: + case CodeCompletionContext::CCC_ObjCMessageReceiver: + case CodeCompletionContext::CCC_ParenthesizedExpression: + case CodeCompletionContext::CCC_Statement: + case CodeCompletionContext::CCC_Recovery: + if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) + if (Method->isInstanceMethod()) + if (ObjCInterfaceDecl *Interface = Method->getClassInterface()) + ObjCImplementation = Interface->getImplementation(); + break; + + default: + break; + } + } /// \brief Whether we should include code patterns in the completion /// results. @@ -165,10 +201,6 @@ namespace { 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(); } @@ -198,12 +230,25 @@ namespace { void setPreferredSelector(Selector Sel) { PreferredSelector = Sel; } + + /// \brief Retrieve the code-completion context for which results are + /// being collected. + const CodeCompletionContext &getCompletionContext() const { + return CompletionContext; + } /// \brief Specify whether nested-name-specifiers are allowed. void allowNestedNameSpecifiers(bool Allow = true) { AllowNestedNameSpecifiers = Allow; } + /// \brief Return the semantic analysis object for which we are collecting + /// code completion results. + Sema &getSema() const { return SemaRef; } + + /// \brief Retrieve the allocator used to allocate code completion strings. + CodeCompletionAllocator &getAllocator() const { return Allocator; } + /// \brief Determine whether the given declaration is at all interesting /// as a code-completion result. /// @@ -278,6 +323,7 @@ namespace { bool IsObjCIvar(NamedDecl *ND) const; bool IsObjCMessageReceiver(NamedDecl *ND) const; bool IsObjCCollection(NamedDecl *ND) const; + bool IsImpossibleToSatisfy(NamedDecl *ND) const; //@} }; } @@ -324,11 +370,11 @@ public: return *this; } - iterator operator++(int) { + /*iterator operator++(int) { iterator tmp(*this); ++(*this); return tmp; - } + }*/ reference operator*() const { if (NamedDecl *ND = DeclOrIterator.dyn_cast<NamedDecl *>()) @@ -464,15 +510,20 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND, return false; } } - - // C++ constructors are never found by name lookup. - if (isa<CXXConstructorDecl>(ND)) + + // Skip out-of-line declarations and definitions. + // NOTE: Unless it's an Objective-C property, method, or ivar, where + // the contexts can be messy. + if (!ND->getDeclContext()->Equals(ND->getLexicalDeclContext()) && + !(isa<ObjCPropertyDecl>(ND) || isa<ObjCIvarDecl>(ND) || + isa<ObjCMethodDecl>(ND))) return false; - + if (Filter == &ResultBuilder::IsNestedNameSpecifier || ((isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) && Filter != &ResultBuilder::IsNamespace && - Filter != &ResultBuilder::IsNamespaceOrAlias)) + Filter != &ResultBuilder::IsNamespaceOrAlias && + Filter != 0)) AsNestedNameSpecifier = true; // Filter out any unwanted results. @@ -535,7 +586,6 @@ SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) { case BuiltinType::Overload: case BuiltinType::Dependent: - case BuiltinType::UndeducedAuto: return STC_Other; case BuiltinType::ObjCId: @@ -621,23 +671,66 @@ QualType clang::getDeclUsageType(ASTContext &C, NamedDecl *ND) { return T.getNonReferenceType(); } -void ResultBuilder::AdjustResultPriorityForPreferredType(Result &R) { - QualType T = getDeclUsageType(SemaRef.Context, R.Declaration); - if (T.isNull()) - return; +void ResultBuilder::AdjustResultPriorityForDecl(Result &R) { + // If this is an Objective-C method declaration whose selector matches our + // preferred selector, give it a priority boost. + if (!PreferredSelector.isNull()) + if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(R.Declaration)) + if (PreferredSelector == Method->getSelector()) + R.Priority += CCD_SelectorMatch; - CanQualType TC = SemaRef.Context.getCanonicalType(T); - // Check for exactly-matching types (modulo qualifiers). - if (SemaRef.Context.hasSameUnqualifiedType(PreferredType, TC)) { - if (PreferredType->isVoidType()) - R.Priority += CCD_VoidMatch; - else - R.Priority /= CCF_ExactTypeMatch; - } // Check for nearly-matching types, based on classification of each. - else if ((getSimplifiedTypeClass(PreferredType) + // If we have a preferred type, adjust the priority for results with exactly- + // matching or nearly-matching types. + if (!PreferredType.isNull()) { + QualType T = getDeclUsageType(SemaRef.Context, R.Declaration); + if (!T.isNull()) { + CanQualType TC = SemaRef.Context.getCanonicalType(T); + // Check for exactly-matching types (modulo qualifiers). + if (SemaRef.Context.hasSameUnqualifiedType(PreferredType, TC)) + R.Priority /= CCF_ExactTypeMatch; + // Check for nearly-matching types, based on classification of each. + else if ((getSimplifiedTypeClass(PreferredType) == getSimplifiedTypeClass(TC)) && - !(PreferredType->isEnumeralType() && TC->isEnumeralType())) - R.Priority /= CCF_SimilarTypeMatch; + !(PreferredType->isEnumeralType() && TC->isEnumeralType())) + R.Priority /= CCF_SimilarTypeMatch; + } + } +} + +void ResultBuilder::MaybeAddConstructorResults(Result R) { + if (!SemaRef.getLangOptions().CPlusPlus || !R.Declaration || + !CompletionContext.wantConstructorResults()) + return; + + ASTContext &Context = SemaRef.Context; + NamedDecl *D = R.Declaration; + CXXRecordDecl *Record = 0; + if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D)) + Record = ClassTemplate->getTemplatedDecl(); + else if ((Record = dyn_cast<CXXRecordDecl>(D))) { + // Skip specializations and partial specializations. + if (isa<ClassTemplateSpecializationDecl>(Record)) + return; + } else { + // There are no constructors here. + return; + } + + Record = Record->getDefinition(); + if (!Record) + return; + + + QualType RecordTy = Context.getTypeDeclType(Record); + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(RecordTy)); + for (DeclContext::lookup_result Ctors = Record->lookup(ConstructorName); + Ctors.first != Ctors.second; ++Ctors.first) { + R.Declaration = *Ctors.first; + R.CursorKind = getCursorKindForDecl(R.Declaration); + Results.push_back(R); + } } void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { @@ -662,6 +755,10 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier)) return; + // C++ constructors are never found by name lookup. + if (isa<CXXConstructorDecl>(R.Declaration)) + return; + ShadowMap &SMap = ShadowMaps.back(); ShadowMapEntry::iterator I, IEnd; ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName()); @@ -719,20 +816,13 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { if (!AllDeclsFound.insert(CanonDecl)) return; - // If this is an Objective-C method declaration whose selector matches our - // preferred selector, give it a priority boost. - if (!PreferredSelector.isNull()) - if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(R.Declaration)) - if (PreferredSelector == Method->getSelector()) - R.Priority += CCD_SelectorMatch; - // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. if (AsNestedNameSpecifier) { R.StartsNestedNameSpecifier = true; R.Priority = CCP_NestedNameSpecifier; - } else if (!PreferredType.isNull()) - AdjustResultPriorityForPreferredType(R); + } else + AdjustResultPriorityForDecl(R); // If this result is supposed to have an informative qualifier, add one. if (R.QualifierIsInformative && !R.Qualifier && @@ -751,6 +841,9 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // map. SMap[R.Declaration->getDeclName()].Add(R.Declaration, Results.size()); Results.push_back(R); + + if (!AsNestedNameSpecifier) + MaybeAddConstructorResults(R); } void ResultBuilder::AddResult(Result R, DeclContext *CurContext, @@ -771,6 +864,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier)) return; + // C++ constructors are never found by name lookup. + if (isa<CXXConstructorDecl>(R.Declaration)) + return; + if (Hiding && CheckHiddenResult(R, CurContext, Hiding)) return; @@ -806,15 +903,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, if (InBaseClass) R.Priority += CCD_InBaseClass; - // If this is an Objective-C method declaration whose selector matches our - // preferred selector, give it a priority boost. - if (!PreferredSelector.isNull()) - if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(R.Declaration)) - if (PreferredSelector == Method->getSelector()) - R.Priority += CCD_SelectorMatch; - - if (!PreferredType.isNull()) - AdjustResultPriorityForPreferredType(R); + AdjustResultPriorityForDecl(R); if (HasObjectTypeQualifiers) if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(R.Declaration)) @@ -832,6 +921,9 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, // Insert this result into the set of results. Results.push_back(R); + + if (!AsNestedNameSpecifier) + MaybeAddConstructorResults(R); } void ResultBuilder::AddResult(Result R) { @@ -864,9 +956,14 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { unsigned IDNS = Decl::IDNS_Ordinary; if (SemaRef.getLangOptions().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member; - else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND)) - return true; - + else if (SemaRef.getLangOptions().ObjC1) { + if (isa<ObjCIvarDecl>(ND)) + return true; + if (isa<ObjCPropertyDecl>(ND) && + SemaRef.canSynthesizeProvisionalIvar(cast<ObjCPropertyDecl>(ND))) + return true; + } + return ND->getIdentifierNamespace() & IDNS; } @@ -880,9 +977,14 @@ bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const { unsigned IDNS = Decl::IDNS_Ordinary; if (SemaRef.getLangOptions().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member; - else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND)) - return true; - + else if (SemaRef.getLangOptions().ObjC1) { + if (isa<ObjCIvarDecl>(ND)) + return true; + if (isa<ObjCPropertyDecl>(ND) && + SemaRef.canSynthesizeProvisionalIvar(cast<ObjCPropertyDecl>(ND))) + return true; + } + return ND->getIdentifierNamespace() & IDNS; } @@ -1038,6 +1140,10 @@ bool ResultBuilder::IsObjCCollection(NamedDecl *ND) const { (SemaRef.getLangOptions().CPlusPlus && T->isRecordType()); } +bool ResultBuilder::IsImpossibleToSatisfy(NamedDecl *ND) const { + return false; +} + /// \rief Determines whether the given declaration is an Objective-C /// instance variable. bool ResultBuilder::IsObjCIvar(NamedDecl *ND) const { @@ -1088,32 +1194,32 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, Results.AddResult(Result("restrict", CCP_Type)); } + CodeCompletionBuilder Builder(Results.getAllocator()); if (LangOpts.CPlusPlus) { // C++-specific - Results.AddResult(Result("bool", CCP_Type)); + Results.AddResult(Result("bool", CCP_Type + + (LangOpts.ObjC1? CCD_bool_in_ObjC : 0))); Results.AddResult(Result("class", CCP_Type)); Results.AddResult(Result("wchar_t", CCP_Type)); // typename qualified-id - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typename"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("qualifier"); - Pattern->AddTextChunk("::"); - Pattern->AddPlaceholderChunk("name"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("typename"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("qualifier"); + Builder.AddTextChunk("::"); + Builder.AddPlaceholderChunk("name"); + Results.AddResult(Result(Builder.TakeString())); if (LangOpts.CPlusPlus0x) { Results.AddResult(Result("auto", CCP_Type)); Results.AddResult(Result("char16_t", CCP_Type)); Results.AddResult(Result("char32_t", CCP_Type)); - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("decltype"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("decltype"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); } } @@ -1124,18 +1230,16 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, // Results.AddResult(Result("_Decimal64")); // Results.AddResult(Result("_Decimal128")); - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typeof"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); - - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typeof"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("type"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("typeof"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("expression"); + Results.AddResult(Result(Builder.TakeString())); + + Builder.AddTypedTextChunk("typeof"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); } } @@ -1180,6 +1284,8 @@ static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC, case Sema::PCC_Condition: case Sema::PCC_RecoveryInFunction: case Sema::PCC_Type: + case Sema::PCC_ParenthesizedExpression: + case Sema::PCC_LocalDeclarationSpecifiers: break; } } @@ -1198,20 +1304,17 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts, static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt); static void AddTypedefResult(ResultBuilder &Results) { - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typedef"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("type"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("name"); - Results.AddResult(CodeCompletionResult(Pattern)); + CodeCompletionBuilder Builder(Results.getAllocator()); + Builder.AddTypedTextChunk("typedef"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("name"); + Results.AddResult(CodeCompletionResult(Builder.TakeString())); } static bool WantTypesInContext(Sema::ParserCompletionContext CCC, const LangOptions &LangOpts) { - if (LangOpts.CPlusPlus) - return true; - switch (CCC) { case Sema::PCC_Namespace: case Sema::PCC_Class: @@ -1221,16 +1324,20 @@ static bool WantTypesInContext(Sema::ParserCompletionContext CCC, case Sema::PCC_Statement: case Sema::PCC_RecoveryInFunction: case Sema::PCC_Type: + case Sema::PCC_ParenthesizedExpression: + case Sema::PCC_LocalDeclarationSpecifiers: return true; - case Sema::PCC_ObjCInterface: - case Sema::PCC_ObjCImplementation: case Sema::PCC_Expression: case Sema::PCC_Condition: + return LangOpts.CPlusPlus; + + case Sema::PCC_ObjCInterface: + case Sema::PCC_ObjCImplementation: return false; case Sema::PCC_ForInit: - return LangOpts.ObjC1 || LangOpts.C99; + return LangOpts.CPlusPlus || LangOpts.ObjC1 || LangOpts.C99; } return false; @@ -1241,58 +1348,53 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Sema &SemaRef, ResultBuilder &Results) { + CodeCompletionBuilder Builder(Results.getAllocator()); + typedef CodeCompletionResult Result; switch (CCC) { case Sema::PCC_Namespace: if (SemaRef.getLangOptions().CPlusPlus) { - CodeCompletionString *Pattern = 0; - if (Results.includeCodePatterns()) { // namespace <identifier> { declarations } - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("namespace"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("declarations"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("namespace"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("identifier"); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("declarations"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Builder.TakeString())); } // namespace identifier = identifier ; - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("namespace"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("name"); - Pattern->AddChunk(CodeCompletionString::CK_Equal); - Pattern->AddPlaceholderChunk("namespace"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("namespace"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("name"); + Builder.AddChunk(CodeCompletionString::CK_Equal); + Builder.AddPlaceholderChunk("namespace"); + Results.AddResult(Result(Builder.TakeString())); // Using directives - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("using"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("namespace"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("identifier"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("using"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("namespace"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("identifier"); + Results.AddResult(Result(Builder.TakeString())); // asm(string-literal) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("asm"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("string-literal"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("asm"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("string-literal"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); if (Results.includeCodePatterns()) { // Explicit template instantiation - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("template"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("declaration"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("template"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("declaration"); + Results.AddResult(Result(Builder.TakeString())); } } @@ -1305,47 +1407,42 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, case Sema::PCC_Class: if (SemaRef.getLangOptions().CPlusPlus) { // Using declaration - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("using"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("qualifier"); - Pattern->AddTextChunk("::"); - Pattern->AddPlaceholderChunk("name"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("using"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("qualifier"); + Builder.AddTextChunk("::"); + Builder.AddPlaceholderChunk("name"); + Results.AddResult(Result(Builder.TakeString())); // using typename qualifier::name (only in a dependent context) if (SemaRef.CurContext->isDependentContext()) { - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("using"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("typename"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("qualifier"); - Pattern->AddTextChunk("::"); - Pattern->AddPlaceholderChunk("name"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("using"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("typename"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("qualifier"); + Builder.AddTextChunk("::"); + Builder.AddPlaceholderChunk("name"); + Results.AddResult(Result(Builder.TakeString())); } if (CCC == Sema::PCC_Class) { AddTypedefResult(Results); // public: - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("public"); - Pattern->AddChunk(CodeCompletionString::CK_Colon); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("public"); + Builder.AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Builder.TakeString())); // protected: - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("protected"); - Pattern->AddChunk(CodeCompletionString::CK_Colon); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("protected"); + Builder.AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Builder.TakeString())); // private: - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("private"); - Pattern->AddChunk(CodeCompletionString::CK_Colon); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("private"); + Builder.AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Builder.TakeString())); } } // Fall through @@ -1354,12 +1451,11 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, case Sema::PCC_MemberTemplate: if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { // template < parameters > - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("template"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("parameters"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("template"); + Builder.AddChunk(CodeCompletionString::CK_LeftAngle); + Builder.AddPlaceholderChunk("parameters"); + Builder.AddChunk(CodeCompletionString::CK_RightAngle); + Results.AddResult(Result(Builder.TakeString())); } AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); @@ -1386,136 +1482,126 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, case Sema::PCC_Statement: { AddTypedefResult(Results); - CodeCompletionString *Pattern = 0; if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("try"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Pattern->AddTextChunk("catch"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("declaration"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("try"); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Builder.AddTextChunk("catch"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("declaration"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Builder.TakeString())); } if (SemaRef.getLangOptions().ObjC1) AddObjCStatementResults(Results, true); if (Results.includeCodePatterns()) { // if (condition) { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("if"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTypedTextChunk("if"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (SemaRef.getLangOptions().CPlusPlus) - Pattern->AddPlaceholderChunk("condition"); + Builder.AddPlaceholderChunk("condition"); else - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Builder.TakeString())); // switch (condition) { } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("switch"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTypedTextChunk("switch"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (SemaRef.getLangOptions().CPlusPlus) - Pattern->AddPlaceholderChunk("condition"); + Builder.AddPlaceholderChunk("condition"); else - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Builder.TakeString())); } // Switch-specific statements. if (!SemaRef.getCurFunction()->SwitchStack.empty()) { // case expression: - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("case"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_Colon); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("case"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Builder.TakeString())); // default: - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("default"); - Pattern->AddChunk(CodeCompletionString::CK_Colon); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("default"); + Builder.AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Builder.TakeString())); } if (Results.includeCodePatterns()) { /// while (condition) { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("while"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTypedTextChunk("while"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (SemaRef.getLangOptions().CPlusPlus) - Pattern->AddPlaceholderChunk("condition"); + Builder.AddPlaceholderChunk("condition"); else - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Builder.TakeString())); // do { statements } while ( expression ); - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("do"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Pattern->AddTextChunk("while"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("do"); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Builder.AddTextChunk("while"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); // for ( for-init-statement ; condition ; expression ) { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("for"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTypedTextChunk("for"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99) - Pattern->AddPlaceholderChunk("init-statement"); + Builder.AddPlaceholderChunk("init-statement"); else - Pattern->AddPlaceholderChunk("init-expression"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); - Pattern->AddPlaceholderChunk("condition"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); - Pattern->AddPlaceholderChunk("inc-expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + Builder.AddPlaceholderChunk("init-expression"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); + Builder.AddPlaceholderChunk("condition"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); + Builder.AddPlaceholderChunk("inc-expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Builder.TakeString())); } if (S->getContinueParent()) { // continue ; - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("continue"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("continue"); + Results.AddResult(Result(Builder.TakeString())); } if (S->getBreakParent()) { // break ; - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("break"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("break"); + Results.AddResult(Result(Builder.TakeString())); } // "return expression ;" or "return ;", depending on whether we @@ -1529,29 +1615,26 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, else if (SemaRef.getCurBlock() && !SemaRef.getCurBlock()->ReturnType.isNull()) isVoid = SemaRef.getCurBlock()->ReturnType->isVoidType(); - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("return"); + Builder.AddTypedTextChunk("return"); if (!isVoid) { - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("expression"); } - Results.AddResult(Result(Pattern)); + Results.AddResult(Result(Builder.TakeString())); // goto identifier ; - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("goto"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("label"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("goto"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("label"); + Results.AddResult(Result(Builder.TakeString())); // Using directives - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("using"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("namespace"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("identifier"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("using"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("namespace"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("identifier"); + Results.AddResult(Result(Builder.TakeString())); } // Fall through (for statement expressions). @@ -1560,8 +1643,8 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); // Fall through: conditions and statements can have expressions. + case Sema::PCC_ParenthesizedExpression: case Sema::PCC_Expression: { - CodeCompletionString *Pattern = 0; if (SemaRef.getLangOptions().CPlusPlus) { // 'this', if we're in a non-static member function. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) @@ -1573,103 +1656,93 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Results.AddResult(Result("false")); // dynamic_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("dynamic_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("dynamic_cast"); + Builder.AddChunk(CodeCompletionString::CK_LeftAngle); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_RightAngle); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); // static_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("static_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("static_cast"); + Builder.AddChunk(CodeCompletionString::CK_LeftAngle); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_RightAngle); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); // reinterpret_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("reinterpret_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("reinterpret_cast"); + Builder.AddChunk(CodeCompletionString::CK_LeftAngle); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_RightAngle); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); // const_cast < type-id > ( expression ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("const_cast"); - Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); - Pattern->AddPlaceholderChunk("type"); - Pattern->AddChunk(CodeCompletionString::CK_RightAngle); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("const_cast"); + Builder.AddChunk(CodeCompletionString::CK_LeftAngle); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_RightAngle); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); // typeid ( expression-or-type ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("typeid"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression-or-type"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("typeid"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression-or-type"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); // new T ( ... ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("new"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("type"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expressions"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("new"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expressions"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); // new T [ ] ( ... ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("new"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("type"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); - Pattern->AddPlaceholderChunk("size"); - Pattern->AddChunk(CodeCompletionString::CK_RightBracket); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expressions"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("new"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_LeftBracket); + Builder.AddPlaceholderChunk("size"); + Builder.AddChunk(CodeCompletionString::CK_RightBracket); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expressions"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); // delete expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("delete"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("delete"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("expression"); + Results.AddResult(Result(Builder.TakeString())); // delete [] expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("delete"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); - Pattern->AddChunk(CodeCompletionString::CK_RightBracket); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("delete"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftBracket); + Builder.AddChunk(CodeCompletionString::CK_RightBracket); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("expression"); + Results.AddResult(Result(Builder.TakeString())); // throw expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("throw"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("throw"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("expression"); + Results.AddResult(Result(Builder.TakeString())); // FIXME: Rethrow? } @@ -1687,16 +1760,16 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, } // sizeof expression - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("sizeof"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression-or-type"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk("sizeof"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression-or-type"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); break; } case Sema::PCC_Type: + case Sema::PCC_LocalDeclarationSpecifiers: break; } @@ -1707,16 +1780,56 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Results.AddResult(Result("operator")); } +/// \brief Retrieve the string representation of the given type as a string +/// that has the appropriate lifetime for code completion. +/// +/// This routine provides a fast path where we provide constant strings for +/// common type names. +const char *GetCompletionTypeString(QualType T, + ASTContext &Context, + CodeCompletionAllocator &Allocator) { + PrintingPolicy Policy(Context.PrintingPolicy); + Policy.AnonymousTagLocations = false; + + if (!T.getLocalQualifiers()) { + // Built-in type names are constant strings. + if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) + return BT->getName(Context.getLangOptions()); + + // Anonymous tag types are constant strings. + if (const TagType *TagT = dyn_cast<TagType>(T)) + if (TagDecl *Tag = TagT->getDecl()) + if (!Tag->getIdentifier() && !Tag->getTypedefForAnonDecl()) { + switch (Tag->getTagKind()) { + case TTK_Struct: return "struct <anonymous>"; + case TTK_Class: return "class <anonymous>"; + case TTK_Union: return "union <anonymous>"; + case TTK_Enum: return "enum <anonymous>"; + } + } + } + + // Slow path: format the type as a string. + std::string Result; + T.getAsStringInternal(Result, Policy); + return Allocator.CopyString(Result); +} + /// \brief If the given declaration has an associated type, add it as a result /// type chunk. static void AddResultTypeChunk(ASTContext &Context, NamedDecl *ND, - CodeCompletionString *Result) { + CodeCompletionBuilder &Result) { if (!ND) return; - + + // Skip constructors and conversion functions, which have their return types + // built into their names. + if (isa<CXXConstructorDecl>(ND) || isa<CXXConversionDecl>(ND)) + return; + // Determine the type of the declaration (if it has a type). - QualType T; + QualType T; if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) T = Function->getResultType(); else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) @@ -1735,25 +1848,21 @@ static void AddResultTypeChunk(ASTContext &Context, if (T.isNull() || Context.hasSameType(T, Context.DependentTy)) return; - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - - std::string TypeStr; - T.getAsStringInternal(TypeStr, Policy); - Result->AddResultTypeChunk(TypeStr); + Result.AddResultTypeChunk(GetCompletionTypeString(T, Context, + Result.getAllocator())); } static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod, - CodeCompletionString *Result) { + CodeCompletionBuilder &Result) { if (SentinelAttr *Sentinel = FunctionOrMethod->getAttr<SentinelAttr>()) if (Sentinel->getSentinel() == 0) { if (Context.getLangOptions().ObjC1 && Context.Idents.get("nil").hasMacroDefinition()) - Result->AddTextChunk(", nil"); + Result.AddTextChunk(", nil"); else if (Context.Idents.get("NULL").hasMacroDefinition()) - Result->AddTextChunk(", NULL"); + Result.AddTextChunk(", NULL"); else - Result->AddTextChunk(", (void*)0"); + Result.AddTextChunk(", (void*)0"); } } @@ -1784,7 +1893,8 @@ static std::string FormatFunctionParameter(ASTContext &Context, // The argument for a block pointer parameter is a block literal with // the appropriate type. - FunctionProtoTypeLoc *Block = 0; + FunctionTypeLoc *Block = 0; + FunctionProtoTypeLoc *BlockProto = 0; TypeLoc TL; if (TypeSourceInfo *TSInfo = Param->getTypeSourceInfo()) { TL = TSInfo->getTypeLoc().getUnqualifiedLoc(); @@ -1808,8 +1918,9 @@ static std::string FormatFunctionParameter(ASTContext &Context, // then we're done. if (BlockPointerTypeLoc *BlockPtr = dyn_cast<BlockPointerTypeLoc>(&TL)) { - TL = BlockPtr->getPointeeLoc(); - Block = dyn_cast<FunctionProtoTypeLoc>(&TL); + TL = BlockPtr->getPointeeLoc().IgnoreParens(); + Block = dyn_cast<FunctionTypeLoc>(&TL); + BlockProto = dyn_cast<FunctionProtoTypeLoc>(&TL); } break; } @@ -1834,47 +1945,65 @@ static std::string FormatFunctionParameter(ASTContext &Context, // We have the function prototype behind the block pointer type, as it was // written in the source. - std::string Result = "(^)("; - for (unsigned I = 0, N = Block->getNumArgs(); I != N; ++I) { - if (I) - Result += ", "; - Result += FormatFunctionParameter(Context, Block->getArg(I)); - - if (I == N - 1 && Block->getTypePtr()->isVariadic()) - Result += ", ..."; - } - if (Block->getTypePtr()->isVariadic() && Block->getNumArgs() == 0) - Result += "..."; - else if (Block->getNumArgs() == 0 && !Context.getLangOptions().CPlusPlus) - Result += "void"; - - Result += ")"; - Block->getTypePtr()->getResultType().getAsStringInternal(Result, - Context.PrintingPolicy); + std::string Result; + QualType ResultType = Block->getTypePtr()->getResultType(); + if (!ResultType->isVoidType()) + ResultType.getAsStringInternal(Result, Context.PrintingPolicy); + + Result = '^' + Result; + if (!BlockProto || Block->getNumArgs() == 0) { + if (BlockProto && BlockProto->getTypePtr()->isVariadic()) + Result += "(...)"; + else + Result += "(void)"; + } else { + Result += "("; + for (unsigned I = 0, N = Block->getNumArgs(); I != N; ++I) { + if (I) + Result += ", "; + Result += FormatFunctionParameter(Context, Block->getArg(I)); + + if (I == N - 1 && BlockProto->getTypePtr()->isVariadic()) + Result += ", ..."; + } + Result += ")"; + } + + if (Param->getIdentifier()) + Result += Param->getIdentifier()->getName(); + return Result; } /// \brief Add function parameter chunks to the given code completion string. static void AddFunctionParameterChunks(ASTContext &Context, FunctionDecl *Function, - CodeCompletionString *Result) { + CodeCompletionBuilder &Result, + unsigned Start = 0, + bool InOptional = false) { typedef CodeCompletionString::Chunk Chunk; + bool FirstParameter = true; - CodeCompletionString *CCStr = Result; - - for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) { + for (unsigned P = Start, N = Function->getNumParams(); P != N; ++P) { ParmVarDecl *Param = Function->getParamDecl(P); - if (Param->hasDefaultArg()) { + if (Param->hasDefaultArg() && !InOptional) { // 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; + CodeCompletionBuilder Opt(Result.getAllocator()); + if (!FirstParameter) + Opt.AddChunk(Chunk(CodeCompletionString::CK_Comma)); + AddFunctionParameterChunks(Context, Function, Opt, P, true); + Result.AddOptionalChunk(Opt.TakeString()); + break; } - if (P != 0) - CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma)); + if (FirstParameter) + FirstParameter = false; + else + Result.AddChunk(Chunk(CodeCompletionString::CK_Comma)); + + InOptional = false; // Format the placeholder string. std::string PlaceholderStr = FormatFunctionParameter(Context, Param); @@ -1883,34 +2012,36 @@ static void AddFunctionParameterChunks(ASTContext &Context, PlaceholderStr += ", ..."; // Add the placeholder string. - CCStr->AddPlaceholderChunk(PlaceholderStr); + Result.AddPlaceholderChunk( + Result.getAllocator().CopyString(PlaceholderStr)); } if (const FunctionProtoType *Proto = Function->getType()->getAs<FunctionProtoType>()) if (Proto->isVariadic()) { if (Proto->getNumArgs() == 0) - CCStr->AddPlaceholderChunk("..."); + Result.AddPlaceholderChunk("..."); - MaybeAddSentinel(Context, Function, CCStr); + MaybeAddSentinel(Context, Function, Result); } } /// \brief Add template parameter chunks to the given code completion string. static void AddTemplateParameterChunks(ASTContext &Context, TemplateDecl *Template, - CodeCompletionString *Result, - unsigned MaxParameters = 0) { + CodeCompletionBuilder &Result, + unsigned MaxParameters = 0, + unsigned Start = 0, + bool InDefaultArg = false) { typedef CodeCompletionString::Chunk Chunk; - - 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) { + for (TemplateParameterList::iterator P = Params->begin() + Start; + P != PEnd; ++P) { bool HasDefaultArg = false; std::string PlaceholderStr; if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { @@ -1926,7 +2057,7 @@ static void AddTemplateParameterChunks(ASTContext &Context, HasDefaultArg = TTP->hasDefaultArgument(); } else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + = dyn_cast<NonTypeTemplateParmDecl>(*P)) { if (NTTP->getIdentifier()) PlaceholderStr = NTTP->getIdentifier()->getName(); NTTP->getType().getAsStringInternal(PlaceholderStr, @@ -1947,28 +2078,35 @@ static void AddTemplateParameterChunks(ASTContext &Context, HasDefaultArg = TTP->hasDefaultArgument(); } - if (HasDefaultArg) { + if (HasDefaultArg && !InDefaultArg) { // 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; + CodeCompletionBuilder Opt(Result.getAllocator()); + if (!FirstParameter) + Opt.AddChunk(Chunk(CodeCompletionString::CK_Comma)); + AddTemplateParameterChunks(Context, Template, Opt, MaxParameters, + P - Params->begin(), true); + Result.AddOptionalChunk(Opt.TakeString()); + break; } + InDefaultArg = false; + if (FirstParameter) FirstParameter = false; else - CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma)); + Result.AddChunk(Chunk(CodeCompletionString::CK_Comma)); // Add the placeholder string. - CCStr->AddPlaceholderChunk(PlaceholderStr); + Result.AddPlaceholderChunk( + Result.getAllocator().CopyString(PlaceholderStr)); } } /// \brief Add a qualifier to the given code-completion string, if the /// provided nested-name-specifier is non-NULL. static void -AddQualifierToCompletionString(CodeCompletionString *Result, +AddQualifierToCompletionString(CodeCompletionBuilder &Result, NestedNameSpecifier *Qualifier, bool QualifierIsInformative, ASTContext &Context) { @@ -1981,18 +2119,38 @@ AddQualifierToCompletionString(CodeCompletionString *Result, Qualifier->print(OS, Context.PrintingPolicy); } if (QualifierIsInformative) - Result->AddInformativeChunk(PrintedNNS); + Result.AddInformativeChunk(Result.getAllocator().CopyString(PrintedNNS)); else - Result->AddTextChunk(PrintedNNS); + Result.AddTextChunk(Result.getAllocator().CopyString(PrintedNNS)); } -static void AddFunctionTypeQualsToCompletionString(CodeCompletionString *Result, - FunctionDecl *Function) { +static void +AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, + FunctionDecl *Function) { const FunctionProtoType *Proto = Function->getType()->getAs<FunctionProtoType>(); if (!Proto || !Proto->getTypeQuals()) return; + // FIXME: Add ref-qualifier! + + // Handle single qualifiers without copying + if (Proto->getTypeQuals() == Qualifiers::Const) { + Result.AddInformativeChunk(" const"); + return; + } + + if (Proto->getTypeQuals() == Qualifiers::Volatile) { + Result.AddInformativeChunk(" volatile"); + return; + } + + if (Proto->getTypeQuals() == Qualifiers::Restrict) { + Result.AddInformativeChunk(" restrict"); + return; + } + + // Handle multiple qualifiers. std::string QualsStr; if (Proto->getTypeQuals() & Qualifiers::Const) QualsStr += " const"; @@ -2000,7 +2158,82 @@ static void AddFunctionTypeQualsToCompletionString(CodeCompletionString *Result, QualsStr += " volatile"; if (Proto->getTypeQuals() & Qualifiers::Restrict) QualsStr += " restrict"; - Result->AddInformativeChunk(QualsStr); + Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr)); +} + +/// \brief Add the name of the given declaration +static void AddTypedNameChunk(ASTContext &Context, NamedDecl *ND, + CodeCompletionBuilder &Result) { + typedef CodeCompletionString::Chunk Chunk; + + DeclarationName Name = ND->getDeclName(); + if (!Name) + return; + + switch (Name.getNameKind()) { + case DeclarationName::CXXOperatorName: { + const char *OperatorName = 0; + switch (Name.getCXXOverloadedOperator()) { + case OO_None: + case OO_Conditional: + case NUM_OVERLOADED_OPERATORS: + OperatorName = "operator"; + break; + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case OO_##Name: OperatorName = "operator" Spelling; break; +#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) +#include "clang/Basic/OperatorKinds.def" + + case OO_New: OperatorName = "operator new"; break; + case OO_Delete: OperatorName = "operator delete"; break; + case OO_Array_New: OperatorName = "operator new[]"; break; + case OO_Array_Delete: OperatorName = "operator delete[]"; break; + case OO_Call: OperatorName = "operator()"; break; + case OO_Subscript: OperatorName = "operator[]"; break; + } + Result.AddTypedTextChunk(OperatorName); + break; + } + + case DeclarationName::Identifier: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXLiteralOperatorName: + Result.AddTypedTextChunk( + Result.getAllocator().CopyString(ND->getNameAsString())); + break; + + case DeclarationName::CXXUsingDirective: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + break; + + case DeclarationName::CXXConstructorName: { + CXXRecordDecl *Record = 0; + QualType Ty = Name.getCXXNameType(); + if (const RecordType *RecordTy = Ty->getAs<RecordType>()) + Record = cast<CXXRecordDecl>(RecordTy->getDecl()); + else if (const InjectedClassNameType *InjectedTy + = Ty->getAs<InjectedClassNameType>()) + Record = InjectedTy->getDecl(); + else { + Result.AddTypedTextChunk( + Result.getAllocator().CopyString(ND->getNameAsString())); + break; + } + + Result.AddTypedTextChunk( + Result.getAllocator().CopyString(Record->getNameAsString())); + if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { + Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); + AddTemplateParameterChunks(Context, Template, Result); + Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); + } + break; + } + } } /// \brief If possible, create a new code completion string for the given @@ -2011,39 +2244,42 @@ static void AddFunctionTypeQualsToCompletionString(CodeCompletionString *Result, /// result is all that is needed. CodeCompletionString * CodeCompletionResult::CreateCodeCompletionString(Sema &S, - CodeCompletionString *Result) { + CodeCompletionAllocator &Allocator) { typedef CodeCompletionString::Chunk Chunk; + CodeCompletionBuilder Result(Allocator, Priority, Availability); - if (Kind == RK_Pattern) - return Pattern->Clone(Result); + if (Kind == RK_Pattern) { + Pattern->Priority = Priority; + Pattern->Availability = Availability; + return Pattern; + } - if (!Result) - Result = new CodeCompletionString; - if (Kind == RK_Keyword) { - Result->AddTypedTextChunk(Keyword); - return Result; + Result.AddTypedTextChunk(Keyword); + return Result.TakeString(); } if (Kind == RK_Macro) { MacroInfo *MI = S.PP.getMacroInfo(Macro); assert(MI && "Not a macro?"); - Result->AddTypedTextChunk(Macro->getName()); + Result.AddTypedTextChunk( + Result.getAllocator().CopyString(Macro->getName())); if (!MI->isFunctionLike()) - return Result; + return Result.TakeString(); // Format a function-like macro with placeholders for the arguments. - Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); + Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); A != AEnd; ++A) { if (A != MI->arg_begin()) - Result->AddChunk(Chunk(CodeCompletionString::CK_Comma)); + Result.AddChunk(Chunk(CodeCompletionString::CK_Comma)); if (!MI->isVariadic() || A != AEnd - 1) { // Non-variadic argument. - Result->AddPlaceholderChunk((*A)->getName()); + Result.AddPlaceholderChunk( + Result.getAllocator().CopyString((*A)->getName())); continue; } @@ -2051,24 +2287,25 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, // variadic macros, providing a single placeholder for the rest of the // arguments. if ((*A)->isStr("__VA_ARGS__")) - Result->AddPlaceholderChunk("..."); + Result.AddPlaceholderChunk("..."); else { std::string Arg = (*A)->getName(); Arg += "..."; - Result->AddPlaceholderChunk(Arg); + Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg)); } } - Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); - return Result; + Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + return Result.TakeString(); } assert(Kind == RK_Declaration && "Missed a result kind?"); NamedDecl *ND = Declaration; if (StartsNestedNameSpecifier) { - Result->AddTypedTextChunk(ND->getNameAsString()); - Result->AddTextChunk("::"); - return Result; + Result.AddTypedTextChunk( + Result.getAllocator().CopyString(ND->getNameAsString())); + Result.AddTextChunk("::"); + return Result.TakeString(); } AddResultTypeChunk(S.Context, ND, Result); @@ -2076,20 +2313,20 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTypedTextChunk(Function->getNameAsString()); - Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); + AddTypedNameChunk(S.Context, ND, Result); + Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); - Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); AddFunctionTypeQualsToCompletionString(Result, Function); - return Result; + return Result.TakeString(); } if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); FunctionDecl *Function = FunTmpl->getTemplatedDecl(); - Result->AddTypedTextChunk(Function->getNameAsString()); - + AddTypedNameChunk(S.Context, Function, Result); + // Figure out which template parameters are deduced (or have default // arguments). llvm::SmallVector<bool, 16> Deduced; @@ -2103,7 +2340,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, // FIXME: We need to abstract template parameters better! bool HasDefaultArg = false; NamedDecl *Param = FunTmpl->getTemplateParameters()->getParam( - LastDeducibleArgument - 1); + LastDeducibleArgument - 1); if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) HasDefaultArg = TTP->hasDefaultArgument(); else if (NonTypeTemplateParmDecl *NTTP @@ -2124,48 +2361,50 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, // 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->AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); + Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); AddTemplateParameterChunks(S.Context, FunTmpl, Result, LastDeducibleArgument); - Result->AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); + Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); } // Add the function parameters - Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); + Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); - Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); AddFunctionTypeQualsToCompletionString(Result, Function); - return Result; + return Result.TakeString(); } if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTypedTextChunk(Template->getNameAsString()); - Result->AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); + Result.AddTypedTextChunk( + Result.getAllocator().CopyString(Template->getNameAsString())); + Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); AddTemplateParameterChunks(S.Context, Template, Result); - Result->AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); - return Result; + Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); + return Result.TakeString(); } if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) { Selector Sel = Method->getSelector(); if (Sel.isUnarySelector()) { - Result->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); - return Result; + Result.AddTypedTextChunk(Result.getAllocator().CopyString( + Sel.getNameForSlot(0))); + return Result.TakeString(); } - std::string SelName = Sel.getIdentifierInfoForSlot(0)->getName().str(); + std::string SelName = Sel.getNameForSlot(0).str(); SelName += ':'; if (StartParameter == 0) - Result->AddTypedTextChunk(SelName); + Result.AddTypedTextChunk(Result.getAllocator().CopyString(SelName)); else { - Result->AddInformativeChunk(SelName); + Result.AddInformativeChunk(Result.getAllocator().CopyString(SelName)); // If there is only one parameter, and we're past it, add an empty // typed-text chunk since there is nothing to type. if (Method->param_size() == 1) - Result->AddTypedTextChunk(""); + Result.AddTypedTextChunk(""); } unsigned Idx = 0; for (ObjCMethodDecl::param_iterator P = Method->param_begin(), @@ -2174,16 +2413,14 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if (Idx > 0) { std::string Keyword; if (Idx > StartParameter) - Result->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Result.AddChunk(CodeCompletionString::CK_HorizontalSpace); if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) Keyword += II->getName().str(); Keyword += ":"; if (Idx < StartParameter || AllParametersAreInformative) - Result->AddInformativeChunk(Keyword); - else if (Idx == StartParameter) - Result->AddTypedTextChunk(Keyword); - else - Result->AddTextChunk(Keyword); + Result.AddInformativeChunk(Result.getAllocator().CopyString(Keyword)); + else + Result.AddTypedTextChunk(Result.getAllocator().CopyString(Keyword)); } // If we're before the starting parameter, skip the placeholder. @@ -2206,44 +2443,47 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, Arg += ", ..."; if (DeclaringEntity) - Result->AddTextChunk(Arg); + Result.AddTextChunk(Result.getAllocator().CopyString(Arg)); else if (AllParametersAreInformative) - Result->AddInformativeChunk(Arg); + Result.AddInformativeChunk(Result.getAllocator().CopyString(Arg)); else - Result->AddPlaceholderChunk(Arg); + Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg)); } if (Method->isVariadic()) { if (Method->param_size() == 0) { if (DeclaringEntity) - Result->AddTextChunk(", ..."); + Result.AddTextChunk(", ..."); else if (AllParametersAreInformative) - Result->AddInformativeChunk(", ..."); + Result.AddInformativeChunk(", ..."); else - Result->AddPlaceholderChunk(", ..."); + Result.AddPlaceholderChunk(", ..."); } MaybeAddSentinel(S.Context, Method, Result); } - return Result; + return Result.TakeString(); } if (Qualifier) AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTypedTextChunk(ND->getNameAsString()); - return Result; + Result.AddTypedTextChunk( + Result.getAllocator().CopyString(ND->getNameAsString())); + return Result.TakeString(); } CodeCompletionString * CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( unsigned CurrentArg, - Sema &S) const { + Sema &S, + CodeCompletionAllocator &Allocator) const { typedef CodeCompletionString::Chunk Chunk; - CodeCompletionString *Result = new CodeCompletionString; + // FIXME: Set priority, availability appropriately. + CodeCompletionBuilder Result(Allocator, 1, CXAvailability_Available); FunctionDecl *FDecl = getFunction(); AddResultTypeChunk(S.Context, FDecl, Result); const FunctionProtoType *Proto @@ -2252,25 +2492,28 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( // 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)); - Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); - Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); - Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); - return Result; + Result.AddTextChunk(GetCompletionTypeString(FT->getResultType(), + S.Context, + Result.getAllocator())); + Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); + Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); + Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + return Result.TakeString(); } if (FDecl) - Result->AddTextChunk(FDecl->getNameAsString()); + Result.AddTextChunk( + Result.getAllocator().CopyString(FDecl->getNameAsString())); else - Result->AddTextChunk( - Proto->getResultType().getAsString(S.Context.PrintingPolicy)); + Result.AddTextChunk( + Result.getAllocator().CopyString( + Proto->getResultType().getAsString(S.Context.PrintingPolicy))); - Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); + Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs(); for (unsigned I = 0; I != NumParams; ++I) { if (I) - Result->AddChunk(Chunk(CodeCompletionString::CK_Comma)); + Result.AddChunk(Chunk(CodeCompletionString::CK_Comma)); std::string ArgString; QualType ArgType; @@ -2285,34 +2528,44 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy); if (I == CurrentArg) - Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, - ArgString)); + Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, + Result.getAllocator().CopyString(ArgString))); else - Result->AddTextChunk(ArgString); + Result.AddTextChunk(Result.getAllocator().CopyString(ArgString)); } if (Proto && Proto->isVariadic()) { - Result->AddChunk(Chunk(CodeCompletionString::CK_Comma)); + Result.AddChunk(Chunk(CodeCompletionString::CK_Comma)); if (CurrentArg < NumParams) - Result->AddTextChunk("..."); + Result.AddTextChunk("..."); else - Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); + Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); } - Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); - return Result; + return Result.TakeString(); } unsigned clang::getMacroUsagePriority(llvm::StringRef MacroName, + const LangOptions &LangOpts, bool PreferredTypeIsPointer) { unsigned Priority = CCP_Macro; - // Treat the "nil" and "NULL" macros as null pointer constants. - if (MacroName.equals("nil") || MacroName.equals("NULL")) { + // Treat the "nil", "Nil" and "NULL" macros as null pointer constants. + if (MacroName.equals("nil") || MacroName.equals("NULL") || + MacroName.equals("Nil")) { Priority = CCP_Constant; if (PreferredTypeIsPointer) Priority = Priority / CCF_SimilarTypeMatch; - } + } + // Treat "YES", "NO", "true", and "false" as constants. + else if (MacroName.equals("YES") || MacroName.equals("NO") || + MacroName.equals("true") || MacroName.equals("false")) + Priority = CCP_Constant; + // Treat "bool" as a type. + else if (MacroName.equals("bool")) + Priority = CCP_Type + (LangOpts.ObjC1? CCD_bool_in_ObjC : 0); + return Priority; } @@ -2385,14 +2638,18 @@ static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results, typedef CodeCompletionResult Result; Results.EnterNewScope(); + for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); M != MEnd; ++M) { Results.AddResult(Result(M->first, getMacroUsagePriority(M->first->getName(), + PP.getLangOptions(), TargetTypeIsPointer))); } + Results.ExitScope(); + } static void AddPrettyFunctionResults(const LangOptions &LangOpts, @@ -2400,6 +2657,7 @@ static void AddPrettyFunctionResults(const LangOptions &LangOpts, typedef CodeCompletionResult Result; Results.EnterNewScope(); + Results.AddResult(Result("__PRETTY_FUNCTION__", CCP_Constant)); Results.AddResult(Result("__FUNCTION__", CCP_Constant)); if (LangOpts.C99 || LangOpts.CPlusPlus0x) @@ -2414,9 +2672,6 @@ static void HandleCodeCompleteResults(Sema *S, unsigned NumResults) { if (CodeCompleter) CodeCompleter->ProcessCodeCompleteResults(*S, Context, Results, NumResults); - - for (unsigned I = 0; I != NumResults; ++I) - Results[I].Destroy(); } static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S, @@ -2439,11 +2694,24 @@ static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S, case Sema::PCC_Template: case Sema::PCC_MemberTemplate: - case Sema::PCC_RecoveryInFunction: - return CodeCompletionContext::CCC_Other; + if (S.CurContext->isFileContext()) + return CodeCompletionContext::CCC_TopLevel; + else if (S.CurContext->isRecord()) + return CodeCompletionContext::CCC_ClassStructUnion; + else + return CodeCompletionContext::CCC_Other; - case Sema::PCC_Expression: + case Sema::PCC_RecoveryInFunction: + return CodeCompletionContext::CCC_Recovery; + case Sema::PCC_ForInit: + if (S.getLangOptions().CPlusPlus || S.getLangOptions().C99 || + S.getLangOptions().ObjC1) + return CodeCompletionContext::CCC_ParenthesizedExpression; + else + return CodeCompletionContext::CCC_Expression; + + case Sema::PCC_Expression: case Sema::PCC_Condition: return CodeCompletionContext::CCC_Expression; @@ -2452,6 +2720,12 @@ static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S, case Sema::PCC_Type: return CodeCompletionContext::CCC_Type; + + case Sema::PCC_ParenthesizedExpression: + return CodeCompletionContext::CCC_ParenthesizedExpression; + + case Sema::PCC_LocalDeclarationSpecifiers: + return CodeCompletionContext::CCC_Type; } return CodeCompletionContext::CCC_Other; @@ -2490,7 +2764,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, for (CXXMethodDecl::method_iterator M = Method->begin_overridden_methods(), MEnd = Method->end_overridden_methods(); M != MEnd; ++M) { - CodeCompletionString *Pattern = new CodeCompletionString; + CodeCompletionBuilder Builder(Results.getAllocator()); CXXMethodDecl *Overridden = const_cast<CXXMethodDecl *>(*M); if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl()) continue; @@ -2504,13 +2778,14 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, std::string Str; llvm::raw_string_ostream OS(Str); NNS->print(OS, S.Context.PrintingPolicy); - Pattern->AddTextChunk(OS.str()); + Builder.AddTextChunk(Results.getAllocator().CopyString(OS.str())); } } else if (!InContext->Equals(Overridden->getDeclContext())) continue; - Pattern->AddTypedTextChunk(Overridden->getNameAsString()); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTypedTextChunk(Results.getAllocator().CopyString( + Overridden->getNameAsString())); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); bool FirstParam = true; for (CXXMethodDecl::param_iterator P = Method->param_begin(), PEnd = Method->param_end(); @@ -2518,12 +2793,13 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, if (FirstParam) FirstParam = false; else - Pattern->AddChunk(CodeCompletionString::CK_Comma); + Builder.AddChunk(CodeCompletionString::CK_Comma); - Pattern->AddPlaceholderChunk((*P)->getIdentifier()->getName()); + Builder.AddPlaceholderChunk(Results.getAllocator().CopyString( + (*P)->getIdentifier()->getName())); } - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(CodeCompletionResult(Pattern, + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Builder.TakeString(), CCP_SuperCompletion, CXCursor_CXXMethod)); Results.Ignore(Overridden); @@ -2533,9 +2809,10 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, void Sema::CodeCompleteOrdinaryName(Scope *S, ParserCompletionContext CompletionContext) { typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + mapCodeCompletionContext(*this, CompletionContext)); Results.EnterNewScope(); - + // Determine how to filter results, e.g., so that the names of // values (functions, enumerators, function templates, etc.) are // only allowed where we can have an expression. @@ -2548,16 +2825,12 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, case PCC_Template: case PCC_MemberTemplate: case PCC_Type: + case PCC_LocalDeclarationSpecifiers: Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); break; case PCC_Statement: - // For statements that are expressions, we prefer to call 'void' functions - // rather than functions that return a result, since then the result would - // be ignored. - Results.setPreferredType(Context.VoidTy); - // Fall through - + case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_ForInit: case PCC_Condition: @@ -2590,6 +2863,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, Results.ExitScope(); switch (CompletionContext) { + case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_Statement: case PCC_RecoveryInFunction: @@ -2607,22 +2881,33 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, case PCC_ForInit: case PCC_Condition: case PCC_Type: + case PCC_LocalDeclarationSpecifiers: break; } if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results); - HandleCodeCompleteResults(this, CodeCompleter, - mapCodeCompletionContext(*this, CompletionContext), + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); } -void Sema::CodeCompleteDeclarator(Scope *S, - bool AllowNonIdentifiers, - bool AllowNestedNameSpecifiers) { +static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, + ParsedType Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents, + bool AtArgumentExpression, + bool IsSuper, + ResultBuilder &Results); + +void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, + bool AllowNonIdentifiers, + bool AllowNestedNameSpecifiers) { typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + AllowNestedNameSpecifiers + ? CodeCompletionContext::CCC_PotentiallyQualifiedName + : CodeCompletionContext::CCC_Name); Results.EnterNewScope(); // Type qualifiers can come after names. @@ -2639,20 +2924,41 @@ void Sema::CodeCompleteDeclarator(Scope *S, // Add nested-name-specifiers. if (AllowNestedNameSpecifiers) { Results.allowNestedNameSpecifiers(); + Results.setFilter(&ResultBuilder::IsImpossibleToSatisfy); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer, CodeCompleter->includeGlobals()); + Results.setFilter(0); } } Results.ExitScope(); + // If we're in a context where we might have an expression (rather than a + // declaration), and what we've seen so far is an Objective-C type that could + // be a receiver of a class message, this may be a class message send with + // the initial opening bracket '[' missing. Add appropriate completions. + if (AllowNonIdentifiers && !AllowNestedNameSpecifiers && + DS.getTypeSpecType() == DeclSpec::TST_typename && + DS.getStorageClassSpecAsWritten() == DeclSpec::SCS_unspecified && + !DS.isThreadSpecified() && !DS.isExternInLinkageSpec() && + DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified && + DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && + DS.getTypeQualifiers() == 0 && + S && + (S->getFlags() & Scope::DeclScope) != 0 && + (S->getFlags() & (Scope::ClassScope | Scope::TemplateParamScope | + Scope::FunctionPrototypeScope | + Scope::AtCatchScope)) == 0) { + ParsedType T = DS.getRepAsType(); + if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType()) + AddClassMessageCompletions(*this, S, T, 0, 0, false, false, Results); + } + // Note that we intentionally suppress macro results here, since we do not // encourage using macros to produce the names of entities. - HandleCodeCompleteResults(this, CodeCompleter, - AllowNestedNameSpecifiers - ? CodeCompletionContext::CCC_PotentiallyQualifiedName - : CodeCompletionContext::CCC_Name, + HandleCodeCompleteResults(this, CodeCompleter, + Results.getCompletionContext(), Results.data(), Results.size()); } @@ -2675,8 +2981,8 @@ struct Sema::CodeCompleteExpressionData { void Sema::CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData &Data) { typedef CodeCompletionResult Result; - ResultBuilder Results(*this); - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Expression); if (Data.ObjCCollection) Results.setFilter(&ResultBuilder::IsObjCCollection); else if (Data.IntegralConstantExpression) @@ -2720,10 +3026,21 @@ void Sema::CodeCompleteExpression(Scope *S, Results.data(),Results.size()); } +void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) { + if (E.isInvalid()) + CodeCompleteOrdinaryName(S, PCC_RecoveryInFunction); + else if (getLangOptions().ObjC1) + CodeCompleteObjCInstanceMessage(S, E.take(), 0, 0, false); +} + +/// \brief The set of properties that have already been added, referenced by +/// property name. +typedef llvm::SmallPtrSet<IdentifierInfo*, 16> AddedPropertiesSet; static void AddObjCProperties(ObjCContainerDecl *Container, bool AllowCategories, DeclContext *CurContext, + AddedPropertiesSet &AddedProperties, ResultBuilder &Results) { typedef CodeCompletionResult Result; @@ -2731,40 +3048,46 @@ static void AddObjCProperties(ObjCContainerDecl *Container, for (ObjCContainerDecl::prop_iterator P = Container->prop_begin(), PEnd = Container->prop_end(); P != PEnd; - ++P) - Results.MaybeAddResult(Result(*P, 0), CurContext); + ++P) { + if (AddedProperties.insert(P->getIdentifier())) + Results.MaybeAddResult(Result(*P, 0), CurContext); + } // Add properties in referenced protocols. if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), PEnd = Protocol->protocol_end(); P != PEnd; ++P) - AddObjCProperties(*P, AllowCategories, CurContext, Results); + AddObjCProperties(*P, AllowCategories, CurContext, AddedProperties, + Results); } else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){ if (AllowCategories) { // Look through categories. for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category; Category = Category->getNextClassCategory()) - AddObjCProperties(Category, AllowCategories, CurContext, Results); + AddObjCProperties(Category, AllowCategories, CurContext, + AddedProperties, Results); } // Look through protocols. for (ObjCInterfaceDecl::all_protocol_iterator I = IFace->all_referenced_protocol_begin(), E = IFace->all_referenced_protocol_end(); I != E; ++I) - AddObjCProperties(*I, AllowCategories, CurContext, Results); + AddObjCProperties(*I, AllowCategories, CurContext, AddedProperties, + Results); // Look in the superclass. if (IFace->getSuperClass()) AddObjCProperties(IFace->getSuperClass(), AllowCategories, CurContext, - Results); + AddedProperties, Results); } else if (const ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) { // Look through protocols. for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(), PEnd = Category->protocol_end(); P != PEnd; ++P) - AddObjCProperties(*P, AllowCategories, CurContext, Results); + AddObjCProperties(*P, AllowCategories, CurContext, AddedProperties, + Results); } } @@ -2788,7 +3111,10 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, return; } - ResultBuilder Results(*this, &ResultBuilder::IsMember); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext(CodeCompletionContext::CCC_MemberAccess, + BaseType), + &ResultBuilder::IsMember); Results.EnterNewScope(); if (const RecordType *Record = BaseType->getAs<RecordType>()) { // Indicate that we are performing a member access, and the cv-qualifiers @@ -2821,18 +3147,20 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, } } else if (!IsArrow && BaseType->getAsObjCInterfacePointerType()) { // Objective-C property reference. + AddedPropertiesSet AddedProperties; // Add property results based on our interface. const ObjCObjectPointerType *ObjCPtr = BaseType->getAsObjCInterfacePointerType(); assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); - AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, CurContext, Results); + AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, CurContext, + AddedProperties, Results); // Add properties from the protocols in a qualified interface. for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(), E = ObjCPtr->qual_end(); I != E; ++I) - AddObjCProperties(*I, true, CurContext, Results); + AddObjCProperties(*I, true, CurContext, AddedProperties, Results); } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCObjectType())) { // Objective-C instance variable access. @@ -2858,8 +3186,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, // Hand off the results found for code completion. HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext(CodeCompletionContext::CCC_MemberAccess, - BaseType), + Results.getCompletionContext(), Results.data(),Results.size()); } @@ -2893,7 +3220,7 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { return; } - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), ContextKind); CodeCompletionDeclConsumer Consumer(Results, CurContext); // First pass: look for tags. @@ -2907,12 +3234,13 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer); } - HandleCodeCompleteResults(this, CodeCompleter, ContextKind, + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); } void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) { - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_TypeQualifiers); Results.EnterNewScope(); if (!(DS.getTypeQualifiers() & DeclSpec::TQ_const)) Results.AddResult("const"); @@ -2923,7 +3251,7 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) { Results.AddResult("restrict"); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_TypeQualifiers, + Results.getCompletionContext(), Results.data(), Results.size()); } @@ -2993,7 +3321,8 @@ void Sema::CodeCompleteCase(Scope *S) { } // Add any enumerators that have not yet been mentioned. - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Expression); Results.EnterNewScope(); for (EnumDecl::enumerator_iterator E = Enum->enumerator_begin(), EEnd = Enum->enumerator_end(); @@ -3001,15 +3330,16 @@ void Sema::CodeCompleteCase(Scope *S) { if (EnumeratorsSeen.count(*E)) continue; - Results.AddResult(CodeCompletionResult(*E, Qualifier), - CurContext, 0, false); + CodeCompletionResult R(*E, Qualifier); + R.Priority = CCP_EnumInCase; + Results.AddResult(R, CurContext, 0, false); } Results.ExitScope(); if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Expression, + CodeCompletionContext::CCC_OtherWithMacros, Results.data(),Results.size()); } @@ -3196,9 +3526,10 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx)) return; - ResultBuilder Results(*this); - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Name); Results.EnterNewScope(); + // 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(); @@ -3226,7 +3557,9 @@ void Sema::CodeCompleteUsing(Scope *S) { if (!CodeCompleter) return; - ResultBuilder Results(*this, &ResultBuilder::IsNestedNameSpecifier); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_PotentiallyQualifiedName, + &ResultBuilder::IsNestedNameSpecifier); Results.EnterNewScope(); // If we aren't in class scope, we could see the "namespace" keyword. @@ -3241,7 +3574,7 @@ void Sema::CodeCompleteUsing(Scope *S) { Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_PotentiallyQualifiedName, Results.data(),Results.size()); } @@ -3251,7 +3584,9 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { // After "using namespace", we expect to see a namespace name or namespace // alias. - ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Namespace, + &ResultBuilder::IsNamespaceOrAlias); Results.EnterNewScope(); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, @@ -3266,12 +3601,20 @@ 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()) { + bool SuppressedGlobalResults + = Ctx && !CodeCompleter->includeGlobals() && isa<TranslationUnitDecl>(Ctx); + + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + SuppressedGlobalResults + ? CodeCompletionContext::CCC_Namespace + : CodeCompletionContext::CCC_Other, + &ResultBuilder::IsNamespace); + + if (Ctx && Ctx->isFileContext() && !SuppressedGlobalResults) { // 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 @@ -3294,7 +3637,7 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { } HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + Results.getCompletionContext(), Results.data(),Results.size()); } @@ -3303,12 +3646,14 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { return; // After "namespace", we expect to see a namespace or alias. - ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Namespace, + &ResultBuilder::IsNamespaceOrAlias); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, CodeCompleter->includeGlobals()); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Namespace, + Results.getCompletionContext(), Results.data(),Results.size()); } @@ -3317,7 +3662,9 @@ void Sema::CodeCompleteOperatorName(Scope *S) { return; typedef CodeCompletionResult Result; - ResultBuilder Results(*this, &ResultBuilder::IsType); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Type, + &ResultBuilder::IsType); Results.EnterNewScope(); // Add the names of overloadable operators. @@ -3342,14 +3689,15 @@ void Sema::CodeCompleteOperatorName(Scope *S) { } void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, - CXXBaseOrMemberInitializer** Initializers, + CXXCtorInitializer** Initializers, unsigned NumInitializers) { CXXConstructorDecl *Constructor = static_cast<CXXConstructorDecl *>(ConstructorD); if (!Constructor) return; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_PotentiallyQualifiedName); Results.EnterNewScope(); // Fill in any already-initialized fields or base classes. @@ -3360,10 +3708,12 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, InitializedBases.insert( Context.getCanonicalType(QualType(Initializers[I]->getBaseClass(), 0))); else - InitializedFields.insert(cast<FieldDecl>(Initializers[I]->getMember())); + InitializedFields.insert(cast<FieldDecl>( + Initializers[I]->getAnyMember())); } // Add completions for base classes. + CodeCompletionBuilder Builder(Results.getAllocator()); bool SawLastInitializer = (NumInitializers == 0); CXXRecordDecl *ClassDecl = Constructor->getParent(); for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), @@ -3378,13 +3728,13 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, continue; } - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk( - Base->getType().getAsString(Context.PrintingPolicy)); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("args"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(CodeCompletionResult(Pattern, + Builder.AddTypedTextChunk( + Results.getAllocator().CopyString( + Base->getType().getAsString(Context.PrintingPolicy))); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("args"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Builder.TakeString(), SawLastInitializer? CCP_NextInitializer : CCP_MemberDeclaration)); SawLastInitializer = false; @@ -3403,13 +3753,13 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, continue; } - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk( - Base->getType().getAsString(Context.PrintingPolicy)); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("args"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(CodeCompletionResult(Pattern, + Builder.AddTypedTextChunk( + Builder.getAllocator().CopyString( + Base->getType().getAsString(Context.PrintingPolicy))); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("args"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Builder.TakeString(), SawLastInitializer? CCP_NextInitializer : CCP_MemberDeclaration)); SawLastInitializer = false; @@ -3422,28 +3772,28 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, if (!InitializedFields.insert(cast<FieldDecl>(Field->getCanonicalDecl()))) { SawLastInitializer = NumInitializers > 0 && - Initializers[NumInitializers - 1]->isMemberInitializer() && - Initializers[NumInitializers - 1]->getMember() == *Field; + Initializers[NumInitializers - 1]->isAnyMemberInitializer() && + Initializers[NumInitializers - 1]->getAnyMember() == *Field; continue; } if (!Field->getDeclName()) continue; - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(Field->getIdentifier()->getName()); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("args"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(CodeCompletionResult(Pattern, + Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( + Field->getIdentifier()->getName())); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("args"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Builder.TakeString(), SawLastInitializer? CCP_NextInitializer - : CCP_MemberDeclaration)); + : CCP_MemberDeclaration, + CXCursor_MemberRef)); SawLastInitializer = false; } Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Name, + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } @@ -3457,21 +3807,19 @@ static void AddObjCImplementationResults(const LangOptions &LangOpts, // Since we have an implementation, we can end it. Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end))); - CodeCompletionString *Pattern = 0; + CodeCompletionBuilder Builder(Results.getAllocator()); if (LangOpts.ObjC2) { // @dynamic - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,dynamic)); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("property"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,dynamic)); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("property"); + Results.AddResult(Result(Builder.TakeString())); // @synthesize - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synthesize)); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("property"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synthesize)); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("property"); + Results.AddResult(Result(Builder.TakeString())); } } @@ -3497,54 +3845,50 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts, static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; - CodeCompletionString *Pattern = 0; + CodeCompletionBuilder Builder(Results.getAllocator()); // @class name ; - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class)); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("name"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class)); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("name"); + Results.AddResult(Result(Builder.TakeString())); if (Results.includeCodePatterns()) { // @interface name // FIXME: Could introduce the whole pattern, including superclasses and // such. - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,interface)); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("class"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,interface)); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("class"); + Results.AddResult(Result(Builder.TakeString())); // @protocol name - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol)); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("protocol"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol)); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("protocol"); + Results.AddResult(Result(Builder.TakeString())); // @implementation name - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,implementation)); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("class"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,implementation)); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("class"); + Results.AddResult(Result(Builder.TakeString())); } // @compatibility_alias name - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,compatibility_alias)); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("alias"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("class"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,compatibility_alias)); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("alias"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("class"); + Results.AddResult(Result(Builder.TakeString())); } void Sema::CodeCompleteObjCAtDirective(Scope *S, Decl *ObjCImpDecl, bool InInterface) { typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); if (ObjCImpDecl) AddObjCImplementationResults(getLangOptions(), Results, false); @@ -3560,78 +3904,72 @@ void Sema::CodeCompleteObjCAtDirective(Scope *S, Decl *ObjCImpDecl, static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; - CodeCompletionString *Pattern = 0; + CodeCompletionBuilder Builder(Results.getAllocator()); // @encode ( type-name ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,encode)); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("type-name"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,encode)); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("type-name"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); // @protocol ( protocol-name ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol)); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("protocol-name"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol)); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("protocol-name"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); // @selector ( selector ) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,selector)); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("selector"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,selector)); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("selector"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); } static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; - CodeCompletionString *Pattern = 0; + CodeCompletionBuilder Builder(Results.getAllocator()); if (Results.includeCodePatterns()) { // @try { statements } @catch ( declaration ) { statements } @finally // { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,try)); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Pattern->AddTextChunk("@catch"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("parameter"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Pattern->AddTextChunk("@finally"); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,try)); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Builder.AddTextChunk("@catch"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("parameter"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Builder.AddTextChunk("@finally"); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Builder.TakeString())); } // @throw - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw)); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw)); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("expression"); + Results.AddResult(Result(Builder.TakeString())); if (Results.includeCodePatterns()) { // @synchronized ( expression ) { statements } - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synchronized)); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.AddResult(Result(Pattern)); + Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synchronized)); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Builder.TakeString())); } } @@ -3647,7 +3985,8 @@ static void AddObjCVisibilityResults(const LangOptions &LangOpts, } void Sema::CodeCompleteObjCAtVisibility(Scope *S) { - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); AddObjCVisibilityResults(getLangOptions(), Results, false); Results.ExitScope(); @@ -3657,7 +3996,8 @@ void Sema::CodeCompleteObjCAtVisibility(Scope *S) { } void Sema::CodeCompleteObjCAtStatement(Scope *S) { - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); AddObjCStatementResults(Results, false); AddObjCExpressionResults(Results, false); @@ -3668,7 +4008,8 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) { } void Sema::CodeCompleteObjCAtExpression(Scope *S) { - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); AddObjCExpressionResults(Results, false); Results.ExitScope(); @@ -3714,7 +4055,8 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { unsigned Attributes = ODS.getPropertyAttributes(); typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readonly)) Results.AddResult(CodeCompletionResult("readonly")); @@ -3729,18 +4071,18 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic)) Results.AddResult(CodeCompletionResult("nonatomic")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) { - CodeCompletionString *Setter = new CodeCompletionString; - Setter->AddTypedTextChunk("setter"); - Setter->AddTextChunk(" = "); - Setter->AddPlaceholderChunk("method"); - Results.AddResult(CodeCompletionResult(Setter)); + CodeCompletionBuilder Setter(Results.getAllocator()); + Setter.AddTypedTextChunk("setter"); + Setter.AddTextChunk(" = "); + Setter.AddPlaceholderChunk("method"); + Results.AddResult(CodeCompletionResult(Setter.TakeString())); } if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_getter)) { - CodeCompletionString *Getter = new CodeCompletionString; - Getter->AddTypedTextChunk("getter"); - Getter->AddTextChunk(" = "); - Getter->AddPlaceholderChunk("method"); - Results.AddResult(CodeCompletionResult(Getter)); + CodeCompletionBuilder Getter(Results.getAllocator()); + Getter.AddTypedTextChunk("getter"); + Getter.AddTextChunk(" = "); + Getter.AddPlaceholderChunk("method"); + Results.AddResult(CodeCompletionResult(Getter.TakeString())); } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, @@ -3759,7 +4101,8 @@ enum ObjCMethodKind { static bool isAcceptableObjCSelector(Selector Sel, ObjCMethodKind WantKind, IdentifierInfo **SelIdents, - unsigned NumSelIdents) { + unsigned NumSelIdents, + bool AllowSameLength = true) { if (NumSelIdents > Sel.getNumArgs()) return false; @@ -3769,6 +4112,9 @@ static bool isAcceptableObjCSelector(Selector Sel, case MK_OneArgSelector: return Sel.getNumArgs() == 1; } + if (!AllowSameLength && NumSelIdents && NumSelIdents == Sel.getNumArgs()) + return false; + for (unsigned I = 0; I != NumSelIdents; ++I) if (SelIdents[I] != Sel.getIdentifierInfoForSlot(I)) return false; @@ -3779,11 +4125,18 @@ static bool isAcceptableObjCSelector(Selector Sel, static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, ObjCMethodKind WantKind, IdentifierInfo **SelIdents, - unsigned NumSelIdents) { + unsigned NumSelIdents, + bool AllowSameLength = true) { return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents, - NumSelIdents); + NumSelIdents, AllowSameLength); } - + +namespace { + /// \brief A set of selectors, which is used to avoid introducing multiple + /// completions with the same selector into the result set. + typedef llvm::SmallPtrSet<Selector, 16> VisitedSelectorSet; +} + /// \brief Add all of the Objective-C methods in the given Objective-C /// container to the set of results. /// @@ -3800,6 +4153,9 @@ static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, /// \param CurContext the context in which we're performing the lookup that /// finds methods. /// +/// \param AllowSameLength Whether we allow a method to be added to the list +/// when it has the same number of parameters as we have selector identifiers. +/// /// \param Results the structure into which we'll add results. static void AddObjCMethods(ObjCContainerDecl *Container, bool WantInstanceMethods, @@ -3807,6 +4163,8 @@ static void AddObjCMethods(ObjCContainerDecl *Container, IdentifierInfo **SelIdents, unsigned NumSelIdents, DeclContext *CurContext, + VisitedSelectorSet &Selectors, + bool AllowSameLength, ResultBuilder &Results, bool InOriginalClass = true) { typedef CodeCompletionResult Result; @@ -3816,9 +4174,13 @@ static void AddObjCMethods(ObjCContainerDecl *Container, if ((*M)->isInstanceMethod() == WantInstanceMethods) { // Check whether the selector identifiers we've been given are a // subset of the identifiers for this particular method. - if (!isAcceptableObjCMethod(*M, WantKind, SelIdents, NumSelIdents)) + if (!isAcceptableObjCMethod(*M, WantKind, SelIdents, NumSelIdents, + AllowSameLength)) continue; + if (!Selectors.insert((*M)->getSelector())) + continue; + Result R = Result(*M, 0); R.StartParameter = NumSelIdents; R.AllParametersAreInformative = (WantKind != MK_Any); @@ -3828,6 +4190,17 @@ static void AddObjCMethods(ObjCContainerDecl *Container, } } + // Visit the protocols of protocols. + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { + const ObjCList<ObjCProtocolDecl> &Protocols + = Protocol->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) + AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents, + CurContext, Selectors, AllowSameLength, Results, false); + } + ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container); if (!IFace) return; @@ -3838,13 +4211,14 @@ static void AddObjCMethods(ObjCContainerDecl *Container, E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents, - CurContext, Results, false); + CurContext, Selectors, AllowSameLength, Results, false); // Add methods in categories. for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl; CatDecl = CatDecl->getNextClassCategory()) { AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results, InOriginalClass); + NumSelIdents, CurContext, Selectors, AllowSameLength, + Results, InOriginalClass); // Add a categories protocol methods. const ObjCList<ObjCProtocolDecl> &Protocols @@ -3853,29 +4227,31 @@ static void AddObjCMethods(ObjCContainerDecl *Container, E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results, false); + NumSelIdents, CurContext, Selectors, AllowSameLength, + Results, false); // Add methods in category implementations. if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation()) AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results, InOriginalClass); + NumSelIdents, CurContext, Selectors, AllowSameLength, + Results, InOriginalClass); } // Add methods in superclass. if (IFace->getSuperClass()) AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind, - SelIdents, NumSelIdents, CurContext, Results, false); + SelIdents, NumSelIdents, CurContext, Selectors, + AllowSameLength, Results, false); // Add methods in our implementation, if any. if (ObjCImplementationDecl *Impl = IFace->getImplementation()) AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results, InOriginalClass); + NumSelIdents, CurContext, Selectors, AllowSameLength, + Results, InOriginalClass); } -void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl, - Decl **Methods, - unsigned NumMethods) { +void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl) { typedef CodeCompletionResult Result; // Try to find the interface where getters might live. @@ -3890,32 +4266,20 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl, } // Find all of the potential getters. - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - // FIXME: We need to do this because Objective-C methods don't get - // pushed into DeclContexts early enough. Argh! - for (unsigned I = 0; I != NumMethods; ++I) { - if (ObjCMethodDecl *Method - = dyn_cast_or_null<ObjCMethodDecl>(Methods[I])) - if (Method->isInstanceMethod() && - isAcceptableObjCMethod(Method, MK_ZeroArgSelector, 0, 0)) { - Result R = Result(Method, 0); - R.AllParametersAreInformative = true; - Results.MaybeAddResult(R, CurContext); - } - } - - AddObjCMethods(Class, true, MK_ZeroArgSelector, 0, 0, CurContext, Results); + VisitedSelectorSet Selectors; + AddObjCMethods(Class, true, MK_ZeroArgSelector, 0, 0, CurContext, Selectors, + /*AllowSameLength=*/true, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, Results.data(),Results.size()); } -void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl, - Decl **Methods, - unsigned NumMethods) { +void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl) { typedef CodeCompletionResult Result; // Try to find the interface where setters might live. @@ -3931,23 +4295,13 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl, } // Find all of the potential getters. - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - // FIXME: We need to do this because Objective-C methods don't get - // pushed into DeclContexts early enough. Argh! - for (unsigned I = 0; I != NumMethods; ++I) { - if (ObjCMethodDecl *Method - = dyn_cast_or_null<ObjCMethodDecl>(Methods[I])) - if (Method->isInstanceMethod() && - isAcceptableObjCMethod(Method, MK_OneArgSelector, 0, 0)) { - Result R = Result(Method, 0); - R.AllParametersAreInformative = true; - Results.MaybeAddResult(R, CurContext); - } - } - - AddObjCMethods(Class, true, MK_OneArgSelector, 0, 0, CurContext, Results); + VisitedSelectorSet Selectors; + AddObjCMethods(Class, true, MK_OneArgSelector, 0, 0, CurContext, + Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, @@ -3955,9 +4309,11 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl, Results.data(),Results.size()); } -void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS) { +void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, + bool IsParameter) { typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Type); Results.EnterNewScope(); // Add context-sensitive, Objective-C parameter-passing keywords. @@ -3982,6 +4338,26 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS) { Results.AddResult("oneway"); } + // If we're completing the return type of an Objective-C method and the + // identifier IBAction refers to a macro, provide a completion item for + // an action, e.g., + // IBAction)<#selector#>:(id)sender + if (DS.getObjCDeclQualifier() == 0 && !IsParameter && + Context.Idents.get("IBAction").hasMacroDefinition()) { + typedef CodeCompletionString::Chunk Chunk; + CodeCompletionBuilder Builder(Results.getAllocator(), CCP_CodePattern, + CXAvailability_Available); + Builder.AddTypedTextChunk("IBAction"); + Builder.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + Builder.AddPlaceholderChunk("selector"); + Builder.AddChunk(Chunk(CodeCompletionString::CK_Colon)); + Builder.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); + Builder.AddTextChunk("id"); + Builder.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + Builder.AddTextChunk("sender"); + Results.AddResult(CodeCompletionResult(Builder.TakeString())); + } + // Add various builtin type names and specifiers. AddOrdinaryNameResults(PCC_Type, S, *this, Results); Results.ExitScope(); @@ -4005,7 +4381,7 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS) { /// common uses of Objective-C. This routine returns that class type, /// or NULL if no better result could be determined. static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { - ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E); + ObjCMessageExpr *Msg = dyn_cast_or_null<ObjCMessageExpr>(E); if (!Msg) return 0; @@ -4102,10 +4478,21 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword, // Try to find a superclass method with the same selector. ObjCMethodDecl *SuperMethod = 0; - while ((Class = Class->getSuperClass()) && !SuperMethod) + while ((Class = Class->getSuperClass()) && !SuperMethod) { + // Check in the class SuperMethod = Class->getMethod(CurMethod->getSelector(), CurMethod->isInstanceMethod()); + // Check in categories or class extensions. + if (!SuperMethod) { + for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category; + Category = Category->getNextClassCategory()) + if ((SuperMethod = Category->getMethod(CurMethod->getSelector(), + CurMethod->isInstanceMethod()))) + break; + } + } + if (!SuperMethod) return 0; @@ -4129,45 +4516,52 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword, } // We have a superclass method. Now, form the send-to-super completion. - CodeCompletionString *Pattern = new CodeCompletionString; + CodeCompletionBuilder Builder(Results.getAllocator()); // Give this completion a return type. - AddResultTypeChunk(S.Context, SuperMethod, Pattern); + AddResultTypeChunk(S.Context, SuperMethod, Builder); // If we need the "super" keyword, add it (plus some spacing). if (NeedSuperKeyword) { - Pattern->AddTypedTextChunk("super"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTypedTextChunk("super"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); } Selector Sel = CurMethod->getSelector(); if (Sel.isUnarySelector()) { if (NeedSuperKeyword) - Pattern->AddTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); + Builder.AddTextChunk(Builder.getAllocator().CopyString( + Sel.getNameForSlot(0))); else - Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); + Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( + Sel.getNameForSlot(0))); } else { ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin(); for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I, ++CurP) { if (I > NumSelIdents) - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); if (I < NumSelIdents) - Pattern->AddInformativeChunk( - Sel.getIdentifierInfoForSlot(I)->getName().str() + ":"); + Builder.AddInformativeChunk( + Builder.getAllocator().CopyString( + Sel.getNameForSlot(I) + ":")); else if (NeedSuperKeyword || I > NumSelIdents) { - Pattern->AddTextChunk( - Sel.getIdentifierInfoForSlot(I)->getName().str() + ":"); - Pattern->AddPlaceholderChunk((*CurP)->getIdentifier()->getName()); + Builder.AddTextChunk( + Builder.getAllocator().CopyString( + Sel.getNameForSlot(I) + ":")); + Builder.AddPlaceholderChunk(Builder.getAllocator().CopyString( + (*CurP)->getIdentifier()->getName())); } else { - Pattern->AddTypedTextChunk( - Sel.getIdentifierInfoForSlot(I)->getName().str() + ":"); - Pattern->AddPlaceholderChunk((*CurP)->getIdentifier()->getName()); + Builder.AddTypedTextChunk( + Builder.getAllocator().CopyString( + Sel.getNameForSlot(I) + ":")); + Builder.AddPlaceholderChunk(Builder.getAllocator().CopyString( + (*CurP)->getIdentifier()->getName())); } } } - Results.AddResult(CodeCompletionResult(Pattern, CCP_SuperCompletion, + Results.AddResult(CodeCompletionResult(Builder.TakeString(), CCP_SuperCompletion, SuperMethod->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl)); @@ -4176,10 +4570,10 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword, void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_ObjCMessageReceiver, + &ResultBuilder::IsObjCMessageReceiver); - // Find anything that looks like it could be a message receiver. - Results.setFilter(&ResultBuilder::IsObjCMessageReceiver); CodeCompletionDeclConsumer Consumer(Results, CurContext); Results.EnterNewScope(); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, @@ -4199,15 +4593,15 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCMessageReceiver, + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, IdentifierInfo **SelIdents, - unsigned NumSelIdents) { + unsigned NumSelIdents, + bool AtArgumentExpression) { ObjCInterfaceDecl *CDecl = 0; if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { // Figure out which interface we're in. @@ -4223,15 +4617,11 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, if (CurMethod->isInstanceMethod()) { // We are inside an instance method, which means that the message // send [super ...] is actually calling an instance method on the - // current object. Build the super expression and handle this like - // an instance method. - QualType SuperTy = Context.getObjCInterfaceType(CDecl); - SuperTy = Context.getObjCObjectPointerType(SuperTy); - ExprResult Super - = Owned(new (Context) ObjCSuperExpr(SuperLoc, SuperTy)); - return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), + // current object. + return CodeCompleteObjCInstanceMessage(S, 0, SelIdents, NumSelIdents, - /*IsSuper=*/true); + AtArgumentExpression, + CDecl); } // Fall through to send to the superclass in CDecl. @@ -4256,7 +4646,8 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, id.setIdentifier(Super, SuperLoc); ExprResult SuperExpr = ActOnIdExpression(S, SS, id, false, false); return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(), - SelIdents, NumSelIdents); + SelIdents, NumSelIdents, + AtArgumentExpression); } // Fall through @@ -4266,71 +4657,105 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, if (CDecl) Receiver = ParsedType::make(Context.getObjCInterfaceType(CDecl)); return CodeCompleteObjCClassMessage(S, Receiver, SelIdents, - NumSelIdents, /*IsSuper=*/true); + NumSelIdents, AtArgumentExpression, + /*IsSuper=*/true); } -void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, - IdentifierInfo **SelIdents, - unsigned NumSelIdents) { - CodeCompleteObjCClassMessage(S, Receiver, SelIdents, NumSelIdents, false); +/// \brief Given a set of code-completion results for the argument of a message +/// send, determine the preferred type (if any) for that argument expression. +static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results, + unsigned NumSelIdents) { + typedef CodeCompletionResult Result; + ASTContext &Context = Results.getSema().Context; + + QualType PreferredType; + unsigned BestPriority = CCP_Unlikely * 2; + Result *ResultsData = Results.data(); + for (unsigned I = 0, N = Results.size(); I != N; ++I) { + Result &R = ResultsData[I]; + if (R.Kind == Result::RK_Declaration && + isa<ObjCMethodDecl>(R.Declaration)) { + if (R.Priority <= BestPriority) { + ObjCMethodDecl *Method = cast<ObjCMethodDecl>(R.Declaration); + if (NumSelIdents <= Method->param_size()) { + QualType MyPreferredType = Method->param_begin()[NumSelIdents - 1] + ->getType(); + if (R.Priority < BestPriority || PreferredType.isNull()) { + BestPriority = R.Priority; + PreferredType = MyPreferredType; + } else if (!Context.hasSameUnqualifiedType(PreferredType, + MyPreferredType)) { + PreferredType = QualType(); + } + } + } + } + } + + return PreferredType; } -void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, - IdentifierInfo **SelIdents, - unsigned NumSelIdents, - bool IsSuper) { +static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, + ParsedType Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents, + bool AtArgumentExpression, + bool IsSuper, + ResultBuilder &Results) { typedef CodeCompletionResult Result; ObjCInterfaceDecl *CDecl = 0; - + // If the given name refers to an interface type, retrieve the // corresponding declaration. if (Receiver) { - QualType T = GetTypeFromParser(Receiver, 0); + QualType T = SemaRef.GetTypeFromParser(Receiver, 0); if (!T.isNull()) if (const ObjCObjectType *Interface = T->getAs<ObjCObjectType>()) CDecl = Interface->getInterface(); } - + // Add all of the factory methods in this Objective-C class, its protocols, // superclasses, categories, implementation, etc. - ResultBuilder Results(*this); Results.EnterNewScope(); - + // If this is a send-to-super, try to add the special "super" send // completion. if (IsSuper) { if (ObjCMethodDecl *SuperMethod - = AddSuperSendCompletion(*this, false, SelIdents, NumSelIdents, - Results)) + = AddSuperSendCompletion(SemaRef, false, SelIdents, NumSelIdents, + Results)) Results.Ignore(SuperMethod); } - + // If we're inside an Objective-C method definition, prefer its selector to // others. - if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) + if (ObjCMethodDecl *CurMethod = SemaRef.getCurMethodDecl()) Results.setPreferredSelector(CurMethod->getSelector()); - + + VisitedSelectorSet Selectors; if (CDecl) - AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext, + AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, + SemaRef.CurContext, Selectors, AtArgumentExpression, Results); else { // We're messaging "id" as a type; provide all class/factory methods. - + // If we have an external source, load the entire class method // pool from the AST file. - if (ExternalSource) { - for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors(); + if (SemaRef.ExternalSource) { + for (uint32_t I = 0, + N = SemaRef.ExternalSource->GetNumExternalSelectors(); I != N; ++I) { - Selector Sel = ExternalSource->GetExternalSelector(I); - if (Sel.isNull() || MethodPool.count(Sel)) + Selector Sel = SemaRef.ExternalSource->GetExternalSelector(I); + if (Sel.isNull() || SemaRef.MethodPool.count(Sel)) continue; - - ReadMethodPool(Sel); + + SemaRef.ReadMethodPool(Sel); } } - - for (GlobalMethodPool::iterator M = MethodPool.begin(), - MEnd = MethodPool.end(); + + for (Sema::GlobalMethodPool::iterator M = SemaRef.MethodPool.begin(), + MEnd = SemaRef.MethodPool.end(); M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.second; MethList && MethList->Method; @@ -4338,16 +4763,43 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; - + Result R(MethList->Method, 0); R.StartParameter = NumSelIdents; R.AllParametersAreInformative = false; - Results.MaybeAddResult(R, CurContext); + Results.MaybeAddResult(R, SemaRef.CurContext); } } } + + Results.ExitScope(); +} + +void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents, + bool AtArgumentExpression, + bool IsSuper) { + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); + AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents, + AtArgumentExpression, IsSuper, Results); + + // If we're actually at the argument expression (rather than prior to the + // selector), we're actually performing code completion for an expression. + // Determine whether we have a single, best method. If so, we can + // code-complete the expression using the corresponding parameter type as + // our preferred type, improving completion results. + if (AtArgumentExpression) { + QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, + NumSelIdents); + if (PreferredType.isNull()) + CodeCompleteOrdinaryName(S, PCC_Expression); + else + CodeCompleteExpression(S, PreferredType); + return; + } - Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, Results.data(), Results.size()); @@ -4355,30 +4807,45 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, IdentifierInfo **SelIdents, - unsigned NumSelIdents) { - CodeCompleteObjCInstanceMessage(S, Receiver, SelIdents, NumSelIdents, false); -} - -void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, - IdentifierInfo **SelIdents, unsigned NumSelIdents, - bool IsSuper) { + bool AtArgumentExpression, + ObjCInterfaceDecl *Super) { typedef CodeCompletionResult Result; Expr *RecExpr = static_cast<Expr *>(Receiver); // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. - DefaultFunctionArrayLvalueConversion(RecExpr); - QualType ReceiverType = RecExpr->getType(); + if (RecExpr) + DefaultFunctionArrayLvalueConversion(RecExpr); + QualType ReceiverType = RecExpr? RecExpr->getType() + : Super? Context.getObjCObjectPointerType( + Context.getObjCInterfaceType(Super)) + : Context.getObjCIdType(); + // If we're messaging an expression with type "id" or "Class", check + // whether we know something special about the receiver that allows + // us to assume a more-specific receiver type. + if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType()) + if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr)) { + if (ReceiverType->isObjCClassType()) + return CodeCompleteObjCClassMessage(S, + ParsedType::make(Context.getObjCInterfaceType(IFace)), + SelIdents, NumSelIdents, + AtArgumentExpression, Super); + + ReceiverType = Context.getObjCObjectPointerType( + Context.getObjCInterfaceType(IFace)); + } + // Build the set of methods we can see. - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); // If this is a send-to-super, try to add the special "super" send // completion. - if (IsSuper) { + if (Super) { if (ObjCMethodDecl *SuperMethod = AddSuperSendCompletion(*this, false, SelIdents, NumSelIdents, Results)) @@ -4389,14 +4856,9 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, // others. if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) Results.setPreferredSelector(CurMethod->getSelector()); - - // If we're messaging an expression with type "id" or "Class", check - // whether we know something special about the receiver that allows - // us to assume a more-specific receiver type. - if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType()) - if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr)) - ReceiverType = Context.getObjCObjectPointerType( - Context.getObjCInterfaceType(IFace)); + + // Keep track of the selectors we've already added. + VisitedSelectorSet Selectors; // Handle messages to Class. This really isn't a message to an instance // method, so we treat it the same way we would treat a message send to a @@ -4406,7 +4868,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMethod->getClassInterface()) AddObjCMethods(ClassDecl, false, MK_Any, SelIdents, NumSelIdents, - CurContext, Results); + CurContext, Selectors, AtArgumentExpression, Results); } } // Handle messages to a qualified ID ("id<foo>"). @@ -4417,21 +4879,22 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, E = QualID->qual_end(); I != E; ++I) AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext, - Results); + Selectors, AtArgumentExpression, Results); } // Handle messages to a pointer to interface type. else if (const ObjCObjectPointerType *IFacePtr = ReceiverType->getAsObjCInterfacePointerType()) { // Search the class, its superclasses, etc., for instance methods. AddObjCMethods(IFacePtr->getInterfaceDecl(), true, MK_Any, SelIdents, - NumSelIdents, CurContext, Results); + NumSelIdents, CurContext, Selectors, AtArgumentExpression, + Results); // Search protocols for instance methods. for (ObjCObjectPointerType::qual_iterator I = IFacePtr->qual_begin(), E = IFacePtr->qual_end(); I != E; ++I) AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext, - Results); + Selectors, AtArgumentExpression, Results); } // Handle messages to "id". else if (ReceiverType->isObjCIdType()) { @@ -4460,7 +4923,10 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; - + + if (!Selectors.insert(MethList->Method->getSelector())) + continue; + Result R(MethList->Method, 0); R.StartParameter = NumSelIdents; R.AllParametersAreInformative = false; @@ -4468,8 +4934,24 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, } } } - Results.ExitScope(); + + + // If we're actually at the argument expression (rather than prior to the + // selector), we're actually performing code completion for an expression. + // Determine whether we have a single, best method. If so, we can + // code-complete the expression using the corresponding parameter type as + // our preferred type, improving completion results. + if (AtArgumentExpression) { + QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, + NumSelIdents); + if (PreferredType.isNull()) + CodeCompleteOrdinaryName(S, PCC_Expression); + else + CodeCompleteExpression(S, PreferredType); + return; + } + HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, Results.data(),Results.size()); @@ -4506,7 +4988,8 @@ void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents, } } - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_SelectorName); Results.EnterNewScope(); for (GlobalMethodPool::iterator M = MethodPool.begin(), MEnd = MethodPool.end(); @@ -4516,10 +4999,11 @@ void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents, if (!isAcceptableObjCSelector(Sel, MK_Any, SelIdents, NumSelIdents)) continue; - CodeCompletionString *Pattern = new CodeCompletionString; + CodeCompletionBuilder Builder(Results.getAllocator()); if (Sel.isUnarySelector()) { - Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( + Sel.getNameForSlot(0))); + Results.AddResult(Builder.TakeString()); continue; } @@ -4527,16 +5011,17 @@ void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents, for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I) { if (I == NumSelIdents) { if (!Accumulator.empty()) { - Pattern->AddInformativeChunk(Accumulator); + Builder.AddInformativeChunk(Builder.getAllocator().CopyString( + Accumulator)); Accumulator.clear(); } } - Accumulator += Sel.getIdentifierInfoForSlot(I)->getName().str(); + Accumulator += Sel.getNameForSlot(I).str(); Accumulator += ':'; } - Pattern->AddTypedTextChunk(Accumulator); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( Accumulator)); + Results.AddResult(Builder.TakeString()); } Results.ExitScope(); @@ -4575,35 +5060,46 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, unsigned NumProtocols) { - ResultBuilder Results(*this); - Results.EnterNewScope(); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_ObjCProtocolName); - // Tell the result set to ignore all of the protocols we have - // already seen. - for (unsigned I = 0; I != NumProtocols; ++I) - if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first, - Protocols[I].second)) - Results.Ignore(Protocol); - - // Add all protocols. - AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, false, - Results); + if (CodeCompleter && CodeCompleter->includeGlobals()) { + Results.EnterNewScope(); + + // Tell the result set to ignore all of the protocols we have + // already seen. + // FIXME: This doesn't work when caching code-completion results. + for (unsigned I = 0; I != NumProtocols; ++I) + if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first, + Protocols[I].second)) + Results.Ignore(Protocol); + + // Add all protocols. + AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, false, + Results); - Results.ExitScope(); + Results.ExitScope(); + } + HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_ObjCProtocolName, Results.data(),Results.size()); } void Sema::CodeCompleteObjCProtocolDecl(Scope *) { - ResultBuilder Results(*this); - Results.EnterNewScope(); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_ObjCProtocolName); - // Add all protocols. - AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, true, - Results); + if (CodeCompleter && CodeCompleter->includeGlobals()) { + Results.EnterNewScope(); + + // Add all protocols. + AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, true, + Results); - Results.ExitScope(); + Results.ExitScope(); + } + HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_ObjCProtocolName, Results.data(),Results.size()); @@ -4639,7 +5135,8 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, } void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); // Add all classes. @@ -4647,6 +5144,8 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { false, Results); Results.ExitScope(); + // FIXME: Add a special context for this, use cached global completion + // results. HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, Results.data(),Results.size()); @@ -4654,7 +5153,8 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); // Make sure that we ignore the class we're currently defining. @@ -4668,13 +5168,16 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, false, Results); Results.ExitScope(); + // FIXME: Add a special context for this, use cached global completion + // results. HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, Results.data(),Results.size()); } void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); // Add all unimplemented classes. @@ -4682,6 +5185,8 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { true, Results); Results.ExitScope(); + // FIXME: Add a special context for this, use cached global completion + // results. HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, Results.data(),Results.size()); @@ -4692,7 +5197,8 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, SourceLocation ClassNameLoc) { typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); // Ignore any categories we find that have already been implemented by this // interface. @@ -4734,7 +5240,8 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, if (!Class) return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc); - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); // Add all of the categories that have have corresponding interface // declarations in this class and any of its superclasses, except for @@ -4761,7 +5268,8 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) { typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); // Figure out where this @synthesize lives. ObjCContainerDecl *Container @@ -4779,14 +5287,15 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) { Results.Ignore(PropertyImpl->getPropertyDecl()); // Add any properties that we find. + AddedPropertiesSet AddedProperties; Results.EnterNewScope(); if (ObjCImplementationDecl *ClassImpl = dyn_cast<ObjCImplementationDecl>(Container)) AddObjCProperties(ClassImpl->getClassInterface(), false, CurContext, - Results); + AddedProperties, Results); else AddObjCProperties(cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(), - false, CurContext, Results); + false, CurContext, AddedProperties, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, @@ -4798,7 +5307,8 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName, Decl *ObjCImpDecl) { typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); // Figure out where this @synthesize lives. ObjCContainerDecl *Container @@ -4847,7 +5357,6 @@ static void FindImplementableMethods(ASTContext &Context, ObjCContainerDecl *Container, bool WantInstanceMethods, QualType ReturnType, - bool IsInImplementation, KnownMethodsMap &KnownMethods, bool InOriginalClass = true) { if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)) { @@ -4855,28 +5364,23 @@ static void FindImplementableMethods(ASTContext &Context, const ObjCList<ObjCProtocolDecl> &Protocols = IFace->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), - E = Protocols.end(); + E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods, - InOriginalClass); + KnownMethods, InOriginalClass); - // If we're not in the implementation of a class, also visit the - // superclass. - if (!IsInImplementation && IFace->getSuperClass()) - FindImplementableMethods(Context, IFace->getSuperClass(), - WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods, - false); - - // Add methods from any class extensions (but not from categories; - // those should go into category implementations). - for (const ObjCCategoryDecl *Cat = IFace->getFirstClassExtension(); Cat; - Cat = Cat->getNextClassExtension()) + // Add methods from any class extensions and categories. + for (const ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat; + Cat = Cat->getNextClassCategory()) FindImplementableMethods(Context, const_cast<ObjCCategoryDecl*>(Cat), WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods, - InOriginalClass); + KnownMethods, false); + + // Visit the superclass. + if (IFace->getSuperClass()) + FindImplementableMethods(Context, IFace->getSuperClass(), + WantInstanceMethods, ReturnType, + KnownMethods, false); } if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) { @@ -4884,11 +5388,16 @@ static void FindImplementableMethods(ASTContext &Context, const ObjCList<ObjCProtocolDecl> &Protocols = Category->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), - E = Protocols.end(); + E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods, - InOriginalClass); + KnownMethods, InOriginalClass); + + // If this category is the original class, jump to the interface. + if (InOriginalClass && Category->getClassInterface()) + FindImplementableMethods(Context, Category->getClassInterface(), + WantInstanceMethods, ReturnType, KnownMethods, + false); } if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { @@ -4899,7 +5408,7 @@ static void FindImplementableMethods(ASTContext &Context, E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods, false); + KnownMethods, false); } // Add methods in this container. This operation occurs last because @@ -4918,6 +5427,632 @@ static void FindImplementableMethods(ASTContext &Context, } } +/// \brief Add the parenthesized return or parameter type chunk to a code +/// completion string. +static void AddObjCPassingTypeChunk(QualType Type, + ASTContext &Context, + CodeCompletionBuilder &Builder) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk(GetCompletionTypeString(Type, Context, + Builder.getAllocator())); + Builder.AddChunk(CodeCompletionString::CK_RightParen); +} + +/// \brief Determine whether the given class is or inherits from a class by +/// the given name. +static bool InheritsFromClassNamed(ObjCInterfaceDecl *Class, + llvm::StringRef Name) { + if (!Class) + return false; + + if (Class->getIdentifier() && Class->getIdentifier()->getName() == Name) + return true; + + return InheritsFromClassNamed(Class->getSuperClass(), Name); +} + +/// \brief Add code completions for Objective-C Key-Value Coding (KVC) and +/// Key-Value Observing (KVO). +static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, + bool IsInstanceMethod, + QualType ReturnType, + ASTContext &Context, + const KnownMethodsMap &KnownMethods, + ResultBuilder &Results) { + IdentifierInfo *PropName = Property->getIdentifier(); + if (!PropName || PropName->getLength() == 0) + return; + + + // Builder that will create each code completion. + typedef CodeCompletionResult Result; + CodeCompletionAllocator &Allocator = Results.getAllocator(); + CodeCompletionBuilder Builder(Allocator); + + // The selector table. + SelectorTable &Selectors = Context.Selectors; + + // The property name, copied into the code completion allocation region + // on demand. + struct KeyHolder { + CodeCompletionAllocator &Allocator; + llvm::StringRef Key; + const char *CopiedKey; + + KeyHolder(CodeCompletionAllocator &Allocator, llvm::StringRef Key) + : Allocator(Allocator), Key(Key), CopiedKey(0) { } + + operator const char *() { + if (CopiedKey) + return CopiedKey; + + return CopiedKey = Allocator.CopyString(Key); + } + } Key(Allocator, PropName->getName()); + + // The uppercased name of the property name. + std::string UpperKey = PropName->getName(); + if (!UpperKey.empty()) + UpperKey[0] = toupper(UpperKey[0]); + + bool ReturnTypeMatchesProperty = ReturnType.isNull() || + Context.hasSameUnqualifiedType(ReturnType.getNonReferenceType(), + Property->getType()); + bool ReturnTypeMatchesVoid + = ReturnType.isNull() || ReturnType->isVoidType(); + + // Add the normal accessor -(type)key. + if (IsInstanceMethod && + !KnownMethods.count(Selectors.getNullarySelector(PropName)) && + ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) { + if (ReturnType.isNull()) + AddObjCPassingTypeChunk(Property->getType(), Context, Builder); + + Builder.AddTypedTextChunk(Key); + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + CXCursor_ObjCInstanceMethodDecl)); + } + + // If we have an integral or boolean property (or the user has provided + // an integral or boolean return type), add the accessor -(type)isKey. + if (IsInstanceMethod && + ((!ReturnType.isNull() && + (ReturnType->isIntegerType() || ReturnType->isBooleanType())) || + (ReturnType.isNull() && + (Property->getType()->isIntegerType() || + Property->getType()->isBooleanType())))) { + std::string SelectorName = (llvm::Twine("is") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("BOOL"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk( + Allocator.CopyString(SelectorId->getName())); + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // Add the normal mutator. + if (IsInstanceMethod && ReturnTypeMatchesVoid && + !Property->getSetterMethodDecl()) { + std::string SelectorName = (llvm::Twine("set") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk( + Allocator.CopyString(SelectorId->getName())); + Builder.AddTypedTextChunk(":"); + AddObjCPassingTypeChunk(Property->getType(), Context, Builder); + Builder.AddTextChunk(Key); + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // Indexed and unordered accessors + unsigned IndexedGetterPriority = CCP_CodePattern; + unsigned IndexedSetterPriority = CCP_CodePattern; + unsigned UnorderedGetterPriority = CCP_CodePattern; + unsigned UnorderedSetterPriority = CCP_CodePattern; + if (const ObjCObjectPointerType *ObjCPointer + = Property->getType()->getAs<ObjCObjectPointerType>()) { + if (ObjCInterfaceDecl *IFace = ObjCPointer->getInterfaceDecl()) { + // If this interface type is not provably derived from a known + // collection, penalize the corresponding completions. + if (!InheritsFromClassNamed(IFace, "NSMutableArray")) { + IndexedSetterPriority += CCD_ProbablyNotObjCCollection; + if (!InheritsFromClassNamed(IFace, "NSArray")) + IndexedGetterPriority += CCD_ProbablyNotObjCCollection; + } + + if (!InheritsFromClassNamed(IFace, "NSMutableSet")) { + UnorderedSetterPriority += CCD_ProbablyNotObjCCollection; + if (!InheritsFromClassNamed(IFace, "NSSet")) + UnorderedGetterPriority += CCD_ProbablyNotObjCCollection; + } + } + } else { + IndexedGetterPriority += CCD_ProbablyNotObjCCollection; + IndexedSetterPriority += CCD_ProbablyNotObjCCollection; + UnorderedGetterPriority += CCD_ProbablyNotObjCCollection; + UnorderedSetterPriority += CCD_ProbablyNotObjCCollection; + } + + // Add -(NSUInteger)countOf<key> + if (IsInstanceMethod && + (ReturnType.isNull() || ReturnType->isIntegerType())) { + std::string SelectorName = (llvm::Twine("countOf") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSUInteger"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk( + Allocator.CopyString(SelectorId->getName())); + Results.AddResult(Result(Builder.TakeString(), + std::min(IndexedGetterPriority, + UnorderedGetterPriority), + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // Indexed getters + // Add -(id)objectInKeyAtIndex:(NSUInteger)index + if (IsInstanceMethod && + (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { + std::string SelectorName + = (llvm::Twine("objectIn") + UpperKey + "AtIndex").str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("id"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSUInteger"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("index"); + Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // Add -(NSArray *)keyAtIndexes:(NSIndexSet *)indexes + if (IsInstanceMethod && + (ReturnType.isNull() || + (ReturnType->isObjCObjectPointerType() && + ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && + ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() + ->getName() == "NSArray"))) { + std::string SelectorName + = (llvm::Twine(Property->getName()) + "AtIndexes").str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSArray *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSIndexSet *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("indexes"); + Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // Add -(void)getKey:(type **)buffer range:(NSRange)inRange + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName = (llvm::Twine("get") + UpperKey).str(); + IdentifierInfo *SelectorIds[2] = { + &Context.Idents.get(SelectorName), + &Context.Idents.get("range") + }; + + if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("object-type"); + Builder.AddTextChunk(" **"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("buffer"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTypedTextChunk("range:"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSRange"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("inRange"); + Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // Mutable indexed accessors + + // - (void)insertObject:(type *)object inKeyAtIndex:(NSUInteger)index + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName = (llvm::Twine("in") + UpperKey + "AtIndex").str(); + IdentifierInfo *SelectorIds[2] = { + &Context.Idents.get("insertObject"), + &Context.Idents.get(SelectorName) + }; + + if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk("insertObject:"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("object-type"); + Builder.AddTextChunk(" *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("object"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("NSUInteger"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("index"); + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // - (void)insertKey:(NSArray *)array atIndexes:(NSIndexSet *)indexes + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName = (llvm::Twine("insert") + UpperKey).str(); + IdentifierInfo *SelectorIds[2] = { + &Context.Idents.get(SelectorName), + &Context.Idents.get("atIndexes") + }; + + if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSArray *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("array"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTypedTextChunk("atIndexes:"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("NSIndexSet *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("indexes"); + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // -(void)removeObjectFromKeyAtIndex:(NSUInteger)index + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName + = (llvm::Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSUInteger"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("index"); + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // -(void)removeKeyAtIndexes:(NSIndexSet *)indexes + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName + = (llvm::Twine("remove") + UpperKey + "AtIndexes").str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSIndexSet *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("indexes"); + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // - (void)replaceObjectInKeyAtIndex:(NSUInteger)index withObject:(id)object + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName + = (llvm::Twine("replaceObjectIn") + UpperKey + "AtIndex").str(); + IdentifierInfo *SelectorIds[2] = { + &Context.Idents.get(SelectorName), + &Context.Idents.get("withObject") + }; + + if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("NSUInteger"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("index"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTypedTextChunk("withObject:"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("id"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("object"); + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // - (void)replaceKeyAtIndexes:(NSIndexSet *)indexes withKey:(NSArray *)array + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName1 + = (llvm::Twine("replace") + UpperKey + "AtIndexes").str(); + std::string SelectorName2 = (llvm::Twine("with") + UpperKey).str(); + IdentifierInfo *SelectorIds[2] = { + &Context.Idents.get(SelectorName1), + &Context.Idents.get(SelectorName2) + }; + + if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName1 + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("NSIndexSet *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("indexes"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName2 + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSArray *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("array"); + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // Unordered getters + // - (NSEnumerator *)enumeratorOfKey + if (IsInstanceMethod && + (ReturnType.isNull() || + (ReturnType->isObjCObjectPointerType() && + ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && + ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() + ->getName() == "NSEnumerator"))) { + std::string SelectorName = (llvm::Twine("enumeratorOf") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSEnumerator *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); + Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // - (type *)memberOfKey:(type *)object + if (IsInstanceMethod && + (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { + std::string SelectorName = (llvm::Twine("memberOf") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("object-type"); + Builder.AddTextChunk(" *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + if (ReturnType.isNull()) { + Builder.AddPlaceholderChunk("object-type"); + Builder.AddTextChunk(" *"); + } else { + Builder.AddTextChunk(GetCompletionTypeString(ReturnType, Context, + Builder.getAllocator())); + } + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("object"); + Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // Mutable unordered accessors + // - (void)addKeyObject:(type *)object + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName + = (llvm::Twine("add") + UpperKey + llvm::Twine("Object")).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("object-type"); + Builder.AddTextChunk(" *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("object"); + Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // - (void)addKey:(NSSet *)objects + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName = (llvm::Twine("add") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSSet *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("objects"); + Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // - (void)removeKeyObject:(type *)object + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName + = (llvm::Twine("remove") + UpperKey + llvm::Twine("Object")).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("object-type"); + Builder.AddTextChunk(" *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("object"); + Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // - (void)removeKey:(NSSet *)objects + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName = (llvm::Twine("remove") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSSet *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("objects"); + Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // - (void)intersectKey:(NSSet *)objects + if (IsInstanceMethod && ReturnTypeMatchesVoid) { + std::string SelectorName = (llvm::Twine("intersect") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("void"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSSet *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddTextChunk("objects"); + Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, + CXCursor_ObjCInstanceMethodDecl)); + } + } + + // Key-Value Observing + // + (NSSet *)keyPathsForValuesAffectingKey + if (!IsInstanceMethod && + (ReturnType.isNull() || + (ReturnType->isObjCObjectPointerType() && + ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && + ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() + ->getName() == "NSSet"))) { + std::string SelectorName + = (llvm::Twine("keyPathsForValuesAffecting") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("NSSet *"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + CXCursor_ObjCInstanceMethodDecl)); + } + } +} + void Sema::CodeCompleteObjCMethodDecl(Scope *S, bool IsInstanceMethod, ParsedType ReturnTy, @@ -4926,33 +6061,27 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // provided. QualType ReturnType = GetTypeFromParser(ReturnTy); - // Determine where we should start searching for methods, and where we - ObjCContainerDecl *SearchDecl = 0, *CurrentDecl = 0; + // Determine where we should start searching for methods. + ObjCContainerDecl *SearchDecl = 0; bool IsInImplementation = false; if (Decl *D = IDecl) { if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D)) { SearchDecl = Impl->getClassInterface(); - CurrentDecl = Impl; IsInImplementation = true; } else if (ObjCCategoryImplDecl *CatImpl - = dyn_cast<ObjCCategoryImplDecl>(D)) { + = dyn_cast<ObjCCategoryImplDecl>(D)) { SearchDecl = CatImpl->getCategoryDecl(); - CurrentDecl = CatImpl; IsInImplementation = true; - } else { + } else SearchDecl = dyn_cast<ObjCContainerDecl>(D); - CurrentDecl = SearchDecl; - } } if (!SearchDecl && S) { - if (DeclContext *DC = static_cast<DeclContext *>(S->getEntity())) { + if (DeclContext *DC = static_cast<DeclContext *>(S->getEntity())) SearchDecl = dyn_cast<ObjCContainerDecl>(DC); - CurrentDecl = SearchDecl; - } } - if (!SearchDecl || !CurrentDecl) { + if (!SearchDecl) { HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, 0, 0); @@ -4962,24 +6091,12 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // Find all of the methods that we could declare/implement here. KnownMethodsMap KnownMethods; FindImplementableMethods(Context, SearchDecl, IsInstanceMethod, - ReturnType, IsInImplementation, KnownMethods); + ReturnType, KnownMethods); - // Erase any methods that have already been declared or - // implemented here. - for (ObjCContainerDecl::method_iterator M = CurrentDecl->meth_begin(), - MEnd = CurrentDecl->meth_end(); - M != MEnd; ++M) { - if ((*M)->isInstanceMethod() != IsInstanceMethod) - continue; - - KnownMethodsMap::iterator Pos = KnownMethods.find((*M)->getSelector()); - if (Pos != KnownMethods.end()) - KnownMethods.erase(Pos); - } - // Add declarations or definitions for each of the known methods. typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); Results.EnterNewScope(); PrintingPolicy Policy(Context.PrintingPolicy); Policy.AnonymousTagLocations = false; @@ -4987,22 +6104,18 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, MEnd = KnownMethods.end(); M != MEnd; ++M) { ObjCMethodDecl *Method = M->second.first; - CodeCompletionString *Pattern = new CodeCompletionString; + CodeCompletionBuilder Builder(Results.getAllocator()); // If the result type was not already provided, add it to the // pattern as (type). - if (ReturnType.isNull()) { - std::string TypeStr; - Method->getResultType().getAsStringInternal(TypeStr, Policy); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddTextChunk(TypeStr); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - } + if (ReturnType.isNull()) + AddObjCPassingTypeChunk(Method->getResultType(), Context, Builder); Selector Sel = Method->getSelector(); // Add the first part of the selector to the pattern. - Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); + Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( + Sel.getNameForSlot(0))); // Add parameters to the pattern. unsigned I = 0; @@ -5011,59 +6124,82 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, P != PEnd; (void)++P, ++I) { // Add the part of the selector name. if (I == 0) - Pattern->AddChunk(CodeCompletionString::CK_Colon); + Builder.AddTypedTextChunk(":"); else if (I < Sel.getNumArgs()) { - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk(Sel.getIdentifierInfoForSlot(I)->getName()); - Pattern->AddChunk(CodeCompletionString::CK_Colon); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTypedTextChunk( + Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":")); } else break; // Add the parameter type. - std::string TypeStr; - (*P)->getOriginalType().getAsStringInternal(TypeStr, Policy); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddTextChunk(TypeStr); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); + AddObjCPassingTypeChunk((*P)->getOriginalType(), Context, Builder); if (IdentifierInfo *Id = (*P)->getIdentifier()) - Pattern->AddTextChunk(Id->getName()); + Builder.AddTextChunk(Builder.getAllocator().CopyString( Id->getName())); } if (Method->isVariadic()) { if (Method->param_size() > 0) - Pattern->AddChunk(CodeCompletionString::CK_Comma); - Pattern->AddTextChunk("..."); + Builder.AddChunk(CodeCompletionString::CK_Comma); + Builder.AddTextChunk("..."); } if (IsInImplementation && Results.includeCodePatterns()) { // We will be defining the method here, so add a compound statement. - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); if (!Method->getResultType()->isVoidType()) { // If the result type is not void, add a return clause. - Pattern->AddTextChunk("return"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Builder.AddTextChunk("return"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); } else - Pattern->AddPlaceholderChunk("statements"); + Builder.AddPlaceholderChunk("statements"); - Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); - Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); } unsigned Priority = CCP_CodePattern; if (!M->second.second) Priority += CCD_InBaseClass; - Results.AddResult(Result(Pattern, Priority, + Results.AddResult(Result(Builder.TakeString(), Priority, Method->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl)); } + // Add Key-Value-Coding and Key-Value-Observing accessor methods for all of + // the properties in this class and its categories. + if (Context.getLangOptions().ObjC2) { + llvm::SmallVector<ObjCContainerDecl *, 4> Containers; + Containers.push_back(SearchDecl); + + ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(SearchDecl); + if (!IFace) + if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(SearchDecl)) + IFace = Category->getClassInterface(); + + if (IFace) { + for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category; + Category = Category->getNextClassCategory()) + Containers.push_back(Category); + } + + for (unsigned I = 0, N = Containers.size(); I != N; ++I) { + for (ObjCContainerDecl::prop_iterator P = Containers[I]->prop_begin(), + PEnd = Containers[I]->prop_end(); + P != PEnd; ++P) { + AddObjCKeyValueCompletions(*P, IsInstanceMethod, ReturnType, Context, + KnownMethods, Results); + } + } + } + Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, @@ -5092,7 +6228,8 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, // Build the set of methods we can see. typedef CodeCompletionResult Result; - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_Other); if (ReturnTy) Results.setPreferredType(GetTypeFromParser(ReturnTy).getNonReferenceType()); @@ -5114,9 +6251,10 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, if (NumSelIdents && NumSelIdents <= MethList->Method->param_size()) { ParmVarDecl *Param = MethList->Method->param_begin()[NumSelIdents-1]; if (Param->getIdentifier()) { - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(Param->getIdentifier()->getName()); - Results.AddResult(Pattern); + CodeCompletionBuilder Builder(Results.getAllocator()); + Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( + Param->getIdentifier()->getName())); + Results.AddResult(Builder.TakeString()); } } @@ -5138,167 +6276,149 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, } void Sema::CodeCompletePreprocessorDirective(bool InConditional) { - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_PreprocessorDirective); Results.EnterNewScope(); // #if <condition> - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("if"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("condition"); - Results.AddResult(Pattern); + CodeCompletionBuilder Builder(Results.getAllocator()); + Builder.AddTypedTextChunk("if"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("condition"); + Results.AddResult(Builder.TakeString()); // #ifdef <macro> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("ifdef"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("macro"); - Results.AddResult(Pattern); - + Builder.AddTypedTextChunk("ifdef"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("macro"); + Results.AddResult(Builder.TakeString()); + // #ifndef <macro> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("ifndef"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("macro"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("ifndef"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("macro"); + Results.AddResult(Builder.TakeString()); if (InConditional) { // #elif <condition> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("elif"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("condition"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("elif"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("condition"); + Results.AddResult(Builder.TakeString()); // #else - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("else"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("else"); + Results.AddResult(Builder.TakeString()); // #endif - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("endif"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("endif"); + Results.AddResult(Builder.TakeString()); } // #include "header" - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("include"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("\""); - Pattern->AddPlaceholderChunk("header"); - Pattern->AddTextChunk("\""); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("include"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("\""); + Builder.AddPlaceholderChunk("header"); + Builder.AddTextChunk("\""); + Results.AddResult(Builder.TakeString()); // #include <header> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("include"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("<"); - Pattern->AddPlaceholderChunk("header"); - Pattern->AddTextChunk(">"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("include"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("<"); + Builder.AddPlaceholderChunk("header"); + Builder.AddTextChunk(">"); + Results.AddResult(Builder.TakeString()); // #define <macro> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("define"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("macro"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("define"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("macro"); + Results.AddResult(Builder.TakeString()); // #define <macro>(<args>) - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("define"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("macro"); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("args"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("define"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("macro"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("args"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Builder.TakeString()); // #undef <macro> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("undef"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("macro"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("undef"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("macro"); + Results.AddResult(Builder.TakeString()); // #line <number> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("line"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("number"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("line"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("number"); + Results.AddResult(Builder.TakeString()); // #line <number> "filename" - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("line"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("number"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("\""); - Pattern->AddPlaceholderChunk("filename"); - Pattern->AddTextChunk("\""); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("line"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("number"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("\""); + Builder.AddPlaceholderChunk("filename"); + Builder.AddTextChunk("\""); + Results.AddResult(Builder.TakeString()); // #error <message> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("error"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("message"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("error"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("message"); + Results.AddResult(Builder.TakeString()); // #pragma <arguments> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("pragma"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("arguments"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("pragma"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("arguments"); + Results.AddResult(Builder.TakeString()); if (getLangOptions().ObjC1) { // #import "header" - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("import"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("\""); - Pattern->AddPlaceholderChunk("header"); - Pattern->AddTextChunk("\""); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("import"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("\""); + Builder.AddPlaceholderChunk("header"); + Builder.AddTextChunk("\""); + Results.AddResult(Builder.TakeString()); // #import <header> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("import"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("<"); - Pattern->AddPlaceholderChunk("header"); - Pattern->AddTextChunk(">"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("import"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("<"); + Builder.AddPlaceholderChunk("header"); + Builder.AddTextChunk(">"); + Results.AddResult(Builder.TakeString()); } // #include_next "header" - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("include_next"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("\""); - Pattern->AddPlaceholderChunk("header"); - Pattern->AddTextChunk("\""); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("include_next"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("\""); + Builder.AddPlaceholderChunk("header"); + Builder.AddTextChunk("\""); + Results.AddResult(Builder.TakeString()); // #include_next <header> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("include_next"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk("<"); - Pattern->AddPlaceholderChunk("header"); - Pattern->AddTextChunk(">"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("include_next"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("<"); + Builder.AddPlaceholderChunk("header"); + Builder.AddTextChunk(">"); + Results.AddResult(Builder.TakeString()); // #warning <message> - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("warning"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddPlaceholderChunk("message"); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk("warning"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("message"); + Results.AddResult(Builder.TakeString()); // Note: #ident and #sccs are such crazy anachronisms that we don't provide // completions for them. And __include_macros is a Clang-internal extension @@ -5319,43 +6439,45 @@ void Sema::CodeCompleteInPreprocessorConditionalExclusion(Scope *S) { } void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) { - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + IsDefinition? CodeCompletionContext::CCC_MacroName + : CodeCompletionContext::CCC_MacroNameUse); if (!IsDefinition && (!CodeCompleter || CodeCompleter->includeMacros())) { // Add just the names of macros, not their arguments. + CodeCompletionBuilder Builder(Results.getAllocator()); Results.EnterNewScope(); for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); M != MEnd; ++M) { - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk(M->first->getName()); - Results.AddResult(Pattern); + Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( + M->first->getName())); + Results.AddResult(Builder.TakeString()); } Results.ExitScope(); } else if (IsDefinition) { // FIXME: Can we detect when the user just wrote an include guard above? } - HandleCodeCompleteResults(this, CodeCompleter, - IsDefinition? CodeCompletionContext::CCC_MacroName - : CodeCompletionContext::CCC_MacroNameUse, + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompletePreprocessorExpression() { - ResultBuilder Results(*this); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompletionContext::CCC_PreprocessorExpression); if (!CodeCompleter || CodeCompleter->includeMacros()) AddMacroResults(PP, Results); // defined (<macro>) Results.EnterNewScope(); - CodeCompletionString *Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("defined"); - Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddChunk(CodeCompletionString::CK_LeftParen); - Pattern->AddPlaceholderChunk("macro"); - Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Pattern); + CodeCompletionBuilder Builder(Results.getAllocator()); + Builder.AddTypedTextChunk("defined"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("macro"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Builder.TakeString()); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, @@ -5381,10 +6503,9 @@ void Sema::CodeCompleteNaturalLanguage() { 0, 0); } -void Sema::GatherGlobalCodeCompletions( +void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, llvm::SmallVectorImpl<CodeCompletionResult> &Results) { - ResultBuilder Builder(*this); - + ResultBuilder Builder(*this, Allocator, CodeCompletionContext::CCC_Recovery); if (!CodeCompleter || CodeCompleter->includeGlobals()) { CodeCompletionDeclConsumer Consumer(Builder, Context.getTranslationUnitDecl()); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f5e045a..dd30c12 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -26,6 +26,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/CharUnits.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Parse/ParseDiagnostic.h" @@ -59,7 +60,7 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr) { /// and then return NULL. ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, - bool isClassName, + bool isClassName, bool HasTrailingDot, ParsedType ObjectTypePtr) { // Determine where we will perform name lookup. DeclContext *LookupCtx = 0; @@ -192,13 +193,15 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, T = getElaboratedType(ETK_None, *SS, T); } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { - T = Context.getObjCInterfaceType(IDecl); - } else { + if (!HasTrailingDot) + T = Context.getObjCInterfaceType(IDecl); + } + + if (T.isNull()) { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); return ParsedType(); } - return ParsedType::make(T); } @@ -544,7 +547,9 @@ static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) return CD->isCopyConstructor(); - return D->isCopyAssignment(); + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + return Method->isCopyAssignmentOperator(); + return false; } bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { @@ -554,11 +559,8 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { return false; // Ignore class templates. - if (D->getDeclContext()->isDependentContext()) - return false; - - // We warn for unused decls internal to the translation unit. - if (D->getLinkage() == ExternalLinkage) + if (D->getDeclContext()->isDependentContext() || + D->getLexicalDeclContext()->isDependentContext()) return false; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { @@ -575,25 +577,32 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { return false; } - if (FD->isThisDeclarationADefinition()) - return !Context.DeclMustBeEmitted(FD); - return true; - } + if (FD->isThisDeclarationADefinition() && + Context.DeclMustBeEmitted(FD)) + return false; + + } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (!VD->isFileVarDecl() || + VD->getType().isConstant(Context) || + Context.DeclMustBeEmitted(VD)) + return false; - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; - if ( VD->isFileVarDecl() && - !VD->getType().isConstant(Context)) - return !Context.DeclMustBeEmitted(VD); + } else { + return false; } - return false; - } + // Only warn for unused decls internal to the translation unit. + if (D->getLinkage() == ExternalLinkage) + return false; + + return true; +} - void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { +void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { if (!D) return; @@ -620,6 +629,9 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (D->isUsed() || D->hasAttr<UnusedAttr>()) return false; + if (isa<LabelDecl>(D)) + return true; + // White-list anything that isn't a local variable. if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) || !D->getDeclContext()->isFunctionOrMethod()) @@ -662,16 +674,29 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return true; } +/// DiagnoseUnusedDecl - Emit warnings about declarations that are not used +/// unless they are marked attr(unused). void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { if (!ShouldDiagnoseUnusedDecl(D)) return; + unsigned DiagID; if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable()) - Diag(D->getLocation(), diag::warn_unused_exception_param) - << D->getDeclName(); + DiagID = diag::warn_unused_exception_param; + else if (isa<LabelDecl>(D)) + DiagID = diag::warn_unused_label; else - Diag(D->getLocation(), diag::warn_unused_variable) - << D->getDeclName(); + DiagID = diag::warn_unused_variable; + + Diag(D->getLocation(), DiagID) << D->getDeclName(); +} + +static void CheckPoppedLabel(LabelDecl *L, Sema &S) { + // 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->getStmt() == 0) + S.Diag(L->getLocation(), diag::err_undeclared_label_use) <<L->getDeclName(); } void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { @@ -690,9 +715,13 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (!D->getDeclName()) continue; // Diagnose unused variables in this scope. - if (S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) + if (!S->hasErrorOccurred()) DiagnoseUnusedDecl(D); + // If this was a forward reference to a label, verify it was defined. + if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) + CheckPoppedLabel(LD, *this); + // Remove this name from our lexical scope. IdResolver.RemoveDecl(D); } @@ -769,17 +798,6 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) { return S; } -void Sema::InitBuiltinVaListType() { - if (!Context.getBuiltinVaListType().isNull()) - return; - - IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list"); - NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, SourceLocation(), - LookupOrdinaryName, ForRedeclaration); - TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl); - Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef)); -} - /// LazilyCreateBuiltin - The specified Builtin-ID was first used at /// file scope. lazily create a decl for it. ForRedeclaration is true /// if we're creating this built-in in anticipation of redeclaring the @@ -789,9 +807,6 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, SourceLocation Loc) { Builtin::ID BID = (Builtin::ID)bid; - if (Context.BuiltinInfo.hasVAListUse(BID)) - InitBuiltinVaListType(); - ASTContext::GetBuiltinTypeError Error; QualType R = Context.GetBuiltinType(BID, Error); switch (Error) { @@ -801,13 +816,13 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, case ASTContext::GE_Missing_stdio: if (ForRedeclaration) - Diag(Loc, diag::err_implicit_decl_requires_stdio) + Diag(Loc, diag::warn_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) + Diag(Loc, diag::warn_implicit_decl_requires_setjmp) << Context.BuiltinInfo.GetName(BID); return 0; } @@ -817,7 +832,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, << Context.BuiltinInfo.GetName(BID) << R; if (Context.BuiltinInfo.getHeaderName(BID) && - Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl) + Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl, Loc) != Diagnostic::Ignored) Diag(Loc, diag::note_please_include_header) << Context.BuiltinInfo.getHeaderName(BID) @@ -834,7 +849,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, // Create Decl objects for each parameter, adding them to the // FunctionDecl. - if (FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) { + if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) { llvm::SmallVector<ParmVarDecl*, 16> Params; for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, @@ -1026,11 +1041,11 @@ static void MergeDeclAttributes(Decl *New, Decl *Old, ASTContext &C) { // we process them. if (!New->hasAttrs()) New->setAttrs(AttrVec()); - for (Decl::attr_iterator i = Old->attr_begin(), e = Old->attr_end(); i != e; - ++i) { - // FIXME: Make this more general than just checking for Overloadable. - if (!DeclHasAttr(New, *i) && (*i)->getKind() != attr::Overloadable) { - Attr *NewAttr = (*i)->clone(C); + for (specific_attr_iterator<InheritableAttr> + i = Old->specific_attr_begin<InheritableAttr>(), + e = Old->specific_attr_end<InheritableAttr>(); i != e; ++i) { + if (!DeclHasAttr(New, *i)) { + InheritableAttr *NewAttr = cast<InheritableAttr>((*i)->clone(C)); NewAttr->setInherited(true); New->addAttr(NewAttr); } @@ -1061,7 +1076,8 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { if (isa<CXXDestructorDecl>(MD)) return Sema::CXXDestructor; - assert(MD->isCopyAssignment() && "Must have copy assignment operator"); + assert(MD->isCopyAssignmentOperator() && + "Must have copy assignment operator"); return Sema::CXXCopyAssignment; } @@ -1147,15 +1163,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // // Note also that we DO NOT return at this point, because we still have // other tests to run. - const FunctionType *OldType = OldQType->getAs<FunctionType>(); + const FunctionType *OldType = cast<FunctionType>(OldQType); const FunctionType *NewType = New->getType()->getAs<FunctionType>(); - const FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); - const FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); + FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); + FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); + bool RequiresAdjustment = false; if (OldTypeInfo.getCC() != CC_Default && NewTypeInfo.getCC() == CC_Default) { - NewQType = Context.getCallConvType(NewQType, OldTypeInfo.getCC()); - New->setType(NewQType); - NewQType = Context.getCanonicalType(NewQType); + NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); + RequiresAdjustment = true; } else if (!Context.isSameCallConv(OldTypeInfo.getCC(), NewTypeInfo.getCC())) { // Calling conventions really aren't compatible, so complain. @@ -1169,25 +1185,29 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { } // FIXME: diagnose the other way around? - if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) { - NewQType = Context.getNoReturnType(NewQType); - New->setType(NewQType); - assert(NewQType.isCanonical()); + if (OldTypeInfo.getNoReturn() && !NewTypeInfo.getNoReturn()) { + NewTypeInfo = NewTypeInfo.withNoReturn(true); + RequiresAdjustment = true; } // Merge regparm attribute. - if (OldType->getRegParmType() != NewType->getRegParmType()) { - if (NewType->getRegParmType()) { + if (OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) { + if (NewTypeInfo.getRegParm()) { Diag(New->getLocation(), diag::err_regparm_mismatch) << NewType->getRegParmType() << OldType->getRegParmType(); Diag(Old->getLocation(), diag::note_previous_declaration); return true; } - - NewQType = Context.getRegParmType(NewQType, OldType->getRegParmType()); - New->setType(NewQType); - assert(NewQType.isCanonical()); + + NewTypeInfo = NewTypeInfo.withRegParm(OldTypeInfo.getRegParm()); + RequiresAdjustment = true; + } + + if (RequiresAdjustment) { + NewType = Context.adjustFunctionType(NewType, NewTypeInfo); + New->setType(QualType(NewType, 0)); + NewQType = Context.getCanonicalType(New->getType()); } if (getLangOptions().CPlusPlus) { @@ -1195,17 +1215,19 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // Certain function declarations cannot be overloaded: // -- Function declarations that differ only in the return type // cannot be overloaded. - QualType OldReturnType - = cast<FunctionType>(OldQType.getTypePtr())->getResultType(); - QualType NewReturnType - = cast<FunctionType>(NewQType.getTypePtr())->getResultType(); + QualType OldReturnType = OldType->getResultType(); + QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType(); QualType ResQT; if (OldReturnType != NewReturnType) { if (NewReturnType->isObjCObjectPointerType() && OldReturnType->isObjCObjectPointerType()) ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); if (ResQT.isNull()) { - Diag(New->getLocation(), diag::err_ovl_diff_return_type); + if (New->isCXXClassMember() && New->isOutOfLine()) + Diag(New->getLocation(), + diag::err_member_def_does_not_match_ret_type) << New; + else + Diag(New->getLocation(), diag::err_ovl_diff_return_type); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); return true; } @@ -1268,9 +1290,19 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // (C++98 8.3.5p3): // All declarations for a function shall agree exactly in both the // return type and the parameter-type-list. - // attributes should be ignored when comparing. - if (Context.getNoReturnType(OldQType, false) == - Context.getNoReturnType(NewQType, false)) + // We also want to respect all the extended bits except noreturn. + + // noreturn should now match unless the old type info didn't have it. + QualType OldQTypeForComparison = OldQType; + if (!OldTypeInfo.getNoReturn() && NewTypeInfo.getNoReturn()) { + assert(OldQType == QualType(OldType, 0)); + const FunctionType *OldTypeForComparison + = Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true)); + OldQTypeForComparison = QualType(OldTypeForComparison, 0); + assert(OldQTypeForComparison.isCanonical()); + } + + if (OldQTypeForComparison == NewQType) return MergeCompatibleFunctionDecls(New, Old); // Fall through for conflicting redeclarations and redefinitions. @@ -1292,10 +1324,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { OldProto->arg_type_end()); NewQType = Context.getFunctionType(NewFuncType->getResultType(), ParamTypes.data(), ParamTypes.size(), - OldProto->isVariadic(), - OldProto->getTypeQuals(), - false, false, 0, 0, - OldProto->getExtInfo()); + OldProto->getExtProtoInfo()); New->setType(NewQType); New->setHasInheritedPrototype(); @@ -1377,9 +1406,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0], ArgTypes.size(), - OldProto->isVariadic(), 0, - false, false, 0, 0, - OldProto->getExtInfo())); + OldProto->getExtProtoInfo())); return MergeCompatibleFunctionDecls(New, Old); } @@ -1444,48 +1471,26 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { return false; } -/// MergeVarDecl - We just parsed a variable 'New' which has the same name -/// and scope as a previous declaration 'Old'. Figure out how to resolve this -/// situation, merging decls or emitting diagnostics as appropriate. +/// MergeVarDecl - We parsed a variable 'New' which has the same name and scope +/// as a previous declaration 'Old'. Figure out how to merge their types, +/// emitting diagnostics as appropriate. /// -/// 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. +/// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back +/// to here in AddInitializerToDecl and AddCXXDirectInitializerToDecl. We can't +/// check them before the initializer is attached. /// -void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { - // If the new decl is already invalid, don't do any other checking. - if (New->isInvalidDecl()) +void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) { + if (New->isInvalidDecl() || Old->isInvalidDecl()) return; - // Verify the old decl was also a variable. - VarDecl *Old = 0; - if (!Previous.isSingleResult() || - !(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) { - Diag(New->getLocation(), diag::err_redefinition_different_kind) - << New->getDeclName(); - Diag(Previous.getRepresentativeDecl()->getLocation(), - diag::note_previous_definition); - return New->setInvalidDecl(); - } - - // C++ [class.mem]p1: - // A member shall not be declared twice in the member-specification [...] - // - // Here, we need only consider static data members. - if (Old->isStaticDataMember() && !New->isOutOfLine()) { - Diag(New->getLocation(), diag::err_duplicate_member) - << New->getIdentifier(); - Diag(Old->getLocation(), diag::note_previous_declaration); - New->setInvalidDecl(); - } - - MergeDeclAttributes(New, Old, Context); - - // Merge the types QualType MergedT; if (getLangOptions().CPlusPlus) { - if (Context.hasSameType(New->getType(), Old->getType())) - MergedT = New->getType(); + AutoType *AT = New->getType()->getContainedAutoType(); + if (AT && !AT->isDeduced()) { + // We don't know what the new type is until the initializer is attached. + return; + } else if (Context.hasSameType(New->getType(), Old->getType())) + return; // C++ [basic.link]p10: // [...] the types specified by all declarations referring to a given // object or function shall be identical, except that declarations for an @@ -1509,7 +1514,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { MergedT = Old->getType(); } else if (New->getType()->isObjCObjectPointerType() && Old->getType()->isObjCObjectPointerType()) { - MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); + MergedT = Context.mergeObjCGCQualifiers(New->getType(), + Old->getType()); } } else { MergedT = Context.mergeTypes(New->getType(), Old->getType()); @@ -1521,6 +1527,49 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } New->setType(MergedT); +} + +/// MergeVarDecl - We just parsed a variable 'New' which has the same name +/// 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 +/// definitions here, since the initializer hasn't been attached. +/// +void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { + // If the new decl is already invalid, don't do any other checking. + if (New->isInvalidDecl()) + return; + + // Verify the old decl was also a variable. + VarDecl *Old = 0; + if (!Previous.isSingleResult() || + !(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) { + Diag(New->getLocation(), diag::err_redefinition_different_kind) + << New->getDeclName(); + Diag(Previous.getRepresentativeDecl()->getLocation(), + diag::note_previous_definition); + return New->setInvalidDecl(); + } + + // C++ [class.mem]p1: + // A member shall not be declared twice in the member-specification [...] + // + // Here, we need only consider static data members. + if (Old->isStaticDataMember() && !New->isOutOfLine()) { + Diag(New->getLocation(), diag::err_duplicate_member) + << New->getIdentifier(); + Diag(Old->getLocation(), diag::note_previous_declaration); + New->setInvalidDecl(); + } + + MergeDeclAttributes(New, Old, Context); + + // Merge the types. + MergeVarDeclTypes(New, Old); + if (New->isInvalidDecl()) + return; // C99 6.2.2p4: Check if we have a static decl followed by a non-static. if (New->getStorageClass() == SC_Static && @@ -1547,6 +1596,20 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } + // Check if extern is followed by non-extern and vice-versa. + if (New->hasExternalStorage() && + !Old->hasLinkage() && Old->isLocalVarDecl()) { + Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + if (Old->hasExternalStorage() && + !New->hasLinkage() && New->isLocalVarDecl()) { + Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. // FIXME: The test for external storage here seems wrong? We still @@ -1602,7 +1665,6 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// no declarator (e.g. "struct foo;") is parsed. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS) { - // FIXME: Error on auto/register at file scope // FIXME: Error on inline/virtual/explicit // FIXME: Warn on useless __thread // FIXME: Warn on useless const/volatile @@ -1635,15 +1697,15 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } 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)) + // If we're dealing with a decl but not a TagDecl, assume that + // whatever routines created it handled the friendship aspect. + if (TagD && !Tag) return 0; return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0)); } if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { - ProcessDeclAttributeList(S, Record, DS.getAttributes()); + ProcessDeclAttributeList(S, Record, DS.getAttributes().getList()); if (!Record->getDeclName() && Record->isDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { @@ -1654,12 +1716,24 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); } + } - // Microsoft allows unnamed struct/union fields. Don't complain - // about them. - // FIXME: Should we support Microsoft's extensions in this area? - if (Record->getDeclName() && getLangOptions().Microsoft) - return Tag; + // Check for Microsoft C extension: anonymous struct. + if (getLangOptions().Microsoft && !getLangOptions().CPlusPlus && + CurContext->isRecord() && + DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { + // Handle 2 kinds of anonymous struct: + // struct STRUCT; + // and + // STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct. + RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag); + if ((Record && Record->getDeclName() && !Record->isDefinition()) || + (DS.getTypeSpecType() == DeclSpec::TST_typename && + DS.getRepAsType().get()->isStructureType())) { + Diag(DS.getSourceRange().getBegin(), diag::ext_ms_anonymous_struct) + << DS.getSourceRange(); + return BuildMicrosoftCAnonymousStruct(S, DS, Record); + } } if (getLangOptions().CPlusPlus && @@ -1688,6 +1762,25 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, return TagD; } +/// ActOnVlaStmt - This rouine if finds a vla expression in a decl spec. +/// builds a statement for it and returns it so it is evaluated. +StmtResult Sema::ActOnVlaStmt(const DeclSpec &DS) { + StmtResult R; + if (DS.getTypeSpecType() == DeclSpec::TST_typeofExpr) { + Expr *Exp = DS.getRepAsExpr(); + QualType Ty = Exp->getType(); + if (Ty->isPointerType()) { + do + Ty = Ty->getAs<PointerType>()->getPointeeType(); + while (Ty->isPointerType()); + } + if (Ty->isVariableArrayType()) { + R = ActOnExprStmt(MakeFullExpr(Exp)); + } + } + return R; +} + /// We are trying to inject an anonymous member into the given scope; /// check if there's an existing declaration that can't be overloaded. /// @@ -1707,11 +1800,10 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, // Pick a representative declaration. NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl(); - if (PrevDecl && Owner->isRecord()) { - RecordDecl *Record = cast<RecordDecl>(Owner); - if (!SemaRef.isDeclInScope(PrevDecl, Record, S)) - return false; - } + assert(PrevDecl && "Expected a non-null Decl"); + + if (!SemaRef.isDeclInScope(PrevDecl, Owner, S)) + return false; SemaRef.Diag(NameLoc, diagnostic) << Name; SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration); @@ -1738,18 +1830,24 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner, RecordDecl *AnonRecord, - AccessSpecifier AS) { + AccessSpecifier AS, + llvm::SmallVector<NamedDecl*, 2> &Chaining, + bool MSAnonStruct) { unsigned diagKind = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl : diag::err_anonymous_struct_member_redecl; bool Invalid = false; - for (RecordDecl::field_iterator F = AnonRecord->field_begin(), - FEnd = AnonRecord->field_end(); - F != FEnd; ++F) { - if ((*F)->getDeclName()) { - if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, (*F)->getDeclName(), - (*F)->getLocation(), diagKind)) { + + // Look every FieldDecl and IndirectFieldDecl with a name. + for (RecordDecl::decl_iterator D = AnonRecord->decls_begin(), + DEnd = AnonRecord->decls_end(); + D != DEnd; ++D) { + if ((isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D)) && + cast<NamedDecl>(*D)->getDeclName()) { + ValueDecl *VD = cast<ValueDecl>(*D); + if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(), + VD->getLocation(), diagKind)) { // 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 @@ -1761,20 +1859,34 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, // definition, the members of the anonymous union are // considered to have been defined in the scope in which the // anonymous union is declared. - Owner->makeDeclVisibleInContext(*F); - S->AddDecl(*F); - SemaRef.IdResolver.AddDecl(*F); + unsigned OldChainingSize = Chaining.size(); + if (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(VD)) + for (IndirectFieldDecl::chain_iterator PI = IF->chain_begin(), + PE = IF->chain_end(); PI != PE; ++PI) + Chaining.push_back(*PI); + else + Chaining.push_back(VD); + + assert(Chaining.size() >= 2); + NamedDecl **NamedChain = + new (SemaRef.Context)NamedDecl*[Chaining.size()]; + for (unsigned i = 0; i < Chaining.size(); i++) + NamedChain[i] = Chaining[i]; + + IndirectFieldDecl* IndirectField = + IndirectFieldDecl::Create(SemaRef.Context, Owner, VD->getLocation(), + VD->getIdentifier(), VD->getType(), + NamedChain, Chaining.size()); + + IndirectField->setAccess(AS); + IndirectField->setImplicit(); + SemaRef.PushOnScopeChains(IndirectField, S); // That includes picking up the appropriate access specifier. - if (AS != AS_none) (*F)->setAccess(AS); + if (AS != AS_none) IndirectField->setAccess(AS); + + Chaining.resize(OldChainingSize); } - } else if (const RecordType *InnerRecordType - = (*F)->getType()->getAs<RecordType>()) { - RecordDecl *InnerRecord = InnerRecordType->getDecl(); - if (InnerRecord->isAnonymousStructOrUnion()) - Invalid = Invalid || - InjectAnonymousStructOrUnionMembers(SemaRef, S, Owner, - InnerRecord, AS); } } @@ -1819,7 +1931,7 @@ StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) { llvm_unreachable("unknown storage class specifier"); } -/// ActOnAnonymousStructOrUnion - Handle the declaration of an +/// BuildAnonymousStructOrUnion - 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. @@ -1852,7 +1964,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Recover by adding 'static'. DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), - PrevSpec, DiagID); + PrevSpec, DiagID, getLangOptions()); } // C++ [class.union]p3: // A storage class is not allowed in a declaration of an @@ -1865,7 +1977,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Recover by removing the storage specifier. DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(), - PrevSpec, DiagID); + PrevSpec, DiagID, getLangOptions()); } // C++ [class.union]p2: @@ -1898,10 +2010,16 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, } else if (RecordDecl *MemRecord = dyn_cast<RecordDecl>(*Mem)) { if (!MemRecord->isAnonymousStructOrUnion() && MemRecord->getDeclName()) { - // This is a nested type declaration. - Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type) - << (int)Record->isUnion(); - Invalid = true; + // Visual C++ allows type definition in anonymous struct or union. + if (getLangOptions().Microsoft) + Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_type) + << (int)Record->isUnion(); + else { + // This is a nested type declaration. + Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type) + << (int)Record->isUnion(); + Invalid = true; + } } } else if (isa<AccessSpecDecl>(*Mem)) { // Any access specifier is fine. @@ -1915,9 +2033,17 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, DK = diag::err_anonymous_record_with_function; else if (isa<VarDecl>(*Mem)) DK = diag::err_anonymous_record_with_static; - Diag((*Mem)->getLocation(), DK) + + // Visual C++ allows type definition in anonymous struct or union. + if (getLangOptions().Microsoft && + DK == diag::err_anonymous_record_with_type) + Diag((*Mem)->getLocation(), diag::ext_anonymous_record_with_type) << (int)Record->isUnion(); + else { + Diag((*Mem)->getLocation(), DK) + << (int)Record->isUnion(); Invalid = true; + } } } } @@ -1942,11 +2068,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, TInfo, /*BitWidth=*/0, /*Mutable=*/false); Anon->setAccess(AS); - if (getLangOptions().CPlusPlus) { + if (getLangOptions().CPlusPlus) FieldCollector->Add(cast<FieldDecl>(Anon)); - if (!cast<CXXRecordDecl>(Record)->isEmpty()) - cast<CXXRecordDecl>(OwningClass)->setEmpty(false); - } } else { DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); assert(SCSpec != DeclSpec::SCS_typedef && @@ -1978,7 +2101,11 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. - if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS)) + llvm::SmallVector<NamedDecl*, 2> Chain; + Chain.push_back(Anon); + + if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, + Chain, false)) Invalid = true; // Mark this as an anonymous struct/union type. Note that we do not @@ -1995,6 +2122,57 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, return Anon; } +/// BuildMicrosoftCAnonymousStruct - Handle the declaration of an +/// Microsoft C anonymous structure. +/// Ref: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx +/// Example: +/// +/// struct A { int a; }; +/// struct B { struct A; int b; }; +/// +/// void foo() { +/// B var; +/// var.a = 3; +/// } +/// +Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, + RecordDecl *Record) { + + // If there is no Record, get the record via the typedef. + if (!Record) + Record = DS.getRepAsType().get()->getAsStructureType()->getDecl(); + + // Mock up a declarator. + Declarator Dc(DS, Declarator::TypeNameContext); + TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); + assert(TInfo && "couldn't build declarator info for anonymous struct"); + + // Create a declaration for this anonymous struct. + NamedDecl* Anon = FieldDecl::Create(Context, + cast<RecordDecl>(CurContext), + DS.getSourceRange().getBegin(), + /*IdentifierInfo=*/0, + Context.getTypeDeclType(Record), + TInfo, + /*BitWidth=*/0, /*Mutable=*/false); + Anon->setImplicit(); + + // Add the anonymous struct object to the current context. + CurContext->addDecl(Anon); + + // Inject the members of the anonymous struct into the current + // context and into the identifier resolver chain for name lookup + // purposes. + llvm::SmallVector<NamedDecl*, 2> Chain; + Chain.push_back(Anon); + + if (InjectAnonymousStructOrUnionMembers(*this, S, CurContext, + Record->getDefinition(), + AS_none, Chain, true)) + Anon->setInvalidDecl(); + + return Anon; +} /// GetNameForDeclarator - Determine the full declaration name for the /// given Declarator. @@ -2216,7 +2394,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, diag::err_declarator_need_ident) << D.getDeclSpec().getSourceRange() << D.getSourceRange(); return 0; - } + } else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType)) + return 0; // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. @@ -2228,6 +2407,10 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, if (D.getCXXScopeSpec().isInvalid()) D.setInvalidType(); else if (D.getCXXScopeSpec().isSet()) { + if (DiagnoseUnexpandedParameterPack(D.getCXXScopeSpec(), + UPPC_DeclarationQualifier)) + return 0; + bool EnteringContext = !D.getDeclSpec().isFriendSpecified(); DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext); if (!DC) { @@ -2248,11 +2431,30 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, RequireCompleteDeclContext(D.getCXXScopeSpec(), DC)) return 0; - if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) { - Diag(D.getIdentifierLoc(), - diag::err_member_def_undefined_record) - << Name << DC << D.getCXXScopeSpec().getRange(); - D.setInvalidType(); + if (isa<CXXRecordDecl>(DC)) { + if (!cast<CXXRecordDecl>(DC)->hasDefinition()) { + Diag(D.getIdentifierLoc(), + diag::err_member_def_undefined_record) + << Name << DC << D.getCXXScopeSpec().getRange(); + D.setInvalidType(); + } else if (isa<CXXRecordDecl>(CurContext) && + !D.getDeclSpec().isFriendSpecified()) { + // The user provided a superfluous scope specifier inside a class + // definition: + // + // class X { + // void X::f(); + // }; + if (CurContext->Equals(DC)) + Diag(D.getIdentifierLoc(), diag::warn_member_extra_qualification) + << Name << FixItHint::CreateRemoval(D.getCXXScopeSpec().getRange()); + else + Diag(D.getIdentifierLoc(), diag::err_member_qualification) + << Name << D.getCXXScopeSpec().getRange(); + + // Pretend that this qualifier was not here. + D.getCXXScopeSpec().clear(); + } } // Check whether we need to rebuild the type of the given @@ -2264,12 +2466,33 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, D.setInvalidType(); } } - + + // C++ [class.mem]p13: + // If T is the name of a class, then each of the following shall have a + // name different from T: + // - every static data member of class T; + // - every member function of class T + // - every member of class T that is itself a type; + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) + if (Record->getIdentifier() && Record->getDeclName() == Name) { + Diag(D.getIdentifierLoc(), diag::err_member_name_of_class) + << Name; + + // If this is a typedef, we'll end up spewing multiple diagnostics. + // Just return early; it's safer. + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) + return 0; + } + NamedDecl *New; TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType R = TInfo->getType(); + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, + UPPC_DeclarationType)) + D.setInvalidType(); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); @@ -2425,7 +2648,16 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, Oversized); if (FixedType.isNull()) return FixedType; FixedType = Context.getPointerType(FixedType); - return Qs.apply(FixedType); + return Qs.apply(Context, FixedType); + } + if (const ParenType* PTy = dyn_cast<ParenType>(Ty)) { + QualType Inner = PTy->getInnerType(); + QualType FixedType = + TryToFixInvalidVariablyModifiedType(Inner, Context, SizeIsNegative, + Oversized); + if (FixedType.isNull()) return FixedType; + FixedType = Context.getParenType(FixedType); + return Qs.apply(Context, FixedType); } const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T); @@ -2595,6 +2827,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, Context.setjmp_bufDecl(NewTD); else if (II->isStr("sigjmp_buf")) Context.setsigjmp_bufDecl(NewTD); + else if (II->isStr("__builtin_va_list")) + Context.setBuiltinVaListType(Context.getTypedefType(NewTD)); } return NewTD; @@ -2666,7 +2900,7 @@ static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) { } NamedDecl* -Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, +Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, @@ -2715,73 +2949,99 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.setInvalidType(); } } - if (DC->isRecord() && !CurContext->isRecord()) { - // This is an out-of-line definition of a static data member. + + bool isExplicitSpecialization = false; + VarDecl *NewVD; + if (!getLangOptions().CPlusPlus) { + NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), + II, R, TInfo, SC, SCAsWritten); + + if (D.isInvalidType()) + NewVD->setInvalidDecl(); + } else { + if (DC->isRecord() && !CurContext->isRecord()) { + // This is an out-of-line definition of a static data member. + if (SC == SC_Static) { + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_out_of_line) + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + } else if (SC == SC_None) + SC = SC_Static; + } if (SC == SC_Static) { - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_static_out_of_line) - << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - } else if (SC == SC_None) - SC = SC_Static; - } - if (SC == SC_Static) { - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { - if (RD->isLocalClass()) - Diag(D.getIdentifierLoc(), - diag::err_static_data_member_not_allowed_in_local_class) - << Name << RD->getDeclName(); + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { + if (RD->isLocalClass()) + Diag(D.getIdentifierLoc(), + diag::err_static_data_member_not_allowed_in_local_class) + << Name << RD->getDeclName(); + + // C++ [class.union]p1: If a union contains a static data member, + // the program is ill-formed. + // + // We also disallow static data members in anonymous structs. + if (CurContext->isRecord() && (RD->isUnion() || !RD->getDeclName())) + Diag(D.getIdentifierLoc(), + diag::err_static_data_member_not_allowed_in_union_or_anon_struct) + << Name << RD->isUnion(); + } } - } - // Match up the template parameter lists with the scope specifier, then - // determine whether we have a template or a template specialization. - bool isExplicitSpecialization = false; - unsigned NumMatchedTemplateParamLists = TemplateParamLists.size(); - bool Invalid = false; - if (TemplateParameterList *TemplateParams + // Match up the template parameter lists with the scope specifier, then + // determine whether we have a template or a template specialization. + isExplicitSpecialization = false; + unsigned NumMatchedTemplateParamLists = TemplateParamLists.size(); + bool Invalid = false; + if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getSourceRange().getBegin(), + D.getDeclSpec().getSourceRange().getBegin(), D.getCXXScopeSpec(), - (TemplateParameterList**)TemplateParamLists.get(), - TemplateParamLists.size(), + TemplateParamLists.get(), + TemplateParamLists.size(), /*never a friend*/ false, isExplicitSpecialization, Invalid)) { - // All but one template parameter lists have been matching. - --NumMatchedTemplateParamLists; - - 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()); + // All but one template parameter lists have been matching. + --NumMatchedTemplateParamLists; + + 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; + isExplicitSpecialization = true; + } } - } - VarDecl *NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), - II, R, TInfo, SC, SCAsWritten); + NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), + II, R, TInfo, SC, SCAsWritten); - if (D.isInvalidType() || Invalid) - NewVD->setInvalidDecl(); + // If this decl has an auto type in need of deduction, mark the VarDecl so + // we can diagnose uses of it in its own initializer. + if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto) { + NewVD->setParsingAutoInit(R->getContainedAutoType()); + } + + if (D.isInvalidType() || Invalid) + NewVD->setInvalidDecl(); - SetNestedNameSpecifier(NewVD, D); + SetNestedNameSpecifier(NewVD, D); - if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { - NewVD->setTemplateParameterListsInfo(Context, - NumMatchedTemplateParamLists, - (TemplateParameterList**)TemplateParamLists.release()); + if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { + NewVD->setTemplateParameterListsInfo(Context, + NumMatchedTemplateParamLists, + TemplateParamLists.release()); + } } if (D.getDeclSpec().isThreadSpecified()) { @@ -2801,11 +3061,29 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, ProcessDeclAttributes(S, NewVD, D); // Handle GNU asm-label extension (encoded as an attribute). - if (Expr *E = (Expr*) D.getAsmLabel()) { + if (Expr *E = (Expr*)D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast<StringLiteral>(E); - NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), - Context, SE->getString())); + llvm::StringRef Label = SE->getString(); + if (S->getFnParent() != 0) { + switch (SC) { + case SC_None: + case SC_Auto: + Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; + break; + case SC_Register: + if (!Context.Target.isValidGCCRegisterName(Label)) + Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; + break; + case SC_Static: + case SC_Extern: + case SC_PrivateExtern: + break; + } + } + + NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), + Context, Label)); } // Diagnose shadowed variables before filtering for scope. @@ -2817,33 +3095,37 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // declaration has linkage). FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage()); - // Merge the decl with the existing one if appropriate. - if (!Previous.empty()) { - if (Previous.isSingleResult() && - isa<FieldDecl>(Previous.getFoundDecl()) && - D.getCXXScopeSpec().isSet()) { - // The user tried to define a non-static data member - // out-of-line (C++ [dcl.meaning]p1). - Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line) + if (!getLangOptions().CPlusPlus) + CheckVariableDeclaration(NewVD, Previous, Redeclaration); + else { + // Merge the decl with the existing one if appropriate. + if (!Previous.empty()) { + if (Previous.isSingleResult() && + isa<FieldDecl>(Previous.getFoundDecl()) && + D.getCXXScopeSpec().isSet()) { + // The user tried to define a non-static data member + // out-of-line (C++ [dcl.meaning]p1). + Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line) + << D.getCXXScopeSpec().getRange(); + Previous.clear(); + NewVD->setInvalidDecl(); + } + } else if (D.getCXXScopeSpec().isSet()) { + // No previous declaration in the qualifying scope. + Diag(D.getIdentifierLoc(), diag::err_no_member) + << Name << computeDeclContext(D.getCXXScopeSpec(), true) << D.getCXXScopeSpec().getRange(); - Previous.clear(); NewVD->setInvalidDecl(); } - } else if (D.getCXXScopeSpec().isSet()) { - // No previous declaration in the qualifying scope. - Diag(D.getIdentifierLoc(), diag::err_no_member) - << Name << computeDeclContext(D.getCXXScopeSpec(), true) - << D.getCXXScopeSpec().getRange(); - NewVD->setInvalidDecl(); - } - - CheckVariableDeclaration(NewVD, Previous, Redeclaration); - // This is an explicit specialization of a static data member. Check it. - if (isExplicitSpecialization && !NewVD->isInvalidDecl() && - CheckMemberSpecialization(NewVD, Previous)) - NewVD->setInvalidDecl(); + CheckVariableDeclaration(NewVD, Previous, Redeclaration); + // This is an explicit specialization of a static data member. Check it. + if (isExplicitSpecialization && !NewVD->isInvalidDecl() && + CheckMemberSpecialization(NewVD, Previous)) + NewVD->setInvalidDecl(); + } + // attributes declared post-definition are currently ignored // FIXME: This should be handled in attribute merging, not // here. @@ -2866,7 +3148,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // member, set the visibility of this variable. if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord()) AddPushedVisibilityAttribute(NewVD); - + MarkUnusedFileScopedDecl(NewVD); return NewVD; @@ -2883,13 +3165,13 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { // Return if warning is ignored. - if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored) + if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, R.getNameLoc()) == + Diagnostic::Ignored) return; - // Don't diagnose declarations at file scope. The scope might not - // have a DeclContext if (e.g.) we're parsing a function prototype. - DeclContext *NewDC = static_cast<DeclContext*>(S->getEntity()); - if (NewDC && NewDC->isFileContext()) + // Don't diagnose declarations at file scope. + DeclContext *NewDC = D->getDeclContext(); + if (NewDC->isFileContext()) return; // Only diagnose if we're shadowing an unambiguous field or variable. @@ -2900,6 +3182,36 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { if (!isa<VarDecl>(ShadowedDecl) && !isa<FieldDecl>(ShadowedDecl)) return; + // Fields are not shadowed by variables in C++ static methods. + if (isa<FieldDecl>(ShadowedDecl)) + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewDC)) + if (MD->isStatic()) + return; + + if (VarDecl *shadowedVar = dyn_cast<VarDecl>(ShadowedDecl)) + if (shadowedVar->isExternC()) { + // Don't warn for this case: + // + // @code + // extern int bob; + // void f() { + // extern int bob; + // } + // @endcode + if (D->isExternC()) + return; + + // For shadowing external vars, make sure that we point to the global + // declaration, not a locally scoped extern declaration. + for (VarDecl::redecl_iterator + I = shadowedVar->redecls_begin(), E = shadowedVar->redecls_end(); + I != E; ++I) + if (I->isFileVarDecl()) { + ShadowedDecl = *I; + break; + } + } + DeclContext *OldDC = ShadowedDecl->getDeclContext(); // Only warn about certain kinds of shadowing for class members. @@ -2937,6 +3249,10 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { /// \brief Check -Wshadow without the advantage of a previous lookup. void Sema::CheckShadow(Scope *S, VarDecl *D) { + if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, D->getLocation()) == + Diagnostic::Ignored) + return; + LookupResult R(*this, D->getDeclName(), D->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); LookupName(R, S); @@ -2971,7 +3287,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, // This includes arrays of objects with address space qualifiers, but not // automatic variables that point to other address spaces. // ISO/IEC TR 18037 S5.1.2 - if (NewVD->hasLocalStorage() && (T.getAddressSpace() != 0)) { + if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); return NewVD->setInvalidDecl(); } @@ -2979,7 +3295,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, if (NewVD->hasLocalStorage() && T.isObjCGCWeak() && !NewVD->hasAttr<BlocksAttr>()) Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); - + bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr<CleanupAttr>() || NewVD->hasAttr<BlocksAttr>()) @@ -3115,23 +3431,42 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. -void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { +bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { // Look for virtual methods in base classes that this method might override. CXXBasePaths Paths; FindOverriddenMethodData Data; Data.Method = MD; Data.S = this; + bool AddedAny = false; if (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(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && - !CheckOverridingFunctionAttributes(MD, OldMD)) + !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { MD->addOverriddenMethod(OldMD->getCanonicalDecl()); + AddedAny = true; + } } } } + + return AddedAny; +} + +static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) { + LookupResult Prev(S, NewFD->getDeclName(), NewFD->getLocation(), + Sema::LookupOrdinaryName, Sema::ForRedeclaration); + S.LookupQualifiedName(Prev, NewFD->getDeclContext()); + assert(!Prev.isAmbiguous() && + "Cannot have an ambiguity in previous-declaration lookup"); + for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); + Func != FuncEnd; ++Func) { + if (isa<FunctionDecl>(*Func) && + isNearlyMatchingFunction(S.Context, cast<FunctionDecl>(*Func), NewFD)) + S.Diag((*Func)->getLocation(), diag::note_member_def_close_match); + } } NamedDecl* @@ -3171,315 +3506,336 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, SC = SC_Static; break; } - case DeclSpec::SCS_private_extern: SC = SC_PrivateExtern;break; + case DeclSpec::SCS_private_extern: SC = SC_PrivateExtern; break; } 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(); - - DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); - FunctionDecl::StorageClass SCAsWritten - = StorageClassSpecToFunctionDeclStorageClass(SCSpec); - - // 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. - if (!DC->isRecord() && - 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->getAs<FunctionType>()->getResultType()->isObjCObjectType()) { Diag(D.getIdentifierLoc(), diag::err_object_cannot_be_passed_returned_by_value) << 0 - << R->getAs<FunctionType>()->getResultType(); + << R->getAs<FunctionType>()->getResultType(); D.setInvalidType(); } - - bool isVirtualOkay = false; + FunctionDecl *NewFD; - - if (isFriend) { - // 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 (Name.getNameKind() == DeclarationName::CXXConstructorName) { - // This is a C++ constructor declaration. - assert(DC->isRecord() && - "Constructors can only be declared in a member context"); - - R = CheckConstructorDeclarator(D, R, SC); - - // Create the new declaration - NewFD = CXXConstructorDecl::Create(Context, - cast<CXXRecordDecl>(DC), - NameInfo, R, TInfo, - isExplicit, isInline, - /*isImplicitlyDeclared=*/false); - } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { - // This is a C++ destructor declaration. - if (DC->isRecord()) { - R = CheckDestructorDeclarator(D, R, SC); - - NewFD = CXXDestructorDecl::Create(Context, - cast<CXXRecordDecl>(DC), - NameInfo, R, - isInline, - /*isImplicitlyDeclared=*/false); - NewFD->setTypeSourceInfo(TInfo); - - isVirtualOkay = true; - } else { - Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); - - // Create a FunctionDecl to satisfy the function definition parsing - // code path. - NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, TInfo, SC, SCAsWritten, isInline, - /*hasPrototype=*/true); - D.setInvalidType(); - } - } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { - if (!DC->isRecord()) { - Diag(D.getIdentifierLoc(), - diag::err_conv_function_not_member); - return 0; - } - - CheckConversionDeclarator(D, R, SC); - NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), - NameInfo, R, TInfo, - 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 - // constructor if it has no return type). - // must have an invalid constructor that has a return type - if (Name.getAsIdentifierInfo() && - Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ - Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) - << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) - << SourceRange(D.getIdentifierLoc()); - return 0; - } - - bool isStatic = SC == SC_Static; - - // [class.free]p1: - // Any allocation function for a class T is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_New || - Name.getCXXOverloadedOperator() == OO_Array_New) - isStatic = true; - - // [class.free]p6 Any deallocation function for a class X is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_Delete || - Name.getCXXOverloadedOperator() == OO_Array_Delete) - isStatic = true; - - // This is a C++ method declaration. - NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), - NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline); - - isVirtualOkay = !isStatic; - } else { + bool isInline = D.getDeclSpec().isInlineSpecified(); + bool isFriend = false; + DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); + FunctionDecl::StorageClass SCAsWritten + = StorageClassSpecToFunctionDeclStorageClass(SCSpec); + FunctionTemplateDecl *FunctionTemplate = 0; + bool isExplicitSpecialization = false; + bool isFunctionTemplateSpecialization = false; + unsigned NumMatchedTemplateParamLists = 0; + + if (!getLangOptions().CPlusPlus) { // Determine whether the function was written with a // prototype. This true when: - // - we're in C++ (where every function has a prototype), // - 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 = - getLangOptions().CPlusPlus || - (D.getNumTypeObjects() && D.getTypeObject(0).Fun.hasPrototype) || - (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); - + (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || + (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); + NewFD = FunctionDecl::Create(Context, DC, NameInfo, R, TInfo, SC, SCAsWritten, isInline, HasPrototype); - } - - if (D.isInvalidType()) - NewFD->setInvalidDecl(); + if (D.isInvalidType()) + NewFD->setInvalidDecl(); + + // Set the lexical context. + NewFD->setLexicalDeclContext(CurContext); + // Filter out previous declarations that don't match the scope. + FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage()); + } else { + isFriend = D.getDeclSpec().isFriendSpecified(); + bool isVirtual = D.getDeclSpec().isVirtualSpecified(); + bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + bool isVirtualOkay = false; + + // 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. + if (!DC->isRecord() && + RequireNonAbstractType(D.getIdentifierLoc(), + R->getAs<FunctionType>()->getResultType(), + diag::err_abstract_type_in_decl, + AbstractReturnType)) + D.setInvalidType(); - SetNestedNameSpecifier(NewFD, D); - // Set the lexical context. If the declarator has a C++ - // scope specifier, or is the object of a friend declaration, the - // lexical context will be different from the semantic context. - NewFD->setLexicalDeclContext(CurContext); + if (isFriend) { + // 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 (Name.getNameKind() == DeclarationName::CXXConstructorName) { + // This is a C++ constructor declaration. + assert(DC->isRecord() && + "Constructors can only be declared in a member context"); + + R = CheckConstructorDeclarator(D, R, SC); + + // Create the new declaration + NewFD = CXXConstructorDecl::Create(Context, + cast<CXXRecordDecl>(DC), + NameInfo, R, TInfo, + isExplicit, isInline, + /*isImplicitlyDeclared=*/false); + } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { + // This is a C++ destructor declaration. + if (DC->isRecord()) { + R = CheckDestructorDeclarator(D, R, SC); + + NewFD = CXXDestructorDecl::Create(Context, + cast<CXXRecordDecl>(DC), + NameInfo, R, TInfo, + isInline, + /*isImplicitlyDeclared=*/false); + isVirtualOkay = true; + } else { + Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); - // Match up the template parameter lists with the scope specifier, then - // determine whether we have a template or a template specialization. - FunctionTemplateDecl *FunctionTemplate = 0; - bool isExplicitSpecialization = false; - bool isFunctionTemplateSpecialization = false; - unsigned NumMatchedTemplateParamLists = TemplateParamLists.size(); - bool Invalid = false; - if (TemplateParameterList *TemplateParams - = MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getSourceRange().getBegin(), - D.getCXXScopeSpec(), - (TemplateParameterList**)TemplateParamLists.get(), - TemplateParamLists.size(), - isFriend, - isExplicitSpecialization, - Invalid)) { - // All but one template parameter lists have been matching. - --NumMatchedTemplateParamLists; + // Create a FunctionDecl to satisfy the function definition parsing + // code path. + NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), + Name, R, TInfo, SC, SCAsWritten, isInline, + /*hasPrototype=*/true); + D.setInvalidType(); + } + } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { + if (!DC->isRecord()) { + Diag(D.getIdentifierLoc(), + diag::err_conv_function_not_member); + return 0; + } - if (TemplateParams->size() > 0) { - // This is a function template + CheckConversionDeclarator(D, R, SC); + NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), + NameInfo, R, TInfo, + isInline, isExplicit); - // Check that we can declare a template here. - if (CheckTemplateDeclScope(S, TemplateParams)) + 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 + // constructor if it has no return type). + // must have an invalid constructor that has a return type + if (Name.getAsIdentifierInfo() && + Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ + Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) + << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) + << SourceRange(D.getIdentifierLoc()); return 0; + } + + bool isStatic = SC == SC_Static; + + // [class.free]p1: + // Any allocation function for a class T is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_New || + Name.getCXXOverloadedOperator() == OO_Array_New) + isStatic = true; + + // [class.free]p6 Any deallocation function for a class X is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) + isStatic = true; + + // This is a C++ method declaration. + NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), + NameInfo, R, TInfo, + isStatic, SCAsWritten, isInline); - FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, + isVirtualOkay = !isStatic; + } else { + // Determine whether the function was written with a + // prototype. This true when: + // - we're in C++ (where every function has a prototype), + NewFD = FunctionDecl::Create(Context, DC, + NameInfo, R, TInfo, SC, SCAsWritten, isInline, + true/*HasPrototype*/); + } + SetNestedNameSpecifier(NewFD, D); + isExplicitSpecialization = false; + isFunctionTemplateSpecialization = false; + NumMatchedTemplateParamLists = TemplateParamLists.size(); + if (D.isInvalidType()) + NewFD->setInvalidDecl(); + + // Set the lexical context. If the declarator has a C++ + // scope specifier, or is the object of a friend declaration, the + // lexical context will be different from the semantic context. + NewFD->setLexicalDeclContext(CurContext); + + // Match up the template parameter lists with the scope specifier, then + // determine whether we have a template or a template specialization. + bool Invalid = false; + if (TemplateParameterList *TemplateParams + = MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getSourceRange().getBegin(), + D.getCXXScopeSpec(), + TemplateParamLists.get(), + TemplateParamLists.size(), + isFriend, + isExplicitSpecialization, + Invalid)) { + // All but one template parameter lists have been matching. + --NumMatchedTemplateParamLists; + + if (TemplateParams->size() > 0) { + // This is a function template + + // 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 { - // This is a function template specialization. - isFunctionTemplateSpecialization = true; - - // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". - if (isFriend && isFunctionTemplateSpecialization) { - // We want to remove the "template<>", found here. - SourceRange RemoveRange = TemplateParams->getSourceRange(); - - // If we remove the template<> and the name is not a - // template-id, we're actually silently creating a problem: - // the friend declaration will refer to an untemplated decl, - // and clearly the user wants a template specialization. So - // we need to insert '<>' after the name. - SourceLocation InsertLoc; - if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { - InsertLoc = D.getName().getSourceRange().getEnd(); - InsertLoc = PP.getLocForEndOfToken(InsertLoc); + FunctionTemplate->setLexicalDeclContext(CurContext); + NewFD->setDescribedFunctionTemplate(FunctionTemplate); + } else { + // This is a function template specialization. + isFunctionTemplateSpecialization = true; + + // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". + if (isFriend && isFunctionTemplateSpecialization) { + // We want to remove the "template<>", found here. + SourceRange RemoveRange = TemplateParams->getSourceRange(); + + // If we remove the template<> and the name is not a + // template-id, we're actually silently creating a problem: + // the friend declaration will refer to an untemplated decl, + // and clearly the user wants a template specialization. So + // we need to insert '<>' after the name. + SourceLocation InsertLoc; + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { + InsertLoc = D.getName().getSourceRange().getEnd(); + InsertLoc = PP.getLocForEndOfToken(InsertLoc); + } + + Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) + << Name << RemoveRange + << FixItHint::CreateRemoval(RemoveRange) + << FixItHint::CreateInsertion(InsertLoc, "<>"); + } + } } - Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) - << Name << RemoveRange - << FixItHint::CreateRemoval(RemoveRange) - << FixItHint::CreateInsertion(InsertLoc, "<>"); - } + if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { + NewFD->setTemplateParameterListsInfo(Context, + NumMatchedTemplateParamLists, + TemplateParamLists.release()); } - } - if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { - NewFD->setTemplateParameterListsInfo(Context, - NumMatchedTemplateParamLists, - (TemplateParameterList**)TemplateParamLists.release()); - } - - if (Invalid) { - NewFD->setInvalidDecl(); - if (FunctionTemplate) - FunctionTemplate->setInvalidDecl(); - } + if (Invalid) { + NewFD->setInvalidDecl(); + if (FunctionTemplate) + FunctionTemplate->setInvalidDecl(); + } - // C++ [dcl.fct.spec]p5: - // The virtual specifier shall only be used in declarations of - // nonstatic class member functions that appear within a - // member-specification of a class declaration; see 10.3. - // - if (isVirtual && !NewFD->isInvalidDecl()) { - if (!isVirtualOkay) { - Diag(D.getDeclSpec().getVirtualSpecLoc(), - diag::err_virtual_non_function); - } else if (!CurContext->isRecord()) { - // 'virtual' was specified outside of the class. - Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class) - << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); - } else { - // Okay: Add virtual to the method. - CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC); - CurClass->setMethodAsVirtual(NewFD); + // C++ [dcl.fct.spec]p5: + // The virtual specifier shall only be used in declarations of + // nonstatic class member functions that appear within a + // member-specification of a class declaration; see 10.3. + // + if (isVirtual && !NewFD->isInvalidDecl()) { + if (!isVirtualOkay) { + Diag(D.getDeclSpec().getVirtualSpecLoc(), + diag::err_virtual_non_function); + } else if (!CurContext->isRecord()) { + // 'virtual' was specified outside of the class. + Diag(D.getDeclSpec().getVirtualSpecLoc(), + diag::err_virtual_out_of_class) + << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); + } else if (NewFD->getDescribedFunctionTemplate()) { + // C++ [temp.mem]p3: + // A member function template shall not be virtual. + Diag(D.getDeclSpec().getVirtualSpecLoc(), + diag::err_virtual_member_function_template) + << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); + } else { + // Okay: Add virtual to the method. + NewFD->setVirtualAsWritten(true); + } } - } - // C++ [dcl.fct.spec]p3: - // The inline specifier shall not appear on a block scope function declaration. - if (isInline && !NewFD->isInvalidDecl() && getLangOptions().CPlusPlus) { - if (CurContext->isFunctionOrMethod()) { - // 'inline' is not allowed on block scope function declaration. - Diag(D.getDeclSpec().getInlineSpecLoc(), - diag::err_inline_declaration_block_scope) << Name - << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); + // C++ [dcl.fct.spec]p3: + // The inline specifier shall not appear on a block scope function declaration. + if (isInline && !NewFD->isInvalidDecl()) { + if (CurContext->isFunctionOrMethod()) { + // 'inline' is not allowed on block scope function declaration. + Diag(D.getDeclSpec().getInlineSpecLoc(), + diag::err_inline_declaration_block_scope) << Name + << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); + } } - } - // C++ [dcl.fct.spec]p6: - // The explicit specifier shall be used only in the declaration of a - // constructor or conversion function within its class definition; see 12.3.1 - // and 12.3.2. - if (isExplicit && !NewFD->isInvalidDecl()) { - if (!CurContext->isRecord()) { - // 'explicit' was specified outside of the class. - Diag(D.getDeclSpec().getExplicitSpecLoc(), - diag::err_explicit_out_of_class) - << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); - } else if (!isa<CXXConstructorDecl>(NewFD) && - !isa<CXXConversionDecl>(NewFD)) { - // 'explicit' was specified on a function that wasn't a constructor - // or conversion function. - Diag(D.getDeclSpec().getExplicitSpecLoc(), - diag::err_explicit_non_ctor_or_conv_function) - << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); - } - } - - // Filter out previous declarations that don't match the scope. - FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage()); - - if (isFriend) { - // DC is the namespace in which the function is being declared. - assert((DC->isFileContext() || !Previous.empty()) && - "previously-undeclared friend function being created " - "in a non-namespace context"); - - // For now, claim that the objects have no previous declaration. - if (FunctionTemplate) { - FunctionTemplate->setObjectOfFriendDecl(false); - FunctionTemplate->setAccess(AS_public); + // C++ [dcl.fct.spec]p6: + // The explicit specifier shall be used only in the declaration of a + // constructor or conversion function within its class definition; see 12.3.1 + // and 12.3.2. + if (isExplicit && !NewFD->isInvalidDecl()) { + if (!CurContext->isRecord()) { + // 'explicit' was specified outside of the class. + Diag(D.getDeclSpec().getExplicitSpecLoc(), + diag::err_explicit_out_of_class) + << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); + } else if (!isa<CXXConstructorDecl>(NewFD) && + !isa<CXXConversionDecl>(NewFD)) { + // 'explicit' was specified on a function that wasn't a constructor + // or conversion function. + Diag(D.getDeclSpec().getExplicitSpecLoc(), + diag::err_explicit_non_ctor_or_conv_function) + << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); + } + } + + // Filter out previous declarations that don't match the scope. + FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage()); + + if (isFriend) { + // For now, claim that the objects have no previous declaration. + if (FunctionTemplate) { + FunctionTemplate->setObjectOfFriendDecl(false); + FunctionTemplate->setAccess(AS_public); + } + NewFD->setObjectOfFriendDecl(false); + NewFD->setAccess(AS_public); } - NewFD->setObjectOfFriendDecl(false); - NewFD->setAccess(AS_public); - } - if (SC == SC_Static && isa<CXXMethodDecl>(NewFD) && - !CurContext->isRecord()) { - // C++ [class.static]p1: - // A data or function member of a class may be declared static - // in a class definition, in which case it is a static member of - // the class. + if (isa<CXXMethodDecl>(NewFD) && DC == CurContext && IsFunctionDefinition) { + // A method is implicitly inline if it's defined in its class + // definition. + NewFD->setImplicitlyInline(); + } - // Complain about the 'static' specifier if it's on an out-of-line - // member function definition. - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_static_out_of_line) - << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - } + if (SC == SC_Static && isa<CXXMethodDecl>(NewFD) && + !CurContext->isRecord()) { + // C++ [class.static]p1: + // A data or function member of a class may be declared static + // in a class definition, in which case it is a static member of + // the class. + // Complain about the 'static' specifier if it's on an out-of-line + // member function definition. + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_out_of_line) + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + } + } + // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. @@ -3491,8 +3847,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Copy the parameter declarations from the declarator D to the function // declaration NewFD, if they are available. First scavenge them into Params. llvm::SmallVector<ParmVarDecl*, 16> Params; - if (D.getNumTypeObjects() > 0) { - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + if (D.isFunctionDeclarator()) { + DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs // function that takes no arguments, not a function that takes a @@ -3510,7 +3866,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (getLangOptions().CPlusPlus && Param->getType().getUnqualifiedType() != Context.VoidTy) 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) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param); @@ -3547,168 +3902,209 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Finally, we know we have the right number of parameters, install them. NewFD->setParams(Params.data(), Params.size()); - // If the declarator is a template-id, translate the parser's template - // argument list into our AST format. - bool HasExplicitTemplateArgs = false; - TemplateArgumentListInfo TemplateArgs; - if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getName().TemplateId; - TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); - TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(*this, - TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - translateTemplateArguments(TemplateArgsPtr, - TemplateArgs); - TemplateArgsPtr.release(); + // Process the non-inheritable attributes on this declaration. + ProcessDeclAttributes(S, NewFD, D, + /*NonInheritable=*/true, /*Inheritable=*/false); + + if (!getLangOptions().CPlusPlus) { + // Perform semantic checking on the function declaration. + bool isExplctSpecialization=false; + CheckFunctionDeclaration(S, NewFD, Previous, isExplctSpecialization, + Redeclaration); + assert((NewFD->isInvalidDecl() || !Redeclaration || + Previous.getResultKind() != LookupResult::FoundOverloaded) && + "previous declaration set still overloaded"); + } else { + // If the declarator is a template-id, translate the parser's template + // argument list into our AST format. + bool HasExplicitTemplateArgs = false; + TemplateArgumentListInfo TemplateArgs; + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + translateTemplateArguments(TemplateArgsPtr, + TemplateArgs); + TemplateArgsPtr.release(); - HasExplicitTemplateArgs = true; + HasExplicitTemplateArgs = true; - 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) - << FixItHint::CreateInsertion( - D.getDeclSpec().getSourceRange().getBegin(), - "template<> "); - isFunctionTemplateSpecialization = true; - } else { - // "friend void foo<>(int);" is an implicit specialization decl. - isFunctionTemplateSpecialization = true; - } - } else if (isFriend && isFunctionTemplateSpecialization) { - // This combination is only possible in a recovery case; the user - // wrote something like: - // template <> friend void foo(int); - // which we're recovering from as if the user had written: - // friend void foo<>(int); - // Go ahead and fake up a template id. - HasExplicitTemplateArgs = true; - TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); - TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); - } - - // If it's a friend (and only if it's a friend), it's possible - // that either the specialized function type or the specialized - // template is dependent, and therefore matching will fail. In - // this case, don't check the specialization yet. - if (isFunctionTemplateSpecialization && isFriend && - (NewFD->getType()->isDependentType() || DC->isDependentContext())) { - assert(HasExplicitTemplateArgs && - "friend function specialization without template args"); - if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, - Previous)) - NewFD->setInvalidDecl(); - } else if (isFunctionTemplateSpecialization) { - if (CheckFunctionTemplateSpecialization(NewFD, - (HasExplicitTemplateArgs ? &TemplateArgs : 0), - Previous)) - NewFD->setInvalidDecl(); - } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { - if (CheckMemberSpecialization(NewFD, Previous)) - NewFD->setInvalidDecl(); - } + if (FunctionTemplate) { + // Function template with explicit template arguments. + Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); + + 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) + << FixItHint::CreateInsertion( + D.getDeclSpec().getSourceRange().getBegin(), + "template<> "); + isFunctionTemplateSpecialization = true; + } else { + // "friend void foo<>(int);" is an implicit specialization decl. + isFunctionTemplateSpecialization = true; + } + } else if (isFriend && isFunctionTemplateSpecialization) { + // This combination is only possible in a recovery case; the user + // wrote something like: + // template <> friend void foo(int); + // which we're recovering from as if the user had written: + // friend void foo<>(int); + // Go ahead and fake up a template id. + HasExplicitTemplateArgs = true; + TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); + TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); + } + + // If it's a friend (and only if it's a friend), it's possible + // that either the specialized function type or the specialized + // template is dependent, and therefore matching will fail. In + // this case, don't check the specialization yet. + if (isFunctionTemplateSpecialization && isFriend && + (NewFD->getType()->isDependentType() || DC->isDependentContext())) { + assert(HasExplicitTemplateArgs && + "friend function specialization without template args"); + if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, + Previous)) + NewFD->setInvalidDecl(); + } else if (isFunctionTemplateSpecialization) { + if (CheckFunctionTemplateSpecialization(NewFD, + (HasExplicitTemplateArgs ? &TemplateArgs : 0), + Previous)) + NewFD->setInvalidDecl(); + } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { + if (CheckMemberSpecialization(NewFD, Previous)) + NewFD->setInvalidDecl(); + } - // Perform semantic checking on the function declaration. - bool OverloadableAttrRequired = false; // FIXME: HACK! - CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, - Redeclaration, /*FIXME:*/OverloadableAttrRequired); + // Perform semantic checking on the function declaration. + CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, + Redeclaration); - assert((NewFD->isInvalidDecl() || !Redeclaration || - Previous.getResultKind() != LookupResult::FoundOverloaded) && - "previous declaration set still overloaded"); + assert((NewFD->isInvalidDecl() || !Redeclaration || + Previous.getResultKind() != LookupResult::FoundOverloaded) && + "previous declaration set still overloaded"); - NamedDecl *PrincipalDecl = (FunctionTemplate - ? cast<NamedDecl>(FunctionTemplate) - : NewFD); + NamedDecl *PrincipalDecl = (FunctionTemplate + ? cast<NamedDecl>(FunctionTemplate) + : NewFD); - if (isFriend && Redeclaration) { - AccessSpecifier Access = AS_public; - if (!NewFD->isInvalidDecl()) - Access = NewFD->getPreviousDeclaration()->getAccess(); + if (isFriend && Redeclaration) { + AccessSpecifier Access = AS_public; + if (!NewFD->isInvalidDecl()) + Access = NewFD->getPreviousDeclaration()->getAccess(); - NewFD->setAccess(Access); - if (FunctionTemplate) FunctionTemplate->setAccess(Access); + NewFD->setAccess(Access); + if (FunctionTemplate) FunctionTemplate->setAccess(Access); - PrincipalDecl->setObjectOfFriendDecl(true); - } + PrincipalDecl->setObjectOfFriendDecl(true); + } - if (NewFD->isOverloadedOperator() && !DC->isRecord() && - PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) - PrincipalDecl->setNonMemberOperator(); + if (NewFD->isOverloadedOperator() && !DC->isRecord() && + PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + PrincipalDecl->setNonMemberOperator(); - // If we have a function template, check the template parameter - // list. This will check and merge default template arguments. - if (FunctionTemplate) { - FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDeclaration(); - CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), - PrevTemplate? PrevTemplate->getTemplateParameters() : 0, - D.getDeclSpec().isFriendSpecified()? TPC_FriendFunctionTemplate - : TPC_FunctionTemplate); - } + // If we have a function template, check the template parameter + // list. This will check and merge default template arguments. + if (FunctionTemplate) { + FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDeclaration(); + CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), + PrevTemplate? PrevTemplate->getTemplateParameters() : 0, + D.getDeclSpec().isFriendSpecified() + ? (IsFunctionDefinition + ? TPC_FriendFunctionTemplateDefinition + : TPC_FriendFunctionTemplate) + : (D.getCXXScopeSpec().isSet() && + DC && DC->isRecord() && + DC->isDependentContext()) + ? TPC_ClassTemplateMember + : TPC_FunctionTemplate); + } + + if (NewFD->isInvalidDecl()) { + // Ignore all the rest of this. + } else if (!Redeclaration) { + // Fake up an access specifier if it's supposed to be a class member. + if (isa<CXXRecordDecl>(NewFD->getDeclContext())) + NewFD->setAccess(AS_public); + + // Qualified decls generally require a previous declaration. + if (D.getCXXScopeSpec().isSet()) { + // ...with the major exception of templated-scope or + // dependent-scope friend declarations. + + // TODO: we currently also suppress this check in dependent + // contexts because (1) the parameter depth will be off when + // matching friend templates and (2) we might actually be + // selecting a friend based on a dependent factor. But there + // are situations where these conditions don't apply and we + // can actually do this check immediately. + if (isFriend && + (NumMatchedTemplateParamLists || + D.getCXXScopeSpec().getScopeRep()->isDependent() || + CurContext->isDependentContext())) { + // ignore these + } else { + // 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, + // C++ [namespace.memdef]p2). For example: + // + // class X { + // void f() const; + // }; + // + // void X::f() { } // ill-formed + // + // Complain about this problem, and attempt to suggest close + // 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) + << Name << DC << D.getCXXScopeSpec().getRange(); + NewFD->setInvalidDecl(); + + DiagnoseInvalidRedeclaration(*this, NewFD); + } - if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { - // Fake up an access specifier if it's supposed to be a class member. - if (!Redeclaration && isa<CXXRecordDecl>(NewFD->getDeclContext())) - NewFD->setAccess(AS_public); + // Unqualified local friend declarations are required to resolve + // to something. + } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) { + Diag(D.getIdentifierLoc(), diag::err_no_matching_local_friend); + NewFD->setInvalidDecl(); + DiagnoseInvalidRedeclaration(*this, NewFD); + } - // An out-of-line member function declaration must also be a - // definition (C++ [dcl.meaning]p1). - // 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. We also allow these declarations as an extension - // for compatibility with old SWIG code which likes to generate them. - if (!IsFunctionDefinition && !isFriend && - !isFunctionTemplateSpecialization && !isExplicitSpecialization) { + } else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && + !isFriend && !isFunctionTemplateSpecialization && + !isExplicitSpecialization) { + // An out-of-line member function declaration must also be a + // definition (C++ [dcl.meaning]p1). + // 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. We also allow these declarations as an extension + // for compatibility with old SWIG code which likes to generate them. Diag(NewFD->getLocation(), diag::ext_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); } - if (!Redeclaration && !(isFriend && CurContext->isDependentContext())) { - // 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, - // C++ [namespace.memdef]p2). For example: - // - // class X { - // void f() const; - // }; - // - // void X::f() { } // ill-formed - // - // Complain about this problem, and attempt to suggest close - // 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) - << Name << DC << D.getCXXScopeSpec().getRange(); - NewFD->setInvalidDecl(); - - LookupResult Prev(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, - ForRedeclaration); - LookupQualifiedName(Prev, DC); - assert(!Prev.isAmbiguous() && - "Cannot have an ambiguity in previous-declaration lookup"); - for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); - Func != FuncEnd; ++Func) { - if (isa<FunctionDecl>(*Func) && - isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD)) - Diag((*Func)->getLocation(), diag::note_member_def_close_match); - } - } } - + + // Handle attributes. We need to have merged decls when handling attributes // (for example to check for conflicts, etc). // FIXME: This needs to happen before we merge declarations. Then, // let attribute merging cope with attribute conflicts. - ProcessDeclAttributes(S, NewFD, D); + ProcessDeclAttributes(S, NewFD, D, + /*NonInheritable=*/false, /*Inheritable=*/true); // attributes declared post-definition are currently ignored // FIXME: This should happen during attribute merging @@ -3723,17 +4119,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, AddKnownFunctionAttributes(NewFD); - if (OverloadableAttrRequired && !NewFD->hasAttr<OverloadableAttr>()) { - // If a function name is overloadable in C, then every function - // with that name must be marked "overloadable". - Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) - << Redeclaration << NewFD; - if (!Previous.empty()) - Diag(Previous.getRepresentativeDecl()->getLocation(), - diag::note_attribute_overloadable_prev_overload); - NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(), Context)); - } - if (NewFD->hasAttr<OverloadableAttr>() && !NewFD->getType()->getAs<FunctionProtoType>()) { Diag(NewFD->getLocation(), @@ -3742,9 +4127,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Turn this into a variadic function with no parameters. const FunctionType *FT = NewFD->getType()->getAs<FunctionType>(); - QualType R = Context.getFunctionType(FT->getResultType(), - 0, 0, true, 0, false, false, 0, 0, - FT->getExtInfo()); + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + EPI.ExtInfo = FT->getExtInfo(); + + QualType R = Context.getFunctionType(FT->getResultType(), 0, 0, EPI); NewFD->setType(R); } @@ -3762,14 +4149,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Set this FunctionDecl's range up to the right paren. NewFD->setLocEnd(D.getSourceRange().getEnd()); - if (FunctionTemplate && NewFD->isInvalidDecl()) - FunctionTemplate->setInvalidDecl(); - - if (FunctionTemplate) - return FunctionTemplate; + if (getLangOptions().CPlusPlus) { + if (FunctionTemplate) { + if (NewFD->isInvalidDecl()) + FunctionTemplate->setInvalidDecl(); + return FunctionTemplate; + } + } MarkUnusedFileScopedDecl(NewFD); + if (getLangOptions().CUDA) + if (IdentifierInfo *II = NewFD->getIdentifier()) + if (!NewFD->isInvalidDecl() && + NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { + if (II->isStr("cudaConfigureCall")) { + if (!R->getAs<FunctionType>()->getResultType()->isScalarType()) + Diag(NewFD->getLocation(), diag::err_config_scalar_return); + + Context.setcudaConfigureCallDecl(NewFD); + } + } + return NewFD; } @@ -3790,8 +4191,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, - bool &Redeclaration, - bool &OverloadableAttrRequired) { + bool &Redeclaration) { // If NewFD is already known erroneous, don't do any of this checking. if (NewFD->isInvalidDecl()) { // If this is a class member, mark the class invalid immediately. @@ -3836,9 +4236,6 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Redeclaration = true; OldDecl = Previous.getFoundDecl(); } else { - if (!getLangOptions().CPlusPlus) - OverloadableAttrRequired = true; - switch (CheckOverload(S, NewFD, Previous, OldDecl, /*NewIsUsingDecl*/ false)) { case Ovl_Match: @@ -3853,6 +4250,23 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Redeclaration = false; break; } + + if (!getLangOptions().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) { + // If a function name is overloadable in C, then every function + // with that name must be marked "overloadable". + Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) + << Redeclaration << NewFD; + NamedDecl *OverloadedDecl = 0; + if (Redeclaration) + OverloadedDecl = OldDecl; + else if (!Previous.empty()) + OverloadedDecl = Previous.getRepresentativeDecl(); + if (OverloadedDecl) + Diag(OverloadedDecl->getLocation(), + diag::note_attribute_overloadable_prev_overload); + NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(), + Context)); + } } if (Redeclaration) { @@ -3907,23 +4321,11 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(ClassType)); -// NewFD->getDeclName().dump(); -// Name.dump(); 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); @@ -3932,8 +4334,23 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // Find any virtual functions that this function overrides. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD)) { if (!Method->isFunctionTemplateSpecialization() && - !Method->getDescribedFunctionTemplate()) - AddOverriddenMethods(Method->getParent(), Method); + !Method->getDescribedFunctionTemplate()) { + if (AddOverriddenMethods(Method->getParent(), Method)) { + // If the function was marked as "static", we have a problem. + if (NewFD->getStorageClass() == SC_Static) { + Diag(NewFD->getLocation(), diag::err_static_overrides_virtual) + << NewFD->getDeclName(); + for (CXXMethodDecl::method_iterator + Overridden = Method->begin_overridden_methods(), + OverriddenEnd = Method->end_overridden_methods(); + Overridden != OverriddenEnd; + ++Overridden) { + Diag((*Overridden)->getLocation(), + diag::note_overridden_virtual_function); + } + } + } + } } // Extra checking for C++ overloaded operators (C++ [over.oper]). @@ -3951,6 +4368,18 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // during delayed parsing anyway. if (!CurContext->isRecord()) CheckCXXDefaultArguments(NewFD); + + // If this function declares a builtin function, check the type of this + // declaration against the expected type for the builtin. + if (unsigned BuiltinID = NewFD->getBuiltinID()) { + ASTContext::GetBuiltinTypeError Error; + QualType T = Context.GetBuiltinType(BuiltinID, Error); + if (!T.isNull() && !Context.hasSameType(T, NewFD->getType())) { + // The type of this function differs from the type of the builtin, + // so forget about the builtin entirely. + Context.BuiltinInfo.ForgetBuiltin(BuiltinID, Context.Idents); + } + } } } @@ -3976,7 +4405,6 @@ void Sema::CheckMain(FunctionDecl* FD) { 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); } @@ -4043,6 +4471,11 @@ void Sema::CheckMain(FunctionDecl* FD) { if (nparams == 1 && !FD->isInvalidDecl()) { Diag(FD->getLocation(), diag::warn_main_one_arg); } + + if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) { + Diag(FD->getLocation(), diag::err_main_template_decl); + FD->setInvalidDecl(); + } } bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { @@ -4061,17 +4494,14 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { return true; } -void Sema::AddInitializerToDecl(Decl *dcl, Expr *init) { - AddInitializerToDecl(dcl, init, /*DirectInit=*/false); -} - /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. -void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { +void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, + bool DirectInit, bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore // the initializer. - if (RealDecl == 0) + if (RealDecl == 0 || RealDecl->isInvalidDecl()) return; if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) { @@ -4095,14 +4525,32 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { if (getLangOptions().CPlusPlus && RealDecl->getLexicalDeclContext()->isRecord() && isa<NamedDecl>(RealDecl)) - Diag(RealDecl->getLocation(), diag::err_member_initialization) - << cast<NamedDecl>(RealDecl)->getDeclName(); + Diag(RealDecl->getLocation(), diag::err_member_initialization); else Diag(RealDecl->getLocation(), diag::err_illegal_initializer); RealDecl->setInvalidDecl(); return; } + // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. + if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) { + VDecl->setParsingAutoInit(false); + + QualType DeducedType; + if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) { + Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure) + << VDecl->getDeclName() << VDecl->getType() << Init->getType() + << Init->getSourceRange(); + RealDecl->setInvalidDecl(); + return; + } + VDecl->setType(DeducedType); + + // If this is a redeclaration, check that the type we just deduced matches + // the previously declared type. + if (VarDecl *Old = VDecl->getPreviousDeclaration()) + MergeVarDeclTypes(VDecl, Old); + } // A definition must end up with a complete type, which means it must be @@ -4132,27 +4580,34 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } - // C++ [class.static.data]p4 - // If a static data member is of const integral or const - // enumeration type, its declaration in the class definition can - // specify a constant-initializer which shall be an integral - // constant expression (5.19). In that case, the member can appear - // in integral constant expressions. The member shall still be - // defined in a namespace scope if it is used in the program and the - // namespace scope definition shall not contain an initializer. - // - // We already performed a redefinition check above, but for static - // data members we also need to check whether there was an in-class - // declaration with an initializer. const VarDecl* PrevInit = 0; - if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { - Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); - Diag(PrevInit->getLocation(), diag::note_previous_definition); - return; - } + if (getLangOptions().CPlusPlus) { + // C++ [class.static.data]p4 + // If a static data member is of const integral or const + // enumeration type, its declaration in the class definition can + // specify a constant-initializer which shall be an integral + // constant expression (5.19). In that case, the member can appear + // in integral constant expressions. The member shall still be + // defined in a namespace scope if it is used in the program and the + // namespace scope definition shall not contain an initializer. + // + // We already performed a redefinition check above, but for static + // data members we also need to check whether there was an in-class + // declaration with an initializer. + if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { + Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); + Diag(PrevInit->getLocation(), diag::note_previous_definition); + return; + } - if (getLangOptions().CPlusPlus && VDecl->hasLocalStorage()) - getCurFunction()->setHasBranchProtectedScope(); + if (VDecl->hasLocalStorage()) + getCurFunction()->setHasBranchProtectedScope(); + + if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer)) { + VDecl->setInvalidDecl(); + return; + } + } // Capture the variable that is being initialized and the style of // initialization. @@ -4169,7 +4624,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // Get the decls type and save a reference for later, since // CheckInitializerTypes may change it. QualType DclT = VDecl->getType(), SavT = DclT; - if (VDecl->isBlockVarDecl()) { + if (VDecl->isLocalVarDecl()) { if (VDecl->hasExternalStorage()) { // C99 6.7.8p5 Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); @@ -4200,34 +4655,38 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // static const int value = 17; // }; - // Attach the initializer - VDecl->setInit(Init); + // Try to perform the initialization regardless. + if (!VDecl->isInvalidDecl()) { + InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, &Init, 1), + &DclT); + if (Result.isInvalid()) { + VDecl->setInvalidDecl(); + return; + } + + Init = Result.takeAs<Expr>(); + } // C++ [class.mem]p4: // A member-declarator can contain a constant-initializer only // 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() && - (!Context.getCanonicalType(T).isConstQualified() || - !T->isIntegralOrEnumerationType())) { - Diag(VDecl->getLocation(), diag::err_member_initialization) - << VDecl->getDeclName() << Init->getSourceRange(); + + // Do nothing on dependent types. + if (T->isDependentType()) { + + // Require constness. + } else if (!T.isConstQualified()) { + Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const) + << Init->getSourceRange(); VDecl->setInvalidDecl(); - } else { - // C++ [class.static.data]p4: - // If a static data member is of const integral or const - // enumeration type, its declaration in the class definition - // can specify a constant-initializer which shall be an - // integral constant expression (5.19). - if (!Init->isTypeDependent() && - !Init->getType()->isIntegralOrEnumerationType()) { - // We have a non-dependent, non-integral or enumeration type. - Diag(Init->getSourceRange().getBegin(), - diag::err_in_class_initializer_non_integral_type) - << Init->getType() << Init->getSourceRange(); - VDecl->setInvalidDecl(); - } else if (!Init->isTypeDependent() && !Init->isValueDependent()) { + + // We allow integer constant expressions in all cases. + } else if (T->isIntegralOrEnumerationType()) { + if (!Init->isValueDependent()) { // Check whether the expression is a constant expression. llvm::APSInt Value; SourceLocation Loc; @@ -4235,12 +4694,37 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { Diag(Loc, diag::err_in_class_initializer_non_constant) << Init->getSourceRange(); VDecl->setInvalidDecl(); - } else if (!VDecl->getType()->isDependentType()) - ImpCastExprToType(Init, VDecl->getType(), CK_IntegralCast); + } + } + + // We allow floating-point constants as an extension in C++03, and + // C++0x has far more complicated rules that we don't really + // implement fully. + } else { + bool Allowed = false; + if (getLangOptions().CPlusPlus0x) { + Allowed = T->isLiteralType(); + } else if (T->isFloatingType()) { // also permits complex, which is ok + Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type) + << T << Init->getSourceRange(); + Allowed = true; + } + + if (!Allowed) { + Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type) + << T << Init->getSourceRange(); + VDecl->setInvalidDecl(); + + // TODO: there are probably expressions that pass here that shouldn't. + } else if (!Init->isValueDependent() && + !Init->isConstantInitializer(Context, false)) { + Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant) + << Init->getSourceRange(); + VDecl->setInvalidDecl(); } } } else if (VDecl->isFileVarDecl()) { - if (VDecl->getStorageClass() == SC_Extern && + if (VDecl->getStorageClassAsWritten() == SC_Extern && (!getLangOptions().CPlusPlus || !Context.getBaseElementType(VDecl->getType()).isConstQualified())) Diag(VDecl->getLocation(), diag::warn_extern_init); @@ -4273,28 +4757,35 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { Init->setType(DclT); } - Init = MaybeCreateCXXExprWithTemporaries(Init); + + // If this variable is a local declaration with record type, make sure it + // doesn't have a flexible member initialization. We only support this as a + // global/static definition. + if (VDecl->hasLocalStorage()) + if (const RecordType *RT = VDecl->getType()->getAs<RecordType>()) + if (RT->getDecl()->hasFlexibleArrayMember()) { + // Check whether the initializer tries to initialize the flexible + // array member itself to anything other than an empty initializer list. + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { + unsigned Index = std::distance(RT->getDecl()->field_begin(), + RT->getDecl()->field_end()) - 1; + if (Index < ILE->getNumInits() && + !(isa<InitListExpr>(ILE->getInit(Index)) && + cast<InitListExpr>(ILE->getInit(Index))->getNumInits() == 0)) { + Diag(VDecl->getLocation(), diag::err_nonstatic_flexible_variable); + VDecl->setInvalidDecl(); + } + } + } + + // Check any implicit conversions within the expression. + CheckImplicitConversions(Init, VDecl->getLocation()); + + Init = MaybeCreateExprWithCleanups(Init); // Attach the initializer to the decl. VDecl->setInit(Init); - if (getLangOptions().CPlusPlus) { - if (!VDecl->isInvalidDecl() && - !VDecl->getDeclContext()->isDependentContext() && - VDecl->hasGlobalStorage() && !VDecl->isStaticLocal() && - !Init->isConstantInitializer(Context, - VDecl->getType()->isReferenceType())) - Diag(VDecl->getLocation(), diag::warn_global_constructor) - << Init->getSourceRange(); - - // Make sure we mark the destructor as used if necessary. - QualType InitType = VDecl->getType(); - while (const ArrayType *Array = Context.getAsArrayType(InitType)) - InitType = Context.getBaseElementType(Array); - if (const RecordType *Record = InitType->getAs<RecordType>()) - FinalizeVarWithDestructor(VDecl, Record); - } - - return; + CheckCompleteVariableDeclaration(VDecl); } /// ActOnInitializerError - Given that there was an error parsing an @@ -4308,6 +4799,13 @@ void Sema::ActOnInitializerError(Decl *D) { VarDecl *VD = dyn_cast<VarDecl>(D); if (!VD) return; + // Auto types are meaningless if we can't make sense of the initializer. + if (VD->isParsingAutoInit()) { + VD->setParsingAutoInit(false); + VD->setInvalidDecl(); + return; + } + QualType Ty = VD->getType(); if (Ty->isDependentType()) return; @@ -4332,7 +4830,7 @@ void Sema::ActOnInitializerError(Decl *D) { } void Sema::ActOnUninitializedDecl(Decl *RealDecl, - bool TypeContainsUndeducedAuto) { + bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore it. if (RealDecl == 0) return; @@ -4341,7 +4839,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, QualType Type = Var->getType(); // C++0x [dcl.spec.auto]p3 - if (TypeContainsUndeducedAuto) { + if (TypeMayContainAuto && Type->getContainedAutoType()) { + Var->setParsingAutoInit(false); + Diag(Var->getLocation(), diag::err_auto_var_requires_init) << Var->getDeclName() << Type; Var->setInvalidDecl(); @@ -4365,7 +4865,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, // 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 (!Type->isDependentType() && Var->isBlockVarDecl() && + if (!Type->isDependentType() && Var->isLocalVarDecl() && !Var->getLinkage() && !Var->isInvalidDecl() && RequireCompleteType(Var->getLocation(), Type, diag::err_typecheck_decl_incomplete_type)) @@ -4488,22 +4988,62 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, MultiExprArg(*this, 0, 0)); if (Init.isInvalid()) Var->setInvalidDecl(); - else if (Init.get()) { - Var->setInit(MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>())); - - if (getLangOptions().CPlusPlus && !Var->isInvalidDecl() && - Var->hasGlobalStorage() && !Var->isStaticLocal() && - !Var->getDeclContext()->isDependentContext() && - !Var->getInit()->isConstantInitializer(Context, false)) - Diag(Var->getLocation(), diag::warn_global_constructor); - } + else if (Init.get()) + Var->setInit(MaybeCreateExprWithCleanups(Init.get())); } - if (!Var->isInvalidDecl() && getLangOptions().CPlusPlus && Record) - FinalizeVarWithDestructor(Var, Record); + CheckCompleteVariableDeclaration(Var); } } +void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { + if (var->isInvalidDecl()) return; + + // All the following checks are C++ only. + if (!getLangOptions().CPlusPlus) return; + + QualType baseType = Context.getBaseElementType(var->getType()); + if (baseType->isDependentType()) return; + + // __block variables might require us to capture a copy-initializer. + if (var->hasAttr<BlocksAttr>()) { + // It's currently invalid to ever have a __block variable with an + // array type; should we diagnose that here? + + // Regardless, we don't want to ignore array nesting when + // constructing this copy. + QualType type = var->getType(); + + if (type->isStructureOrClassType()) { + SourceLocation poi = var->getLocation(); + Expr *varRef = new (Context) DeclRefExpr(var, type, VK_LValue, poi); + ExprResult result = + PerformCopyInitialization( + InitializedEntity::InitializeBlock(poi, type, false), + poi, Owned(varRef)); + if (!result.isInvalid()) { + result = MaybeCreateExprWithCleanups(result); + Expr *init = result.takeAs<Expr>(); + Context.setBlockVarCopyInits(var, init); + } + } + } + + // Check for global constructors. + if (!var->getDeclContext()->isDependentContext() && + var->hasGlobalStorage() && + !var->isStaticLocal() && + var->getInit() && + !var->getInit()->isConstantInitializer(Context, + baseType->isReferenceType())) + Diag(var->getLocation(), diag::warn_global_constructor) + << var->getInit()->getSourceRange(); + + // Require the destructor. + if (const RecordType *recordType = baseType->getAs<RecordType>()) + FinalizeVarWithDestructor(var, recordType); +} + Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, Decl **Group, unsigned NumDecls) { @@ -4512,6 +5052,41 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, if (DS.isTypeSpecOwned()) Decls.push_back(DS.getRepAsDecl()); + // C++0x [dcl.spec.auto]p7: + // If the type deduced for the template parameter U is not the same in each + // deduction, the program is ill-formed. + // FIXME: When initializer-list support is added, a distinction is needed + // between the deduced type U and the deduced type which 'auto' stands for. + // auto a = 0, b = { 1, 2, 3 }; + // is legal because the deduced type U is 'int' in both cases. + bool TypeContainsAuto = DS.getTypeSpecType() == DeclSpec::TST_auto; + if (TypeContainsAuto && NumDecls > 1) { + QualType Deduced; + CanQualType DeducedCanon; + VarDecl *DeducedDecl = 0; + for (unsigned i = 0; i != NumDecls; ++i) { + if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) { + AutoType *AT = D->getType()->getContainedAutoType(); + if (AT && AT->isDeduced()) { + QualType U = AT->getDeducedType(); + CanQualType UCanon = Context.getCanonicalType(U); + if (Deduced.isNull()) { + Deduced = U; + DeducedCanon = UCanon; + DeducedDecl = D; + } else if (DeducedCanon != UCanon) { + Diag(DS.getTypeSpecTypeLoc(), diag::err_auto_different_deductions) + << Deduced << DeducedDecl->getDeclName() + << U << D->getDeclName() + << DeducedDecl->getInit()->getSourceRange() + << D->getInit()->getSourceRange(); + break; + } + } + } + } + } + for (unsigned i = 0; i != NumDecls; ++i) if (Decl *D = Group[i]) Decls.push_back(D); @@ -4543,24 +5118,42 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { DiagnoseFunctionSpecifiers(D); - // Check that there are no default arguments inside the type of this - // parameter (C++ only). - if (getLangOptions().CPlusPlus) - CheckExtraCXXDefaultArguments(D); - TagDecl *OwnedDecl = 0; TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedDecl); QualType parmDeclType = TInfo->getType(); - if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { - // C++ [dcl.fct]p6: - // Types shall not be defined in return or parameter types. - Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type) - << Context.getTypeDeclType(OwnedDecl); + if (getLangOptions().CPlusPlus) { + // Check that there are no default arguments inside the type of this + // parameter. + CheckExtraCXXDefaultArguments(D); + + if (OwnedDecl && OwnedDecl->isDefinition()) { + // C++ [dcl.fct]p6: + // Types shall not be defined in return or parameter types. + Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type) + << Context.getTypeDeclType(OwnedDecl); + } + + // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). + if (D.getCXXScopeSpec().isSet()) { + Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) + << D.getCXXScopeSpec().getRange(); + D.getCXXScopeSpec().clear(); + } + } + + // Ensure we have a valid name + IdentifierInfo *II = 0; + if (D.hasName()) { + II = D.getIdentifier(); + if (!II) { + Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name) + << GetNameForDeclarator(D).getName().getAsString(); + D.setInvalidType(true); + } } // Check for redeclaration of parameters, e.g. int foo(int x, int x); - IdentifierInfo *II = D.getIdentifier(); if (II) { LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, ForRedeclaration); @@ -4595,13 +5188,6 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (D.isInvalidType()) 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(); - } - // Add the parameter declaration into this scope. S->AddDecl(New); if (II) @@ -4629,10 +5215,6 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param, ParmVarDecl * const *ParamEnd) { - if (Diags.getDiagnosticLevel(diag::warn_unused_parameter) == - Diagnostic::Ignored) - return; - // Don't diagnose unused-parameter errors in template instantiations; we // will already have done so in the template itself. if (!ActiveTemplateInstantiations.empty()) @@ -4647,6 +5229,35 @@ void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param, } } +void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, + ParmVarDecl * const *ParamEnd, + QualType ReturnTy, + NamedDecl *D) { + if (LangOpts.NumLargeByValueCopy == 0) // No check. + return; + + // Warn if the return value is pass-by-value and larger than the specified + // threshold. + if (ReturnTy->isPODType()) { + unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity(); + if (Size > LangOpts.NumLargeByValueCopy) + Diag(D->getLocation(), diag::warn_return_value_size) + << D->getDeclName() << Size; + } + + // Warn if any parameter is pass-by-value and larger than the specified + // threshold. + for (; Param != ParamEnd; ++Param) { + QualType T = (*Param)->getType(); + if (!T->isPODType()) + continue; + unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); + if (Size > LangOpts.NumLargeByValueCopy) + Diag((*Param)->getLocation(), diag::warn_parameter_size) + << (*Param)->getDeclName() << Size; + } +} + ParmVarDecl *Sema::CheckParameter(DeclContext *DC, TypeSourceInfo *TSInfo, QualType T, IdentifierInfo *Name, @@ -4688,9 +5299,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls) { - assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && - "Not a function declarator!"); - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared' // for a K&R function. @@ -4724,14 +5333,7 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, 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. - } - + assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); Decl *DP = HandleDeclarator(ParentScope, D, @@ -4806,7 +5408,12 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { const FunctionDecl *Definition; if (FD->hasBody(Definition) && !canRedefineFunction(Definition, getLangOptions())) { - Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName(); + if (getLangOptions().GNUMode && Definition->isInlineSpecified() && + Definition->getStorageClass() == SC_Extern) + Diag(FD->getLocation(), diag::err_redefinition_extern_inline) + << FD->getDeclName() << getLangOptions().CPlusPlus; + else + Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName(); Diag(Definition->getLocation(), diag::note_previous_definition); } @@ -4839,10 +5446,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { PushDeclContext(FnBodyScope, FD); // Check the validity of our function parameters - CheckParmsForFunctionDef(FD); - - bool ShouldCheckShadow = - Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored; + CheckParmsForFunctionDef(FD->param_begin(), FD->param_end(), + /*CheckParameterNames=*/true); // Introduce our parameters into the function scope for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { @@ -4851,8 +5456,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // If this has an identifier, add it to the scope stack. if (Param->getIdentifier() && FnBodyScope) { - if (ShouldCheckShadow) - CheckShadow(FnBodyScope, Param); + CheckShadow(FnBodyScope, Param); PushOnScopeChains(Param, FnBodyScope); } @@ -4945,6 +5549,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (!FD->isInvalidDecl()) { DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); + DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(), + FD->getResultType(), FD); // If this is a constructor, we need a vtable. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD)) @@ -4957,55 +5563,18 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); - MD->setEndLoc(Body->getLocEnd()); - if (!MD->isInvalidDecl()) + if (Body) + MD->setEndLoc(Body->getLocEnd()); + if (!MD->isInvalidDecl()) { DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); + DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(), + MD->getResultType(), MD); + } } else { return 0; } // Verify and clean out per-function state. - - // Check goto/label use. - FunctionScopeInfo *CurFn = getCurFunction(); - for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator - I = CurFn->LabelMap.begin(), E = CurFn->LabelMap.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. - if (Body == 0) { - // The whole function wasn't parsed correctly. - 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 - // label in it. - - // Give the label a sub-statement. - L->setSubStmt(new (Context) NullStmt(L->getIdentLoc())); - - CompoundStmt *Compound = isa<CXXTryStmt>(Body) ? - cast<CXXTryStmt>(Body)->getTryBlock() : - cast<CompoundStmt>(Body); - llvm::SmallVector<Stmt*, 64> Elements(Compound->body_begin(), - Compound->body_end()); - Elements.push_back(L); - Compound->setStmts(Context, Elements.data(), Elements.size()); - } - if (Body) { // C++ constructors that have function-try-blocks can't have return // statements in the handlers of that block. (C++ [except.handle]p14) @@ -5091,11 +5660,13 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, DeclSpec DS; unsigned DiagID; bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID); - Error = Error; // Silence warning. + (void)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(), + D.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(), + false, false, SourceLocation(), 0, + 0, 0, true, SourceLocation(), + false, SourceLocation(), false, 0,0,0, Loc, Loc, D), SourceLocation()); D.SetIdentifier(&II, Loc); @@ -5154,8 +5725,6 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } - if (Context.BuiltinInfo.isNoReturn(BuiltinID)) - FD->setType(Context.getNoReturnType(FD->getType())); if (Context.BuiltinInfo.isNoThrow(BuiltinID)) FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isConst(BuiltinID)) @@ -5210,17 +5779,46 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, D.getIdentifier(), TInfo); - if (const TagType *TT = T->getAs<TagType>()) { - TagDecl *TD = TT->getDecl(); + // Bail out immediately if we have an invalid declaration. + if (D.isInvalidType()) { + NewTD->setInvalidDecl(); + return NewTD; + } + + // C++ [dcl.typedef]p8: + // If the typedef declaration defines an unnamed class (or + // enum), the first typedef-name declared by the declaration + // to be that class type (or enum type) is used to denote the + // class type (or enum type) for linkage purposes only. + // We need to check whether the type was declared in the declaration. + switch (D.getDeclSpec().getTypeSpecType()) { + case TST_enum: + case TST_struct: + case TST_union: + case TST_class: { + TagDecl *tagFromDeclSpec = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); + + // Do nothing if the tag is not anonymous or already has an + // associated typedef (from an earlier typedef in this decl group). + if (tagFromDeclSpec->getIdentifier()) break; + if (tagFromDeclSpec->getTypedefForAnonDecl()) break; + + // A well-formed anonymous tag must always be a TUK_Definition. + assert(tagFromDeclSpec->isThisDeclarationADefinition()); + + // The type must match the tag exactly; no qualifiers allowed. + if (!Context.hasSameType(T, Context.getTagDeclType(tagFromDeclSpec))) + break; - // If the TagDecl that the TypedefDecl points to is an anonymous decl - // keep track of the TypedefDecl. - if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl()) - TD->setTypedefForAnonDecl(NewTD); + // Otherwise, set this is the anon-decl typedef for the tag. + tagFromDeclSpec->setTypedefForAnonDecl(NewTD); + break; + } + + default: + break; } - if (D.isInvalidType()) - NewTD->setInvalidDecl(); return NewTD; } @@ -5273,14 +5871,17 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, AccessSpecifier AS, - MultiTemplateParamsArg TemplateParameterLists, - bool &OwnedDecl, bool &IsDependent) { + SourceLocation KWLoc, CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParameterLists, + bool &OwnedDecl, bool &IsDependent, + bool ScopedEnum, bool ScopedEnumUsesClassTag, + TypeResult UnderlyingType) { // If this is not a definition, it must have a name. assert((Name != 0 || TUK == TUK_Definition) && "Nameless record must be a definition!"); + assert(TemplateParameterLists.size() == 0 || TUK != TUK_Reference); OwnedDecl = false; TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); @@ -5289,11 +5890,16 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, bool isExplicitSpecialization = false; unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size(); bool Invalid = false; - if (TUK != TUK_Reference) { + + // We only need to do this matching if we have template parameters + // or a scope specifier, which also conveniently avoids this work + // for non-C++ cases. + if (NumMatchedTemplateParamLists || + (SS.isNotEmpty() && TUK != TUK_Reference)) { if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, - (TemplateParameterList**)TemplateParameterLists.get(), - TemplateParameterLists.size(), + TemplateParameterLists.get(), + TemplateParameterLists.size(), TUK == TUK_Friend, isExplicitSpecialization, Invalid)) { @@ -5322,6 +5928,41 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + // Figure out the underlying type if this a enum declaration. We need to do + // this early, because it's needed to detect if this is an incompatible + // redeclaration. + llvm::PointerUnion<const Type*, TypeSourceInfo*> EnumUnderlying; + + if (Kind == TTK_Enum) { + if (UnderlyingType.isInvalid() || (!UnderlyingType.get() && ScopedEnum)) + // No underlying type explicitly specified, or we failed to parse the + // type, default to int. + EnumUnderlying = Context.IntTy.getTypePtr(); + else if (UnderlyingType.get()) { + // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an + // integral type; any cv-qualification is ignored. + TypeSourceInfo *TI = 0; + QualType T = GetTypeFromParser(UnderlyingType.get(), &TI); + EnumUnderlying = TI; + + SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); + + if (!T->isDependentType() && !T->isIntegralType(Context)) { + Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) + << T; + // Recover by falling back to int. + EnumUnderlying = Context.IntTy.getTypePtr(); + } + + if (DiagnoseUnexpandedParameterPack(UnderlyingLoc, TI, + UPPC_FixedUnderlyingType)) + EnumUnderlying = Context.IntTy.getTypePtr(); + + } else if (getLangOptions().Microsoft) + // Microsoft enums are always of int type. + EnumUnderlying = Context.IntTy.getTypePtr(); + } + DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; bool isStdBadAlloc = false; @@ -5374,7 +6015,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // and that current instantiation has any dependent base // classes, we might find something at instantiation time: treat // this as a dependent elaborated-type-specifier. - if (Previous.wasNotFoundInCurrentInstantiation()) { + // But this only makes any sense for reference-like lookups. + if (Previous.wasNotFoundInCurrentInstantiation() && + (TUK == TUK_Reference || TUK == TUK_Friend)) { IsDependent = true; return 0; } @@ -5406,6 +6049,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC)) SearchDC = SearchDC->getParent(); } + } else if (S->isFunctionPrototypeScope()) { + // If this is an enum declaration in function prototype scope, set its + // initial context to the translation unit. + SearchDC = Context.getTranslationUnitDecl(); } if (Previous.isSingleResult() && @@ -5467,7 +6114,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // Find the context where we'll be declaring the tag. // FIXME: We would like to maintain the current DeclContext as the // lexical context, - while (SearchDC->isRecord()) + while (SearchDC->isRecord() || SearchDC->isTransparentContext()) SearchDC = SearchDC->getParent(); // Find the scope where we'll be declaring the tag. @@ -5554,6 +6201,41 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) { + const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl); + + // All conflicts with previous declarations are recovered by + // returning the previous declaration. + if (ScopedEnum != PrevEnum->isScoped()) { + Diag(KWLoc, diag::err_enum_redeclare_scoped_mismatch) + << PrevEnum->isScoped(); + Diag(PrevTagDecl->getLocation(), diag::note_previous_use); + return PrevTagDecl; + } + else if (EnumUnderlying && PrevEnum->isFixed()) { + QualType T; + if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>()) + T = TI->getType(); + else + T = QualType(EnumUnderlying.get<const Type*>(), 0); + + if (!Context.hasSameUnqualifiedType(T, PrevEnum->getIntegerType())) { + Diag(NameLoc.isValid() ? NameLoc : KWLoc, + diag::err_enum_redeclare_type_mismatch) + << T + << PrevEnum->getIntegerType(); + Diag(PrevTagDecl->getLocation(), diag::note_previous_use); + return PrevTagDecl; + } + } + else if (!EnumUnderlying.isNull() != PrevEnum->isFixed()) { + Diag(KWLoc, diag::err_enum_redeclare_fixed_mismatch) + << PrevEnum->isFixed(); + Diag(PrevTagDecl->getLocation(), diag::note_previous_use); + return PrevTagDecl; + } + } + if (!Invalid) { // If this is a use, just return the declaration we found. @@ -5587,7 +6269,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } else { // If the type is currently being defined, complain // about a nested redefinition. - TagType *Tag = cast<TagType>(Context.getTagDeclType(PrevTagDecl)); + const TagType *Tag + = cast<TagType>(Context.getTagDeclType(PrevTagDecl)); if (Tag->isBeingDefined()) { Diag(NameLoc, diag::err_nested_redefinition) << Name; Diag(PrevTagDecl->getLocation(), @@ -5689,24 +6372,49 @@ CreateNewDecl: // PrevDecl. TagDecl *New; + bool IsForwardReference = false; if (Kind == TTK_Enum) { // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // enum X { A, B, C } D; D should chain to X. New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc, - cast_or_null<EnumDecl>(PrevDecl)); + cast_or_null<EnumDecl>(PrevDecl), ScopedEnum, + ScopedEnumUsesClassTag, !EnumUnderlying.isNull()); // If this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; - if (PrevDecl && (Def = cast<EnumDecl>(PrevDecl)->getDefinition())) { + if (getLangOptions().CPlusPlus0x && cast<EnumDecl>(New)->isFixed()) { + // C++0x: 7.2p2: opaque-enum-declaration. + // Conflicts are diagnosed above. Do nothing. + } + else if (PrevDecl && (Def = cast<EnumDecl>(PrevDecl)->getDefinition())) { Diag(Loc, diag::ext_forward_ref_enum_def) << New; Diag(Def->getLocation(), diag::note_previous_definition); } else { - Diag(Loc, - getLangOptions().CPlusPlus? diag::err_forward_ref_enum - : diag::ext_forward_ref_enum); + unsigned DiagID = diag::ext_forward_ref_enum; + if (getLangOptions().Microsoft) + DiagID = diag::ext_ms_forward_ref_enum; + else if (getLangOptions().CPlusPlus) + DiagID = diag::err_forward_ref_enum; + Diag(Loc, DiagID); + + // If this is a forward-declared reference to an enumeration, make a + // note of it; we won't actually be introducing the declaration into + // the declaration context. + if (TUK == TUK_Reference) + IsForwardReference = true; } } + + if (EnumUnderlying) { + EnumDecl *ED = cast<EnumDecl>(New); + if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>()) + ED->setIntegerTypeSourceInfo(TI); + else + ED->setIntegerType(QualType(EnumUnderlying.get<const Type*>(), 0)); + ED->setPromotionType(ED->getIntegerType()); + } + } else { // struct/union/class @@ -5798,7 +6506,10 @@ CreateNewDecl: PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false); } else if (Name) { S = getNonFieldDeclScope(S); - PushOnScopeChains(New, S); + PushOnScopeChains(New, S, !IsForwardReference); + if (IsForwardReference) + SearchDC->makeDeclVisibleInContext(New, /* Recoverable = */ false); + } else { CurContext->addDecl(New); } @@ -5823,6 +6534,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { } void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, + ClassVirtSpecifiers &CVS, SourceLocation LBraceLoc) { AdjustDeclIfTemplate(TagD); CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD); @@ -5832,6 +6544,11 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, if (!Record->getIdentifier()) return; + if (CVS.isFinalSpecified()) + Record->addAttr(new (Context) FinalAttr(CVS.getFinalLoc(), Context)); + if (CVS.isExplicitSpecified()) + Record->addAttr(new (Context) ExplicitAttr(CVS.getExplicitLoc(), Context)); + // 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 @@ -5842,7 +6559,9 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, CurContext, Record->getLocation(), Record->getIdentifier(), Record->getTagKeywordLoc(), - Record); + /*PrevDecl=*/0, + /*DelayTypeCreation=*/true); + Context.getTypeDeclType(InjectedClassName, Record); InjectedClassName->setImplicit(); InjectedClassName->setAccess(AS_public); if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) @@ -5899,7 +6618,9 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, << FieldName << FieldTy << BitWidth->getSourceRange(); return Diag(FieldLoc, diag::err_not_integral_type_anon_bitfield) << FieldTy << BitWidth->getSourceRange(); - } + } else if (DiagnoseUnexpandedParameterPack(const_cast<Expr *>(BitWidth), + UPPC_BitFieldWidth)) + return true; // If the bit-width is type- or value-dependent, don't try to check // it now. @@ -5974,9 +6695,17 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType T = TInfo->getType(); - if (getLangOptions().CPlusPlus) + if (getLangOptions().CPlusPlus) { CheckExtraCXXDefaultArguments(D); + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, + UPPC_DataMemberType)) { + D.setInvalidType(); + T = Context.IntTy; + TInfo = Context.getTrivialTypeSourceInfo(T, Loc); + } + } + DiagnoseFunctionSpecifiers(D); if (D.getDeclSpec().isThreadSpecified()) @@ -6128,35 +6857,27 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } if (!InvalidDecl && getLangOptions().CPlusPlus) { - CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record); + if (Record->isUnion()) { + if (const RecordType *RT = EltTy->getAs<RecordType>()) { + CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (RDecl->getDefinition()) { + // C++ [class.union]p1: 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 (CheckNontrivialField(NewFD)) + NewFD->setInvalidDecl(); + } + } - if (!T->isPODType()) - CXXRecord->setPOD(false); - if (!ZeroWidth) - CXXRecord->setEmpty(false); - if (T->isReferenceType()) - CXXRecord->setHasTrivialConstructor(false); - - if (const RecordType *RT = EltTy->getAs<RecordType>()) { - CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (RDecl->getDefinition()) { - 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() && CheckNontrivialField(NewFD)) - NewFD->setInvalidDecl(); + // C++ [class.union]p1: If a union contains a member of reference type, + // the program is ill-formed. + if (EltTy->isReferenceType()) { + Diag(NewFD->getLocation(), diag::err_union_member_of_reference_type) + << NewFD->getDeclName() << EltTy; + NewFD->setInvalidDecl(); } } } @@ -6171,18 +6892,6 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, Diag(Loc, diag::warn_attribute_weak_on_field); NewFD->setAccess(AS); - - // C++ [dcl.init.aggr]p1: - // An aggregate is an array or a class (clause 9) with [...] no - // private or protected non-static data members (clause 11). - // A POD must be an aggregate. - if (getLangOptions().CPlusPlus && - (AS == AS_private || AS == AS_protected)) { - CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record); - CXXRecord->setAggregate(false); - CXXRecord->setPOD(false); - } - return NewFD; } @@ -6532,7 +7241,7 @@ void Sema::ActOnFields(Scope* S, FieldDecl *FD = cast<FieldDecl>(Fields[i]); // Get the type for the field. - Type *FDTy = FD->getType().getTypePtr(); + const Type *FDTy = FD->getType().getTypePtr(); if (!FD->isAnonymousStructOrUnion()) { // Remember all fields written by the user. @@ -6563,10 +7272,22 @@ void Sema::ActOnFields(Scope* S, FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } else if (FDTy->isIncompleteArrayType() && i == NumFields - 1 && - Record && !Record->isUnion()) { + } else if (FDTy->isIncompleteArrayType() && Record && + ((i == NumFields - 1 && !Record->isUnion()) || + (getLangOptions().Microsoft && + (i == NumFields - 1 || Record->isUnion())))) { // Flexible array member. - if (NumNamedMembers < 1) { + // Microsoft is more permissive regarding flexible array. + // It will accept flexible array in union and also + // as the sole element of a struct/class. + if (getLangOptions().Microsoft) { + if (Record->isUnion()) + Diag(FD->getLocation(), diag::ext_flexible_array_union) + << FD->getDeclName(); + else if (NumFields == 1) + Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate) + << FD->getDeclName() << Record->getTagKind(); + } else if (NumNamedMembers < 1) { Diag(FD->getLocation(), diag::err_flexible_array_empty_struct) << FD->getDeclName(); FD->setInvalidDecl(); @@ -6581,7 +7302,6 @@ void Sema::ActOnFields(Scope* S, EnclosingDecl->setInvalidDecl(); continue; } - // Okay, we have a legal flexible array member at the end of the struct. if (Record) Record->setHasFlexibleArrayMember(true); @@ -6641,7 +7361,64 @@ void Sema::ActOnFields(Scope* S, // Okay, we successfully defined 'Record'. if (Record) { - Record->completeDefinition(); + bool Completed = false; + if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) { + if (!CXXRecord->isInvalidDecl()) { + // Set access bits correctly on the directly-declared conversions. + UnresolvedSetImpl *Convs = CXXRecord->getConversionFunctions(); + for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); + I != E; ++I) + Convs->setAccess(I, (*I)->getAccess()); + + if (!CXXRecord->isDependentType()) { + // Add any implicitly-declared members to this class. + AddImplicitlyDeclaredMembersToClass(CXXRecord); + + // If we have virtual base classes, we may end up finding multiple + // final overriders for a given virtual function. Check for this + // problem now. + if (CXXRecord->getNumVBases()) { + CXXFinalOverriderMap FinalOverriders; + CXXRecord->getFinalOverriders(FinalOverriders); + + for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), + MEnd = FinalOverriders.end(); + M != MEnd; ++M) { + for (OverridingMethods::iterator SO = M->second.begin(), + SOEnd = M->second.end(); + SO != SOEnd; ++SO) { + assert(SO->second.size() > 0 && + "Virtual function without overridding functions?"); + if (SO->second.size() == 1) + continue; + + // C++ [class.virtual]p2: + // In a derived class, if a virtual member function of a base + // class subobject has more than one final overrider the + // program is ill-formed. + Diag(Record->getLocation(), diag::err_multiple_final_overriders) + << (NamedDecl *)M->first << Record; + Diag(M->first->getLocation(), + diag::note_overridden_virtual_function); + for (OverridingMethods::overriding_iterator + OM = SO->second.begin(), + OMEnd = SO->second.end(); + OM != OMEnd; ++OM) + Diag(OM->Method->getLocation(), diag::note_final_overrider) + << (NamedDecl *)M->first << OM->Method->getParent(); + + Record->setInvalidDecl(); + } + } + CXXRecord->completeDefinition(&FinalOverriders); + Completed = true; + } + } + } + } + + if (!Completed) + Record->completeDefinition(); } else { ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(RecFields.data()); @@ -6695,9 +7472,11 @@ static bool isRepresentableIntegerValue(ASTContext &Context, assert(T->isIntegralType(Context) && "Integral type required!"); unsigned BitWidth = Context.getIntWidth(T); - if (Value.isUnsigned() || Value.isNonNegative()) - return Value.getActiveBits() < BitWidth; - + if (Value.isUnsigned() || Value.isNonNegative()) { + if (T->isSignedIntegerType()) + --BitWidth; + return Value.getActiveBits() <= BitWidth; + } return Value.getMinSignedBits() <= BitWidth; } @@ -6734,6 +7513,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, unsigned IntWidth = Context.Target.getIntWidth(); llvm::APSInt EnumVal(IntWidth); QualType EltTy; + + if (Val && DiagnoseUnexpandedParameterPack(Val, UPPC_EnumeratorValue)) + Val = 0; + if (Val) { if (Enum->isDependentType() || Val->isTypeDependent()) EltTy = Context.DependentTy; @@ -6761,12 +7544,30 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } } - // C++0x [dcl.enum]p5: - // If the underlying type is not fixed, the type of each enumerator - // is the type of its initializing value: - // - If an initializer is specified for an enumerator, the - // initializing value has the same type as the expression. - EltTy = Val->getType(); + if (Enum->isFixed()) { + EltTy = Enum->getIntegerType(); + + // C++0x [dcl.enum]p5: + // ... if the initializing value of an enumerator cannot be + // represented by the underlying type, the program is ill-formed. + if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) { + if (getLangOptions().Microsoft) { + Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy; + ImpCastExprToType(Val, EltTy, CK_IntegralCast); + } else + Diag(IdLoc, diag::err_enumerator_too_large) + << EltTy; + } else + ImpCastExprToType(Val, EltTy, CK_IntegralCast); + } + else { + // C++0x [dcl.enum]p5: + // If the underlying type is not fixed, the type of each enumerator + // is the type of its initializing value: + // - If an initializer is specified for an enumerator, the + // initializing value has the same type as the expression. + EltTy = Val->getType(); + } } } } @@ -6783,7 +7584,12 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // // GCC uses 'int' for its unspecified integral type, as does // C99 6.7.2.2p3. - EltTy = Context.IntTy; + if (Enum->isFixed()) { + EltTy = Enum->getIntegerType(); + } + else { + EltTy = Context.IntTy; + } } else { // Assign the last value + 1. EnumVal = LastEnumConst->getInitVal(); @@ -6803,13 +7609,20 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // sufficient to contain the incremented value. If no such type // exists, the program is ill-formed. QualType T = getNextLargerIntegralType(Context, EltTy); - if (T.isNull()) { + if (T.isNull() || Enum->isFixed()) { // There is no integral type larger enough to represent this // value. Complain, then allow the value to wrap around. EnumVal = LastEnumConst->getInitVal(); - EnumVal.zext(EnumVal.getBitWidth() * 2); - Diag(IdLoc, diag::warn_enumerator_too_large) - << EnumVal.toString(10); + EnumVal = EnumVal.zext(EnumVal.getBitWidth() * 2); + ++EnumVal; + if (Enum->isFixed()) + // When the underlying type is fixed, this is ill-formed. + Diag(IdLoc, diag::err_enumerator_wrapped) + << EnumVal.toString(10) + << EltTy; + else + Diag(IdLoc, diag::warn_enumerator_too_large) + << EnumVal.toString(10); } else { EltTy = T; } @@ -6819,7 +7632,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // value, then increment. EnumVal = LastEnumConst->getInitVal(); EnumVal.setIsSigned(EltTy->isSignedIntegerType()); - EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); + EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); ++EnumVal; // If we're not in C++, diagnose the overflow of enumerator values, @@ -6841,7 +7654,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, if (!EltTy->isDependentType()) { // Make the enumerator value match the signedness and size of the // enumerator's type. - EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); + EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); EnumVal.setIsSigned(EltTy->isSignedIntegerType()); } @@ -6850,11 +7663,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } -Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, - Decl *lastEnumConst, - SourceLocation IdLoc, - IdentifierInfo *Id, - SourceLocation EqualLoc, ExprTy *val) { +Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, + SourceLocation IdLoc, IdentifierInfo *Id, + AttributeList *Attr, + SourceLocation EqualLoc, ExprTy *val) { EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl); EnumConstantDecl *LastEnumConst = cast_or_null<EnumConstantDecl>(lastEnumConst); @@ -6890,11 +7702,25 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, } } - EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst, - IdLoc, Id, Val); + // C++ [class.mem]p13: + // If T is the name of a class, then each of the following shall have a + // name different from T: + // - every enumerator of every member of class T that is an enumerated + // type + if (CXXRecordDecl *Record + = dyn_cast<CXXRecordDecl>( + TheEnumDecl->getDeclContext()->getRedeclContext())) + if (Record->getIdentifier() && Record->getIdentifier() == Id) + Diag(IdLoc, diag::err_member_name_of_class) << Id; + + EnumConstantDecl *New = + CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val); - // Register this decl in the current scope stack. if (New) { + // Process attributes. + if (Attr) ProcessDeclAttributeList(S, New, Attr); + + // Register this decl in the current scope stack. New->setAccess(TheEnumDecl->getAccess()); PushOnScopeChains(New, S); } @@ -6961,7 +7787,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, } // Figure out the type that should be used for this enum. - // FIXME: Support -fshort-enums. QualType BestType; unsigned BestWidth; @@ -6977,8 +7802,19 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, QualType BestPromotionType; bool Packed = Enum->getAttr<PackedAttr>() ? true : false; - - if (NumNegativeBits) { + // -fshort-enums is the equivalent to specifying the packed attribute on all + // enum definitions. + if (LangOpts.ShortEnums) + Packed = true; + + if (Enum->isFixed()) { + BestType = BestPromotionType = Enum->getIntegerType(); + // We don't need to set BestWidth, because BestType is going to be the type + // of the enumerators, but we do anyway because otherwise some compilers + // warn that it might be used uninitialized. + BestWidth = CharWidth; + } + else if (NumNegativeBits) { // If there is a negative value, figure out the smallest integer type (of // int/long/longlong) that fits. // If it's packed, check also if it fits a char or a short. @@ -7081,12 +7917,13 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, } // Adjust the APSInt value. - InitVal.extOrTrunc(NewWidth); + InitVal = InitVal.extOrTrunc(NewWidth); InitVal.setIsSigned(NewSign); ECD->setInitVal(InitVal); // Adjust the Expr initializer and type. - if (ECD->getInitExpr()) + if (ECD->getInitExpr() && + !Context.hasSameType(NewTy, ECD->getInitExpr()->getType())) ECD->setInitExpr(ImplicitCastExpr::Create(Context, NewTy, CK_IntegralCast, ECD->getInitExpr(), diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 25af73a..cbc940f 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -78,6 +78,13 @@ static bool isFunctionOrMethodOrBlock(const Decl *d) { return isa<BlockDecl>(d); } +/// Return true if the given decl has a declarator that should have +/// been processed by Sema::GetTypeForDeclarator. +static bool hasDeclarator(const Decl *d) { + // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl. + return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefDecl>(d); +} + /// hasFunctionProto - Return true if the given decl has a argument /// information. This decl should have already passed /// isFunctionOrMethod or isFunctionOrMethodOrBlock. @@ -127,6 +134,12 @@ static bool isFunctionOrMethodVariadic(const Decl *d) { } } +static bool isInstanceMethod(const Decl *d) { + if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(d)) + return MethodDecl->isInstance(); + return false; +} + static inline bool isNSStringType(QualType T, ASTContext &Ctx) { const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>(); if (!PT) @@ -191,7 +204,7 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - sizeExpr = static_cast<Expr *>(Attr.getArg(0)); + sizeExpr = Attr.getArg(0); } // Instantiate/Install the vector type, and let Sema build the type for us. @@ -242,7 +255,7 @@ static void HandleIBAction(Decl *d, const AttributeList &Attr, Sema &S) { return; } - S.Diag(Attr.getLoc(), diag::err_attribute_ibaction) << Attr.getName(); + S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName(); } static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) { @@ -259,7 +272,7 @@ static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) { return; } - S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); + S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); } static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, @@ -274,7 +287,7 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, // The IBOutletCollection attributes only apply to instance variables of // Objective-C classes. if (!(isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))) { - S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); + S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); return; } if (const ValueDecl *VD = dyn_cast<ValueDecl>(d)) @@ -323,7 +336,10 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - unsigned NumArgs = getFunctionOrMethodNumArgs(d); + // In C++ the implicit 'this' function parameter also counts, and they are + // counted from one. + bool HasImplicitThisParam = isInstanceMethod(d); + unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam; // The nonnull attribute only applies to pointers. llvm::SmallVector<unsigned, 10> NonNullArgs; @@ -333,7 +349,7 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // The argument must be an integer constant expression. - Expr *Ex = static_cast<Expr *>(*I); + Expr *Ex = *I; llvm::APSInt ArgNum(32); if (Ex->isTypeDependent() || Ex->isValueDependent() || !Ex->isIntegerConstantExpr(ArgNum, S.Context)) { @@ -351,9 +367,18 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { } --x; + if (HasImplicitThisParam) { + if (x == 0) { + S.Diag(Attr.getLoc(), + diag::err_attribute_invalid_implicit_this_argument) + << "nonnull" << Ex->getSourceRange(); + return; + } + --x; + } // Is the function argument a pointer type? - QualType T = getFunctionOrMethodArgType(d, x); + QualType T = getFunctionOrMethodArgType(d, x).getNonReferenceType(); if (!T->isAnyPointerType() && !T->isBlockPointerType()) { // FIXME: Should also highlight argument in decl. S.Diag(Attr.getLoc(), diag::warn_nonnull_pointers_only) @@ -368,13 +393,30 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // arguments have a nonnull attribute. if (NonNullArgs.empty()) { for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) { - QualType T = getFunctionOrMethodArgType(d, I); + QualType T = getFunctionOrMethodArgType(d, I).getNonReferenceType(); if (T->isAnyPointerType() || T->isBlockPointerType()) NonNullArgs.push_back(I); + else if (const RecordType *UT = T->getAsUnionType()) { + if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) { + RecordDecl *UD = UT->getDecl(); + for (RecordDecl::field_iterator it = UD->field_begin(), + itend = UD->field_end(); it != itend; ++it) { + T = it->getType(); + if (T->isAnyPointerType() || T->isBlockPointerType()) { + NonNullArgs.push_back(I); + break; + } + } + } + } } + // No pointer arguments? if (NonNullArgs.empty()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); + // Warn the trivial case only if attribute is not coming from a + // macro instantiation. + if (Attr.getLoc().isFileID()) + S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); return; } } @@ -437,7 +479,10 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { return; } - unsigned NumArgs = getFunctionOrMethodNumArgs(d); + // In C++ the implicit 'this' function parameter also counts, and they are + // counted from one. + bool HasImplicitThisParam = isInstanceMethod(d); + unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam; llvm::StringRef Module = AL.getParameterName()->getName(); @@ -450,7 +495,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { for (AttributeList::arg_iterator I = AL.arg_begin(), E = AL.arg_end(); I != E; ++I) { - Expr *IdxExpr = static_cast<Expr *>(*I); + Expr *IdxExpr = *I; llvm::APSInt ArgNum(32); if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) { @@ -467,6 +512,15 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { continue; } --x; + if (HasImplicitThisParam) { + if (x == 0) { + S.Diag(AL.getLoc(), diag::err_attribute_invalid_implicit_this_argument) + << "ownership" << IdxExpr->getSourceRange(); + return; + } + --x; + } + switch (K) { case OwnershipAttr::Takes: case OwnershipAttr::Holds: { @@ -485,7 +539,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { case OwnershipAttr::Returns: { if (AL.getNumArgs() > 1) { // Is the function argument an integer type? - Expr *IdxExpr = static_cast<Expr *>(AL.getArg(0)); + Expr *IdxExpr = AL.getArg(0); llvm::APSInt ArgNum(32); if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) { @@ -532,11 +586,23 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { start, size)); } -static bool isStaticVarOrStaticFunciton(Decl *D) { - if (VarDecl *VD = dyn_cast<VarDecl>(D)) - return VD->getStorageClass() == SC_Static; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - return FD->getStorageClass() == SC_Static; +/// Whether this declaration has internal linkage for the purposes of +/// things that want to complain about things not have internal linkage. +static bool hasEffectivelyInternalLinkage(NamedDecl *D) { + switch (D->getLinkage()) { + case NoLinkage: + case InternalLinkage: + return true; + + // Template instantiations that go from external to unique-external + // shouldn't get diagnosed. + case UniqueExternalLinkage: + return true; + + case ExternalLinkage: + return false; + } + llvm_unreachable("unknown linkage kind!"); return false; } @@ -547,6 +613,14 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } + if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << 2 /*variables and functions*/; + return; + } + + NamedDecl *nd = cast<NamedDecl>(d); + // gcc rejects // class c { // static int a __attribute__((weakref ("v2"))); @@ -560,7 +634,7 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { const DeclContext *Ctx = d->getDeclContext()->getRedeclContext(); if (!Ctx->isFileContext()) { S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) << - dyn_cast<NamedDecl>(d)->getNameAsString(); + nd->getNameAsString(); return; } @@ -582,9 +656,8 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { // This looks like a bug in gcc. We reject that for now. We should revisit // it if this behaviour is actually used. - if (!isStaticVarOrStaticFunciton(d)) { - S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_static) << - dyn_cast<NamedDecl>(d)->getNameAsString(); + if (!hasEffectivelyInternalLinkage(nd)) { + S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_static); return; } @@ -593,7 +666,7 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Should we? How to check that weakref is before or after alias? if (Attr.getNumArgs() == 1) { - Expr *Arg = static_cast<Expr*>(Attr.getArg(0)); + Expr *Arg = Attr.getArg(0); Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); @@ -604,7 +677,8 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { } // GCC will accept anything as the argument of weakref. Should we // check for an existing decl? - d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, Str->getString())); + d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, + Str->getString())); } d->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context)); @@ -617,7 +691,7 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - Expr *Arg = static_cast<Expr*>(Attr.getArg(0)); + Expr *Arg = Attr.getArg(0); Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); @@ -627,14 +701,37 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } + if (S.Context.Target.getTriple().getOS() == llvm::Triple::Darwin) { + S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin); + return; + } + // FIXME: check if target symbol exists in current file - d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, Str->getString())); + d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, + Str->getString())); +} + +static void HandleNakedAttr(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) NakedAttr(Attr.getLoc(), S.Context)); } static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // check the attribute arguments. + // Check the attribute arguments. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; @@ -642,7 +739,7 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << 0 /*function*/; return; } @@ -650,7 +747,7 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, } static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // check the attribute arguments. + // Check the attribute arguments. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; @@ -667,10 +764,56 @@ static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only); } -static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { - /* Diagnostics (if any) was emitted by Sema::ProcessFnAttr(). */ +static void HandleMayAliasAttr(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; + } + + d->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context)); +} + +static void HandleNoCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) { assert(Attr.isInvalid() == false); - d->addAttr(::new (S.Context) NoReturnAttr(Attr.getLoc(), S.Context)); + if (isa<VarDecl>(d)) + d->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context)); + else + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 12 /* variable */; +} + +static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) { + assert(Attr.isInvalid() == false); + if (isa<VarDecl>(d)) + d->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context)); + else + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 12 /* variable */; +} + +static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) { + if (hasDeclarator(d)) return; + + if (S.CheckNoReturnAttr(attr)) return; + + if (!isa<ObjCMethodDecl>(d)) { + S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << attr.getName() << 0 /*function*/; + return; + } + + d->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context)); +} + +bool Sema::CheckNoReturnAttr(const AttributeList &attr) { + if (attr.getNumArgs() != 0) { + Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + attr.setInvalid(); + return true; + } + + return false; } static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, @@ -705,10 +848,11 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr, /* Returning a Vector Class in Registers - According to the PPU ABI specifications, a class with a single member of vector type is returned in - memory when used as the return value of a function. This results in inefficient code when implementing - vector classes. To return the value in a single vector register, add the vecreturn attribute to the class - definition. This attribute is also applicable to struct types. + According to the PPU ABI specifications, a class with a single member of + vector type is returned in memory when used as the return value of a function. + This results in inefficient code when implementing vector classes. To return + the value in a single vector register, add the vecreturn attribute to the + class definition. This attribute is also applicable to struct types. Example: @@ -724,7 +868,7 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr, return result; // This will be returned in a register } */ - if (!isa<CXXRecordDecl>(d)) { + if (!isa<RecordDecl>(d)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr.getName() << 9 /*class*/; return; @@ -735,6 +879,28 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr, return; } + RecordDecl *record = cast<RecordDecl>(d); + int count = 0; + + if (!isa<CXXRecordDecl>(record)) { + S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member); + return; + } + + if (!cast<CXXRecordDecl>(record)->isPOD()) { + S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_pod_record); + return; + } + + for (RecordDecl::field_iterator iter = record->field_begin(); + iter != record->field_end(); iter++) { + if ((count == 1) || !iter->getType()->isVectorType()) { + S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member); + return; + } + count++; + } + d->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context)); } @@ -755,9 +921,9 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { } if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) && - !isa<TypeDecl>(d)) { + !isa<TypeDecl>(d) && !isa<LabelDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; + << Attr.getName() << 14 /*variable, function, labels*/; return; } @@ -795,7 +961,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { int priority = 65535; // FIXME: Do not hardcode such constants. if (Attr.getNumArgs() > 0) { - Expr *E = static_cast<Expr *>(Attr.getArg(0)); + Expr *E = Attr.getArg(0); llvm::APSInt Idx(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { @@ -812,7 +978,8 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context, priority)); + d->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context, + priority)); } static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -825,7 +992,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { int priority = 65535; // FIXME: Do not hardcode such constants. if (Attr.getNumArgs() > 0) { - Expr *E = static_cast<Expr *>(Attr.getArg(0)); + Expr *E = Attr.getArg(0); llvm::APSInt Idx(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { @@ -842,27 +1009,59 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context, priority)); + d->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context, + priority)); } static void HandleDeprecatedAttr(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; + int noArgs = Attr.getNumArgs(); + if (noArgs > 1) { + S.Diag(Attr.getLoc(), + diag::err_attribute_wrong_number_arguments) << "0 or 1"; + return; + } + // Handle the case where deprecated attribute has a text message. + StringLiteral *SE; + if (noArgs == 1) { + Expr *ArgExpr = Attr.getArg(0); + SE = dyn_cast<StringLiteral>(ArgExpr); + if (!SE) { + S.Diag(ArgExpr->getLocStart(), + diag::err_attribute_not_string) << "deprecated"; + return; + } } + else + SE = StringLiteral::CreateEmpty(S.Context, 1); - d->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, + SE->getString())); } static void HandleUnavailableAttr(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; + int noArgs = Attr.getNumArgs(); + if (noArgs > 1) { + S.Diag(Attr.getLoc(), + diag::err_attribute_wrong_number_arguments) << "0 or 1"; return; } - - d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context)); + // Handle the case where unavailable attribute has a text message. + StringLiteral *SE; + if (noArgs == 1) { + Expr *ArgExpr = Attr.getArg(0); + SE = dyn_cast<StringLiteral>(ArgExpr); + if (!SE) { + S.Diag(ArgExpr->getLocStart(), + diag::err_attribute_not_string) << "unavailable"; + return; + } + } + else + SE = StringLiteral::CreateEmpty(S.Context, 1); + d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, + SE->getString())); } static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -872,7 +1071,7 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - Expr *Arg = static_cast<Expr*>(Attr.getArg(0)); + Expr *Arg = Attr.getArg(0); Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); @@ -982,7 +1181,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { int sentinel = 0; if (Attr.getNumArgs() > 0) { - Expr *E = static_cast<Expr *>(Attr.getArg(0)); + Expr *E = Attr.getArg(0); llvm::APSInt Idx(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { @@ -1001,7 +1200,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { int nullPos = 0; if (Attr.getNumArgs() > 1) { - Expr *E = static_cast<Expr *>(Attr.getArg(1)); + Expr *E = Attr.getArg(1); llvm::APSInt Idx(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { @@ -1046,7 +1245,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { QualType Ty = V->getType(); if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d) - : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); + : 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; @@ -1062,7 +1261,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { << Attr.getName() << 6 /*function, method or block */; return; } - d->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel, nullPos)); + d->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel, + nullPos)); } static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) { @@ -1093,28 +1293,28 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getLoc(), S.Context)); } -static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) { +static void HandleWeakAttr(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; + if (attr.getNumArgs() != 0) { + S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - /* weak only applies to non-static declarations */ - if (isStaticVarOrStaticFunciton(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) << - dyn_cast<NamedDecl>(D)->getNameAsString(); + if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) { + S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << attr.getName() << 2 /*variables and functions*/; 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*/; + NamedDecl *nd = cast<NamedDecl>(d); + + // 'weak' only applies to declarations with external linkage. + if (hasEffectivelyInternalLinkage(nd)) { + S.Diag(attr.getLoc(), diag::err_attribute_weak_static); return; } - D->addAttr(::new (S.Context) WeakAttr(Attr.getLoc(), S.Context)); + nd->addAttr(::new (S.Context) WeakAttr(attr.getLoc(), S.Context)); } static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { @@ -1163,7 +1363,7 @@ static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr, unsigned WGSize[3]; for (unsigned i = 0; i < 3; ++i) { - Expr *E = static_cast<Expr *>(Attr.getArg(i)); + Expr *E = Attr.getArg(i); llvm::APSInt ArgNum(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(ArgNum, S.Context)) { @@ -1187,7 +1387,7 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Make sure that there is a string literal as the sections's single // argument. - Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0)); + Expr *ArgExpr = Attr.getArg(0); StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr); if (!SE) { S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) << "section"; @@ -1208,7 +1408,8 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - D->addAttr(::new (S.Context) SectionAttr(Attr.getLoc(), S.Context, SE->getString())); + D->addAttr(::new (S.Context) SectionAttr(Attr.getLoc(), S.Context, + SE->getString())); } @@ -1262,27 +1463,27 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Look up the function // FIXME: Lookup probably isn't looking in the right place - // FIXME: The lookup source location should be in the attribute, not the - // start of the attribute. NamedDecl *CleanupDecl - = S.LookupSingleName(S.TUScope, Attr.getParameterName(), Attr.getLoc(), - Sema::LookupOrdinaryName); + = S.LookupSingleName(S.TUScope, Attr.getParameterName(), + Attr.getParameterLoc(), Sema::LookupOrdinaryName); if (!CleanupDecl) { - S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) << + S.Diag(Attr.getParameterLoc(), 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) << - Attr.getParameterName(); + S.Diag(Attr.getParameterLoc(), + diag::err_attribute_cleanup_arg_not_function) + << Attr.getParameterName(); return; } if (FD->getNumParams() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_func_must_take_one_arg) << - Attr.getParameterName(); + S.Diag(Attr.getParameterLoc(), + diag::err_attribute_cleanup_func_must_take_one_arg) + << Attr.getParameterName(); return; } @@ -1290,14 +1491,16 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { // 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(), + if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(), + ParamTy, Ty) != Sema::Compatible) { + S.Diag(Attr.getParameterLoc(), diag::err_attribute_cleanup_func_arg_incompatible_type) << Attr.getParameterName() << ParamTy << Ty; return; } d->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD)); + S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD); } /// Handle __attribute__((format_arg((idx)))) attribute based on @@ -1312,12 +1515,15 @@ 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. - unsigned NumArgs = getFunctionOrMethodNumArgs(d); + + // In C++ the implicit 'this' function parameter also counts, and they are + // counted from one. + bool HasImplicitThisParam = isInstanceMethod(d); + unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam; unsigned FirstIdx = 1; + // checks for the 2nd argument - Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0)); + Expr *IdxExpr = Attr.getArg(0); llvm::APSInt Idx(32); if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { @@ -1334,6 +1540,15 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { unsigned ArgIdx = Idx.getZExtValue() - 1; + if (HasImplicitThisParam) { + if (ArgIdx == 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_implicit_this_argument) + << "format_arg" << IdxExpr->getSourceRange(); + return; + } + ArgIdx--; + } + // make sure the format string is really a string QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); @@ -1360,7 +1575,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context, Idx.getZExtValue())); + d->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context, + Idx.getZExtValue())); } enum FormatAttrKind { @@ -1387,7 +1603,8 @@ static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) { if (Format == "scanf" || Format == "printf" || Format == "printf0" || Format == "strfmon" || Format == "cmn_err" || Format == "strftime" || Format == "NSString" || Format == "CFString" || Format == "vcmn_err" || - Format == "zcmn_err") + Format == "zcmn_err" || + Format == "kprintf") // OpenBSD. return SupportedFormat; if (Format == "gcc_diag" || Format == "gcc_cdiag" || @@ -1425,7 +1642,7 @@ static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr, Attr.setInvalid(); return; } - Expr *priorityExpr = static_cast<Expr *>(Attr.getArg(0)); + Expr *priorityExpr = Attr.getArg(0); llvm::APSInt priority(32); if (priorityExpr->isTypeDependent() || priorityExpr->isValueDependent() || @@ -1442,7 +1659,8 @@ static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr, Attr.setInvalid(); return; } - d->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context, prioritynum)); + d->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context, + prioritynum)); } /// Handle __attribute__((format(type,idx,firstarg))) attributes based on @@ -1466,7 +1684,10 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - unsigned NumArgs = getFunctionOrMethodNumArgs(d); + // In C++ the implicit 'this' function parameter also counts, and they are + // counted from one. + bool HasImplicitThisParam = isInstanceMethod(d); + unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam; unsigned FirstIdx = 1; llvm::StringRef Format = Attr.getParameterName()->getName(); @@ -1488,7 +1709,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { } // checks for the 2nd argument - Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0)); + Expr *IdxExpr = Attr.getArg(0); llvm::APSInt Idx(32); if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { @@ -1497,16 +1718,6 @@ 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(); @@ -1518,8 +1729,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (HasImplicitThisParam) { if (ArgIdx == 0) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) - << "a string type" << IdxExpr->getSourceRange(); + S.Diag(Attr.getLoc(), + diag::err_format_attribute_implicit_this_format_string) + << IdxExpr->getSourceRange(); return; } ArgIdx--; @@ -1552,7 +1764,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { } // check the 3rd argument - Expr *FirstArgExpr = static_cast<Expr *>(Attr.getArg(1)); + Expr *FirstArgExpr = Attr.getArg(1); llvm::APSInt FirstArg(32); if (FirstArgExpr->isTypeDependent() || FirstArgExpr->isValueDependent() || !FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) { @@ -1665,7 +1877,7 @@ 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)); + Expr *ArgExpr = Attr.getArg(0); StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr); // Make sure that there is a string literal as the annotation's single @@ -1674,7 +1886,8 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate"; return; } - d->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context, SE->getString())); + d->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context, + SE->getString())); } static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) { @@ -1693,7 +1906,7 @@ static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - S.AddAlignedAttr(Attr.getLoc(), D, static_cast<Expr *>(Attr.getArg(0))); + S.AddAlignedAttr(Attr.getLoc(), D, Attr.getArg(0)); } void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) { @@ -1943,7 +2156,123 @@ static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr, return; } - d->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(), + S.Context)); +} + +static void HandleConstantAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (S.LangOpts.CUDA) { + // check the attribute arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa<VarDecl>(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 12 /*variable*/; + return; + } + + d->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context)); + } else { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant"; + } +} + +static void HandleDeviceAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (S.LangOpts.CUDA) { + // check the attribute arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + 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) CUDADeviceAttr(Attr.getLoc(), S.Context)); + } else { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device"; + } +} + +static void HandleGlobalAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (S.LangOpts.CUDA) { + // 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; + } + + FunctionDecl *FD = cast<FunctionDecl>(d); + if (!FD->getResultType()->isVoidType()) { + TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens(); + if (FunctionTypeLoc* FTL = dyn_cast<FunctionTypeLoc>(&TL)) { + S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) + << FD->getType() + << FixItHint::CreateReplacement(FTL->getResultLoc().getSourceRange(), + "void"); + } else { + S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) + << FD->getType(); + } + return; + } + + d->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context)); + } else { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global"; + } +} + +static void HandleHostAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (S.LangOpts.CUDA) { + // 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) CUDAHostAttr(Attr.getLoc(), S.Context)); + } else { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host"; + } +} + +static void HandleSharedAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (S.LangOpts.CUDA) { + // check the attribute arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa<VarDecl>(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 12 /*variable*/; + return; + } + + d->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context)); + } else { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared"; + } } static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1968,26 +2297,36 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context)); } -static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // Diagnostic is emitted elsewhere: here we store the (valid) Attr +static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) { + if (hasDeclarator(d)) return; + + // Diagnostic is emitted elsewhere: here we store the (valid) attr // in the Decl node for syntactic reasoning, e.g., pretty-printing. - assert(Attr.isInvalid() == false); + CallingConv CC; + if (S.CheckCallingConvAttr(attr, CC)) + return; - switch (Attr.getKind()) { + if (!isa<ObjCMethodDecl>(d)) { + S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << attr.getName() << 0 /*function*/; + return; + } + + switch (attr.getKind()) { case AttributeList::AT_fastcall: - d->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) FastCallAttr(attr.getLoc(), S.Context)); return; case AttributeList::AT_stdcall: - d->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) StdCallAttr(attr.getLoc(), S.Context)); return; case AttributeList::AT_thiscall: - d->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) ThisCallAttr(attr.getLoc(), S.Context)); return; case AttributeList::AT_cdecl: - d->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) CDeclAttr(attr.getLoc(), S.Context)); return; case AttributeList::AT_pascal: - d->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) PascalAttr(attr.getLoc(), S.Context)); return; default: llvm_unreachable("unexpected attribute kind"); @@ -1995,214 +2334,336 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) { } } -static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // check the attribute arguments. - if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; - return; +static void HandleOpenCLKernelAttr(Decl *d, const AttributeList &Attr, Sema &S){ + assert(Attr.isInvalid() == false); + d->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context)); +} + +bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { + if (attr.isInvalid()) + return true; + + if (attr.getNumArgs() != 0) { + Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + attr.setInvalid(); + return true; } - if (!isFunctionOrMethod(d)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + // TODO: diagnose uses of these conventions on the wrong target. + switch (attr.getKind()) { + case AttributeList::AT_cdecl: CC = CC_C; break; + case AttributeList::AT_fastcall: CC = CC_X86FastCall; break; + case AttributeList::AT_stdcall: CC = CC_X86StdCall; break; + case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break; + case AttributeList::AT_pascal: CC = CC_X86Pascal; break; + default: llvm_unreachable("unexpected attribute kind"); return true; + } + + return false; +} + +static void HandleRegparmAttr(Decl *d, const AttributeList &attr, Sema &S) { + if (hasDeclarator(d)) return; + + unsigned numParams; + if (S.CheckRegparmAttr(attr, numParams)) + return; + + if (!isa<ObjCMethodDecl>(d)) { + S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << attr.getName() << 0 /*function*/; return; } - Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0)); + d->addAttr(::new (S.Context) RegparmAttr(attr.getLoc(), S.Context, numParams)); +} + +/// Checks a regparm attribute, returning true if it is ill-formed and +/// otherwise setting numParams to the appropriate value. +bool Sema::CheckRegparmAttr(const AttributeList &attr, unsigned &numParams) { + if (attr.isInvalid()) + return true; + + if (attr.getNumArgs() != 1) { + Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + attr.setInvalid(); + return true; + } + + Expr *NumParamsExpr = attr.getArg(0); llvm::APSInt NumParams(32); if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() || - !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + !NumParamsExpr->isIntegerConstantExpr(NumParams, Context)) { + Diag(attr.getLoc(), diag::err_attribute_argument_not_int) << "regparm" << NumParamsExpr->getSourceRange(); - return; + attr.setInvalid(); + return true; } - if (S.Context.Target.getRegParmMax() == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform) + if (Context.Target.getRegParmMax() == 0) { + Diag(attr.getLoc(), diag::err_attribute_regparm_wrong_platform) << NumParamsExpr->getSourceRange(); - return; + attr.setInvalid(); + return true; } - if (NumParams.getLimitedValue(255) > S.Context.Target.getRegParmMax()) { - S.Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number) - << S.Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange(); - return; + numParams = NumParams.getZExtValue(); + if (numParams > Context.Target.getRegParmMax()) { + Diag(attr.getLoc(), diag::err_attribute_regparm_invalid_number) + << Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange(); + attr.setInvalid(); + return true; } - d->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context, - NumParams.getZExtValue())); + return false; } -static void HandleFinalAttr(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; - } +static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){ + if (S.LangOpts.CUDA) { + // check the attribute arguments. + if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << "1 or 2"; + return; + } - if (!isa<CXXRecordDecl>(d) - && (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual())) { - S.Diag(Attr.getLoc(), - Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type - : diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 7 /*virtual method or class*/; - return; - } - - // FIXME: Conform to C++0x redeclaration rules. - - if (d->getAttr<FinalAttr>()) { - S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "final"; - return; - } + if (!isFunctionOrMethod(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + Expr *MaxThreadsExpr = Attr.getArg(0); + llvm::APSInt MaxThreads(32); + if (MaxThreadsExpr->isTypeDependent() || + MaxThreadsExpr->isValueDependent() || + !MaxThreadsExpr->isIntegerConstantExpr(MaxThreads, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) + << "launch_bounds" << 1 << MaxThreadsExpr->getSourceRange(); + return; + } - d->addAttr(::new (S.Context) FinalAttr(Attr.getLoc(), S.Context)); + llvm::APSInt MinBlocks(32); + if (Attr.getNumArgs() > 1) { + Expr *MinBlocksExpr = Attr.getArg(1); + if (MinBlocksExpr->isTypeDependent() || + MinBlocksExpr->isValueDependent() || + !MinBlocksExpr->isIntegerConstantExpr(MinBlocks, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) + << "launch_bounds" << 2 << MinBlocksExpr->getSourceRange(); + return; + } + } + + d->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context, + MaxThreads.getZExtValue(), + MinBlocks.getZExtValue())); + } else { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "launch_bounds"; + } } //===----------------------------------------------------------------------===// -// C++0x member checking attributes +// Checker-specific attribute handlers. //===----------------------------------------------------------------------===// -static void HandleBaseCheckAttr(Decl *d, const AttributeList &Attr, Sema &S) { - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - if (!isa<CXXRecordDecl>(d)) { - S.Diag(Attr.getLoc(), - Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type - : diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 9 /*class*/; - return; - } - - if (d->getAttr<BaseCheckAttr>()) { - S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "base_check"; - return; - } - - d->addAttr(::new (S.Context) BaseCheckAttr(Attr.getLoc(), S.Context)); +static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { + return type->isObjCObjectPointerType() || S.Context.isObjCNSObjectType(type); +} +static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { + return type->isPointerType() || isValidSubjectOfNSAttribute(S, type); } -static void HandleHidingAttr(Decl *d, const AttributeList &Attr, Sema &S) { - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; +static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) { + ParmVarDecl *param = dyn_cast<ParmVarDecl>(d); + if (!param) { + S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) + << SourceRange(attr.getLoc()) << attr.getName() << 4 /*parameter*/; return; } - if (!isa<RecordDecl>(d->getDeclContext())) { - // FIXME: It's not the type that's the problem - S.Diag(Attr.getLoc(), - Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type - : diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 11 /*member*/; - return; + bool typeOK, cf; + if (attr.getKind() == AttributeList::AT_ns_consumed) { + typeOK = isValidSubjectOfNSAttribute(S, param->getType()); + cf = false; + } else { + typeOK = isValidSubjectOfCFAttribute(S, param->getType()); + cf = true; } - // FIXME: Conform to C++0x redeclaration rules. - - if (d->getAttr<HidingAttr>()) { - S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "hiding"; + if (!typeOK) { + S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) + << SourceRange(attr.getLoc()) << attr.getName() << cf; return; } - d->addAttr(::new (S.Context) HidingAttr(Attr.getLoc(), S.Context)); + if (cf) + param->addAttr(::new (S.Context) CFConsumedAttr(attr.getLoc(), S.Context)); + else + param->addAttr(::new (S.Context) NSConsumedAttr(attr.getLoc(), S.Context)); } -static void HandleOverrideAttr(Decl *d, const AttributeList &Attr, Sema &S) { - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - if (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual()) { - // FIXME: It's not the type that's the problem - S.Diag(Attr.getLoc(), - Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type - : diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 10 /*virtual method*/; - return; - } - - // FIXME: Conform to C++0x redeclaration rules. - - if (d->getAttr<OverrideAttr>()) { - S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "override"; +static void HandleNSConsumesSelfAttr(Decl *d, const AttributeList &attr, + Sema &S) { + if (!isa<ObjCMethodDecl>(d)) { + S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) + << SourceRange(attr.getLoc()) << attr.getName() << 13 /*method*/; return; } - d->addAttr(::new (S.Context) OverrideAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) NSConsumesSelfAttr(attr.getLoc(), S.Context)); } -//===----------------------------------------------------------------------===// -// Checker-specific attribute handlers. -//===----------------------------------------------------------------------===// - -static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, +static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr, Sema &S) { - QualType RetTy; + QualType returnType; if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) - RetTy = MD->getResultType(); + returnType = MD->getResultType(); else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) - RetTy = FD->getResultType(); + returnType = FD->getResultType(); else { - SourceLocation L = Attr.getLoc(); S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(L, L) << Attr.getName() << 3 /* function or method */; + << SourceRange(attr.getLoc()) << attr.getName() + << 3 /* function or method */; return; } - if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAs<PointerType>() - || RetTy->getAs<ObjCObjectPointerType>())) { - SourceLocation L = Attr.getLoc(); + bool typeOK; + bool cf; + switch (attr.getKind()) { + default: llvm_unreachable("invalid ownership attribute"); return; + case AttributeList::AT_ns_returns_autoreleased: + case AttributeList::AT_ns_returns_retained: + case AttributeList::AT_ns_returns_not_retained: + typeOK = isValidSubjectOfNSAttribute(S, returnType); + cf = false; + break; + + case AttributeList::AT_cf_returns_retained: + case AttributeList::AT_cf_returns_not_retained: + typeOK = isValidSubjectOfCFAttribute(S, returnType); + cf = true; + break; + } + + if (!typeOK) { S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << SourceRange(L, L) << Attr.getName(); + << SourceRange(attr.getLoc()) + << attr.getName() << isa<ObjCMethodDecl>(d) << cf; return; } - switch (Attr.getKind()) { + switch (attr.getKind()) { default: assert(0 && "invalid ownership attribute"); return; + case AttributeList::AT_ns_returns_autoreleased: + d->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(attr.getLoc(), + S.Context)); + return; case AttributeList::AT_cf_returns_not_retained: - d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(attr.getLoc(), + S.Context)); return; case AttributeList::AT_ns_returns_not_retained: - d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(attr.getLoc(), + S.Context)); return; case AttributeList::AT_cf_returns_retained: - d->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) CFReturnsRetainedAttr(attr.getLoc(), + S.Context)); return; case AttributeList::AT_ns_returns_retained: - d->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(), S.Context)); + d->addAttr(::new (S.Context) NSReturnsRetainedAttr(attr.getLoc(), + S.Context)); return; }; } static bool isKnownDeclSpecAttr(const AttributeList &Attr) { return Attr.getKind() == AttributeList::AT_dllimport || - Attr.getKind() == AttributeList::AT_dllexport; + Attr.getKind() == AttributeList::AT_dllexport || + Attr.getKind() == AttributeList::AT_uuid; +} + +//===----------------------------------------------------------------------===// +// Microsoft specific attribute handlers. +//===----------------------------------------------------------------------===// + +static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (S.LangOpts.Microsoft || S.LangOpts.Borland) { + // check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + Expr *Arg = Attr.getArg(0); + StringLiteral *Str = dyn_cast<StringLiteral>(Arg); + if (Str == 0 || Str->isWide()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "uuid" << 1; + return; + } + + llvm::StringRef StrRef = Str->getString(); + + bool IsCurly = StrRef.size() > 1 && StrRef.front() == '{' && + StrRef.back() == '}'; + + // Validate GUID length. + if (IsCurly && StrRef.size() != 38) { + S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid); + return; + } + if (!IsCurly && StrRef.size() != 36) { + S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid); + return; + } + + // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or + // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" + llvm::StringRef::iterator I = StrRef.begin(); + if (IsCurly) // Skip the optional '{' + ++I; + + for (int i = 0; i < 36; ++i) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + if (*I != '-') { + S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid); + return; + } + } else if (!isxdigit(*I)) { + S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid); + return; + } + I++; + } + + d->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context, + Str->getString())); + } else + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid"; } //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// -/// 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 if a GNU attribute. FIXME: Applying a C++0x attribute to -/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4). -static void ProcessDeclAttribute(Scope *scope, Decl *D, - const AttributeList &Attr, Sema &S) { - if (Attr.isInvalid()) - return; +static void ProcessNonInheritableDeclAttr(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) { + switch (Attr.getKind()) { + case AttributeList::AT_device: HandleDeviceAttr (D, Attr, S); break; + case AttributeList::AT_host: HandleHostAttr (D, Attr, S); break; + case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break; + default: + break; + } +} - if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr)) - // FIXME: Try to deal with other __declspec attributes! - return; +static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) { switch (Attr.getKind()) { case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break; case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break; @@ -2211,9 +2672,17 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_address_space: case AttributeList::AT_objc_gc: case AttributeList::AT_vector_size: + case AttributeList::AT_neon_vector_type: + case AttributeList::AT_neon_polyvector_type: // Ignore these, these are type attributes, handled by // ProcessTypeAttributes. break; + case AttributeList::AT_device: + case AttributeList::AT_host: + case AttributeList::AT_overloadable: + // Ignore, this is a non-inheritable attribute, handled + // by ProcessNonInheritableDeclAttr. + break; case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break; case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break; case AttributeList::AT_always_inline: @@ -2221,33 +2690,45 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_analyzer_noreturn: HandleAnalyzerNoReturnAttr (D, Attr, S); break; case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; - case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break; case AttributeList::AT_carries_dependency: HandleDependencyAttr (D, Attr, S); break; + case AttributeList::AT_common: HandleCommonAttr (D, Attr, S); break; + case AttributeList::AT_constant: HandleConstantAttr (D, Attr, S); break; case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break; case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break; case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break; case AttributeList::AT_ext_vector_type: HandleExtVectorTypeAttr(scope, D, Attr, S); break; - case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break; case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break; case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break; + case AttributeList::AT_global: HandleGlobalAttr (D, Attr, S); break; case AttributeList::AT_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break; - case AttributeList::AT_hiding: HandleHidingAttr (D, Attr, S); break; + case AttributeList::AT_launch_bounds: + HandleLaunchBoundsAttr(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_may_alias: HandleMayAliasAttr (D, Attr, S); break; + case AttributeList::AT_nocommon: HandleNoCommonAttr (D, Attr, S); break; case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break; case AttributeList::AT_ownership_returns: case AttributeList::AT_ownership_takes: case AttributeList::AT_ownership_holds: HandleOwnershipAttr (D, Attr, S); break; + case AttributeList::AT_naked: HandleNakedAttr (D, Attr, S); break; case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break; case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break; - case AttributeList::AT_override: HandleOverrideAttr (D, Attr, S); break; + case AttributeList::AT_shared: HandleSharedAttr (D, Attr, S); break; case AttributeList::AT_vecreturn: HandleVecReturnAttr (D, Attr, S); break; // Checker-specific. + case AttributeList::AT_cf_consumed: + case AttributeList::AT_ns_consumed: HandleNSConsumedAttr (D, Attr, S); break; + case AttributeList::AT_ns_consumes_self: + HandleNSConsumesSelfAttr(D, Attr, S); break; + + case AttributeList::AT_ns_returns_autoreleased: case AttributeList::AT_ns_returns_not_retained: case AttributeList::AT_cf_returns_not_retained: case AttributeList::AT_ns_returns_retained: @@ -2277,7 +2758,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_objc_exception: HandleObjCExceptionAttr(D, Attr, S); break; - case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break; case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break; case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break; case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break; @@ -2300,6 +2780,12 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_pascal: HandleCallConvAttr(D, Attr, S); break; + case AttributeList::AT_opencl_kernel_function: + HandleOpenCLKernelAttr(D, Attr, S); + break; + case AttributeList::AT_uuid: + HandleUuidAttr(D, Attr, S); + break; default: // Ask target about the attribute. const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); @@ -2310,17 +2796,40 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, } } +/// 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 if a GNU attribute. FIXME: Applying a C++0x attribute to +/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4). +static void ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S, + bool NonInheritable, bool Inheritable) { + if (Attr.isInvalid()) + return; + + if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr)) + // FIXME: Try to deal with other __declspec attributes! + return; + + if (NonInheritable) + ProcessNonInheritableDeclAttr(scope, D, Attr, S); + + if (Inheritable) + ProcessInheritableDeclAttr(scope, D, Attr, S); +} + /// ProcessDeclAttributeList - Apply all the decl attributes in the specified /// attribute list to the specified decl, ignoring any type attributes. -void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList) { +void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, + const AttributeList *AttrList, + bool NonInheritable, bool Inheritable) { for (const AttributeList* l = AttrList; l; l = l->getNext()) { - ProcessDeclAttribute(S, D, *l, *this); + ProcessDeclAttribute(S, D, *l, *this, NonInheritable, Inheritable); } // GCC accepts // static int a9 __attribute__((weakref)); // but that looks really pointless. We reject it. - if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) { + if (Inheritable && D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) { Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) << dyn_cast<NamedDecl>(D)->getNameAsString(); return; @@ -2380,22 +2889,27 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { /// 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; +void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, + bool NonInheritable, bool Inheritable) { + // It's valid to "forward-declare" #pragma weak, in which case we + // have to do this. + if (Inheritable && !WeakUndeclaredIdentifiers.empty()) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { + if (IdentifierInfo *Id = ND->getIdentifier()) { + llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I + = WeakUndeclaredIdentifiers.find(Id); + if (I != WeakUndeclaredIdentifiers.end() && ND->hasLinkage()) { + WeakInfo W = I->second; + DeclApplyPragmaWeak(S, ND, W); + WeakUndeclaredIdentifiers[Id] = W; + } } } } // Apply decl attributes from the DeclSpec if present. - if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes()) - ProcessDeclAttributeList(S, D, Attrs); + if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList()) + ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable); // Walk the declarator structure, applying decl attributes that were in a type // position to the decl itself. This handles cases like: @@ -2403,66 +2917,84 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { // when X is a decl attribute. for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs()) - ProcessDeclAttributeList(S, D, Attrs); + ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable); // Finally, apply any attributes on the decl itself. if (const AttributeList *Attrs = PD.getAttributes()) - ProcessDeclAttributeList(S, D, Attrs); + ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable); } -/// PushParsingDeclaration - Enter a new "scope" of deprecation -/// warnings. -/// -/// The state token we use is the start index of this scope -/// on the warning stack. -Sema::ParsingDeclStackState Sema::PushParsingDeclaration() { - ParsingDeclDepth++; - return (ParsingDeclStackState) DelayedDiagnostics.size(); +// This duplicates a vector push_back but hides the need to know the +// size of the type. +void Sema::DelayedDiagnostics::add(const DelayedDiagnostic &diag) { + assert(StackSize <= StackCapacity); + + // Grow the stack if necessary. + if (StackSize == StackCapacity) { + unsigned newCapacity = 2 * StackCapacity + 2; + char *newBuffer = new char[newCapacity * sizeof(DelayedDiagnostic)]; + const char *oldBuffer = (const char*) Stack; + + if (StackCapacity) + memcpy(newBuffer, oldBuffer, StackCapacity * sizeof(DelayedDiagnostic)); + + delete[] oldBuffer; + Stack = reinterpret_cast<sema::DelayedDiagnostic*>(newBuffer); + StackCapacity = newCapacity; + } + + assert(StackSize < StackCapacity); + new (&Stack[StackSize++]) DelayedDiagnostic(diag); } -void Sema::PopParsingDeclaration(ParsingDeclStackState S, Decl *D) { - assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack"); - ParsingDeclDepth--; +void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state, + Decl *decl) { + DelayedDiagnostics &DD = S.DelayedDiagnostics; - if (DelayedDiagnostics.empty()) - return; + // Check the invariants. + assert(DD.StackSize >= state.SavedStackSize); + assert(state.SavedStackSize >= DD.ActiveStackBase); + assert(DD.ParsingDepth > 0); - unsigned SavedIndex = (unsigned) S; - assert(SavedIndex <= DelayedDiagnostics.size() && - "saved index is out of bounds"); + // Drop the parsing depth. + DD.ParsingDepth--; - unsigned E = DelayedDiagnostics.size(); + // If there are no active diagnostics, we're done. + if (DD.StackSize == DD.ActiveStackBase) + return; // We only want to actually emit delayed diagnostics when we // successfully parsed a decl. - if (D) { - // We really do want to start with 0 here. We get one push for a + if (decl) { + // We emit all the active diagnostics, not just those starting + // from the saved state. The idea is this: we get one push for a // decl spec and another for each declarator; in a decl group like: // deprecated_typedef foo, *bar, baz(); // only the declarator pops will be passed decls. This is correct; // we really do need to consider delayed diagnostics from the decl spec // for each of the different declarations. - for (unsigned I = 0; I != E; ++I) { - if (DelayedDiagnostics[I].Triggered) + for (unsigned i = DD.ActiveStackBase, e = DD.StackSize; i != e; ++i) { + DelayedDiagnostic &diag = DD.Stack[i]; + if (diag.Triggered) continue; - switch (DelayedDiagnostics[I].Kind) { + switch (diag.Kind) { case DelayedDiagnostic::Deprecation: - HandleDelayedDeprecationCheck(DelayedDiagnostics[I], D); + S.HandleDelayedDeprecationCheck(diag, decl); break; case DelayedDiagnostic::Access: - HandleDelayedAccessCheck(DelayedDiagnostics[I], D); + S.HandleDelayedAccessCheck(diag, decl); break; } } } // Destroy all the delayed diagnostics we're about to pop off. - for (unsigned I = SavedIndex; I != E; ++I) - DelayedDiagnostics[I].destroy(); + for (unsigned i = state.SavedStackSize, e = DD.StackSize; i != e; ++i) + DD.Stack[i].destroy(); - DelayedDiagnostics.set_size(SavedIndex); + DD.StackSize = state.SavedStackSize; } static bool isDeclDeprecated(Decl *D) { @@ -2479,20 +3011,34 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, return; DD.Triggered = true; - Diag(DD.Loc, diag::warn_deprecated) - << DD.DeprecationData.Decl->getDeclName(); + if (!DD.getDeprecationMessage().empty()) + Diag(DD.Loc, diag::warn_deprecated_message) + << DD.getDeprecationDecl()->getDeclName() + << DD.getDeprecationMessage(); + else + Diag(DD.Loc, diag::warn_deprecated) + << DD.getDeprecationDecl()->getDeclName(); } -void Sema::EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc) { +void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, + SourceLocation Loc, + bool UnknownObjCClass) { // Delay if we're currently parsing a declaration. - if (ParsingDeclDepth) { - DelayedDiagnostics.push_back(DelayedDiagnostic::makeDeprecation(Loc, D)); + if (DelayedDiagnostics.shouldDelayDiagnostics()) { + DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D, Message)); return; } // Otherwise, don't warn if our current context is deprecated. if (isDeclDeprecated(cast<Decl>(CurContext))) return; - - Diag(Loc, diag::warn_deprecated) << D->getDeclName(); + if (!Message.empty()) + Diag(Loc, diag::warn_deprecated_message) << D->getDeclName() + << Message; + else { + if (!UnknownObjCClass) + Diag(Loc, diag::warn_deprecated) << D->getDeclName(); + else + Diag(Loc, diag::warn_deprecated_fwdclass_message) << D->getDeclName(); + } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 63acdb5..e8abab8 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -63,8 +63,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(), - E = Node->child_end(); I != E; ++I) + for (Stmt::child_range I = Node->children(); I; ++I) IsInvalid |= Visit(*I); return IsInvalid; } @@ -90,7 +89,7 @@ namespace { // C++ [dcl.fct.default]p7 // Local variables shall not be used in default argument // expressions. - if (VDecl->isBlockVarDecl()) + if (VDecl->isLocalVarDecl()) return S->Diag(DRE->getSourceRange().getBegin(), diag::err_param_default_argument_references_local) << VDecl->getDeclName() << DefaultArg->getSourceRange(); @@ -125,21 +124,35 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, // 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). - InitializedEntity Entity = InitializedEntity::InitializeParameter(Param); + InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, + Param); InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(), EqualLoc); InitializationSequence InitSeq(*this, Entity, Kind, &Arg, 1); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, &Arg, 1)); + MultiExprArg(*this, &Arg, 1)); if (Result.isInvalid()) return true; Arg = Result.takeAs<Expr>(); - Arg = MaybeCreateCXXExprWithTemporaries(Arg); + CheckImplicitConversions(Arg, EqualLoc); + Arg = MaybeCreateExprWithCleanups(Arg); // Okay: add the default argument to the parameter Param->setDefaultArg(Arg); + // We have already instantiated this parameter; provide each of the + // instantiations with the uninstantiated default argument. + UnparsedDefaultArgInstantiationsMap::iterator InstPos + = UnparsedDefaultArgInstantiations.find(Param); + if (InstPos != UnparsedDefaultArgInstantiations.end()) { + for (unsigned I = 0, N = InstPos->second.size(); I != N; ++I) + InstPos->second[I]->setUninstantiatedDefaultArg(Arg); + + // We're done tracking this parameter's instantiations. + UnparsedDefaultArgInstantiations.erase(InstPos); + } + return false; } @@ -163,6 +176,12 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, return; } + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) { + Param->setInvalidDecl(); + return; + } + // Check that the default argument is well-formed CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg, this); if (DefaultArgChecker.Visit(DefaultArg)) { @@ -297,7 +316,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { } else if (OldParam->hasDefaultArg()) { // Merge the old default argument into the new parameter. // It's important to use getInit() here; getDefaultArg() - // strips off any top-level CXXExprWithTemporaries. + // strips off any top-level ExprWithCleanups. NewParam->setHasInheritedDefaultArg(); if (OldParam->hasUninstantiatedDefaultArg()) NewParam->setUninstantiatedDefaultArg( @@ -444,7 +463,8 @@ CXXBaseSpecifier * Sema::CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - TypeSourceInfo *TInfo) { + TypeSourceInfo *TInfo, + SourceLocation EllipsisLoc) { QualType BaseType = TInfo->getType(); // C++ [class.union]p1: @@ -455,10 +475,17 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, return 0; } + if (EllipsisLoc.isValid() && + !TInfo->getType()->containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << TInfo->getTypeLoc().getSourceRange(); + EllipsisLoc = SourceLocation(); + } + if (BaseType->isDependentType()) return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, Class->getTagKind() == TTK_Class, - Access, TInfo); + Access, TInfo, EllipsisLoc); SourceLocation BaseLoc = TInfo->getTypeLoc().getBeginLoc(); @@ -493,90 +520,25 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl); assert(CXXBaseDecl && "Base type is not a C++ type"); - // C++0x CWG Issue #817 indicates that [[final]] classes shouldn't be bases. + // C++ [class.derived]p2: + // If a class is marked with the class-virt-specifier final and it appears + // as a base-type-specifier in a base-clause (10 class.derived), the program + // is ill-formed. if (CXXBaseDecl->hasAttr<FinalAttr>()) { - Diag(BaseLoc, diag::err_final_base) << BaseType.getAsString(); + Diag(BaseLoc, diag::err_class_marked_final_used_as_base) + << CXXBaseDecl->getDeclName(); Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl) - << BaseType; + << CXXBaseDecl->getDeclName(); return 0; } - SetClassDeclAttributesFromBase(Class, CXXBaseDecl, Virtual); - if (BaseDecl->isInvalidDecl()) Class->setInvalidDecl(); // Create the base specifier. return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, Class->getTagKind() == TTK_Class, - Access, TInfo); -} - -void Sema::SetClassDeclAttributesFromBase(CXXRecordDecl *Class, - const CXXRecordDecl *BaseClass, - bool BaseIsVirtual) { - // A class with a non-empty base class is not empty. - // FIXME: Standard ref? - if (!BaseClass->isEmpty()) - Class->setEmpty(false); - - // C++ [class.virtual]p1: - // A class that [...] inherits a virtual function is called a polymorphic - // class. - if (BaseClass->isPolymorphic()) - Class->setPolymorphic(true); - - // C++ [dcl.init.aggr]p1: - // An aggregate is [...] a class with [...] no base classes [...]. - Class->setAggregate(false); - - // C++ [class]p4: - // A POD-struct is an aggregate class... - Class->setPOD(false); - - if (BaseIsVirtual) { - // 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 - // class have trivial constructors. - if (!BaseClass->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 (!BaseClass->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 (!BaseClass->hasTrivialCopyAssignment()) - Class->setHasTrivialCopyAssignment(false); - } - - // C++ [class.ctor]p3: - // A destructor is trivial if all the direct base classes of its class - // have trivial destructors. - if (!BaseClass->hasTrivialDestructor()) - Class->setHasTrivialDestructor(false); + Access, TInfo, EllipsisLoc); } /// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is @@ -587,7 +549,8 @@ void Sema::SetClassDeclAttributesFromBase(CXXRecordDecl *Class, BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - ParsedType basetype, SourceLocation BaseLoc) { + ParsedType basetype, SourceLocation BaseLoc, + SourceLocation EllipsisLoc) { if (!classdecl) return true; @@ -598,8 +561,15 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, TypeSourceInfo *TInfo = 0; GetTypeFromParser(basetype, &TInfo); + + if (EllipsisLoc.isInvalid() && + DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo, + UPPC_BaseType)) + return true; + if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange, - Virtual, Access, TInfo)) + Virtual, Access, TInfo, + EllipsisLoc)) return BaseSpec; return true; @@ -885,6 +855,63 @@ Decl *Sema::ActOnAccessSpecifier(AccessSpecifier Access, return ASDecl; } +/// CheckOverrideControl - Check C++0x override control semantics. +void Sema::CheckOverrideControl(const Decl *D) { + const CXXMethodDecl *MD = llvm::dyn_cast<CXXMethodDecl>(D); + if (!MD || !MD->isVirtual()) + return; + + if (MD->isDependentContext()) + return; + + // C++0x [class.virtual]p3: + // If a virtual function is marked with the virt-specifier override and does + // not override a member function of a base class, + // the program is ill-formed. + bool HasOverriddenMethods = + MD->begin_overridden_methods() != MD->end_overridden_methods(); + if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods) { + Diag(MD->getLocation(), + diag::err_function_marked_override_not_overriding) + << MD->getDeclName(); + return; + } + + // C++0x [class.derived]p8: + // In a class definition marked with the class-virt-specifier explicit, + // if a virtual member function that is neither implicitly-declared nor a + // destructor overrides a member function of a base class and it is not + // marked with the virt-specifier override, the program is ill-formed. + if (MD->getParent()->hasAttr<ExplicitAttr>() && !isa<CXXDestructorDecl>(MD) && + HasOverriddenMethods && !MD->hasAttr<OverrideAttr>()) { + llvm::SmallVector<const CXXMethodDecl*, 4> + OverriddenMethods(MD->begin_overridden_methods(), + MD->end_overridden_methods()); + + Diag(MD->getLocation(), diag::err_function_overriding_without_override) + << MD->getDeclName() + << (unsigned)OverriddenMethods.size(); + + for (unsigned I = 0; I != OverriddenMethods.size(); ++I) + Diag(OverriddenMethods[I]->getLocation(), + diag::note_overridden_virtual_function); + } +} + +/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member +/// function overrides a virtual member function marked 'final', according to +/// C++0x [class.virtual]p3. +bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, + const CXXMethodDecl *Old) { + if (!Old->hasAttr<FinalAttr>()) + return false; + + Diag(New->getLocation(), diag::err_final_function_overridden) + << New->getDeclName(); + Diag(Old->getLocation(), diag::note_overridden_virtual_function); + return true; +} + /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one and 'InitExpr' specifies the initializer if @@ -892,12 +919,18 @@ Decl *Sema::ActOnAccessSpecifier(AccessSpecifier Access, Decl * Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, - ExprTy *BW, ExprTy *InitExpr, bool IsDefinition, + ExprTy *BW, const VirtSpecifiers &VS, + ExprTy *InitExpr, bool IsDefinition, bool Deleted) { const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); SourceLocation Loc = NameInfo.getLoc(); + + // For anonymous bitfields, the location should point to the type. + if (Loc.isInvalid()) + Loc = D.getSourceRange().getBegin(); + Expr *BitWidth = static_cast<Expr*>(BW); Expr *Init = static_cast<Expr*>(InitExpr); @@ -951,7 +984,29 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Decl *Member; if (isInstField) { + CXXScopeSpec &SS = D.getCXXScopeSpec(); + + + if (SS.isSet() && !SS.isInvalid()) { + // The user provided a superfluous scope specifier inside a class + // definition: + // + // class X { + // int X::member; + // }; + DeclContext *DC = 0; + if ((DC = computeDeclContext(SS, false)) && DC->Equals(CurContext)) + Diag(D.getIdentifierLoc(), diag::warn_member_extra_qualification) + << Name << FixItHint::CreateRemoval(SS.getRange()); + else + Diag(D.getIdentifierLoc(), diag::err_member_qualification) + << Name << SS.getRange(); + + SS.clear(); + } + // FIXME: Check for template parameters! + // FIXME: Check that the name is an identifier! Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, AS); assert(Member && "HandleField never returns null"); @@ -994,17 +1049,37 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, FunTmpl->getTemplatedDecl()->setAccess(AS); } + if (VS.isOverrideSpecified()) { + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member); + if (!MD || !MD->isVirtual()) { + Diag(Member->getLocStart(), + diag::override_keyword_only_allowed_on_virtual_member_functions) + << "override" << FixItHint::CreateRemoval(VS.getOverrideLoc()); + } else + MD->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context)); + } + if (VS.isFinalSpecified()) { + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member); + if (!MD || !MD->isVirtual()) { + Diag(Member->getLocStart(), + diag::override_keyword_only_allowed_on_virtual_member_functions) + << "final" << FixItHint::CreateRemoval(VS.getFinalLoc()); + } else + MD->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context)); + } + + CheckOverrideControl(Member); + assert((Name || isInstField) && "No identifier for non-field ?"); if (Init) - AddInitializerToDecl(Member, Init, false); + AddInitializerToDecl(Member, Init, false, + DS.getTypeSpecType() == DeclSpec::TST_auto); if (Deleted) // FIXME: Source location is not very good. SetDeclDeleted(Member, D.getSourceRange().getBegin()); - if (isInstField) { + if (isInstField) FieldCollector->Add(cast<FieldDecl>(Member)); - return 0; - } return Member; } @@ -1063,8 +1138,8 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, SourceLocation IdLoc, SourceLocation LParenLoc, ExprTy **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + SourceLocation EllipsisLoc) { if (!ConstructorD) return true; @@ -1084,12 +1159,12 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, // C++ [class.base.init]p2: // Names in a mem-initializer-id are looked up in the scope of the - // constructor’s class and, if not found in that scope, are looked - // up in the scope containing the constructor’s - // definition. [Note: if the constructor’s class contains a member - // with the same name as a direct or virtual base class of the - // class, a mem-initializer-id naming the member or base class and - // composed of a single identifier refers to the class member. A + // constructor's class and, if not found in that scope, are looked + // up in the scope containing the constructor's definition. + // [Note: if the constructor's class contains a member with the + // same name as a direct or virtual base class of the class, a + // mem-initializer-id naming the member or base class and composed + // of a single identifier refers to the class member. A // mem-initializer-id for the hidden base class may be specified // using a qualified name. ] if (!SS.getScopeRep() && !TemplateTypeTy) { @@ -1097,14 +1172,30 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, FieldDecl *Member = 0; DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); - if (Result.first != Result.second) + if (Result.first != Result.second) { Member = dyn_cast<FieldDecl>(*Result.first); - - // FIXME: Handle members of an anonymous union. - - if (Member) - return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, + + if (Member) { + if (EllipsisLoc.isValid()) + Diag(EllipsisLoc, diag::err_pack_expansion_member_init) + << MemberOrBase << SourceRange(IdLoc, RParenLoc); + + return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, LParenLoc, RParenLoc); + } + + // Handle anonymous union case. + if (IndirectFieldDecl* IndirectField + = dyn_cast<IndirectFieldDecl>(*Result.first)) { + if (EllipsisLoc.isValid()) + Diag(EllipsisLoc, diag::err_pack_expansion_member_init) + << MemberOrBase << SourceRange(IdLoc, RParenLoc); + + return BuildMemberInitializer(IndirectField, (Expr**)Args, + NumArgs, IdLoc, + LParenLoc, RParenLoc); + } + } } // It didn't name a member, so see if it names a class. QualType BaseType; @@ -1212,7 +1303,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc); return BuildBaseInitializer(BaseType, TInfo, (Expr **)Args, NumArgs, - LParenLoc, RParenLoc, ClassDecl); + LParenLoc, RParenLoc, ClassDecl, EllipsisLoc); } /// Checks an initializer expression for use of uninitialized fields, such as @@ -1220,8 +1311,10 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, /// uninitialized field was used an updates the SourceLocation parameter; false /// otherwise. static bool InitExprContainsUninitializedFields(const Stmt *S, - const FieldDecl *LhsField, + const ValueDecl *LhsField, SourceLocation *L) { + assert(isa<FieldDecl>(LhsField) || isa<IndirectFieldDecl>(LhsField)); + if (isa<CallExpr>(S)) { // Do not descend into function calls or constructors, as the use // of an uninitialized field may be valid. One would have to inspect @@ -1232,6 +1325,20 @@ static bool InitExprContainsUninitializedFields(const Stmt *S, } if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) { const NamedDecl *RhsField = ME->getMemberDecl(); + + if (const VarDecl *VD = dyn_cast<VarDecl>(RhsField)) { + // The member expression points to a static data member. + assert(VD->isStaticDataMember() && + "Member points to non-static data member!"); + (void)VD; + return false; + } + + if (isa<EnumConstantDecl>(RhsField)) { + // The member expression points to an enum. + return false; + } + if (RhsField == LhsField) { // Initializing a field with itself. Throw a warning. // But wait; there are exceptions! @@ -1247,9 +1354,16 @@ static bool InitExprContainsUninitializedFields(const Stmt *S, *L = ME->getMemberLoc(); return true; } + } else if (isa<SizeOfAlignOfExpr>(S)) { + // sizeof/alignof doesn't reference contents, do not warn. + return false; + } else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(S)) { + // address-of doesn't reference contents (the pointer may be dereferenced + // in the same expression but it would be rare; and weird). + if (UOE->getOpcode() == UO_AddrOf) + return false; } - for (Stmt::const_child_iterator it = S->child_begin(), e = S->child_end(); - it != e; ++it) { + for (Stmt::const_child_range it = S->children(); it; ++it) { if (!*it) { // An expression such as 'member(arg ?: "")' may trigger this. continue; @@ -1261,10 +1375,18 @@ static bool InitExprContainsUninitializedFields(const Stmt *S, } MemInitResult -Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, +Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { + FieldDecl *DirectMember = dyn_cast<FieldDecl>(Member); + IndirectFieldDecl *IndirectMember = dyn_cast<IndirectFieldDecl>(Member); + assert((DirectMember || IndirectMember) && + "Member must be a FieldDecl or IndirectFieldDecl"); + + if (Member->isInvalidDecl()) + return true; + // Diagnose value-uses of fields to initialize themselves, e.g. // foo(foo) // where foo is not also a parameter to the constructor. @@ -1286,12 +1408,12 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); + Expr *Init; if (Member->getType()->isDependentType() || HasDependentArg) { // Can't check initialization for a member of dependent type or when // any of the arguments are type-dependent expressions. - Expr *Init - = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc); + Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + RParenLoc); // Erase any temporaries within this evaluation context; we're not // going to track them in the AST, since we'll be rebuilding the @@ -1299,69 +1421,78 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, ExprTemporaries.erase( ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries, ExprTemporaries.end()); - - return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, - LParenLoc, - Init, - RParenLoc); - + } else { + // Initialize the member. + InitializedEntity MemberEntity = + DirectMember ? InitializedEntity::InitializeMember(DirectMember, 0) + : InitializedEntity::InitializeMember(IndirectMember, 0); + InitializationKind Kind = + InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc); + + InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); + + ExprResult MemberInit = + InitSeq.Perform(*this, MemberEntity, Kind, + MultiExprArg(*this, Args, NumArgs), 0); + if (MemberInit.isInvalid()) + return true; + + CheckImplicitConversions(MemberInit.get(), LParenLoc); + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + MemberInit = MaybeCreateExprWithCleanups(MemberInit); + if (MemberInit.isInvalid()) + return true; + + // If we are in a dependent context, template instantiation will + // perform this type-checking again. Just save the arguments that we + // received in a ParenListExpr. + // FIXME: This isn't quite ideal, since our ASTs don't capture all + // of the information that we have about the member + // initializer. However, deconstructing the ASTs is a dicey process, + // and this approach is far more likely to get the corner cases right. + if (CurContext->isDependentContext()) + Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + RParenLoc); + else + Init = MemberInit.get(); } - - if (Member->isInvalidDecl()) - return true; - - // Initialize the member. - InitializedEntity MemberEntity = - InitializedEntity::InitializeMember(Member, 0); - InitializationKind Kind = - InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc); - - InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); - - ExprResult MemberInit = - InitSeq.Perform(*this, MemberEntity, Kind, - MultiExprArg(*this, Args, NumArgs), 0); - if (MemberInit.isInvalid()) - return true; - - // C++0x [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - MemberInit = MaybeCreateCXXExprWithTemporaries(MemberInit.get()); - if (MemberInit.isInvalid()) - return true; - - // If we are in a dependent context, template instantiation will - // perform this type-checking again. Just save the arguments that we - // received in a ParenListExpr. - // FIXME: This isn't quite ideal, since our ASTs don't capture all - // of the information that we have about the member - // initializer. However, deconstructing the ASTs is a dicey process, - // and this approach is far more likely to get the corner cases right. - if (CurContext->isDependentContext()) { - // Bump the reference count of all of the arguments. - for (unsigned I = 0; I != NumArgs; ++I) - Args[I]->Retain(); - Expr *Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc); - return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, - LParenLoc, - Init, + if (DirectMember) { + return new (Context) CXXCtorInitializer(Context, DirectMember, + IdLoc, LParenLoc, Init, + RParenLoc); + } else { + return new (Context) CXXCtorInitializer(Context, IndirectMember, + IdLoc, LParenLoc, Init, RParenLoc); } +} - return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, - LParenLoc, - MemberInit.get(), - RParenLoc); +MemInitResult +Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, + Expr **Args, unsigned NumArgs, + SourceLocation LParenLoc, + SourceLocation RParenLoc, + CXXRecordDecl *ClassDecl, + SourceLocation EllipsisLoc) { + SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin(); + if (!LangOpts.CPlusPlus0x) + return Diag(Loc, diag::err_delegation_0x_only) + << TInfo->getTypeLoc().getLocalSourceRange(); + + return Diag(Loc, diag::err_delegation_unimplemented) + << TInfo->getTypeLoc().getLocalSourceRange(); } MemInitResult Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Expr **Args, unsigned NumArgs, SourceLocation LParenLoc, SourceLocation RParenLoc, - CXXRecordDecl *ClassDecl) { + CXXRecordDecl *ClassDecl, + SourceLocation EllipsisLoc) { bool HasDependentArg = false; for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); @@ -1375,16 +1506,40 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // 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 + // 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. bool Dependent = BaseType->isDependentType() || HasDependentArg; + if (EllipsisLoc.isValid()) { + // This is a pack expansion. + if (!BaseType->containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << SourceRange(BaseLoc, RParenLoc); + + EllipsisLoc = SourceLocation(); + } + } else { + // Check for any unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(BaseLoc, BaseTInfo, UPPC_Initializer)) + return true; + + for (unsigned I = 0; I != NumArgs; ++I) + if (DiagnoseUnexpandedParameterPack(Args[I])) + return true; + } + // Check for direct and virtual base classes. const CXXBaseSpecifier *DirectBaseSpec = 0; const CXXBaseSpecifier *VirtualBaseSpec = 0; if (!Dependent) { + if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0), + BaseType)) + return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs, + LParenLoc, RParenLoc, ClassDecl, + EllipsisLoc); + FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, VirtualBaseSpec); @@ -1421,11 +1576,12 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries, ExprTemporaries.end()); - return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + return new (Context) CXXCtorInitializer(Context, BaseTInfo, /*IsVirtual=*/false, LParenLoc, BaseInit.takeAs<Expr>(), - RParenLoc); + RParenLoc, + EllipsisLoc); } // C++ [base.class.init]p2: @@ -1454,11 +1610,13 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, MultiExprArg(*this, Args, NumArgs), 0); if (BaseInit.isInvalid()) return true; + + CheckImplicitConversions(BaseInit.get(), LParenLoc); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. - BaseInit = MaybeCreateCXXExprWithTemporaries(BaseInit.get()); + BaseInit = MaybeCreateExprWithCleanups(BaseInit); if (BaseInit.isInvalid()) return true; @@ -1470,25 +1628,23 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // initializer. However, deconstructing the ASTs is a dicey process, // and this approach is far more likely to get the corner cases right. if (CurContext->isDependentContext()) { - // Bump the reference count of all of the arguments. - for (unsigned I = 0; I != NumArgs; ++I) - Args[I]->Retain(); - ExprResult Init = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, RParenLoc)); - return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + return new (Context) CXXCtorInitializer(Context, BaseTInfo, BaseSpec->isVirtual(), LParenLoc, Init.takeAs<Expr>(), - RParenLoc); + RParenLoc, + EllipsisLoc); } - return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + return new (Context) CXXCtorInitializer(Context, BaseTInfo, BaseSpec->isVirtual(), LParenLoc, BaseInit.takeAs<Expr>(), - RParenLoc); + RParenLoc, + EllipsisLoc); } /// ImplicitInitializerKind - How an implicit base or member initializer should @@ -1504,7 +1660,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ImplicitInitializerKind ImplicitInitKind, CXXBaseSpecifier *BaseSpec, bool IsInheritedVirtualBase, - CXXBaseOrMemberInitializer *&CXXBaseInit) { + CXXCtorInitializer *&CXXBaseInit) { InitializedEntity InitEntity = InitializedEntity::InitializeBase(SemaRef.Context, BaseSpec, IsInheritedVirtualBase); @@ -1527,7 +1683,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, Expr *CopyCtorArg = DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, - Constructor->getLocation(), ParamType, 0); + Constructor->getLocation(), ParamType, + VK_LValue, 0); // Cast to the base class to avoid ambiguities. QualType ArgTy = @@ -1554,20 +1711,18 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, assert(false && "Unhandled initializer kind!"); } - if (BaseInit.isInvalid()) - return true; - - BaseInit = SemaRef.MaybeCreateCXXExprWithTemporaries(BaseInit.get()); + BaseInit = SemaRef.MaybeCreateExprWithCleanups(BaseInit); if (BaseInit.isInvalid()) return true; CXXBaseInit = - new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context, + new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(), SourceLocation()), BaseSpec->isVirtual(), SourceLocation(), BaseInit.takeAs<Expr>(), + SourceLocation(), SourceLocation()); return false; @@ -1577,7 +1732,7 @@ static bool BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ImplicitInitializerKind ImplicitInitKind, FieldDecl *Field, - CXXBaseOrMemberInitializer *&CXXMemberInit) { + CXXCtorInitializer *&CXXMemberInit) { if (Field->isInvalidDecl()) return true; @@ -1589,7 +1744,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, Expr *MemberExprBase = DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, - Loc, ParamType, 0); + Loc, ParamType, VK_LValue, 0); // Build a reference to this field within the parameter. CXXScopeSpec SS; @@ -1634,7 +1789,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, // Create a reference to the iteration variable. ExprResult IterationVarRef - = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, Loc); + = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_RValue, Loc); assert(!IterationVarRef.isInvalid() && "Reference to invented variable cannot fail!"); @@ -1671,12 +1826,12 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ExprResult MemberInit = InitSeq.Perform(SemaRef, Entities.back(), InitKind, MultiExprArg(&CopyCtorArgE, 1)); - MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(MemberInit.get()); + MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) return true; CXXMemberInit - = CXXBaseOrMemberInitializer::Create(SemaRef.Context, Field, Loc, Loc, + = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc, Loc, MemberInit.takeAs<Expr>(), Loc, IndexVariables.data(), IndexVariables.size()); @@ -1696,15 +1851,13 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); ExprResult MemberInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg()); - if (MemberInit.isInvalid()) - return true; - MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(MemberInit.get()); + MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) return true; CXXMemberInit = - new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context, + new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, Loc, Loc, MemberInit.get(), Loc); @@ -1742,8 +1895,8 @@ struct BaseAndFieldInfo { CXXConstructorDecl *Ctor; bool AnyErrorsInInits; ImplicitInitializerKind IIK; - llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields; - llvm::SmallVector<CXXBaseOrMemberInitializer*, 8> AllToInit; + llvm::DenseMap<const void *, CXXCtorInitializer*> AllBaseFields; + llvm::SmallVector<CXXCtorInitializer*, 8> AllToInit; BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits) : S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) { @@ -1756,26 +1909,12 @@ struct BaseAndFieldInfo { }; } -static void RecordFieldInitializer(BaseAndFieldInfo &Info, - FieldDecl *Top, FieldDecl *Field, - CXXBaseOrMemberInitializer *Init) { - // If the member doesn't need to be initialized, Init will still be null. - if (!Init) - return; - - Info.AllToInit.push_back(Init); - if (Field != Top) { - Init->setMember(Top); - Init->setAnonUnionMember(Field); - } -} - static bool CollectFieldInitializer(BaseAndFieldInfo &Info, FieldDecl *Top, FieldDecl *Field) { // Overwhelmingly common case: we have a direct initializer for this field. - if (CXXBaseOrMemberInitializer *Init = Info.AllBaseFields.lookup(Field)) { - RecordFieldInitializer(Info, Top, Field, Init); + if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field)) { + Info.AllToInit.push_back(Init); return false; } @@ -1794,8 +1933,8 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // First check for an explicit initializer for one field. for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), EA = FieldClassDecl->field_end(); FA != EA; FA++) { - if (CXXBaseOrMemberInitializer *Init = Info.AllBaseFields.lookup(*FA)) { - RecordFieldInitializer(Info, Top, *FA, Init); + if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(*FA)) { + Info.AllToInit.push_back(Init); // Once we've initialized a field of an anonymous union, the union // field in the class is also initialized, so exit immediately. @@ -1828,29 +1967,31 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, if (Info.AnyErrorsInInits) return false; - CXXBaseOrMemberInitializer *Init = 0; + CXXCtorInitializer *Init = 0; if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Init)) return true; - RecordFieldInitializer(Info, Top, Field, Init); + if (Init) + Info.AllToInit.push_back(Init); + return false; } bool -Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **Initializers, +Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, + CXXCtorInitializer **Initializers, unsigned NumInitializers, bool AnyErrors) { if (Constructor->getDeclContext()->isDependentContext()) { // Just store the initializers as written, they will be checked during // instantiation. if (NumInitializers > 0) { - Constructor->setNumBaseOrMemberInitializers(NumInitializers); - CXXBaseOrMemberInitializer **baseOrMemberInitializers = - new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; + Constructor->setNumCtorInitializers(NumInitializers); + CXXCtorInitializer **baseOrMemberInitializers = + new (Context) CXXCtorInitializer*[NumInitializers]; memcpy(baseOrMemberInitializers, Initializers, - NumInitializers * sizeof(CXXBaseOrMemberInitializer*)); - Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); + NumInitializers * sizeof(CXXCtorInitializer*)); + Constructor->setCtorInitializers(baseOrMemberInitializers); } return false; @@ -1867,12 +2008,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, bool HadError = false; for (unsigned i = 0; i < NumInitializers; i++) { - CXXBaseOrMemberInitializer *Member = Initializers[i]; + CXXCtorInitializer *Member = Initializers[i]; if (Member->isBaseInitializer()) Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member; else - Info.AllBaseFields[Member->getMember()] = Member; + Info.AllBaseFields[Member->getAnyMember()] = Member; } // Keep track of the direct virtual bases. @@ -1887,12 +2028,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) { - if (CXXBaseOrMemberInitializer *Value + if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { Info.AllToInit.push_back(Value); } else if (!AnyErrors) { bool IsInheritedVirtualBase = !DirectVBases.count(VBase); - CXXBaseOrMemberInitializer *CXXBaseInit; + CXXCtorInitializer *CXXBaseInit; if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, VBase, IsInheritedVirtualBase, CXXBaseInit)) { @@ -1911,11 +2052,11 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, if (Base->isVirtual()) continue; - if (CXXBaseOrMemberInitializer *Value + if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { Info.AllToInit.push_back(Value); } else if (!AnyErrors) { - CXXBaseOrMemberInitializer *CXXBaseInit; + CXXCtorInitializer *CXXBaseInit; if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, Base, /*IsInheritedVirtualBase=*/false, CXXBaseInit)) { @@ -1941,12 +2082,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, NumInitializers = Info.AllToInit.size(); if (NumInitializers > 0) { - Constructor->setNumBaseOrMemberInitializers(NumInitializers); - CXXBaseOrMemberInitializer **baseOrMemberInitializers = - new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; + Constructor->setNumCtorInitializers(NumInitializers); + CXXCtorInitializer **baseOrMemberInitializers = + new (Context) CXXCtorInitializer*[NumInitializers]; memcpy(baseOrMemberInitializers, Info.AllToInit.data(), - NumInitializers * sizeof(CXXBaseOrMemberInitializer*)); - Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); + NumInitializers * sizeof(CXXCtorInitializer*)); + Constructor->setCtorInitializers(baseOrMemberInitializers); // Constructors implicitly reference the base and member // destructors. @@ -1967,25 +2108,18 @@ static void *GetKeyForTopLevelField(FieldDecl *Field) { } static void *GetKeyForBase(ASTContext &Context, QualType BaseType) { - return Context.getCanonicalType(BaseType).getTypePtr(); + return const_cast<Type*>(Context.getCanonicalType(BaseType).getTypePtr()); } static void *GetKeyForMember(ASTContext &Context, - CXXBaseOrMemberInitializer *Member, - bool MemberMaybeAnon = false) { - if (!Member->isMemberInitializer()) + CXXCtorInitializer *Member) { + if (!Member->isAnyMemberInitializer()) return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0)); // For fields injected into the class via declaration of an anonymous union, // use its anonymous union class declaration as the unique key. - FieldDecl *Field = Member->getMember(); - - // After SetBaseOrMemberInitializers 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(); - + FieldDecl *Field = Member->getAnyMember(); + // If the field is a member of an anonymous struct or union, our key // is the anonymous record decl that's a direct child of the class. RecordDecl *RD = Field->getParent(); @@ -2007,13 +2141,24 @@ static void *GetKeyForMember(ASTContext &Context, static void DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, const CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **Inits, + CXXCtorInitializer **Inits, unsigned NumInits) { if (Constructor->getDeclContext()->isDependentContext()) return; - if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order) - == Diagnostic::Ignored) + // Don't check initializers order unless the warning is enabled at the + // location of at least one initializer. + bool ShouldCheckOrder = false; + for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) { + CXXCtorInitializer *Init = Inits[InitIndex]; + if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order, + Init->getSourceLocation()) + != Diagnostic::Ignored) { + ShouldCheckOrder = true; + break; + } + } + if (!ShouldCheckOrder) return; // Build the list of bases and members in the order that they'll @@ -2045,10 +2190,10 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, unsigned NumIdealInits = IdealInitKeys.size(); unsigned IdealIndex = 0; - CXXBaseOrMemberInitializer *PrevInit = 0; + CXXCtorInitializer *PrevInit = 0; for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) { - CXXBaseOrMemberInitializer *Init = Inits[InitIndex]; - void *InitKey = GetKeyForMember(SemaRef.Context, Init, true); + CXXCtorInitializer *Init = Inits[InitIndex]; + void *InitKey = GetKeyForMember(SemaRef.Context, Init); // Scan forward to try to find this initializer in the idealized // initializers list. @@ -2064,13 +2209,13 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, SemaRef.Diag(PrevInit->getSourceLocation(), diag::warn_initializer_out_of_order); - if (PrevInit->isMemberInitializer()) - D << 0 << PrevInit->getMember()->getDeclName(); + if (PrevInit->isAnyMemberInitializer()) + D << 0 << PrevInit->getAnyMember()->getDeclName(); else D << 1 << PrevInit->getBaseClassInfo()->getType(); - if (Init->isMemberInitializer()) - D << 0 << Init->getMember()->getDeclName(); + if (Init->isAnyMemberInitializer()) + D << 0 << Init->getAnyMember()->getDeclName(); else D << 1 << Init->getBaseClassInfo()->getType(); @@ -2089,8 +2234,8 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, namespace { bool CheckRedundantInit(Sema &S, - CXXBaseOrMemberInitializer *Init, - CXXBaseOrMemberInitializer *&PrevInit) { + CXXCtorInitializer *Init, + CXXCtorInitializer *&PrevInit) { if (!PrevInit) { PrevInit = Init; return false; @@ -2102,7 +2247,7 @@ bool CheckRedundantInit(Sema &S, << Field->getDeclName() << Init->getSourceRange(); else { - Type *BaseClass = Init->getBaseClass(); + const Type *BaseClass = Init->getBaseClass(); assert(BaseClass && "neither field nor base"); S.Diag(Init->getSourceLocation(), diag::err_multiple_base_initialization) @@ -2115,13 +2260,13 @@ bool CheckRedundantInit(Sema &S, return true; } -typedef std::pair<NamedDecl *, CXXBaseOrMemberInitializer *> UnionEntry; +typedef std::pair<NamedDecl *, CXXCtorInitializer *> UnionEntry; typedef llvm::DenseMap<RecordDecl*, UnionEntry> RedundantUnionMap; bool CheckRedundantUnionInit(Sema &S, - CXXBaseOrMemberInitializer *Init, + CXXCtorInitializer *Init, RedundantUnionMap &Unions) { - FieldDecl *Field = Init->getMember(); + FieldDecl *Field = Init->getAnyMember(); RecordDecl *Parent = Field->getParent(); if (!Parent->isAnonymousStructOrUnion()) return false; @@ -2170,26 +2315,26 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, return; } - CXXBaseOrMemberInitializer **MemInits = - reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits); + CXXCtorInitializer **MemInits = + reinterpret_cast<CXXCtorInitializer **>(meminits); // Mapping for the duplicate initializers check. // For member initializers, this is keyed with a FieldDecl*. // For base initializers, this is keyed with a Type*. - llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members; + llvm::DenseMap<void*, CXXCtorInitializer *> Members; // Mapping for the inconsistent anonymous-union initializers check. RedundantUnionMap MemberUnions; bool HadError = false; for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Init = MemInits[i]; + CXXCtorInitializer *Init = MemInits[i]; // Set the source order index. Init->setSourceOrder(i); - if (Init->isMemberInitializer()) { - FieldDecl *Field = Init->getMember(); + if (Init->isAnyMemberInitializer()) { + FieldDecl *Field = Init->getAnyMember(); if (CheckRedundantInit(*this, Init, Members[Field]) || CheckRedundantUnionInit(*this, Init, MemberUnions)) HadError = true; @@ -2205,7 +2350,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits, NumMemInits); - SetBaseOrMemberInitializers(Constructor, MemInits, NumMemInits, AnyErrors); + SetCtorInitializers(Constructor, MemInits, NumMemInits, AnyErrors); } void @@ -2304,7 +2449,7 @@ void Sema::ActOnDefaultCtorInitializers(Decl *CDtorDecl) { if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(CDtorDecl)) - SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false); + SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false); } bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, @@ -2391,7 +2536,7 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) { Diag(SO->second.front().Method->getLocation(), diag::note_pure_virtual_function) - << SO->second.front().Method->getDeclName(); + << SO->second.front().Method->getDeclName() << RD->getDeclName(); } } @@ -2566,84 +2711,9 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info, /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { - if (!Record || Record->isInvalidDecl()) - return; - - if (!Record->isDependentType()) - AddImplicitlyDeclaredMembersToClass(Record); - - if (Record->isInvalidDecl()) + if (!Record) return; - // Set access bits correctly on the directly-declared conversions. - UnresolvedSetImpl *Convs = Record->getConversionFunctions(); - for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); I != E; ++I) - Convs->setAccess(I, (*I)->getAccess()); - - // Determine whether we need to check for final overriders. We do - // this either when there are virtual base classes (in which case we - // may end up finding multiple final overriders for a given virtual - // function) or any of the base classes is abstract (in which case - // we might detect that this class is abstract). - bool CheckFinalOverriders = false; - if (Record->isPolymorphic() && !Record->isInvalidDecl() && - !Record->isDependentType()) { - if (Record->getNumVBases()) - CheckFinalOverriders = true; - else if (!Record->isAbstract()) { - for (CXXRecordDecl::base_class_const_iterator B = Record->bases_begin(), - BEnd = Record->bases_end(); - B != BEnd; ++B) { - CXXRecordDecl *BaseDecl - = cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl()); - if (BaseDecl->isAbstract()) { - CheckFinalOverriders = true; - break; - } - } - } - } - - if (CheckFinalOverriders) { - CXXFinalOverriderMap FinalOverriders; - Record->getFinalOverriders(FinalOverriders); - - for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), - MEnd = FinalOverriders.end(); - M != MEnd; ++M) { - for (OverridingMethods::iterator SO = M->second.begin(), - SOEnd = M->second.end(); - SO != SOEnd; ++SO) { - assert(SO->second.size() > 0 && - "All virtual functions have overridding virtual functions"); - if (SO->second.size() == 1) { - // C++ [class.abstract]p4: - // A class is abstract if it contains or inherits at least one - // pure virtual function for which the final overrider is pure - // virtual. - if (SO->second.front().Method->isPure()) - Record->setAbstract(true); - continue; - } - - // C++ [class.virtual]p2: - // In a derived class, if a virtual member function of a base - // class subobject has more than one final overrider the - // program is ill-formed. - Diag(Record->getLocation(), diag::err_multiple_final_overriders) - << (NamedDecl *)M->first << Record; - Diag(M->first->getLocation(), diag::note_overridden_virtual_function); - for (OverridingMethods::overriding_iterator OM = SO->second.begin(), - OMEnd = SO->second.end(); - OM != OMEnd; ++OM) - Diag(OM->Method->getLocation(), diag::note_final_overrider) - << (NamedDecl *)M->first << OM->Method->getParent(); - - Record->setInvalidDecl(); - } - } - } - if (Record->isAbstract() && !Record->isInvalidDecl()) { AbstractUsageInfo Info(*this, Record); CheckAbstractClassUsage(Info, Record); @@ -2673,8 +2743,149 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } - if (Record->isDynamicClass()) + if (Record->isDynamicClass() && !Record->isDependentType()) DynamicClasses.push_back(Record); + + if (Record->getIdentifier()) { + // C++ [class.mem]p13: + // If T is the name of a class, then each of the following shall have a + // name different from T: + // - every member of every anonymous union that is a member of class T. + // + // C++ [class.mem]p14: + // In addition, if class T has a user-declared constructor (12.1), every + // non-static data member of class T shall have a name different from T. + for (DeclContext::lookup_result R = Record->lookup(Record->getDeclName()); + R.first != R.second; ++R.first) { + NamedDecl *D = *R.first; + if ((isa<FieldDecl>(D) && Record->hasUserDeclaredConstructor()) || + isa<IndirectFieldDecl>(D)) { + Diag(D->getLocation(), diag::err_member_name_of_class) + << D->getDeclName(); + break; + } + } + } + + // Warn if the class has virtual methods but non-virtual public destructor. + if (Record->isPolymorphic() && !Record->isDependentType()) { + CXXDestructorDecl *dtor = Record->getDestructor(); + if (!dtor || (!dtor->isVirtual() && dtor->getAccess() == AS_public)) + Diag(dtor ? dtor->getLocation() : Record->getLocation(), + diag::warn_non_virtual_dtor) << Context.getRecordType(Record); + } + + // See if a method overloads virtual methods in a base + /// class without overriding any. + if (!Record->isDependentType()) { + for (CXXRecordDecl::method_iterator M = Record->method_begin(), + MEnd = Record->method_end(); + M != MEnd; ++M) { + DiagnoseHiddenVirtualMethods(Record, *M); + } + } + + // Declare inherited constructors. We do this eagerly here because: + // - The standard requires an eager diagnostic for conflicting inherited + // constructors from different classes. + // - The lazy declaration of the other implicit constructors is so as to not + // waste space and performance on classes that are not meant to be + // instantiated (e.g. meta-functions). This doesn't apply to classes that + // have inherited constructors. + DeclareInheritedConstructors(Record); +} + +/// \brief Data used with FindHiddenVirtualMethod +struct FindHiddenVirtualMethodData { + Sema *S; + CXXMethodDecl *Method; + llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverridenAndUsingBaseMethods; + llvm::SmallVector<CXXMethodDecl *, 8> OverloadedMethods; +}; + +/// \brief Member lookup function that determines whether a given C++ +/// method overloads virtual methods in a base class without overriding any, +/// to be used with CXXRecordDecl::lookupInBases(). +static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *UserData) { + RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + + FindHiddenVirtualMethodData &Data + = *static_cast<FindHiddenVirtualMethodData*>(UserData); + + DeclarationName Name = Data.Method->getDeclName(); + assert(Name.getNameKind() == DeclarationName::Identifier); + + bool foundSameNameMethod = false; + llvm::SmallVector<CXXMethodDecl *, 8> overloadedMethods; + for (Path.Decls = BaseRecord->lookup(Name); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + NamedDecl *D = *Path.Decls.first; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { + MD = MD->getCanonicalDecl(); + foundSameNameMethod = true; + // Interested only in hidden virtual methods. + if (!MD->isVirtual()) + continue; + // If the method we are checking overrides a method from its base + // don't warn about the other overloaded methods. + if (!Data.S->IsOverload(Data.Method, MD, false)) + return true; + // Collect the overload only if its hidden. + if (!Data.OverridenAndUsingBaseMethods.count(MD)) + overloadedMethods.push_back(MD); + } + } + + if (foundSameNameMethod) + Data.OverloadedMethods.append(overloadedMethods.begin(), + overloadedMethods.end()); + return foundSameNameMethod; +} + +/// \brief See if a method overloads virtual methods in a base class without +/// overriding any. +void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { + if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual, + MD->getLocation()) == Diagnostic::Ignored) + return; + if (MD->getDeclName().getNameKind() != DeclarationName::Identifier) + return; + + CXXBasePaths Paths(/*FindAmbiguities=*/true, // true to look in all bases. + /*bool RecordPaths=*/false, + /*bool DetectVirtual=*/false); + FindHiddenVirtualMethodData Data; + Data.Method = MD; + Data.S = this; + + // Keep the base methods that were overriden or introduced in the subclass + // by 'using' in a set. A base method not in this set is hidden. + for (DeclContext::lookup_result res = DC->lookup(MD->getDeclName()); + res.first != res.second; ++res.first) { + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*res.first)) + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); + I != E; ++I) + Data.OverridenAndUsingBaseMethods.insert((*I)->getCanonicalDecl()); + if (UsingShadowDecl *shad = dyn_cast<UsingShadowDecl>(*res.first)) + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(shad->getTargetDecl())) + Data.OverridenAndUsingBaseMethods.insert(MD->getCanonicalDecl()); + } + + if (DC->lookupInBases(&FindHiddenVirtualMethod, &Data, Paths) && + !Data.OverloadedMethods.empty()) { + Diag(MD->getLocation(), diag::warn_overloaded_virtual) + << MD << (Data.OverloadedMethods.size() > 1); + + for (unsigned i = 0, e = Data.OverloadedMethods.size(); i != e; ++i) { + CXXMethodDecl *overloadedMD = Data.OverloadedMethods[i]; + Diag(overloadedMD->getLocation(), + diag::note_hidden_overloaded_virtual_declared_here) << overloadedMD; + } + } } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, @@ -2915,7 +3126,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, SC = SC_None; } - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); if (FTI.TypeQuals != 0) { if (FTI.TypeQuals & Qualifiers::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) @@ -2926,20 +3137,31 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, if (FTI.TypeQuals & Qualifiers::Restrict) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "restrict" << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); } + // C++0x [class.ctor]p4: + // A constructor shall not be declared with a ref-qualifier. + if (FTI.hasRefQualifier()) { + Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_constructor) + << FTI.RefQualifierIsLValueRef + << FixItHint::CreateRemoval(FTI.getRefQualifierLoc()); + D.setInvalidType(); + } + // 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. const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); + if (Proto->getResultType() == Context.VoidTy && !D.isInvalidType()) + return R; + + FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); + EPI.TypeQuals = 0; + EPI.RefQualifier = RQ_None; + return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(), - Proto->getNumArgs(), - Proto->isVariadic(), 0, - Proto->hasExceptionSpec(), - Proto->hasAnyExceptionSpec(), - Proto->getNumExceptions(), - Proto->exception_begin(), - Proto->getExtInfo()); + Proto->getNumArgs(), EPI); } /// CheckConstructor - Checks a fully-formed constructor for @@ -2977,13 +3199,6 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { Constructor->setInvalidDecl(); } } - - // Notify the class that we've added a constructor. In principle we - // don't need to do this for out-of-line declarations; in practice - // we only instantiate the most recent declaration of a method, so - // we have to call this for everything but friends. - if (!Constructor->getFriendObjectKind()) - ClassDecl->addedConstructor(Context, Constructor); } /// CheckDestructor - Checks a fully-formed destructor definition for @@ -3071,7 +3286,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, << SourceRange(D.getIdentifierLoc()); } - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); if (FTI.TypeQuals != 0 && !D.isInvalidType()) { if (FTI.TypeQuals & Qualifiers::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) @@ -3085,6 +3300,15 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, D.setInvalidType(); } + // C++0x [class.dtor]p2: + // A destructor shall not be declared with a ref-qualifier. + if (FTI.hasRefQualifier()) { + Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_destructor) + << FTI.RefQualifierIsLValueRef + << FixItHint::CreateRemoval(FTI.getRefQualifierLoc()); + D.setInvalidType(); + } + // Make sure we don't have any parameters. if (FTI.NumArgs > 0 && !FTIHasSingleVoidArgument(FTI)) { Diag(D.getIdentifierLoc(), diag::err_destructor_with_params); @@ -3104,16 +3328,15 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, // parameters (in case any of the errors above fired) and with // "void" as the return type, since destructors don't have return // types. + if (!D.isInvalidType()) + return R; + const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); - if (!Proto) - return QualType(); - - return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, - Proto->hasExceptionSpec(), - Proto->hasAnyExceptionSpec(), - Proto->getNumExceptions(), - Proto->exception_begin(), - Proto->getExtInfo()); + FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); + EPI.Variadic = false; + EPI.TypeQuals = 0; + EPI.RefQualifier = RQ_None; + return Context.getFunctionType(Context.VoidTy, 0, 0, EPI); } /// CheckConversionDeclarator - Called by ActOnDeclarator to check the @@ -3161,7 +3384,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params); // Delete the parameters. - D.getTypeObject(0).Fun.freeArgs(); + D.getFunctionTypeInfo().freeArgs(); D.setInvalidType(); } else if (Proto->isVariadic()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); @@ -3193,15 +3416,8 @@ 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. - if (D.isInvalidType()) { - R = Context.getFunctionType(ConvType, 0, 0, false, - Proto->getTypeQuals(), - Proto->hasExceptionSpec(), - Proto->hasAnyExceptionSpec(), - Proto->getNumExceptions(), - Proto->exception_begin(), - Proto->getExtInfo()); - } + if (D.isInvalidType()) + R = Context.getFunctionType(ConvType, 0, 0, Proto->getExtProtoInfo()); // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) @@ -3234,7 +3450,10 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); if (const ReferenceType *ConvTypeRef = ConvType->getAs<ReferenceType>()) ConvType = ConvTypeRef->getPointeeType(); - if (ConvType->isRecordType()) { + if (Conversion->getTemplateSpecializationKind() != TSK_Undeclared && + Conversion->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) + /* Suppress diagnostics for instantiations. */; + else if (ConvType->isRecordType()) { ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType(); if (ConvType == ClassType) Diag(Conversion->getLocation(), diag::warn_conv_to_self_not_used) @@ -3247,25 +3466,10 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { << ClassType << ConvType; } - if (Conversion->getPrimaryTemplate()) { - // ignore specializations - } else if (Conversion->getPreviousDeclaration()) { - if (FunctionTemplateDecl *ConversionTemplate - = Conversion->getDescribedFunctionTemplate()) { - if (ClassDecl->replaceConversion( - ConversionTemplate->getPreviousDeclaration(), - ConversionTemplate)) - return ConversionTemplate; - } else if (ClassDecl->replaceConversion(Conversion->getPreviousDeclaration(), - Conversion)) - return Conversion; - assert(Conversion->isInvalidDecl() && "Conversion should not get here."); - } else if (FunctionTemplateDecl *ConversionTemplate - = Conversion->getDescribedFunctionTemplate()) - ClassDecl->addConversionFunction(ConversionTemplate); - else - ClassDecl->addConversionFunction(Conversion); - + if (FunctionTemplateDecl *ConversionTemplate + = Conversion->getDescribedFunctionTemplate()) + return ConversionTemplate; + return Conversion; } @@ -3293,20 +3497,22 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList); - if (const VisibilityAttr *attr = Namespc->getAttr<VisibilityAttr>()) - PushVisibilityAttr(attr); + if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>()) + PushNamespaceVisibilityAttr(Attr); if (II) { // C++ [namespace.def]p2: - // The identifier in an original-namespace-definition shall not have been - // previously defined in the declarative region in which the - // original-namespace-definition appears. The identifier in an - // original-namespace-definition is the name of the namespace. Subsequently - // in that declarative region, it is treated as an original-namespace-name. - - NamedDecl *PrevDecl - = LookupSingleName(DeclRegionScope, II, IdentLoc, LookupOrdinaryName, - ForRedeclaration); + // The identifier in an original-namespace-definition shall not + // have been previously defined in the declarative region in + // which the original-namespace-definition appears. The + // identifier in an original-namespace-definition is the name of + // the namespace. Subsequently in that declarative region, it is + // treated as an original-namespace-name. + // + // Since namespace names are unique in their scope, and we don't + // look through using directives, just + DeclContext::lookup_result R = CurContext->getRedeclContext()->lookup(II); + NamedDecl *PrevDecl = R.first == R.second? 0 : *R.first; if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) { // This is an extended namespace definition. @@ -3485,6 +3691,10 @@ Decl *Sema::ActOnUsingDirective(Scope *S, assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); assert(NamespcName && "Invalid NamespcName."); assert(IdentLoc.isValid() && "Invalid NamespceName location."); + + // This can only happen along a recovery path. + while (S->getFlags() & Scope::TemplateParamScope) + S = S->getParent(); assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); UsingDirectiveDecl *UDir = 0; @@ -3562,7 +3772,6 @@ Decl *Sema::ActOnUsingDirective(Scope *S, } // FIXME: We ignore attributes for now. - delete AttrList; return UDir; } @@ -3580,14 +3789,14 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { Decl *Sema::ActOnUsingDeclaration(Scope *S, - AccessSpecifier AS, - bool HasUsingKeyword, - SourceLocation UsingLoc, - CXXScopeSpec &SS, - UnqualifiedId &Name, - AttributeList *AttrList, - bool IsTypeName, - SourceLocation TypenameLoc) { + AccessSpecifier AS, + bool HasUsingKeyword, + SourceLocation UsingLoc, + CXXScopeSpec &SS, + UnqualifiedId &Name, + AttributeList *AttrList, + bool IsTypeName, + SourceLocation TypenameLoc) { assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); switch (Name.getKind()) { @@ -3633,6 +3842,10 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using "); } + if (DiagnoseUnexpandedParameterPack(SS, UPPC_UsingDeclaration) || + DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC_UsingDeclaration)) + return 0; + NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, TargetNameInfo, AttrList, /* IsInstantiation */ false, @@ -3809,20 +4022,16 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, = UsingShadowDecl::Create(Context, CurContext, UD->getLocation(), UD, Target); UD->addShadowDecl(Shadow); - + + Shadow->setAccess(UD->getAccess()); + if (Orig->isInvalidDecl() || UD->isInvalidDecl()) + Shadow->setInvalidDecl(); + if (S) PushOnScopeChains(Shadow, S); else CurContext->addDecl(Shadow); - Shadow->setAccess(UD->getAccess()); - // Register it as a conversion if appropriate. - if (Shadow->getDeclName().getNameKind() - == DeclarationName::CXXConversionFunctionName) - cast<CXXRecordDecl>(CurContext)->addConversionFunction(Shadow); - - if (Orig->isInvalidDecl() || UD->isInvalidDecl()) - Shadow->setInvalidDecl(); return Shadow; } @@ -3893,7 +4102,6 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, assert(IdentLoc.isValid() && "Invalid TargetName location."); // FIXME: We ignore attributes for now. - delete AttrList; if (SS.isEmpty()) { Diag(IdentLoc, diag::err_using_requires_qualname); @@ -3921,8 +4129,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, LookupQualifiedName(Previous, CurContext); } - NestedNameSpecifier *NNS = - static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + NestedNameSpecifier *NNS = SS.getScopeRep(); // Check for invalid redeclarations. if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous)) @@ -3962,7 +4169,14 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return UD; } - // Look up the target name. + // Constructor inheriting using decls get special treatment. + if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) { + if (CheckInheritedConstructorUsingDecl(UD)) + UD->setInvalidDecl(); + return UD; + } + + // Otherwise, look up the target name. LookupResult R(*this, NameInfo, LookupOrdinaryName); @@ -4026,6 +4240,42 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return UD; } +/// Additional checks for a using declaration referring to a constructor name. +bool Sema::CheckInheritedConstructorUsingDecl(UsingDecl *UD) { + if (UD->isTypeName()) { + // FIXME: Cannot specify typename when specifying constructor + return true; + } + + const Type *SourceType = UD->getTargetNestedNameDecl()->getAsType(); + assert(SourceType && + "Using decl naming constructor doesn't have type in scope spec."); + CXXRecordDecl *TargetClass = cast<CXXRecordDecl>(CurContext); + + // Check whether the named type is a direct base class. + CanQualType CanonicalSourceType = SourceType->getCanonicalTypeUnqualified(); + CXXRecordDecl::base_class_iterator BaseIt, BaseE; + for (BaseIt = TargetClass->bases_begin(), BaseE = TargetClass->bases_end(); + BaseIt != BaseE; ++BaseIt) { + CanQualType BaseType = BaseIt->getType()->getCanonicalTypeUnqualified(); + if (CanonicalSourceType == BaseType) + break; + } + + if (BaseIt == BaseE) { + // Did not find SourceType in the bases. + Diag(UD->getUsingLocation(), + diag::err_using_decl_constructor_not_in_direct_base) + << UD->getNameInfo().getSourceRange() + << QualType(SourceType, 0) << TargetClass; + return true; + } + + BaseIt->setInheritConstructors(); + + return false; +} + /// Checks that the given using declaration is not an invalid /// redeclaration. Note that this is checking only for the using decl /// itself, not for any ill-formedness among the UsingShadowDecls. @@ -4132,6 +4382,10 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, return true; } + if (!NamedContext->isDependentContext() && + RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), NamedContext)) + return true; + if (getLangOptions().CPlusPlus0x) { // C++0x [namespace.udecl]p3: // In a using-declaration used as a member-declaration, the @@ -4301,13 +4555,12 @@ namespace { /// to implicitly define the body of a C++ member function; class ImplicitlyDefinedFunctionScope { Sema &S; - DeclContext *PreviousContext; + Sema::ContextRAII SavedContext; public: ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method) - : S(S), PreviousContext(S.CurContext) + : S(S), SavedContext(S, Method) { - S.CurContext = Method; S.PushFunctionScope(); S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); } @@ -4315,11 +4568,32 @@ namespace { ~ImplicitlyDefinedFunctionScope() { S.PopExpressionEvaluationContext(); S.PopFunctionOrBlockScope(); - S.CurContext = PreviousContext; } }; } +static CXXConstructorDecl *getDefaultConstructorUnsafe(Sema &Self, + CXXRecordDecl *D) { + ASTContext &Context = Self.Context; + QualType ClassType = Context.getTypeDeclType(D); + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType.getUnqualifiedType())); + + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // FIXME: In C++0x, a constructor template can be a default constructor. + if (isa<FunctionTemplateDecl>(*Con)) + continue; + + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isDefaultConstructor()) + return Constructor; + } + return 0; +} + CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( CXXRecordDecl *ClassDecl) { // C++ [class.ctor]p5: @@ -4347,8 +4621,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); if (!BaseClassDecl->hasDeclaredDefaultConstructor()) ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl)); - else if (CXXConstructorDecl *Constructor - = BaseClassDecl->getDefaultConstructor()) + else if (CXXConstructorDecl *Constructor + = getDefaultConstructorUnsafe(*this, BaseClassDecl)) ExceptSpec.CalledDecl(Constructor); } } @@ -4362,7 +4636,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( if (!BaseClassDecl->hasDeclaredDefaultConstructor()) ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl)); else if (CXXConstructorDecl *Constructor - = BaseClassDecl->getDefaultConstructor()) + = getDefaultConstructorUnsafe(*this, BaseClassDecl)) ExceptSpec.CalledDecl(Constructor); } } @@ -4378,11 +4652,16 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( ExceptSpec.CalledDecl( DeclareImplicitDefaultConstructor(FieldClassDecl)); else if (CXXConstructorDecl *Constructor - = FieldClassDecl->getDefaultConstructor()) + = getDefaultConstructorUnsafe(*this, FieldClassDecl)) ExceptSpec.CalledDecl(Constructor); } } - + + FunctionProtoType::ExtProtoInfo EPI; + EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification(); + EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification(); + EPI.NumExceptions = ExceptSpec.size(); + EPI.Exceptions = ExceptSpec.data(); // Create the actual constructor declaration. CanQualType ClassType @@ -4393,12 +4672,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(Context, ClassDecl, NameInfo, Context.getFunctionType(Context.VoidTy, - 0, 0, false, 0, - ExceptSpec.hasExceptionSpecification(), - ExceptSpec.hasAnyExceptionSpecification(), - ExceptSpec.size(), - ExceptSpec.data(), - FunctionType::ExtInfo()), + 0, 0, EPI), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, @@ -4408,7 +4682,6 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor()); // Note that we have declared this constructor. - ClassDecl->setDeclaredDefaultConstructor(true); ++ASTContext::NumImplicitDefaultConstructorsDeclared; if (Scope *S = getScopeForContext(ClassDecl)) @@ -4428,15 +4701,193 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); ImplicitlyDefinedFunctionScope Scope(*this, Constructor); - ErrorTrap Trap(*this); - if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false) || + DiagnosticErrorTrap Trap(Diags); + if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); - } else { - Constructor->setUsed(); - MarkVTableUsed(CurrentLocation, ClassDecl); + return; + } + + SourceLocation Loc = Constructor->getLocation(); + Constructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc)); + + Constructor->setUsed(); + MarkVTableUsed(CurrentLocation, ClassDecl); +} + +void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { + // We start with an initial pass over the base classes to collect those that + // inherit constructors from. If there are none, we can forgo all further + // processing. + typedef llvm::SmallVector<const RecordType *, 4> BasesVector; + BasesVector BasesToInheritFrom; + for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(), + BaseE = ClassDecl->bases_end(); + BaseIt != BaseE; ++BaseIt) { + if (BaseIt->getInheritConstructors()) { + QualType Base = BaseIt->getType(); + if (Base->isDependentType()) { + // If we inherit constructors from anything that is dependent, just + // abort processing altogether. We'll get another chance for the + // instantiations. + return; + } + BasesToInheritFrom.push_back(Base->castAs<RecordType>()); + } + } + if (BasesToInheritFrom.empty()) + return; + + // Now collect the constructors that we already have in the current class. + // Those take precedence over inherited constructors. + // C++0x [class.inhctor]p3: [...] a constructor is implicitly declared [...] + // unless there is a user-declared constructor with the same signature in + // the class where the using-declaration appears. + llvm::SmallSet<const Type *, 8> ExistingConstructors; + for (CXXRecordDecl::ctor_iterator CtorIt = ClassDecl->ctor_begin(), + CtorE = ClassDecl->ctor_end(); + CtorIt != CtorE; ++CtorIt) { + ExistingConstructors.insert( + Context.getCanonicalType(CtorIt->getType()).getTypePtr()); + } + + Scope *S = getScopeForContext(ClassDecl); + DeclarationName CreatedCtorName = + Context.DeclarationNames.getCXXConstructorName( + ClassDecl->getTypeForDecl()->getCanonicalTypeUnqualified()); + + // Now comes the true work. + // First, we keep a map from constructor types to the base that introduced + // them. Needed for finding conflicting constructors. We also keep the + // actually inserted declarations in there, for pretty diagnostics. + typedef std::pair<CanQualType, CXXConstructorDecl *> ConstructorInfo; + typedef llvm::DenseMap<const Type *, ConstructorInfo> ConstructorToSourceMap; + ConstructorToSourceMap InheritedConstructors; + for (BasesVector::iterator BaseIt = BasesToInheritFrom.begin(), + BaseE = BasesToInheritFrom.end(); + BaseIt != BaseE; ++BaseIt) { + const RecordType *Base = *BaseIt; + CanQualType CanonicalBase = Base->getCanonicalTypeUnqualified(); + CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(Base->getDecl()); + for (CXXRecordDecl::ctor_iterator CtorIt = BaseDecl->ctor_begin(), + CtorE = BaseDecl->ctor_end(); + CtorIt != CtorE; ++CtorIt) { + // Find the using declaration for inheriting this base's constructors. + DeclarationName Name = + Context.DeclarationNames.getCXXConstructorName(CanonicalBase); + UsingDecl *UD = dyn_cast_or_null<UsingDecl>( + LookupSingleName(S, Name,SourceLocation(), LookupUsingDeclName)); + SourceLocation UsingLoc = UD ? UD->getLocation() : + ClassDecl->getLocation(); + + // C++0x [class.inhctor]p1: The candidate set of inherited constructors + // from the class X named in the using-declaration consists of actual + // constructors and notional constructors that result from the + // transformation of defaulted parameters as follows: + // - all non-template default constructors of X, and + // - for each non-template constructor of X that has at least one + // parameter with a default argument, the set of constructors that + // results from omitting any ellipsis parameter specification and + // successively omitting parameters with a default argument from the + // end of the parameter-type-list. + CXXConstructorDecl *BaseCtor = *CtorIt; + bool CanBeCopyOrMove = BaseCtor->isCopyOrMoveConstructor(); + const FunctionProtoType *BaseCtorType = + BaseCtor->getType()->getAs<FunctionProtoType>(); + + for (unsigned params = BaseCtor->getMinRequiredArguments(), + maxParams = BaseCtor->getNumParams(); + params <= maxParams; ++params) { + // Skip default constructors. They're never inherited. + if (params == 0) + continue; + // Skip copy and move constructors for the same reason. + if (CanBeCopyOrMove && params == 1) + continue; + + // Build up a function type for this particular constructor. + // FIXME: The working paper does not consider that the exception spec + // for the inheriting constructor might be larger than that of the + // source. This code doesn't yet, either. + const Type *NewCtorType; + if (params == maxParams) + NewCtorType = BaseCtorType; + else { + llvm::SmallVector<QualType, 16> Args; + for (unsigned i = 0; i < params; ++i) { + Args.push_back(BaseCtorType->getArgType(i)); + } + FunctionProtoType::ExtProtoInfo ExtInfo = + BaseCtorType->getExtProtoInfo(); + ExtInfo.Variadic = false; + NewCtorType = Context.getFunctionType(BaseCtorType->getResultType(), + Args.data(), params, ExtInfo) + .getTypePtr(); + } + const Type *CanonicalNewCtorType = + Context.getCanonicalType(NewCtorType); + + // Now that we have the type, first check if the class already has a + // constructor with this signature. + if (ExistingConstructors.count(CanonicalNewCtorType)) + continue; + + // Then we check if we have already declared an inherited constructor + // with this signature. + std::pair<ConstructorToSourceMap::iterator, bool> result = + InheritedConstructors.insert(std::make_pair( + CanonicalNewCtorType, + std::make_pair(CanonicalBase, (CXXConstructorDecl*)0))); + if (!result.second) { + // Already in the map. If it came from a different class, that's an + // error. Not if it's from the same. + CanQualType PreviousBase = result.first->second.first; + if (CanonicalBase != PreviousBase) { + const CXXConstructorDecl *PrevCtor = result.first->second.second; + const CXXConstructorDecl *PrevBaseCtor = + PrevCtor->getInheritedConstructor(); + assert(PrevBaseCtor && "Conflicting constructor was not inherited"); + + Diag(UsingLoc, diag::err_using_decl_constructor_conflict); + Diag(BaseCtor->getLocation(), + diag::note_using_decl_constructor_conflict_current_ctor); + Diag(PrevBaseCtor->getLocation(), + diag::note_using_decl_constructor_conflict_previous_ctor); + Diag(PrevCtor->getLocation(), + diag::note_using_decl_constructor_conflict_previous_using); + } + continue; + } + + // OK, we're there, now add the constructor. + // C++0x [class.inhctor]p8: [...] that would be performed by a + // user-writtern inline constructor [...] + DeclarationNameInfo DNI(CreatedCtorName, UsingLoc); + CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create( + Context, ClassDecl, DNI, QualType(NewCtorType, 0), /*TInfo=*/0, + BaseCtor->isExplicit(), /*Inline=*/true, + /*ImplicitlyDeclared=*/true); + NewCtor->setAccess(BaseCtor->getAccess()); + + // Build up the parameter decls and add them. + llvm::SmallVector<ParmVarDecl *, 16> ParamDecls; + for (unsigned i = 0; i < params; ++i) { + ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor, UsingLoc, + /*IdentifierInfo=*/0, + BaseCtorType->getArgType(i), + /*TInfo=*/0, SC_None, + SC_None, /*DefaultArg=*/0)); + } + NewCtor->setParams(ParamDecls.data(), ParamDecls.size()); + NewCtor->setInheritedConstructor(BaseCtor); + + PushOnScopeChains(NewCtor, S, false); + ClassDecl->addDecl(NewCtor); + result.first->second.second = NewCtor; + } + } } } @@ -4483,13 +4934,12 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { } // Create the actual destructor declaration. - QualType Ty = Context.getFunctionType(Context.VoidTy, - 0, 0, false, 0, - ExceptSpec.hasExceptionSpecification(), - ExceptSpec.hasAnyExceptionSpecification(), - ExceptSpec.size(), - ExceptSpec.data(), - FunctionType::ExtInfo()); + FunctionProtoType::ExtProtoInfo EPI; + EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification(); + EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification(); + EPI.NumExceptions = ExceptSpec.size(); + EPI.Exceptions = ExceptSpec.data(); + QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI); CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); @@ -4497,7 +4947,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { = Context.DeclarationNames.getCXXDestructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation()); CXXDestructorDecl *Destructor - = CXXDestructorDecl::Create(Context, ClassDecl, NameInfo, Ty, + = CXXDestructorDecl::Create(Context, ClassDecl, NameInfo, Ty, 0, /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); @@ -4505,7 +4955,6 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); // Note that we have declared this destructor. - ClassDecl->setDeclaredDestructor(true); ++ASTContext::NumImplicitDestructorsDeclared; // Introduce this destructor into its scope. @@ -4533,7 +4982,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, ImplicitlyDefinedFunctionScope Scope(*this, Destructor); - ErrorTrap Trap(*this); + DiagnosticErrorTrap Trap(Diags); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); @@ -4545,6 +4994,9 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, return; } + SourceLocation Loc = Destructor->getLocation(); + Destructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc)); + Destructor->setUsed(); MarkVTableUsed(CurrentLocation, ClassDecl); } @@ -4644,8 +5096,8 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, // Build the call to the assignment operator. ExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0, - OpEqualRef.takeAs<Expr>(), - Loc, &From, 1, 0, Loc); + OpEqualRef.takeAs<Expr>(), + Loc, &From, 1, Loc); if (Call.isInvalid()) return StmtError(); @@ -4693,26 +5145,25 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, // Create a reference to the iteration variable; we'll use this several // times throughout. Expr *IterationVarRef - = S.BuildDeclRefExpr(IterationVar, SizeType, Loc).takeAs<Expr>(); + = S.BuildDeclRefExpr(IterationVar, SizeType, VK_RValue, Loc).take(); assert(IterationVarRef && "Reference to invented variable cannot fail!"); // Create the DeclStmt that holds the iteration variable. Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc); // Create the comparison against the array bound. - llvm::APInt Upper = ArrayTy->getSize(); - Upper.zextOrTrunc(S.Context.getTypeSize(SizeType)); + llvm::APInt Upper + = ArrayTy->getSize().zextOrTrunc(S.Context.getTypeSize(SizeType)); Expr *Comparison - = new (S.Context) BinaryOperator(IterationVarRef->Retain(), - IntegerLiteral::Create(S.Context, - Upper, SizeType, Loc), - BO_NE, S.Context.BoolTy, Loc); + = new (S.Context) BinaryOperator(IterationVarRef, + IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), + BO_NE, S.Context.BoolTy, + VK_RValue, OK_Ordinary, Loc); // Create the pre-increment of the iteration variable. Expr *Increment - = new (S.Context) UnaryOperator(IterationVarRef->Retain(), - UO_PreInc, - SizeType, Loc); + = new (S.Context) UnaryOperator(IterationVarRef, UO_PreInc, SizeType, + VK_LValue, OK_Ordinary, Loc); // Subscript the "from" and "to" expressions with the iteration variable. From = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(From, Loc, @@ -4721,10 +5172,9 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, IterationVarRef, Loc)); // Build the copy for an individual element of the array. - StmtResult Copy = BuildSingleCopyAssign(S, Loc, - ArrayTy->getElementType(), - To, From, - CopyingBaseSubobject, Depth+1); + StmtResult Copy = BuildSingleCopyAssign(S, Loc, ArrayTy->getElementType(), + To, From, CopyingBaseSubobject, + Depth + 1); if (Copy.isInvalid()) return StmtError(); @@ -4881,24 +5331,22 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // An implicitly-declared copy assignment operator is an inline public // member of its class. + FunctionProtoType::ExtProtoInfo EPI; + EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification(); + EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification(); + EPI.NumExceptions = ExceptSpec.size(); + EPI.Exceptions = ExceptSpec.data(); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation()); CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create(Context, ClassDecl, NameInfo, - Context.getFunctionType(RetType, &ArgType, 1, - false, 0, - ExceptSpec.hasExceptionSpecification(), - ExceptSpec.hasAnyExceptionSpecification(), - ExceptSpec.size(), - ExceptSpec.data(), - FunctionType::ExtInfo()), + Context.getFunctionType(RetType, &ArgType, 1, EPI), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, /*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, @@ -4910,7 +5358,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CopyAssignment->setParams(&FromParam, 1); // Note that we have added this copy-assignment operator. - ClassDecl->setDeclaredCopyAssignment(true); ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; if (Scope *S = getScopeForContext(ClassDecl)) @@ -4939,7 +5386,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CopyAssignOperator->setUsed(); ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator); - ErrorTrap Trap(*this); + DiagnosticErrorTrap Trap(Diags); // C++0x [class.copy]p30: // The implicitly-defined or explicitly-defaulted copy assignment operator @@ -4967,7 +5414,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Construct a reference to the "other" object. We'll be using this // throughout the generated ASTs. - Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, Loc).takeAs<Expr>(); + Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, VK_LValue, Loc).take(); assert(OtherRef && "Reference to parameter cannot fail!"); // Construct the "this" pointer. We'll be using this throughout the generated @@ -4982,10 +5429,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Form the assignment: // static_cast<Base*>(this)->Base::operator=(static_cast<Base&>(other)); QualType BaseType = Base->getType().getUnqualifiedType(); - CXXRecordDecl *BaseClassDecl = 0; - if (const RecordType *BaseRecordT = BaseType->getAs<RecordType>()) - BaseClassDecl = cast<CXXRecordDecl>(BaseRecordT->getDecl()); - else { + if (!BaseType->isRecordType()) { Invalid = true; continue; } @@ -4995,7 +5439,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Construct the "from" expression, which is an implicit cast to the // appropriately-qualified base type. - Expr *From = OtherRef->Retain(); + Expr *From = OtherRef; ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals), CK_UncheckedDerivedToBase, VK_LValue, &BasePath); @@ -5073,11 +5517,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, MemberLookup.addDecl(*Field); MemberLookup.resolveKind(); ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType, - Loc, /*IsArrow=*/false, - SS, 0, MemberLookup, 0); + Loc, /*IsArrow=*/false, + SS, 0, MemberLookup, 0); ExprResult To = BuildMemberReferenceExpr(This, This->getType(), - Loc, /*IsArrow=*/true, - SS, 0, MemberLookup, 0); + Loc, /*IsArrow=*/true, + SS, 0, MemberLookup, 0); assert(!From.isInvalid() && "Implicit field reference cannot fail"); assert(!To.isInvalid() && "Implicit field reference cannot fail"); @@ -5097,8 +5541,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, = Context.getAsConstantArrayType(FieldType); Array; Array = Context.getAsConstantArrayType(Array->getElementType())) { - llvm::APInt ArraySize = Array->getSize(); - ArraySize.zextOrTrunc(Size.getBitWidth()); + llvm::APInt ArraySize + = Array->getSize().zextOrTrunc(Size.getBitWidth()); Size *= ArraySize; } @@ -5128,7 +5572,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, CollectableMemCpy->getType(), - Loc, 0).takeAs<Expr>(); + VK_LValue, Loc, 0).take(); assert(CollectableMemCpyRef && "Builtin reference cannot fail"); } } @@ -5148,7 +5592,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, BuiltinMemCpy->getType(), - Loc, 0).takeAs<Expr>(); + VK_LValue, Loc, 0).take(); assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); } @@ -5156,20 +5600,17 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CallArgs.push_back(To.takeAs<Expr>()); CallArgs.push_back(From.takeAs<Expr>()); CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc)); - llvm::SmallVector<SourceLocation, 4> Commas; // FIXME: Silly - Commas.push_back(Loc); - Commas.push_back(Loc); ExprResult Call = ExprError(); if (NeedsCollectableMemCpy) Call = ActOnCallExpr(/*Scope=*/0, CollectableMemCpyRef, Loc, move_arg(CallArgs), - Commas.data(), Loc); + Loc); else Call = ActOnCallExpr(/*Scope=*/0, BuiltinMemCpyRef, Loc, move_arg(CallArgs), - Commas.data(), Loc); + Loc); assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); Statements.push_back(Call.takeAs<Expr>()); @@ -5352,6 +5793,11 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // An implicitly-declared copy constructor is an inline public // member of its class. + FunctionProtoType::ExtProtoInfo EPI; + EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification(); + EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification(); + EPI.NumExceptions = ExceptSpec.size(); + EPI.Exceptions = ExceptSpec.data(); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); @@ -5359,23 +5805,15 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(Context, ClassDecl, NameInfo, Context.getFunctionType(Context.VoidTy, - &ArgType, 1, - false, 0, - ExceptSpec.hasExceptionSpecification(), - ExceptSpec.hasAnyExceptionSpecification(), - ExceptSpec.size(), - ExceptSpec.data(), - FunctionType::ExtInfo()), + &ArgType, 1, EPI), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true); CopyConstructor->setAccess(AS_public); - CopyConstructor->setImplicit(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); // Note that we have declared this constructor. - ClassDecl->setDeclaredCopyConstructor(true); ++ASTContext::NumImplicitCopyConstructorsDeclared; // Add the parameter to the constructor. @@ -5405,9 +5843,9 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor); - ErrorTrap Trap(*this); + DiagnosticErrorTrap Trap(Diags); - if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) || + if (SetCtorInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); @@ -5428,7 +5866,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg ExprArgs, bool RequiresZeroInit, - unsigned ConstructKind) { + unsigned ConstructKind, + SourceRange ParenRange) { bool Elidable = false; // C++0x [class.copy]p34: @@ -5441,17 +5880,15 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, // with the same cv-unqualified type, the copy/move operation // can be omitted by constructing the temporary object // directly into the target of the omitted copy/move - if (Constructor->isCopyConstructor() && ExprArgs.size() >= 1) { + if (ConstructKind == CXXConstructExpr::CK_Complete && + Constructor->isCopyOrMoveConstructor() && ExprArgs.size() >= 1) { Expr *SubExpr = ((Expr **)ExprArgs.get())[0]; - Elidable = SubExpr->isTemporaryObject() && - ConstructKind == CXXConstructExpr::CK_Complete && - Context.hasSameUnqualifiedType(SubExpr->getType(), - Context.getTypeDeclType(Constructor->getParent())); + Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent()); } return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, Elidable, move(ExprArgs), RequiresZeroInit, - ConstructKind); + ConstructKind, ParenRange); } /// BuildCXXConstructExpr - Creates a complete call to a constructor, @@ -5461,7 +5898,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs, bool RequiresZeroInit, - unsigned ConstructKind) { + unsigned ConstructKind, + SourceRange ParenRange) { unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); @@ -5469,21 +5907,25 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, RequiresZeroInit, - static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind))); + static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind), + ParenRange)); } bool Sema::InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, MultiExprArg Exprs) { + // FIXME: Provide the correct paren SourceRange when available. ExprResult TempResult = BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor, - move(Exprs), false, CXXConstructExpr::CK_Complete); + move(Exprs), false, CXXConstructExpr::CK_Complete, + SourceRange()); if (TempResult.isInvalid()) return true; Expr *Temp = TempResult.takeAs<Expr>(); + CheckImplicitConversions(Temp, VD->getLocation()); MarkDeclarationReferenced(VD->getLocation(), Constructor); - Temp = MaybeCreateCXXExprWithTemporaries(Temp); + Temp = MaybeCreateExprWithCleanups(Temp); VD->setInit(Temp); return false; @@ -5500,7 +5942,8 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { << VD->getDeclName() << VD->getType()); - if (!VD->isInvalidDecl() && VD->hasGlobalStorage()) + // TODO: this should be re-enabled for static locals by !CXAAtExit + if (!VD->isInvalidDecl() && VD->hasGlobalStorage() && !VD->isStaticLocal()) Diag(VD->getLocation(), diag::warn_global_destructor); } } @@ -5511,8 +5954,8 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, SourceLocation LParenLoc, MultiExprArg Exprs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool TypeMayContainAuto) { assert(Exprs.size() != 0 && Exprs.get() && "missing expressions"); // If there is no declaration, there was an error parsing it. Just ignore @@ -5527,6 +5970,37 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, return; } + // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. + if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) { + VDecl->setParsingAutoInit(false); + + // FIXME: n3225 doesn't actually seem to indicate this is ill-formed + if (Exprs.size() > 1) { + Diag(Exprs.get()[1]->getSourceRange().getBegin(), + diag::err_auto_var_init_multiple_expressions) + << VDecl->getDeclName() << VDecl->getType() + << VDecl->getSourceRange(); + RealDecl->setInvalidDecl(); + return; + } + + Expr *Init = Exprs.get()[0]; + QualType DeducedType; + if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) { + Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure) + << VDecl->getDeclName() << VDecl->getType() << Init->getType() + << Init->getSourceRange(); + RealDecl->setInvalidDecl(); + return; + } + VDecl->setType(DeducedType); + + // If this is a redeclaration, check that the type we just deduced matches + // the previously declared type. + if (VarDecl *Old = VDecl->getPreviousDeclaration()) + MergeVarDeclTypes(VDecl, Old); + } + // 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); @@ -5583,11 +6057,21 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, return; } + bool IsDependent = false; + for (unsigned I = 0, N = Exprs.size(); I != N; ++I) { + if (DiagnoseUnexpandedParameterPack(Exprs.get()[I], UPPC_Expression)) { + VDecl->setInvalidDecl(); + return; + } + + if (Exprs.get()[I]->isTypeDependent()) + IsDependent = true; + } + // 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())) { + if (VDecl->getType()->isDependentType() || IsDependent) { // Let clients know that initialization was done with a direct initializer. VDecl->setCXXDirectInitializer(true); @@ -5615,21 +6099,14 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, VDecl->setInvalidDecl(); return; } + + CheckImplicitConversions(Result.get(), LParenLoc); - Result = MaybeCreateCXXExprWithTemporaries(Result.get()); + Result = MaybeCreateExprWithCleanups(Result); VDecl->setInit(Result.takeAs<Expr>()); VDecl->setCXXDirectInitializer(true); - if (!VDecl->isInvalidDecl() && - !VDecl->getDeclContext()->isDependentContext() && - VDecl->hasGlobalStorage() && - !VDecl->getInit()->isConstantInitializer(Context, - VDecl->getType()->isReferenceType())) - Diag(VDecl->getLocation(), diag::warn_global_constructor) - << VDecl->getInit()->getSourceRange(); - - if (const RecordType *Record = VDecl->getType()->getAs<RecordType>()) - FinalizeVarWithDestructor(VDecl, Record); + CheckCompleteVariableDeclaration(VDecl); } /// \brief Given a constructor and the set of arguments provided for the @@ -5926,15 +6403,6 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { << LastParam->getType() << (Op == OO_MinusMinus); } - // Notify the class if it got an assignment operator. - if (Op == OO_Equal) { - // Would have returned earlier otherwise. - assert(isa<CXXMethodDecl>(FnDecl) && - "Overloaded = not member, but not filtered."); - CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); - Method->getParent()->addedAssignmentOperator(Context, Method); - } - return false; } @@ -5964,8 +6432,6 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { cast<NonTypeTemplateParmDecl>(Params->getParam(0)); // The template parameter must be a char parameter pack. - // FIXME: This test will always fail because non-type parameter packs - // have not been implemented. if (PmDecl && PmDecl->isTemplateParameterPack() && Context.hasSameType(PmDecl->getType(), Context.CharTy)) Valid = true; @@ -6042,11 +6508,10 @@ FinishedParams: /// by Lang/StrSize. LBraceLoc, if valid, provides the location of /// the '{' brace. Otherwise, this linkage specification does not /// have any braces. -Decl *Sema::ActOnStartLinkageSpecification(Scope *S, - SourceLocation ExternLoc, - SourceLocation LangLoc, - llvm::StringRef Lang, - SourceLocation LBraceLoc) { +Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, + SourceLocation LangLoc, + llvm::StringRef Lang, + SourceLocation LBraceLoc) { LinkageSpecDecl::LanguageIDs Language; if (Lang == "\"C\"") Language = LinkageSpecDecl::lang_c; @@ -6082,13 +6547,13 @@ Decl *Sema::ActOnFinishLinkageSpecification(Scope *S, /// \brief Perform semantic analysis for the variable declaration that /// occurs within a C++ catch clause, returning the newly-created /// variable. -VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, +VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, IdentifierInfo *Name, - SourceLocation Loc, - SourceRange Range) { + SourceLocation Loc) { bool Invalid = false; - + QualType ExDeclType = TInfo->getType(); + // Arrays and functions decay. if (ExDeclType->isArrayType()) ExDeclType = Context.getArrayDecayedType(ExDeclType); @@ -6100,7 +6565,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, // incomplete type, other than [cv] void*. // N2844 forbids rvalue references. if (!ExDeclType->isDependentType() && ExDeclType->isRValueReferenceType()) { - Diag(Loc, diag::err_catch_rvalue_ref) << Range; + Diag(Loc, diag::err_catch_rvalue_ref); Invalid = true; } @@ -6161,7 +6626,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, ExDecl->setExceptionVariable(true); if (!Invalid) { - if (const RecordType *RecordTy = ExDeclType->getAs<RecordType>()) { + if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) { // C++ [except.handle]p16: // The object declared in an exception-declaration or, if the // exception-declaration does not specify a name, a temporary (12.2) is @@ -6171,18 +6636,32 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, // // We just pretend to initialize the object with itself, then make sure // it can be destroyed later. - InitializedEntity Entity = InitializedEntity::InitializeVariable(ExDecl); - Expr *ExDeclRef = DeclRefExpr::Create(Context, 0, SourceRange(), ExDecl, - Loc, ExDeclType, 0); - InitializationKind Kind = InitializationKind::CreateCopy(Loc, - SourceLocation()); - InitializationSequence InitSeq(*this, Entity, Kind, &ExDeclRef, 1); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, &ExDeclRef, 1)); - if (Result.isInvalid()) + QualType initType = ExDeclType; + + InitializedEntity entity = + InitializedEntity::InitializeVariable(ExDecl); + InitializationKind initKind = + InitializationKind::CreateCopy(Loc, SourceLocation()); + + Expr *opaqueValue = + new (Context) OpaqueValueExpr(Loc, initType, VK_LValue, OK_Ordinary); + InitializationSequence sequence(*this, entity, initKind, &opaqueValue, 1); + ExprResult result = sequence.Perform(*this, entity, initKind, + MultiExprArg(&opaqueValue, 1)); + if (result.isInvalid()) Invalid = true; - else - FinalizeVarWithDestructor(ExDecl, RecordTy); + else { + // If the constructor used was non-trivial, set this as the + // "initializer". + CXXConstructExpr *construct = cast<CXXConstructExpr>(result.take()); + if (!construct->getConstructor()->isTrivial()) { + Expr *init = MaybeCreateExprWithCleanups(construct); + ExDecl->setInit(init); + } + + // And make sure it's destructable. + FinalizeVarWithDestructor(ExDecl, recordType); + } } } @@ -6196,9 +6675,16 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, /// handler. Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); - QualType ExDeclType = TInfo->getType(); - bool Invalid = D.isInvalidType(); + + // Check for unexpanded parameter packs. + if (TInfo && DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, + UPPC_ExceptionType)) { + TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, + D.getIdentifierLoc()); + Invalid = true; + } + IdentifierInfo *II = D.getIdentifier(); if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(), LookupOrdinaryName, @@ -6218,10 +6704,9 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { Invalid = true; } - VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, TInfo, + VarDecl *ExDecl = BuildExceptionDeclaration(S, TInfo, D.getIdentifier(), - D.getIdentifierLoc(), - D.getDeclSpec().getSourceRange()); + D.getIdentifierLoc()); if (Invalid) ExDecl->setInvalidDecl(); @@ -6255,6 +6740,9 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, } } + if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression)) + return 0; + Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc, AssertExpr, AssertMessage); @@ -6318,6 +6806,110 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc, return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc); } +/// Handle a friend tag declaration where the scope specifier was +/// templated. +Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, + unsigned TagSpec, SourceLocation TagLoc, + CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, + MultiTemplateParamsArg TempParamLists) { + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); + + bool isExplicitSpecialization = false; + unsigned NumMatchedTemplateParamLists = TempParamLists.size(); + bool Invalid = false; + + if (TemplateParameterList *TemplateParams + = MatchTemplateParametersToScopeSpecifier(TagLoc, SS, + TempParamLists.get(), + TempParamLists.size(), + /*friend*/ true, + isExplicitSpecialization, + Invalid)) { + --NumMatchedTemplateParamLists; + + if (TemplateParams->size() > 0) { + // This is a declaration of a class template. + if (Invalid) + return 0; + + return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, + SS, Name, NameLoc, Attr, + TemplateParams, AS_public).take(); + } else { + // The "template<>" header is extraneous. + Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) + << TypeWithKeyword::getTagTypeKindName(Kind) << Name; + isExplicitSpecialization = true; + } + } + + if (Invalid) return 0; + + assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?"); + + bool isAllExplicitSpecializations = true; + for (unsigned I = 0; I != NumMatchedTemplateParamLists; ++I) { + if (TempParamLists.get()[I]->size()) { + isAllExplicitSpecializations = false; + break; + } + } + + // FIXME: don't ignore attributes. + + // If it's explicit specializations all the way down, just forget + // about the template header and build an appropriate non-templated + // friend. TODO: for source fidelity, remember the headers. + if (isAllExplicitSpecializations) { + ElaboratedTypeKeyword Keyword + = TypeWithKeyword::getKeywordForTagTypeKind(Kind); + QualType T = CheckTypenameType(Keyword, SS.getScopeRep(), *Name, + TagLoc, SS.getRange(), NameLoc); + if (T.isNull()) + return 0; + + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + if (isa<DependentNameType>(T)) { + DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); + TL.setKeywordLoc(TagLoc); + TL.setQualifierRange(SS.getRange()); + TL.setNameLoc(NameLoc); + } else { + ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc()); + TL.setKeywordLoc(TagLoc); + TL.setQualifierRange(SS.getRange()); + cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(NameLoc); + } + + FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc, + TSI, FriendLoc); + Friend->setAccess(AS_public); + CurContext->addDecl(Friend); + return Friend; + } + + // Handle the case of a templated-scope friend class. e.g. + // template <class T> class A<T>::B; + // FIXME: we don't support these right now. + ElaboratedTypeKeyword ETK = TypeWithKeyword::getKeywordForTagTypeKind(Kind); + QualType T = Context.getDependentNameType(ETK, SS.getScopeRep(), Name); + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); + TL.setKeywordLoc(TagLoc); + TL.setQualifierRange(SS.getRange()); + TL.setNameLoc(NameLoc); + + FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc, + TSI, FriendLoc); + Friend->setAccess(AS_public); + Friend->setUnsupportedFriend(true); + CurContext->addDecl(Friend); + return Friend; +} + + /// Handle a friend type declaration. This works in tandem with /// ActOnTag. /// @@ -6336,7 +6928,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc, /// parameters present at all, require proper matching, i.e. /// template <> template <class T> friend class A<int>::B; Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, - MultiTemplateParamsArg TempParams) { + MultiTemplateParamsArg TempParams) { SourceLocation Loc = DS.getSourceRange().getBegin(); assert(DS.isFriendSpecified()); @@ -6351,6 +6943,9 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, if (TheDeclarator.isInvalidType()) return 0; + if (DiagnoseUnexpandedParameterPack(Loc, TSI, UPPC_FriendDeclaration)) + return 0; + // 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. @@ -6386,7 +6981,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, if (unsigned NumTempParamLists = TempParams.size()) D = FriendTemplateDecl::Create(Context, CurContext, Loc, NumTempParamLists, - (TemplateParameterList**) TempParams.release(), + TempParams.release(), TSI, DS.getFriendSpecLoc()); else @@ -6401,10 +6996,8 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, return D; } -Decl *Sema::ActOnFriendFunctionDecl(Scope *S, - Declarator &D, - bool IsDefinition, - MultiTemplateParamsArg TemplateParams) { +Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, + MultiTemplateParamsArg TemplateParams) { const DeclSpec &DS = D.getDeclSpec(); assert(DS.isFriendSpecified()); @@ -6447,26 +7040,94 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, // declared as a friend, scopes outside the innermost enclosing // namespace scope are not considered. - CXXScopeSpec &ScopeQual = D.getCXXScopeSpec(); + CXXScopeSpec &SS = D.getCXXScopeSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); assert(Name); + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(Loc, TInfo, UPPC_FriendDeclaration) || + DiagnoseUnexpandedParameterPack(NameInfo, UPPC_FriendDeclaration) || + DiagnoseUnexpandedParameterPack(SS, UPPC_FriendDeclaration)) + return 0; + // The context we found the declaration in, or in which we should // create the declaration. DeclContext *DC; + Scope *DCScope = S; + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + ForRedeclaration); - // FIXME: handle local classes + // FIXME: there are different rules in local classes + // There are four cases here. + // - There's no scope specifier, in which case we just go to the + // appropriate scope and look for a function or function template + // there as appropriate. // Recover from invalid scope qualifiers as if they just weren't there. - LookupResult Previous(*this, NameInfo, LookupOrdinaryName, - ForRedeclaration); - if (!ScopeQual.isInvalid() && ScopeQual.isSet()) { - DC = computeDeclContext(ScopeQual); + if (SS.isInvalid() || !SS.isSet()) { + // C++0x [namespace.memdef]p3: + // If the name in a friend declaration is neither qualified nor + // a template-id and the declaration is a function or an + // elaborated-type-specifier, the lookup to determine whether + // the entity has been previously declared shall not consider + // any scopes outside the innermost enclosing namespace. + // C++0x [class.friend]p11: + // If a friend declaration appears in a local class and the name + // specified is an unqualified name, a prior declaration is + // looked up without considering scopes that are outside the + // innermost enclosing non-class scope. For a friend function + // declaration, if there is no prior declaration, the program is + // ill-formed. + bool isLocal = cast<CXXRecordDecl>(CurContext)->isLocalClass(); + bool isTemplateId = D.getName().getKind() == UnqualifiedId::IK_TemplateId; + + // Find the appropriate context according to the above. + 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(); + + LookupQualifiedName(Previous, DC); - // FIXME: handle dependent contexts + // TODO: decide what we think about using declarations. + if (isLocal || !Previous.empty()) + break; + + if (isTemplateId) { + if (isa<TranslationUnitDecl>(DC)) break; + } else { + 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 (!Previous.empty() && DC->Equals(CurContext) + && !getLangOptions().CPlusPlus0x) + Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member); + + DCScope = getScopeForDeclContext(S, DC); + + // - There's a non-dependent scope specifier, in which case we + // compute it and do a previous lookup there for a function + // or function template. + } else if (!SS.getScopeRep()->isDependent()) { + DC = computeDeclContext(SS); if (!DC) return 0; - if (RequireCompleteDeclContext(ScopeQual, DC)) return 0; + + if (RequireCompleteDeclContext(SS, DC)) return 0; LookupQualifiedName(Previous, DC); @@ -6493,43 +7154,17 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, if (DC->Equals(CurContext)) Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member); - // Otherwise walk out to the nearest namespace scope looking for matches. + // - There's a scope specifier that does not match any template + // parameter lists, in which case we use some arbitrary context, + // create a method or method template, and wait for instantiation. + // - There's a scope specifier that does match some template + // parameter lists, which we don't handle right now. } 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(); - - LookupQualifiedName(Previous, DC); - - // TODO: decide what we think about using declarations. - if (!Previous.empty()) - 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 (!Previous.empty() && DC->Equals(CurContext) - && !getLangOptions().CPlusPlus0x) - Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member); + assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?"); } - if (DC->isFileContext()) { + if (!DC->isRecord()) { // This implies that it has to be an operator or function. if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName || D.getName().getKind() == UnqualifiedId::IK_DestructorName || @@ -6542,7 +7177,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, } bool Redeclaration = false; - NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, TInfo, Previous, + NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, T, TInfo, Previous, move(TemplateParams), IsDefinition, Redeclaration); @@ -6570,6 +7205,20 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, FrD->setAccess(AS_public); CurContext->addDecl(FrD); + if (ND->isInvalidDecl()) + FrD->setInvalidDecl(); + else { + FunctionDecl *FD; + if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND)) + FD = FTD->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(ND); + + // Mark templated-scope function declarations as unsupported. + if (FD->getNumTemplateParameterLists()) + FrD->setUnsupportedFriend(true); + } + return ND; } @@ -6591,8 +7240,7 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { } static void SearchForReturnInStmt(Sema &Self, Stmt *S) { - for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; - ++CI) { + for (Stmt::child_range CI = S->children(); CI; ++CI) { Stmt *SubStmt = *CI; if (!SubStmt) continue; @@ -6676,6 +7324,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, diag::err_covariant_return_ambiguous_derived_to_base_conv, // FIXME: Should this point to the return type? New->getLocation(), SourceRange(), New->getDeclName(), 0)) { + // FIXME: this note won't trigger for delayed access control + // diagnostics, and it's impossible to get an undelayed error + // here from access control during the original parse because + // the ParsingDeclSpec/ParsingDeclarator are still in scope. Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; } @@ -6703,19 +7355,6 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, return false; } -bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, - const CXXMethodDecl *Old) -{ - if (Old->hasAttr<FinalAttr>()) { - Diag(New->getLocation(), diag::err_final_function_overridden) - << New->getDeclName(); - Diag(Old->getLocation(), diag::note_overridden_virtual_function); - return true; - } - - return false; -} - /// \brief Mark the given method pure. /// /// \param Method the method to be marked pure. @@ -6724,9 +7363,6 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) { if (Method->isVirtual() || Method->getParent()->isDependentContext()) { Method->setPure(); - - // A class is abstract if at least one function is pure virtual. - Method->getParent()->setAbstract(true); return false; } @@ -6831,21 +7467,9 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, } bool Sema::DefineUsedVTables() { - // If any dynamic classes have their key function defined within - // this translation unit, then those vtables are considered "used" and must - // be emitted. - for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { - if (const CXXMethodDecl *KeyFunction - = Context.getKeyFunction(DynamicClasses[I])) { - const FunctionDecl *Definition = 0; - if (KeyFunction->hasBody(Definition)) - MarkVTableUsed(Definition->getLocation(), DynamicClasses[I], true); - } - } - if (VTableUses.empty()) return false; - + // Note: The VTableUses vector could grow as a result of marking // the members of a class as "used", so we check the size each // time through the loop and prefer indices (with are stable) to @@ -6954,13 +7578,13 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { CollectIvarsToConstructOrDestruct(OID, ivars); if (ivars.empty()) return; - llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; + llvm::SmallVector<CXXCtorInitializer*, 32> AllToInit; for (unsigned i = 0; i < ivars.size(); i++) { FieldDecl *Field = ivars[i]; if (Field->isInvalidDecl()) continue; - CXXBaseOrMemberInitializer *Member; + CXXCtorInitializer *Member; InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); InitializationKind InitKind = InitializationKind::CreateDefault(ObjCImplementation->getLocation()); @@ -6968,18 +7592,17 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); ExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind, MultiExprArg()); - MemberInit = MaybeCreateCXXExprWithTemporaries(MemberInit.get()); + MemberInit = MaybeCreateExprWithCleanups(MemberInit); // Note, MemberInit could actually come back empty if no initialization // is required (e.g., because it would call a trivial default constructor) if (!MemberInit.get() || MemberInit.isInvalid()) continue; - + Member = - new (Context) CXXBaseOrMemberInitializer(Context, - Field, SourceLocation(), - SourceLocation(), - MemberInit.takeAs<Expr>(), - SourceLocation()); + new (Context) CXXCtorInitializer(Context, Field, SourceLocation(), + SourceLocation(), + MemberInit.takeAs<Expr>(), + SourceLocation()); AllToInit.push_back(Member); // Be sure that the destructor is accessible and is marked as referenced. diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index a6902a3..66f6f2b 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -24,6 +24,19 @@ using namespace clang; +static void DiagnoseObjCImplementedDeprecations(Sema &S, + NamedDecl *ND, + SourceLocation ImplLoc, + int select) { + if (ND && ND->getAttr<DeprecatedAttr>()) { + S.Diag(ImplLoc, diag::warn_deprecated_def) << select; + if (select == 0) + S.Diag(ND->getLocation(), diag::note_method_declared_at); + else + S.Diag(ND->getLocation(), diag::note_previous_decl) << "class"; + } +} + /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible /// and user declared, in the method definition's AST. void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { @@ -55,9 +68,23 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { // Introduce all of the other parameters into this scope. for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(), - E = MDecl->param_end(); PI != E; ++PI) + E = MDecl->param_end(); PI != E; ++PI) { + ParmVarDecl *Param = (*PI); + if (!Param->isInvalidDecl() && + RequireCompleteType(Param->getLocation(), Param->getType(), + diag::err_typecheck_decl_incomplete_type)) + Param->setInvalidDecl(); if ((*PI)->getIdentifier()) PushOnScopeChains(*PI, FnBodyScope); + } + // Warn on implementating deprecated methods under + // -Wdeprecated-implementations flag. + if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) + if (ObjCMethodDecl *IMD = + IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod())) + DiagnoseObjCImplementedDeprecations(*this, + dyn_cast<NamedDecl>(IMD), + MDecl->getLocation(), 0); } Decl *Sema:: @@ -531,8 +558,14 @@ Decl *Sema::ActOnStartCategoryImplementation( << CatName; Diag(CatIDecl->getImplementation()->getLocation(), diag::note_previous_definition); - } else + } else { CatIDecl->setImplementation(CDecl); + // Warn on implementating category of deprecated class under + // -Wdeprecated-implementations flag. + DiagnoseObjCImplementedDeprecations(*this, + dyn_cast<NamedDecl>(IDecl), + CDecl->getLocation(), 2); + } } CheckObjCDeclScope(CDecl); @@ -641,6 +674,11 @@ Decl *Sema::ActOnStartClassImplementation( } else { // add it to the list. IDecl->setImplementation(IMPDecl); PushOnScopeChains(IMPDecl, TUScope); + // Warn on implementating deprecated class under + // -Wdeprecated-implementations flag. + DiagnoseObjCImplementedDeprecations(*this, + dyn_cast<NamedDecl>(IDecl), + IMPDecl->getLocation(), 1); } return IMPDecl; } @@ -739,36 +777,164 @@ void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, Diag(ImpLoc, diag::warn_incomplete_impl); IncompleteImpl = true; } - Diag(method->getLocation(), DiagID) - << method->getDeclName(); + if (DiagID == diag::warn_unimplemented_protocol_method) + Diag(ImpLoc, DiagID) << method->getDeclName(); + else + Diag(method->getLocation(), DiagID) << method->getDeclName(); } +/// Determines if type B can be substituted for type A. Returns true if we can +/// guarantee that anything that the user will do to an object of type A can +/// also be done to an object of type B. This is trivially true if the two +/// types are the same, or if B is a subclass of A. It becomes more complex +/// in cases where protocols are involved. +/// +/// Object types in Objective-C describe the minimum requirements for an +/// object, rather than providing a complete description of a type. For +/// example, if A is a subclass of B, then B* may refer to an instance of A. +/// The principle of substitutability means that we may use an instance of A +/// anywhere that we may use an instance of B - it will implement all of the +/// ivars of B and all of the methods of B. +/// +/// This substitutability is important when type checking methods, because +/// the implementation may have stricter type definitions than the interface. +/// The interface specifies minimum requirements, but the implementation may +/// have more accurate ones. For example, a method may privately accept +/// instances of B, but only publish that it accepts instances of A. Any +/// object passed to it will be type checked against B, and so will implicitly +/// by a valid A*. Similarly, a method may return a subclass of the class that +/// it is declared as returning. +/// +/// This is most important when considering subclassing. A method in a +/// subclass must accept any object as an argument that its superclass's +/// implementation accepts. It may, however, accept a more general type +/// without breaking substitutability (i.e. you can still use the subclass +/// anywhere that you can use the superclass, but not vice versa). The +/// converse requirement applies to return types: the return type for a +/// subclass method must be a valid object of the kind that the superclass +/// advertises, but it may be specified more accurately. This avoids the need +/// for explicit down-casting by callers. +/// +/// Note: This is a stricter requirement than for assignment. +static bool isObjCTypeSubstitutable(ASTContext &Context, + const ObjCObjectPointerType *A, + const ObjCObjectPointerType *B, + bool rejectId) { + // Reject a protocol-unqualified id. + if (rejectId && B->isObjCIdType()) return false; + + // If B is a qualified id, then A must also be a qualified id and it must + // implement all of the protocols in B. It may not be a qualified class. + // For example, MyClass<A> can be assigned to id<A>, but MyClass<A> is a + // stricter definition so it is not substitutable for id<A>. + if (B->isObjCQualifiedIdType()) { + return A->isObjCQualifiedIdType() && + Context.ObjCQualifiedIdTypesAreCompatible(QualType(A, 0), + QualType(B,0), + false); + } + + /* + // id is a special type that bypasses type checking completely. We want a + // warning when it is used in one place but not another. + if (C.isObjCIdType(A) || C.isObjCIdType(B)) return false; + + + // If B is a qualified id, then A must also be a qualified id (which it isn't + // if we've got this far) + if (B->isObjCQualifiedIdType()) return false; + */ + + // Now we know that A and B are (potentially-qualified) class types. The + // normal rules for assignment apply. + return Context.canAssignObjCInterfaces(A, B); +} + +static SourceRange getTypeRange(TypeSourceInfo *TSI) { + return (TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange()); +} + +static void CheckMethodOverrideReturn(Sema &S, + ObjCMethodDecl *MethodImpl, + ObjCMethodDecl *MethodIface) { + if (S.Context.hasSameUnqualifiedType(MethodImpl->getResultType(), + MethodIface->getResultType())) + return; + + unsigned DiagID = diag::warn_conflicting_ret_types; + + // Mismatches between ObjC pointers go into a different warning + // category, and sometimes they're even completely whitelisted. + if (const ObjCObjectPointerType *ImplPtrTy = + MethodImpl->getResultType()->getAs<ObjCObjectPointerType>()) { + if (const ObjCObjectPointerType *IfacePtrTy = + MethodIface->getResultType()->getAs<ObjCObjectPointerType>()) { + // Allow non-matching return types as long as they don't violate + // the principle of substitutability. Specifically, we permit + // return types that are subclasses of the declared return type, + // or that are more-qualified versions of the declared type. + if (isObjCTypeSubstitutable(S.Context, IfacePtrTy, ImplPtrTy, false)) + return; + + DiagID = diag::warn_non_covariant_ret_types; + } + } + + S.Diag(MethodImpl->getLocation(), DiagID) + << MethodImpl->getDeclName() + << MethodIface->getResultType() + << MethodImpl->getResultType() + << getTypeRange(MethodImpl->getResultTypeSourceInfo()); + S.Diag(MethodIface->getLocation(), diag::note_previous_definition) + << getTypeRange(MethodIface->getResultTypeSourceInfo()); +} + +static void CheckMethodOverrideParam(Sema &S, + ObjCMethodDecl *MethodImpl, + ObjCMethodDecl *MethodIface, + ParmVarDecl *ImplVar, + ParmVarDecl *IfaceVar) { + QualType ImplTy = ImplVar->getType(); + QualType IfaceTy = IfaceVar->getType(); + if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy)) + return; + + unsigned DiagID = diag::warn_conflicting_param_types; + + // Mismatches between ObjC pointers go into a different warning + // category, and sometimes they're even completely whitelisted. + if (const ObjCObjectPointerType *ImplPtrTy = + ImplTy->getAs<ObjCObjectPointerType>()) { + if (const ObjCObjectPointerType *IfacePtrTy = + IfaceTy->getAs<ObjCObjectPointerType>()) { + // Allow non-matching argument types as long as they don't + // violate the principle of substitutability. Specifically, the + // implementation must accept any objects that the superclass + // accepts, however it may also accept others. + if (isObjCTypeSubstitutable(S.Context, ImplPtrTy, IfacePtrTy, true)) + return; + + DiagID = diag::warn_non_contravariant_param_types; + } + } + + S.Diag(ImplVar->getLocation(), DiagID) + << getTypeRange(ImplVar->getTypeSourceInfo()) + << MethodImpl->getDeclName() << IfaceTy << ImplTy; + S.Diag(IfaceVar->getLocation(), diag::note_previous_definition) + << getTypeRange(IfaceVar->getTypeSourceInfo()); +} + + void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, ObjCMethodDecl *IntfMethodDecl) { - if (!Context.typesAreCompatible(IntfMethodDecl->getResultType(), - ImpMethodDecl->getResultType()) && - !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); - } + CheckMethodOverrideReturn(*this, ImpMethodDecl, IntfMethodDecl); for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), IF = IntfMethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); - IM != EM; ++IM, ++IF) { - QualType ParmDeclTy = (*IF)->getType().getUnqualifiedType(); - QualType ParmImpTy = (*IM)->getType().getUnqualifiedType(); - if (Context.typesAreCompatible(ParmDeclTy, ParmImpTy) || - Context.QualifiedIdConformsQualifiedId(ParmDeclTy, ParmImpTy)) - continue; + IM != EM; ++IM, ++IF) + CheckMethodOverrideParam(*this, ImpMethodDecl, IntfMethodDecl, *IM, *IF); - Diag((*IM)->getLocation(), diag::warn_conflicting_param_types) - << ImpMethodDecl->getDeclName() << (*IF)->getType() - << (*IM)->getType(); - Diag((*IF)->getLocation(), diag::note_previous_definition); - } if (ImpMethodDecl->isVariadic() != IntfMethodDecl->isVariadic()) { Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic); Diag(IntfMethodDecl->getLocation(), diag::note_previous_declaration); @@ -835,8 +1001,10 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, IDecl->lookupInstanceMethod(method->getSelector()); if (!MethodInClass || !MethodInClass->isSynthesized()) { unsigned DIAG = diag::warn_unimplemented_protocol_method; - if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) { + if (Diags.getDiagnosticLevel(DIAG, ImpLoc) + != Diagnostic::Ignored) { WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); + Diag(method->getLocation(), diag::note_method_declared_at); Diag(CDecl->getLocation(), diag::note_required_for_protocol_at) << PDecl->getDeclName(); } @@ -852,8 +1020,9 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, !ClsMap.count(method->getSelector()) && (!Super || !Super->lookupClassMethod(method->getSelector()))) { unsigned DIAG = diag::warn_unimplemented_protocol_method; - if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) { + if (Diags.getDiagnosticLevel(DIAG, ImpLoc) != Diagnostic::Ignored) { WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); + Diag(method->getLocation(), diag::note_method_declared_at); Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) << PDecl->getDeclName(); } @@ -921,7 +1090,16 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); } } + if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) { + // Also methods in class extensions need be looked at next. + for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension(); + ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, + const_cast<ObjCCategoryDecl *>(ClsExtDecl), + IncompleteImpl, false); + // Check for any implementation of a methods declared in protocol. for (ObjCInterfaceDecl::all_protocol_iterator PI = I->all_referenced_protocol_begin(), @@ -949,7 +1127,8 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, // Check and see if properties declared in the interface have either 1) // an implementation or 2) there is a @synthesize/@dynamic implementation // of the property in the @implementation. - if (isa<ObjCInterfaceDecl>(CDecl) && !LangOpts.ObjCNonFragileABI2) + if (isa<ObjCInterfaceDecl>(CDecl) && + !(LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2)) DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); llvm::DenseSet<Selector> ClsMap; @@ -1156,7 +1335,21 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, // signature. for (ObjCMethodList *List = &Entry; List; List = List->Next) if (MatchTwoMethodDeclarations(Method, List->Method)) { - List->Method->setDefined(impl); + ObjCMethodDecl *PrevObjCMethod = List->Method; + PrevObjCMethod->setDefined(impl); + // If a method is deprecated, push it in the global pool. + // This is used for better diagnostics. + if (Method->getAttr<DeprecatedAttr>()) { + if (!PrevObjCMethod->getAttr<DeprecatedAttr>()) + List->Method = Method; + } + // If new method is unavailable, push it into global pool + // unless previous one is deprecated. + if (Method->getAttr<UnavailableAttr>()) { + if (!PrevObjCMethod->getAttr<UnavailableAttr>() && + !PrevObjCMethod->getAttr<DeprecatedAttr>()) + List->Method = Method; + } return; } @@ -1180,7 +1373,8 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; bool strictSelectorMatch = receiverIdOrClass && warn && - (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl) != + (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl, + R.getBegin()) != Diagnostic::Ignored); if (warn && MethList.Method && MethList.Next) { bool issueWarning = false; @@ -1314,8 +1508,6 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, Diag(L, diag::warn_missing_atend); } - DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); - // FIXME: Remove these and use the ObjCContainerDecl/DeclContext. llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap; llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap; @@ -1335,8 +1527,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, Diag(Method->getLocation(), diag::err_duplicate_method_decl) << Method->getDeclName(); Diag(PrevMethod->getLocation(), diag::note_previous_declaration); + Method->setInvalidDecl(); } else { - DC->addDecl(Method); InsMap[Method->getSelector()] = Method; /// The following allows us to typecheck messages to "id". AddInstanceMethodToGlobalPool(Method); @@ -1354,8 +1546,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, Diag(Method->getLocation(), diag::err_duplicate_method_decl) << Method->getDeclName(); Diag(PrevMethod->getLocation(), diag::note_previous_declaration); + Method->setInvalidDecl(); } else { - DC->addDecl(Method); ClsMap[Method->getSelector()] = Method; /// The following allows us to typecheck messages to "Class". AddFactoryMethodToGlobalPool(Method); @@ -1377,8 +1569,10 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, // Compare protocol properties with those in category CompareProperties(C, C); - if (C->IsClassExtension()) - DiagnoseClassExtensionDupMethods(C, C->getClassInterface()); + if (C->IsClassExtension()) { + ObjCInterfaceDecl *CCPrimary = C->getClassInterface(); + DiagnoseClassExtensionDupMethods(C, CCPrimary); + } } if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) { if (CDecl->getIdentifier()) @@ -1394,7 +1588,40 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) { IC->setAtEndRange(AtEnd); if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) { - if (LangOpts.ObjCNonFragileABI2) + // Any property declared in a class extension might have user + // declared setter or getter in current class extension or one + // of the other class extensions. Mark them as synthesized as + // property will be synthesized when property with same name is + // seen in the @implementation. + for (const ObjCCategoryDecl *ClsExtDecl = + IDecl->getFirstClassExtension(); + ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) { + for (ObjCContainerDecl::prop_iterator I = ClsExtDecl->prop_begin(), + E = ClsExtDecl->prop_end(); I != E; ++I) { + ObjCPropertyDecl *Property = (*I); + // Skip over properties declared @dynamic + if (const ObjCPropertyImplDecl *PIDecl + = IC->FindPropertyImplDecl(Property->getIdentifier())) + if (PIDecl->getPropertyImplementation() + == ObjCPropertyImplDecl::Dynamic) + continue; + + for (const ObjCCategoryDecl *CExtDecl = + IDecl->getFirstClassExtension(); + CExtDecl; CExtDecl = CExtDecl->getNextClassExtension()) { + if (ObjCMethodDecl *GetterMethod = + CExtDecl->getInstanceMethod(Property->getGetterName())) + GetterMethod->setSynthesized(true); + if (!Property->isReadOnly()) + if (ObjCMethodDecl *SetterMethod = + CExtDecl->getInstanceMethod(Property->getSetterName())) + SetterMethod->setSynthesized(true); + } + } + } + + if (LangOpts.ObjCDefaultSynthProperties && + LangOpts.ObjCNonFragileABI2) DefaultSynthesizeProperties(S, IC, IDecl); ImplMethodsVsClassMethods(S, IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); @@ -1469,6 +1696,7 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) { } Decl *Sema::ActOnMethodDeclaration( + Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, tok::TokenKind MethodType, Decl *ClassDecl, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, @@ -1482,7 +1710,6 @@ Decl *Sema::ActOnMethodDeclaration( // Make sure we can establish a context for the method. if (!ClassDecl) { Diag(MethodLoc, diag::error_missing_method_context); - getCurFunction()->LabelMap.clear(); return 0; } QualType resultDeclType; @@ -1526,6 +1753,20 @@ Decl *Sema::ActOnMethodDeclaration( ArgType = adjustParameterType(ArgType); } + LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc, + LookupOrdinaryName, ForRedeclaration); + LookupName(R, S); + if (R.isSingleResult()) { + NamedDecl *PrevDecl = R.getFoundDecl(); + if (S->isDeclScope(PrevDecl)) { + // FIXME. This should be an error; but will break projects. + Diag(ArgInfo[i].NameLoc, diag::warn_method_param_redefinition) + << ArgInfo[i].Name; + Diag(PrevDecl->getLocation(), + diag::note_previous_declaration); + } + } + ParmVarDecl* Param = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, ArgInfo[i].Name, ArgType, DI, @@ -1544,9 +1785,12 @@ Decl *Sema::ActOnMethodDeclaration( // Apply the attributes to the parameter. ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs); + S->AddDecl(Param); + IdResolver.AddDecl(Param); + Params.push_back(Param); } - + for (unsigned i = 0, e = CNumArgs; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(CParamInfo[i].Param); QualType ArgType = Param->getType(); @@ -1562,8 +1806,7 @@ Decl *Sema::ActOnMethodDeclaration( Param->setInvalidDecl(); } Param->setDeclContext(ObjCMethod); - if (Param->getDeclName()) - IdResolver.RemoveDecl(Param); + Params.push_back(Param); } @@ -1578,10 +1821,7 @@ Decl *Sema::ActOnMethodDeclaration( const ObjCMethodDecl *InterfaceMD = 0; - // 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. + // Add the method now. if (ObjCImplementationDecl *ImpDecl = dyn_cast<ObjCImplementationDecl>(ClassDecl)) { if (MethodType == tok::minus) { @@ -1608,6 +1848,8 @@ Decl *Sema::ActOnMethodDeclaration( if (ObjCMethod->hasAttrs() && containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) Diag(EndLoc, diag::warn_attribute_method_def); + } else { + cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod); } if (PrevMethod) { // You can never have two method definitions with the same name. @@ -1619,9 +1861,13 @@ Decl *Sema::ActOnMethodDeclaration( // If the interface declared this method, and it was deprecated there, // mark it deprecated here. if (InterfaceMD) - if (Attr *DA = InterfaceMD->getAttr<DeprecatedAttr>()) - ObjCMethod->addAttr(::new (Context) DeprecatedAttr(DA->getLocation(), - Context)); + if (Attr *DA = InterfaceMD->getAttr<DeprecatedAttr>()) { + StringLiteral *SE = StringLiteral::CreateEmpty(Context, 1); + ObjCMethod->addAttr(::new (Context) + DeprecatedAttr(DA->getLocation(), + Context, + SE->getString())); + } return ObjCMethod; } @@ -1783,20 +2029,24 @@ void Sema::CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, } void ObjCImplementationDecl::setIvarInitializers(ASTContext &C, - CXXBaseOrMemberInitializer ** initializers, + CXXCtorInitializer ** initializers, unsigned numInitializers) { if (numInitializers > 0) { NumIvarInitializers = numInitializers; - CXXBaseOrMemberInitializer **ivarInitializers = - new (C) CXXBaseOrMemberInitializer*[NumIvarInitializers]; + CXXCtorInitializer **ivarInitializers = + new (C) CXXCtorInitializer*[NumIvarInitializers]; memcpy(ivarInitializers, initializers, - numInitializers * sizeof(CXXBaseOrMemberInitializer*)); + numInitializers * sizeof(CXXCtorInitializer*)); IvarInitializers = ivarInitializers; } } void Sema::DiagnoseUseOfUnimplementedSelectors() { - if (ReferencedSelectors.empty()) + // Warning will be issued only when selector table is + // generated (which means there is at lease one implementation + // in the TU). This is to match gcc's behavior. + if (ReferencedSelectors.empty() || + !Context.AnyObjCImplementation()) return; for (llvm::DenseMap<Selector, SourceLocation>::iterator S = ReferencedSelectors.begin(), diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index c902e77..5d7993b 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -113,6 +113,9 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification) return true; + const FunctionProtoType *NewProto + = New->getType()->getAs<FunctionProtoType>(); + // The new function declaration is only missing an empty exception // specification "throw()". If the throw() specification came from a // function in a system header that has C linkage, just add an empty @@ -121,42 +124,38 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // to many libc functions as an optimization. Unfortunately, that // optimization isn't permitted by the C++ standard, so we're forced // to work around it here. - if (MissingEmptyExceptionSpecification && - isa<FunctionProtoType>(New->getType()) && + if (MissingEmptyExceptionSpecification && NewProto && (Old->getLocation().isInvalid() || Context.getSourceManager().isInSystemHeader(Old->getLocation())) && Old->isExternC()) { - const FunctionProtoType *NewProto - = cast<FunctionProtoType>(New->getType()); + FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); + EPI.HasExceptionSpec = true; + EPI.HasAnyExceptionSpec = false; + EPI.NumExceptions = 0; QualType NewType = Context.getFunctionType(NewProto->getResultType(), NewProto->arg_type_begin(), NewProto->getNumArgs(), - NewProto->isVariadic(), - NewProto->getTypeQuals(), - true, false, 0, 0, - NewProto->getExtInfo()); + EPI); New->setType(NewType); return false; } - if (MissingExceptionSpecification && isa<FunctionProtoType>(New->getType())) { - const FunctionProtoType *NewProto - = cast<FunctionProtoType>(New->getType()); + if (MissingExceptionSpecification && NewProto) { const FunctionProtoType *OldProto = Old->getType()->getAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); + EPI.HasExceptionSpec = OldProto->hasExceptionSpec(); + EPI.HasAnyExceptionSpec = OldProto->hasAnyExceptionSpec(); + EPI.NumExceptions = OldProto->getNumExceptions(); + EPI.Exceptions = OldProto->exception_begin(); + // Update the type of the function with the appropriate exception // specification. QualType NewType = Context.getFunctionType(NewProto->getResultType(), NewProto->arg_type_begin(), NewProto->getNumArgs(), - NewProto->isVariadic(), - NewProto->getTypeQuals(), - OldProto->hasExceptionSpec(), - OldProto->hasAnyExceptionSpec(), - OldProto->getNumExceptions(), - OldProto->exception_begin(), - NewProto->getExtInfo()); + EPI); New->setType(NewType); // If exceptions are disabled, suppress the warning about missing @@ -197,7 +196,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { SourceLocation AfterParenLoc; if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { - TypeLoc TL = TSInfo->getTypeLoc(); + TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL)) AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc()); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 80b4652..65b57c3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -19,6 +19,7 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -48,21 +49,57 @@ using namespace sema; /// used, or produce an error (and return true) if a C++0x deleted /// function is being used. /// -/// If IgnoreDeprecated is set to true, this should not want about deprecated +/// If IgnoreDeprecated is set to true, this should not warn about deprecated /// decls. /// /// \returns true if there was an error (this declaration cannot be /// referenced), false otherwise. /// -bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { - // See if the decl is deprecated. - if (D->getAttr<DeprecatedAttr>()) { - EmitDeprecationWarning(D, Loc); +bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, + bool UnknownObjCClass) { + if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) { + // If there were any diagnostics suppressed by template argument deduction, + // emit them now. + llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >::iterator + Pos = SuppressedDiagnostics.find(D->getCanonicalDecl()); + if (Pos != SuppressedDiagnostics.end()) { + llvm::SmallVectorImpl<PartialDiagnosticAt> &Suppressed = Pos->second; + for (unsigned I = 0, N = Suppressed.size(); I != N; ++I) + Diag(Suppressed[I].first, Suppressed[I].second); + + // Clear out the list of suppressed diagnostics, so that we don't emit + // them again for this specialization. However, we don't remove this + // entry from the table, because we want to avoid ever emitting these + // diagnostics again. + Suppressed.clear(); + } + } + + // See if this is an auto-typed variable whose initializer we are parsing. + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->isParsingAutoInit()) { + Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) + << D->getDeclName(); + return true; + } } + // See if the decl is deprecated. + if (const DeprecatedAttr *DA = D->getAttr<DeprecatedAttr>()) + EmitDeprecationWarning(D, DA->getMessage(), Loc, UnknownObjCClass); + // See if the decl is unavailable - if (D->getAttr<UnavailableAttr>()) { - Diag(Loc, diag::err_unavailable) << D->getDeclName(); + if (const UnavailableAttr *UA = D->getAttr<UnavailableAttr>()) { + if (UA->getMessage().empty()) { + if (!UnknownObjCClass) + Diag(Loc, diag::err_unavailable) << D->getDeclName(); + else + Diag(Loc, diag::warn_unavailable_fwdclass_message) + << D->getDeclName(); + } + else + Diag(Loc, diag::err_unavailable_message) + << D->getDeclName() << UA->getMessage(); Diag(D->getLocation(), diag::note_unavailable_here) << 0; } @@ -75,6 +112,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { } } + // Warn if this is used but marked unused. + if (D->hasAttr<UnusedAttr>()) + Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); + return false; } @@ -167,6 +208,10 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, if (!sentinelExpr) return; if (sentinelExpr->isTypeDependent()) return; if (sentinelExpr->isValueDependent()) return; + + // nullptr_t is always treated as null. + if (sentinelExpr->getType()->isNullPtrType()) return; + if (sentinelExpr->getType()->isAnyPointerType() && sentinelExpr->IgnoreParenCasts()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) @@ -208,32 +253,66 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) { // An lvalue or rvalue of type "array of N T" or "array of unknown bound of // T" can be converted to an rvalue of type "pointer to T". // - if (getLangOptions().C99 || getLangOptions().CPlusPlus || - E->isLvalue(Context) == Expr::LV_Valid) + if (getLangOptions().C99 || getLangOptions().CPlusPlus || E->isLValue()) ImpCastExprToType(E, Context.getArrayDecayedType(Ty), CK_ArrayToPointerDecay); } } -void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { - DefaultFunctionArrayConversion(E); +void Sema::DefaultLvalueConversion(Expr *&E) { + // C++ [conv.lval]p1: + // A glvalue of a non-function, non-array type T can be + // converted to a prvalue. + if (!E->isGLValue()) return; - QualType Ty = E->getType(); - assert(!Ty.isNull() && "DefaultFunctionArrayLvalueConversion - missing type"); - if (!Ty->isDependentType() && Ty.hasQualifiers() && - (!getLangOptions().CPlusPlus || !Ty->isRecordType()) && - E->isLvalue(Context) == Expr::LV_Valid) { - // C++ [conv.lval]p1: - // [...] If T is a non-class type, the type of the rvalue is the - // cv-unqualified version of T. Otherwise, the type of the - // rvalue is T - // - // C99 6.3.2.1p2: - // If the lvalue has qualified type, the value has the unqualified - // version of the type of the lvalue; otherwise, the value has the - // type of the lvalue. - ImpCastExprToType(E, Ty.getUnqualifiedType(), CK_NoOp); + QualType T = E->getType(); + assert(!T.isNull() && "r-value conversion on typeless expression?"); + + // Create a load out of an ObjCProperty l-value, if necessary. + if (E->getObjectKind() == OK_ObjCProperty) { + ConvertPropertyForRValue(E); + if (!E->isGLValue()) + return; } + + // We don't want to throw lvalue-to-rvalue casts on top of + // expressions of certain types in C++. + if (getLangOptions().CPlusPlus && + (E->getType() == Context.OverloadTy || + T->isDependentType() || + T->isRecordType())) + return; + + // The C standard is actually really unclear on this point, and + // DR106 tells us what the result should be but not why. It's + // generally best to say that void types just doesn't undergo + // lvalue-to-rvalue at all. Note that expressions of unqualified + // 'void' type are never l-values, but qualified void can be. + if (T->isVoidType()) + return; + + // C++ [conv.lval]p1: + // [...] If T is a non-class type, the type of the prvalue is the + // cv-unqualified version of T. Otherwise, the type of the + // rvalue is T. + // + // C99 6.3.2.1p2: + // If the lvalue has qualified type, the value has the unqualified + // version of the type of the lvalue; otherwise, the value has the + // type of the lvalue. + if (T.hasQualifiers()) + T = T.getUnqualifiedType(); + + if (const ArraySubscriptExpr *ae = dyn_cast<ArraySubscriptExpr>(E)) + CheckArrayAccess(ae); + + E = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, + E, 0, VK_RValue); +} + +void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { + DefaultFunctionArrayConversion(E); + DefaultLvalueConversion(E); } @@ -242,36 +321,43 @@ void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { /// 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(); +Expr *Sema::UsualUnaryConversions(Expr *&E) { + // First, convert to an r-value. + DefaultFunctionArrayLvalueConversion(E); + + QualType Ty = E->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); - - // C99 6.3.1.1p2: - // - // The following may be used in an expression wherever an int or - // unsigned int may be used: - // - an object or expression with an integer type whose integer - // conversion rank is less than or equal to the rank of int - // and unsigned int. - // - A bit-field of type _Bool, int, signed int, or unsigned int. - // - // If an int can represent all values of the original type, the - // 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, CK_IntegralCast); - return Expr; - } - if (Ty->isPromotableIntegerType()) { - QualType PT = Context.getPromotedIntegerType(Ty); - ImpCastExprToType(Expr, PT, CK_IntegralCast); - return Expr; + + // Try to perform integral promotions if the object has a theoretically + // promotable type. + if (Ty->isIntegralOrUnscopedEnumerationType()) { + // C99 6.3.1.1p2: + // + // The following may be used in an expression wherever an int or + // unsigned int may be used: + // - an object or expression with an integer type whose integer + // conversion rank is less than or equal to the rank of int + // and unsigned int. + // - A bit-field of type _Bool, int, signed int, or unsigned int. + // + // If an int can represent all values of the original type, the + // 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(E); + if (!PTy.isNull()) { + ImpCastExprToType(E, PTy, CK_IntegralCast); + return E; + } + if (Ty->isPromotableIntegerType()) { + QualType PT = Context.getPromotedIntegerType(Ty); + ImpCastExprToType(E, PT, CK_IntegralCast); + return E; + } } - DefaultFunctionArrayLvalueConversion(Expr); - return Expr; + return E; } /// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that @@ -281,12 +367,11 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) { QualType Ty = Expr->getType(); assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type"); + UsualUnaryConversions(Expr); + // If this is a 'float' (CVR qualified or typedef) promote to double. if (Ty->isSpecificBuiltinType(BuiltinType::Float)) - return ImpCastExprToType(Expr, Context.DoubleTy, - CK_FloatingCast); - - UsualUnaryConversions(Expr); + return ImpCastExprToType(Expr, Context.DoubleTy, CK_FloatingCast); } /// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but @@ -318,7 +403,6 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT, return false; } - /// 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 @@ -348,19 +432,271 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) return lhs; - // Perform bitfield promotions. + // Apply unary and bitfield promotions to the LHS's type. + QualType lhs_unpromoted = lhs; + if (lhs->isPromotableIntegerType()) + lhs = Context.getPromotedIntegerType(lhs); QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr); if (!LHSBitfieldPromoteTy.isNull()) lhs = LHSBitfieldPromoteTy; - QualType RHSBitfieldPromoteTy = Context.isPromotableBitField(rhsExpr); - if (!RHSBitfieldPromoteTy.isNull()) - rhs = RHSBitfieldPromoteTy; + if (lhs != lhs_unpromoted && !isCompAssign) + ImpCastExprToType(lhsExpr, lhs, CK_IntegralCast); - QualType destType = Context.UsualArithmeticConversionsType(lhs, rhs); - if (!isCompAssign) - ImpCastExprToType(lhsExpr, destType, CK_Unknown); - ImpCastExprToType(rhsExpr, destType, CK_Unknown); - return destType; + // If both types are identical, no conversion is needed. + if (lhs == rhs) + return lhs; + + // At this point, we have two different arithmetic types. + + // Handle complex types first (C99 6.3.1.8p1). + bool LHSComplexFloat = lhs->isComplexType(); + bool RHSComplexFloat = rhs->isComplexType(); + if (LHSComplexFloat || RHSComplexFloat) { + // if we have an integer operand, the result is the complex type. + + if (!RHSComplexFloat && !rhs->isRealFloatingType()) { + if (rhs->isIntegerType()) { + QualType fp = cast<ComplexType>(lhs)->getElementType(); + ImpCastExprToType(rhsExpr, fp, CK_IntegralToFloating); + ImpCastExprToType(rhsExpr, lhs, CK_FloatingRealToComplex); + } else { + assert(rhs->isComplexIntegerType()); + ImpCastExprToType(rhsExpr, lhs, CK_IntegralComplexToFloatingComplex); + } + return lhs; + } + + if (!LHSComplexFloat && !lhs->isRealFloatingType()) { + if (!isCompAssign) { + // int -> float -> _Complex float + if (lhs->isIntegerType()) { + QualType fp = cast<ComplexType>(rhs)->getElementType(); + ImpCastExprToType(lhsExpr, fp, CK_IntegralToFloating); + ImpCastExprToType(lhsExpr, rhs, CK_FloatingRealToComplex); + } else { + assert(lhs->isComplexIntegerType()); + ImpCastExprToType(lhsExpr, rhs, CK_IntegralComplexToFloatingComplex); + } + } + 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 order = Context.getFloatingTypeOrder(lhs, rhs); + + // If both are complex, just cast to the more precise type. + if (LHSComplexFloat && RHSComplexFloat) { + if (order > 0) { + // _Complex float -> _Complex double + ImpCastExprToType(rhsExpr, lhs, CK_FloatingComplexCast); + return lhs; + + } else if (order < 0) { + // _Complex float -> _Complex double + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_FloatingComplexCast); + return rhs; + } + return lhs; + } + + // If just the LHS is complex, the RHS needs to be converted, + // and the LHS might need to be promoted. + if (LHSComplexFloat) { + if (order > 0) { // LHS is wider + // float -> _Complex double + QualType fp = cast<ComplexType>(lhs)->getElementType(); + ImpCastExprToType(rhsExpr, fp, CK_FloatingCast); + ImpCastExprToType(rhsExpr, lhs, CK_FloatingRealToComplex); + return lhs; + } + + // RHS is at least as wide. Find its corresponding complex type. + QualType result = (order == 0 ? lhs : Context.getComplexType(rhs)); + + // double -> _Complex double + ImpCastExprToType(rhsExpr, result, CK_FloatingRealToComplex); + + // _Complex float -> _Complex double + if (!isCompAssign && order < 0) + ImpCastExprToType(lhsExpr, result, CK_FloatingComplexCast); + + return result; + } + + // Just the RHS is complex, so the LHS needs to be converted + // and the RHS might need to be promoted. + assert(RHSComplexFloat); + + if (order < 0) { // RHS is wider + // float -> _Complex double + if (!isCompAssign) { + QualType fp = cast<ComplexType>(rhs)->getElementType(); + ImpCastExprToType(lhsExpr, fp, CK_FloatingCast); + ImpCastExprToType(lhsExpr, rhs, CK_FloatingRealToComplex); + } + return rhs; + } + + // LHS is at least as wide. Find its corresponding complex type. + QualType result = (order == 0 ? rhs : Context.getComplexType(lhs)); + + // double -> _Complex double + if (!isCompAssign) + ImpCastExprToType(lhsExpr, result, CK_FloatingRealToComplex); + + // _Complex float -> _Complex double + if (order > 0) + ImpCastExprToType(rhsExpr, result, CK_FloatingComplexCast); + + return result; + } + + // Now handle "real" floating types (i.e. float, double, long double). + bool LHSFloat = lhs->isRealFloatingType(); + bool RHSFloat = rhs->isRealFloatingType(); + if (LHSFloat || RHSFloat) { + // If we have two real floating types, convert the smaller operand + // to the bigger result. + if (LHSFloat && RHSFloat) { + int order = Context.getFloatingTypeOrder(lhs, rhs); + if (order > 0) { + ImpCastExprToType(rhsExpr, lhs, CK_FloatingCast); + return lhs; + } + + assert(order < 0 && "illegal float comparison"); + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_FloatingCast); + return rhs; + } + + // If we have an integer operand, the result is the real floating type. + if (LHSFloat) { + if (rhs->isIntegerType()) { + // Convert rhs to the lhs floating point type. + ImpCastExprToType(rhsExpr, lhs, CK_IntegralToFloating); + return lhs; + } + + // Convert both sides to the appropriate complex float. + assert(rhs->isComplexIntegerType()); + QualType result = Context.getComplexType(lhs); + + // _Complex int -> _Complex float + ImpCastExprToType(rhsExpr, result, CK_IntegralComplexToFloatingComplex); + + // float -> _Complex float + if (!isCompAssign) + ImpCastExprToType(lhsExpr, result, CK_FloatingRealToComplex); + + return result; + } + + assert(RHSFloat); + if (lhs->isIntegerType()) { + // Convert lhs to the rhs floating point type. + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_IntegralToFloating); + return rhs; + } + + // Convert both sides to the appropriate complex float. + assert(lhs->isComplexIntegerType()); + QualType result = Context.getComplexType(rhs); + + // _Complex int -> _Complex float + if (!isCompAssign) + ImpCastExprToType(lhsExpr, result, CK_IntegralComplexToFloatingComplex); + + // float -> _Complex float + ImpCastExprToType(rhsExpr, result, CK_FloatingRealToComplex); + + return result; + } + + // Handle GCC complex int extension. + // FIXME: if the operands are (int, _Complex long), we currently + // don't promote the complex. Also, signedness? + const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); + const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); + if (lhsComplexInt && rhsComplexInt) { + int order = Context.getIntegerTypeOrder(lhsComplexInt->getElementType(), + rhsComplexInt->getElementType()); + assert(order && "inequal types with equal element ordering"); + if (order > 0) { + // _Complex int -> _Complex long + ImpCastExprToType(rhsExpr, lhs, CK_IntegralComplexCast); + return lhs; + } + + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_IntegralComplexCast); + return rhs; + } else if (lhsComplexInt) { + // int -> _Complex int + ImpCastExprToType(rhsExpr, lhs, CK_IntegralRealToComplex); + return lhs; + } else if (rhsComplexInt) { + // int -> _Complex int + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_IntegralRealToComplex); + 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->hasSignedIntegerRepresentation(), + rhsSigned = rhs->hasSignedIntegerRepresentation(); + if (lhsSigned == rhsSigned) { + // Same signedness; use the higher-ranked type + if (compare >= 0) { + ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast); + return lhs; + } else if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast); + return 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 + if (rhsSigned) { + ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast); + return lhs; + } else if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast); + return rhs; + } 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. + if (lhsSigned) { + ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast); + return lhs; + } else if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast); + return 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. + QualType result = + Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs); + ImpCastExprToType(rhsExpr, result, CK_IntegralCast); + if (!isCompAssign) + ImpCastExprToType(lhsExpr, result, CK_IntegralCast); + return result; + } } //===----------------------------------------------------------------------===// @@ -409,245 +745,366 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { StringTokLocs.size())); } -/// ShouldSnapshotBlockValueReference - Return true if a reference inside of -/// CurBlock to VD should cause it to be snapshotted (as we do for auto -/// variables defined outside the block) or false if this is not needed (e.g. -/// for values inside the block or for globals). +enum CaptureResult { + /// No capture is required. + CR_NoCapture, + + /// A capture is required. + CR_Capture, + + /// A by-ref capture is required. + CR_CaptureByRef, + + /// An error occurred when trying to capture the given variable. + CR_Error +}; + +/// Diagnose an uncapturable value reference. /// -/// This also keeps the 'hasBlockDeclRefExprs' in the BlockScopeInfo records -/// up-to-date. +/// \param var - the variable referenced +/// \param DC - the context which we couldn't capture through +static CaptureResult +diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, + VarDecl *var, DeclContext *DC) { + switch (S.ExprEvalContexts.back().Context) { + case Sema::Unevaluated: + // The argument will never be evaluated, so don't complain. + return CR_NoCapture; + + case Sema::PotentiallyEvaluated: + case Sema::PotentiallyEvaluatedIfUsed: + break; + + case Sema::PotentiallyPotentiallyEvaluated: + // FIXME: delay these! + break; + } + + // Don't diagnose about capture if we're not actually in code right + // now; in general, there are more appropriate places that will + // diagnose this. + if (!S.CurContext->isFunctionOrMethod()) return CR_NoCapture; + + // This particular madness can happen in ill-formed default + // arguments; claim it's okay and let downstream code handle it. + if (isa<ParmVarDecl>(var) && + S.CurContext == var->getDeclContext()->getParent()) + return CR_NoCapture; + + DeclarationName functionName; + if (FunctionDecl *fn = dyn_cast<FunctionDecl>(var->getDeclContext())) + functionName = fn->getDeclName(); + // FIXME: variable from enclosing block that we couldn't capture from! + + S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function) + << var->getIdentifier() << functionName; + S.Diag(var->getLocation(), diag::note_local_variable_declared_here) + << var->getIdentifier(); + + return CR_Error; +} + +/// There is a well-formed capture at a particular scope level; +/// propagate it through all the nested blocks. +static CaptureResult propagateCapture(Sema &S, unsigned validScopeIndex, + const BlockDecl::Capture &capture) { + VarDecl *var = capture.getVariable(); + + // Update all the inner blocks with the capture information. + for (unsigned i = validScopeIndex + 1, e = S.FunctionScopes.size(); + i != e; ++i) { + BlockScopeInfo *innerBlock = cast<BlockScopeInfo>(S.FunctionScopes[i]); + innerBlock->Captures.push_back( + BlockDecl::Capture(capture.getVariable(), capture.isByRef(), + /*nested*/ true, capture.getCopyExpr())); + innerBlock->CaptureMap[var] = innerBlock->Captures.size(); // +1 + } + + return capture.isByRef() ? CR_CaptureByRef : CR_Capture; +} + +/// shouldCaptureValueReference - Determine if a reference to the +/// given value in the current context requires a variable capture. /// -static bool ShouldSnapshotBlockValueReference(Sema &S, BlockScopeInfo *CurBlock, - ValueDecl *VD) { - // If the value is defined inside the block, we couldn't snapshot it even if - // we wanted to. - if (CurBlock->TheDecl == VD->getDeclContext()) - return false; +/// This also keeps the captures set in the BlockScopeInfo records +/// up-to-date. +static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc, + ValueDecl *value) { + // Only variables ever require capture. + VarDecl *var = dyn_cast<VarDecl>(value); + if (!var) return CR_NoCapture; - // If this is an enum constant or function, it is constant, don't snapshot. - if (isa<EnumConstantDecl>(VD) || isa<FunctionDecl>(VD)) - return false; + // Fast path: variables from the current context never require capture. + DeclContext *DC = S.CurContext; + if (var->getDeclContext() == DC) return CR_NoCapture; - // If this is a reference to an extern, static, or global variable, no need to - // snapshot it. + // Only variables with local storage require capture. // FIXME: What about 'const' variables in C++? - if (const VarDecl *Var = dyn_cast<VarDecl>(VD)) - if (!Var->hasLocalStorage()) - return false; + if (!var->hasLocalStorage()) return CR_NoCapture; - // Blocks that have these can't be constant. - CurBlock->hasBlockDeclRefExprs = true; + // Otherwise, we need to capture. - // If we have nested blocks, the decl may be declared in an outer block (in - // which case that outer block doesn't get "hasBlockDeclRefExprs") or it may - // be defined outside all of the current blocks (in which case the blocks do - // all get the bit). Walk the nesting chain. - for (unsigned I = S.FunctionScopes.size() - 1; I; --I) { - BlockScopeInfo *NextBlock = dyn_cast<BlockScopeInfo>(S.FunctionScopes[I]); + unsigned functionScopesIndex = S.FunctionScopes.size() - 1; + do { + // Only blocks (and eventually C++0x closures) can capture; other + // scopes don't work. + if (!isa<BlockDecl>(DC)) + return diagnoseUncapturableValueReference(S, loc, var, DC); - if (!NextBlock) - continue; + BlockScopeInfo *blockScope = + cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]); + assert(blockScope->TheDecl == static_cast<BlockDecl*>(DC)); - // If we found the defining block for the variable, don't mark the block as - // having a reference outside it. - if (NextBlock->TheDecl == VD->getDeclContext()) - break; + // Check whether we've already captured it in this block. If so, + // we're done. + if (unsigned indexPlus1 = blockScope->CaptureMap[var]) + return propagateCapture(S, functionScopesIndex, + blockScope->Captures[indexPlus1 - 1]); + + functionScopesIndex--; + DC = cast<BlockDecl>(DC)->getDeclContext(); + } while (var->getDeclContext() != DC); - // Otherwise, the DeclRef from the inner block causes the outer one to need - // a snapshot as well. - NextBlock->hasBlockDeclRefExprs = true; + // Okay, we descended all the way to the block that defines the variable. + // Actually try to capture it. + QualType type = var->getType(); + + // Prohibit variably-modified types. + if (type->isVariablyModifiedType()) { + S.Diag(loc, diag::err_ref_vm_type); + S.Diag(var->getLocation(), diag::note_declared_at); + return CR_Error; } - return true; -} + // Prohibit arrays, even in __block variables, but not references to + // them. + if (type->isArrayType()) { + S.Diag(loc, diag::err_ref_array_type); + S.Diag(var->getLocation(), diag::note_declared_at); + return CR_Error; + } + + S.MarkDeclarationReferenced(loc, var); + + // The BlocksAttr indicates the variable is bound by-reference. + bool byRef = var->hasAttr<BlocksAttr>(); + + // Build a copy expression. + Expr *copyExpr = 0; + if (!byRef && S.getLangOptions().CPlusPlus && + !type->isDependentType() && type->isStructureOrClassType()) { + // According to the blocks spec, the capture of a variable from + // the stack requires a const copy constructor. This is not true + // of the copy/move done to move a __block variable to the heap. + type.addConst(); + + Expr *declRef = new (S.Context) DeclRefExpr(var, type, VK_LValue, loc); + ExprResult result = + S.PerformCopyInitialization( + InitializedEntity::InitializeBlock(var->getLocation(), + type, false), + loc, S.Owned(declRef)); + + // Build a full-expression copy expression if initialization + // succeeded and used a non-trivial constructor. Recover from + // errors by pretending that the copy isn't necessary. + if (!result.isInvalid() && + !cast<CXXConstructExpr>(result.get())->getConstructor()->isTrivial()) { + result = S.MaybeCreateExprWithCleanups(result); + copyExpr = result.take(); + } + } + + // We're currently at the declarer; go back to the closure. + functionScopesIndex++; + BlockScopeInfo *blockScope = + cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]); + + // Build a valid capture in this scope. + blockScope->Captures.push_back( + BlockDecl::Capture(var, byRef, /*nested*/ false, copyExpr)); + blockScope->CaptureMap[var] = blockScope->Captures.size(); // +1 + + // Propagate that to inner captures if necessary. + return propagateCapture(S, functionScopesIndex, + blockScope->Captures.back()); +} + +static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *vd, + const DeclarationNameInfo &NameInfo, + bool byRef) { + assert(isa<VarDecl>(vd) && "capturing non-variable"); + + VarDecl *var = cast<VarDecl>(vd); + assert(var->hasLocalStorage() && "capturing non-local"); + assert(byRef == var->hasAttr<BlocksAttr>() && "byref set wrong"); + + QualType exprType = var->getType().getNonReferenceType(); + + BlockDeclRefExpr *BDRE; + if (!byRef) { + // The variable will be bound by copy; make it const within the + // closure, but record that this was done in the expression. + bool constAdded = !exprType.isConstQualified(); + exprType.addConst(); + + BDRE = new (S.Context) BlockDeclRefExpr(var, exprType, VK_LValue, + NameInfo.getLoc(), false, + constAdded); + } else { + BDRE = new (S.Context) BlockDeclRefExpr(var, exprType, VK_LValue, + NameInfo.getLoc(), true); + } + return S.Owned(BDRE); +} ExprResult -Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, +Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, + SourceLocation Loc, const CXXScopeSpec *SS) { DeclarationNameInfo NameInfo(D->getDeclName(), Loc); - return BuildDeclRefExpr(D, Ty, NameInfo, SS); + return BuildDeclRefExpr(D, Ty, VK, NameInfo, SS); } -/// BuildDeclRefExpr - Build a DeclRefExpr. +/// BuildDeclRefExpr - Build an expression that references a +/// declaration that does not require a closure capture. ExprResult -Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, +Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS) { - if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) { - Diag(NameInfo.getLoc(), - diag::err_auto_variable_cannot_appear_in_own_initializer) - << D->getDeclName(); - return ExprError(); - } - - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (isa<NonTypeTemplateParmDecl>(VD)) { - // Non-type template parameters can be referenced anywhere they are - // visible. - Ty = Ty.getNonLValueExprType(Context); - } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { - if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) { - if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) { - Diag(NameInfo.getLoc(), - diag::err_reference_to_local_var_in_enclosing_function) - << D->getIdentifier() << FD->getDeclName(); - Diag(D->getLocation(), diag::note_local_variable_declared_here) - << D->getIdentifier(); - return ExprError(); - } - } - } - } - MarkDeclarationReferenced(NameInfo.getLoc(), D); - return Owned(DeclRefExpr::Create(Context, + Expr *E = DeclRefExpr::Create(Context, SS? (NestedNameSpecifier *)SS->getScopeRep() : 0, - SS? SS->getRange() : SourceRange(), - D, NameInfo, Ty)); -} + SS? SS->getRange() : SourceRange(), + D, NameInfo, Ty, VK); -/// \brief Given a field that represents a member of an anonymous -/// struct/union, build the path from that field's context to the -/// actual member. -/// -/// Construct the sequence of field member references we'll have to -/// perform to get to the field in the anonymous union/struct. The -/// list of members is built from the field outward, so traverse it -/// backwards to go from an object in the current context to the field -/// we found. -/// -/// \returns The variable from which the field access should begin, -/// for an anonymous struct/union that is not a member of another -/// class. Otherwise, returns NULL. -VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field, - llvm::SmallVectorImpl<FieldDecl *> &Path) { - assert(Field->getDeclContext()->isRecord() && - cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion() - && "Field must be stored inside an anonymous struct or union"); - - Path.push_back(Field); - VarDecl *BaseObject = 0; - DeclContext *Ctx = Field->getDeclContext(); - do { - RecordDecl *Record = cast<RecordDecl>(Ctx); - ValueDecl *AnonObject = Record->getAnonymousStructOrUnionObject(); - if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject)) - Path.push_back(AnonField); - else { - BaseObject = cast<VarDecl>(AnonObject); - break; - } - Ctx = Ctx->getParent(); - } while (Ctx->isRecord() && - cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion()); + // Just in case we're building an illegal pointer-to-member. + if (isa<FieldDecl>(D) && cast<FieldDecl>(D)->getBitWidth()) + E->setObjectKind(OK_BitField); - return BaseObject; + return Owned(E); } +static ExprResult +BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, + const CXXScopeSpec &SS, FieldDecl *Field, + DeclAccessPair FoundDecl, + const DeclarationNameInfo &MemberNameInfo); + ExprResult -Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, - FieldDecl *Field, - Expr *BaseObjectExpr, - SourceLocation OpLoc) { - llvm::SmallVector<FieldDecl *, 4> AnonFields; - VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field, - AnonFields); - - // Build the expression that refers to the base object, from - // which we will build a sequence of member references to each - // of the anonymous union objects and, eventually, the field we - // found via name lookup. - bool BaseObjectIsPointer = false; - Qualifiers BaseQuals; - if (BaseObject) { - // BaseObject is an anonymous struct/union variable (and is, - // therefore, not part of another non-anonymous record). - MarkDeclarationReferenced(Loc, BaseObject); - BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(), - SourceLocation()); - BaseQuals - = Context.getCanonicalType(BaseObject->getType()).getQualifiers(); - } else if (BaseObjectExpr) { +Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, + SourceLocation loc, + IndirectFieldDecl *indirectField, + Expr *baseObjectExpr, + SourceLocation opLoc) { + // First, build the expression that refers to the base object. + + bool baseObjectIsPointer = false; + Qualifiers baseQuals; + + // Case 1: the base of the indirect field is not a field. + VarDecl *baseVariable = indirectField->getVarDecl(); + CXXScopeSpec EmptySS; + if (baseVariable) { + assert(baseVariable->getType()->isRecordType()); + + // In principle we could have a member access expression that + // accesses an anonymous struct/union that's a static member of + // the base object's class. However, under the current standard, + // static data members cannot be anonymous structs or unions. + // Supporting this is as easy as building a MemberExpr here. + assert(!baseObjectExpr && "anonymous struct/union is static data member?"); + + DeclarationNameInfo baseNameInfo(DeclarationName(), loc); + + ExprResult result = + BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable); + if (result.isInvalid()) return ExprError(); + + baseObjectExpr = result.take(); + baseObjectIsPointer = false; + baseQuals = baseObjectExpr->getType().getQualifiers(); + + // Case 2: the base of the indirect field is a field and the user + // wrote a member expression. + } else if (baseObjectExpr) { // The caller provided the base object expression. Determine // whether its a pointer and whether it adds any qualifiers to the // anonymous struct/union fields we're looking into. - QualType ObjectType = BaseObjectExpr->getType(); - if (const PointerType *ObjectPtr = ObjectType->getAs<PointerType>()) { - BaseObjectIsPointer = true; - ObjectType = ObjectPtr->getPointeeType(); + QualType objectType = baseObjectExpr->getType(); + + if (const PointerType *ptr = objectType->getAs<PointerType>()) { + baseObjectIsPointer = true; + objectType = ptr->getPointeeType(); + } else { + baseObjectIsPointer = false; } - BaseQuals - = Context.getCanonicalType(ObjectType).getQualifiers(); + baseQuals = objectType.getQualifiers(); + + // Case 3: the base of the indirect field is a field and we should + // build an implicit member access. } else { // We've found a member of an anonymous struct/union that is // inside a non-anonymous struct/union, so in a well-formed // program our base object expression is "this". - DeclContext *DC = getFunctionLevelDeclContext(); - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) { - if (!MD->isStatic()) { - QualType AnonFieldType - = Context.getTagDeclType( - cast<RecordDecl>(AnonFields.back()->getDeclContext())); - QualType ThisType = Context.getTagDeclType(MD->getParent()); - if ((Context.getCanonicalType(AnonFieldType) - == Context.getCanonicalType(ThisType)) || - IsDerivedFrom(ThisType, AnonFieldType)) { - // Our base object expression is "this". - BaseObjectExpr = new (Context) CXXThisExpr(Loc, - MD->getThisType(Context), - /*isImplicit=*/true); - BaseObjectIsPointer = true; - } - } else { - return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method) - << Field->getDeclName()); - } - BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers()); + CXXMethodDecl *method = tryCaptureCXXThis(); + if (!method) { + Diag(loc, diag::err_invalid_member_use_in_static_method) + << indirectField->getDeclName(); + return ExprError(); } - if (!BaseObjectExpr) - return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use) - << Field->getDeclName()); + // Our base object expression is "this". + baseObjectExpr = + new (Context) CXXThisExpr(loc, method->getThisType(Context), + /*isImplicit=*/ true); + baseObjectIsPointer = true; + baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers()); } // 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(); - Qualifiers MemberTypeQuals = - Context.getCanonicalType(MemberType).getQualifiers(); + Expr *result = baseObjectExpr; + IndirectFieldDecl::chain_iterator + FI = indirectField->chain_begin(), FEnd = indirectField->chain_end(); - // CVR attributes from the base are picked up by members, - // except that 'mutable' members don't pick up 'const'. - if ((*FI)->isMutable()) - ResultQuals.removeConst(); + // Build the first member access in the chain with full information. + if (!baseVariable) { + FieldDecl *field = cast<FieldDecl>(*FI); - // GC attributes are never picked up by members. - ResultQuals.removeObjCGCAttr(); + // FIXME: use the real found-decl info! + DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); - // TR 18037 does not allow fields to be declared with address spaces. - assert(!MemberTypeQuals.hasAddressSpace()); + // Make a nameInfo that properly uses the anonymous name. + DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); - Qualifiers NewQuals = ResultQuals + MemberTypeQuals; - if (NewQuals != MemberTypeQuals) - MemberType = Context.getQualifiedType(MemberType, NewQuals); + result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer, + EmptySS, field, foundDecl, + memberNameInfo).take(); + baseObjectIsPointer = false; - MarkDeclarationReferenced(Loc, *FI); - PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI, *FI); - // FIXME: Might this end up being a qualified name? - Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI, - OpLoc, MemberType); - BaseObjectIsPointer = false; - ResultQuals = NewQuals; + // FIXME: check qualified member access } - return Owned(Result); + // In all cases, we should now skip the first declaration in the chain. + ++FI; + + while (FI != FEnd) { + FieldDecl *field = cast<FieldDecl>(*FI++); + + // FIXME: these are somewhat meaningless + DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); + DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); + + result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false, + (FI == FEnd? SS : EmptySS), field, + foundDecl, memberNameInfo) + .take(); + } + + return Owned(result); } /// Decomposes the given name into a DeclarationNameInfo, its location, and @@ -684,28 +1141,6 @@ static void DecomposeUnqualifiedId(Sema &SemaRef, } } -/// Determines whether the given record is "fully-formed" at the given -/// location, i.e. whether a qualified lookup into it is assured of -/// getting consistent results already. -static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) { - if (!Record->hasDefinition()) - return false; - - for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), - E = Record->bases_end(); I != E; ++I) { - CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType()); - CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>(); - if (!BaseRT) return false; - - CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl()); - if (!BaseRecord->hasDefinition() || - !IsFullyFormedScope(SemaRef, BaseRecord)) - return false; - } - - return true; -} - /// Determines if the given class is provably not derived from all of /// the prospective base classes. static bool IsProvablyNotDerivedFrom(Sema &SemaRef, @@ -757,10 +1192,6 @@ enum IMAKind { /// context is not an instance method. IMA_Unresolved_StaticContext, - /// The reference is to a member of an anonymous structure in a - /// non-class context. - IMA_AnonymousMember, - /// All possible referrents are instance members and the current /// context is not an instance method. IMA_Error_StaticContext, @@ -790,19 +1221,16 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, // Collect all the declaring classes of instance members we find. bool hasNonInstance = false; + bool hasField = false; llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes; for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { NamedDecl *D = *I; + if (D->isCXXInstanceMember()) { - CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); + if (dyn_cast<FieldDecl>(D)) + hasField = true; - // If this is a member of an anonymous record, move out to the - // innermost non-anonymous struct or union. If there isn't one, - // that's a special case. - while (R->isAnonymousStructOrUnion()) { - R = dyn_cast<CXXRecordDecl>(R->getParent()); - if (!R) return IMA_AnonymousMember; - } + CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); Classes.insert(R->getCanonicalDecl()); } else @@ -816,8 +1244,24 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, // If the current context is not an instance method, it can't be // an implicit member reference. - if (isStaticContext) - return (hasNonInstance ? IMA_Mixed_StaticContext : IMA_Error_StaticContext); + if (isStaticContext) { + if (hasNonInstance) + return IMA_Mixed_StaticContext; + + if (SemaRef.getLangOptions().CPlusPlus0x && hasField) { + // C++0x [expr.prim.general]p10: + // An id-expression that denotes a non-static data member or non-static + // member function of a class can only be used: + // (...) + // - if that id-expression denotes a non-static data member and it appears in an unevaluated operand. + const Sema::ExpressionEvaluationContextRecord& record = SemaRef.ExprEvalContexts.back(); + bool isUnevaluatedExpression = record.Context == Sema::Unevaluated; + if (isUnevaluatedExpression) + return IMA_Mixed_StaticContext; + } + + return IMA_Error_StaticContext; + } // If we can prove that the current context is unrelated to all the // declaring classes, it can't be an implicit member reference (in @@ -833,23 +1277,24 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, /// Diagnose a reference to a field with no object available. static void DiagnoseInstanceReference(Sema &SemaRef, const CXXScopeSpec &SS, - const LookupResult &R) { - SourceLocation Loc = R.getNameLoc(); + NamedDecl *rep, + const DeclarationNameInfo &nameInfo) { + SourceLocation Loc = nameInfo.getLoc(); SourceRange Range(Loc); if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); - if (R.getAsSingle<FieldDecl>()) { + if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) { if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) { if (MD->isStatic()) { // "invalid use of member 'x' in static member function" SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method) - << Range << R.getLookupName(); + << Range << nameInfo.getName(); return; } } SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use) - << R.getLookupName() << Range; + << nameInfo.getName() << Range; return; } @@ -1001,25 +1446,41 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, return true; } -static ObjCPropertyDecl *OkToSynthesizeProvisionalIvar(Sema &SemaRef, - IdentifierInfo *II, - SourceLocation NameLoc) { - ObjCMethodDecl *CurMeth = SemaRef.getCurMethodDecl(); +ObjCPropertyDecl *Sema::canSynthesizeProvisionalIvar(IdentifierInfo *II) { + ObjCMethodDecl *CurMeth = getCurMethodDecl(); ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); if (!IDecl) return 0; ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); if (!ClassImpDecl) return 0; - ObjCPropertyDecl *property = SemaRef.LookupPropertyDecl(IDecl, II); + ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II); if (!property) return 0; if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) - if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic || + PIDecl->getPropertyIvarDecl()) return 0; return property; } +bool Sema::canSynthesizeProvisionalIvar(ObjCPropertyDecl *Property) { + ObjCMethodDecl *CurMeth = getCurMethodDecl(); + ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); + if (!IDecl) + return false; + ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); + if (!ClassImpDecl) + return false; + if (ObjCPropertyImplDecl *PIDecl + = ClassImpDecl->FindPropertyImplDecl(Property->getIdentifier())) + if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic || + PIDecl->getPropertyIvarDecl()) + return false; + + return true; +} + static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef, LookupResult &Lookup, IdentifierInfo *II, @@ -1032,7 +1493,8 @@ static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef, LookForIvars = false; else LookForIvars = (Lookup.isSingleResult() && - Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()); + Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod() && + (Lookup.getAsSingle<VarDecl>() != 0)); if (!LookForIvars) return 0; @@ -1046,15 +1508,20 @@ static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef, ObjCPropertyDecl *property = SemaRef.LookupPropertyDecl(IDecl, II); if (!property) return 0; - if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) + if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) { DynamicImplSeen = (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); + // property implementation has a designated ivar. No need to assume a new + // one. + if (!DynamicImplSeen && PIDecl->getPropertyIvarDecl()) + return 0; + } if (!DynamicImplSeen) { QualType PropType = SemaRef.Context.getCanonicalType(property->getType()); ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(SemaRef.Context, ClassImpDecl, NameLoc, II, PropType, /*Dinfo=*/0, - ObjCIvarDecl::Protected, + ObjCIvarDecl::Private, (Expr *)0, true); ClassImpDecl->addDecl(Ivar); IDecl->makeDeclVisibleInContext(Ivar, false); @@ -1102,22 +1569,18 @@ ExprResult Sema::ActOnIdExpression(Scope *S, Name.getCXXNameType()->isDependentType()) { DependentID = true; } else if (SS.isSet()) { - DeclContext *DC = computeDeclContext(SS, false); - if (DC) { + if (DeclContext *DC = computeDeclContext(SS, false)) { if (RequireCompleteDeclContext(SS, DC)) return ExprError(); - // FIXME: We should be checking whether DC is the current instantiation. - if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) - DependentID = !IsFullyFormedScope(*this, RD); } else { DependentID = true; } } - if (DependentID) { + if (DependentID) return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand, TemplateArgs); - } + bool IvarLookupFollowUp = false; // Perform the required lookup. LookupResult R(*this, NameInfo, LookupOrdinaryName); @@ -1130,10 +1593,21 @@ ExprResult Sema::ActOnIdExpression(Scope *S, bool MemberOfUnknownSpecialization; LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, MemberOfUnknownSpecialization); + + if (MemberOfUnknownSpecialization || + (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) + return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand, + TemplateArgs); } else { IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); LookupParsedName(R, S, &SS, !IvarLookupFollowUp); + // If the result might be in a dependent base class, this is a dependent + // id-expression. + if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) + return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand, + TemplateArgs); + // If this reference is in an Objective-C method, then we need to do // some special Objective-C lookup, too. if (IvarLookupFollowUp) { @@ -1141,13 +1615,21 @@ ExprResult Sema::ActOnIdExpression(Scope *S, if (E.isInvalid()) return ExprError(); - Expr *Ex = E.takeAs<Expr>(); - if (Ex) return Owned(Ex); - // Synthesize ivars lazily - if (getLangOptions().ObjCNonFragileABI2) { - if (SynthesizeProvisionalIvar(*this, R, II, NameLoc)) + if (Expr *Ex = E.takeAs<Expr>()) + return Owned(Ex); + + // Synthesize ivars lazily. + if (getLangOptions().ObjCDefaultSynthProperties && + getLangOptions().ObjCNonFragileABI2) { + if (SynthesizeProvisionalIvar(*this, R, II, NameLoc)) { + if (const ObjCPropertyDecl *Property = + canSynthesizeProvisionalIvar(II)) { + Diag(NameLoc, diag::warn_synthesized_ivar_access) << II; + Diag(Property->getLocation(), diag::note_property_declare); + } return ActOnIdExpression(S, SS, Id, HasTrailingLParen, isAddressOfOperand); + } } // for further use, this must be set to false if in class method. IvarLookupFollowUp = getCurMethodDecl()->isInstanceMethod(); @@ -1195,33 +1677,16 @@ ExprResult Sema::ActOnIdExpression(Scope *S, if (VarDecl *Var = R.getAsSingle<VarDecl>()) { if (getLangOptions().ObjCNonFragileABI && IvarLookupFollowUp && - !getLangOptions().ObjCNonFragileABI2 && + !(getLangOptions().ObjCDefaultSynthProperties && + getLangOptions().ObjCNonFragileABI2) && Var->isFileVarDecl()) { - ObjCPropertyDecl *Property = - OkToSynthesizeProvisionalIvar(*this, II, NameLoc); + ObjCPropertyDecl *Property = canSynthesizeProvisionalIvar(II); if (Property) { Diag(NameLoc, diag::warn_ivar_variable_conflict) << Var->getDeclName(); Diag(Property->getLocation(), diag::note_property_declare); Diag(Var->getLocation(), diag::note_global_declared_at); } } - } else if (FunctionDecl *Func = R.getAsSingle<FunctionDecl>()) { - if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) { - // C99 DR 316 says that, if a function type comes from a - // function definition (without a prototype), that type is only - // used for checking compatibility. Therefore, when referencing - // the function, we pretend that we don't have the full function - // type. - if (DiagnoseUseOfDecl(Func, NameLoc)) - return ExprError(); - - QualType T = Func->getType(); - QualType NoProtoType = T; - if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>()) - NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType(), - Proto->getExtInfo()); - return BuildDeclRefExpr(Func, NoProtoType, NameLoc, &SS); - } } // Check whether this might be a C++ implicit instance member access. @@ -1259,7 +1724,8 @@ ExprResult Sema::ActOnIdExpression(Scope *S, else if (R.isUnresolvableResult()) MightBeImplicitMember = true; else - MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()); + MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) || + isa<IndirectFieldDecl>(R.getFoundDecl()); if (MightBeImplicitMember) return BuildPossibleImplicitMemberExpr(SS, R, TemplateArgs); @@ -1280,11 +1746,6 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, case IMA_Instance: return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); - case IMA_AnonymousMember: - assert(R.isSingleResult()); - return BuildAnonymousStructUnionMemberReference(R.getNameLoc(), - R.getAsSingle<FieldDecl>()); - case IMA_Mixed: case IMA_Mixed_Unrelated: case IMA_Unresolved: @@ -1299,7 +1760,8 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, case IMA_Error_StaticContext: case IMA_Error_Unrelated: - DiagnoseInstanceReference(*this, SS, R); + DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(), + R.getLookupNameInfo()); return ExprError(); } @@ -1400,11 +1862,17 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, SelfName.setIdentifier(&II, SourceLocation()); CXXScopeSpec SelfScopeSpec; ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, - SelfName, false, false); + SelfName, false, false); + if (SelfExpr.isInvalid()) + return ExprError(); + + Expr *SelfE = SelfExpr.take(); + DefaultLvalueConversion(SelfE); + MarkDeclarationReferenced(Loc, IV); return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), Loc, - SelfExpr.takeAs<Expr>(), true, true)); + SelfE, true, true)); } } else if (CurMethod->isInstanceMethod()) { // We should warn if a local variable hides an ivar. @@ -1607,6 +2075,7 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo, QualType Ty, + ExprValueKind VK, ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = 0) { NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; @@ -1617,7 +2086,65 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange, Member, FoundDecl, MemberNameInfo, - TemplateArgs, Ty); + TemplateArgs, Ty, VK, OK); +} + +static ExprResult +BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, + const CXXScopeSpec &SS, FieldDecl *Field, + DeclAccessPair FoundDecl, + const DeclarationNameInfo &MemberNameInfo) { + // x.a is an l-value if 'a' has a reference type. Otherwise: + // x.a is an l-value/x-value/pr-value if the base is (and note + // that *x is always an l-value), except that if the base isn't + // an ordinary object then we must have an rvalue. + ExprValueKind VK = VK_LValue; + ExprObjectKind OK = OK_Ordinary; + if (!IsArrow) { + if (BaseExpr->getObjectKind() == OK_Ordinary) + VK = BaseExpr->getValueKind(); + else + VK = VK_RValue; + } + if (VK != VK_RValue && Field->isBitField()) + OK = OK_BitField; + + // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] + QualType MemberType = Field->getType(); + if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) { + MemberType = Ref->getPointeeType(); + VK = VK_LValue; + } else { + QualType BaseType = BaseExpr->getType(); + if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType(); + + Qualifiers BaseQuals = BaseType.getQualifiers(); + + // GC attributes are never picked up by members. + BaseQuals.removeObjCGCAttr(); + + // CVR attributes from the base are picked up by members, + // except that 'mutable' members don't pick up 'const'. + if (Field->isMutable()) BaseQuals.removeConst(); + + Qualifiers MemberQuals + = S.Context.getCanonicalType(MemberType).getQualifiers(); + + // TR 18037 does not allow fields to be declared with address spaces. + assert(!MemberQuals.hasAddressSpace()); + + Qualifiers Combined = BaseQuals + MemberQuals; + if (Combined != MemberQuals) + MemberType = S.Context.getQualifiedType(MemberType, Combined); + } + + S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field); + if (S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), + FoundDecl, Field)) + return ExprError(); + return S.Owned(BuildMemberExpr(S.Context, BaseExpr, IsArrow, SS, + Field, FoundDecl, MemberNameInfo, + MemberType, VK, OK)); } /// Builds an implicit member access expression. The current context @@ -1631,29 +2158,30 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, bool IsKnownInstance) { assert(!R.empty() && !R.isAmbiguous()); - SourceLocation Loc = R.getNameLoc(); + SourceLocation loc = R.getNameLoc(); // We may have found a field within an anonymous union or struct // (C++ [class.union]). - // FIXME: This needs to happen post-isImplicitMemberReference? // FIXME: template-ids inside anonymous structs? - if (FieldDecl *FD = R.getAsSingle<FieldDecl>()) - if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion()) - return BuildAnonymousStructUnionMemberReference(Loc, FD); + if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>()) + return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD); - // If this is known to be an instance access, go ahead and build a + // If this is known to be an instance access, go ahead and build an + // implicit 'this' expression now. // 'this' expression now. - DeclContext *DC = getFunctionLevelDeclContext(); - QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); - Expr *This = 0; // null signifies implicit access + CXXMethodDecl *method = tryCaptureCXXThis(); + assert(method && "didn't correctly pre-flight capture of 'this'"); + + QualType thisType = method->getThisType(Context); + Expr *baseExpr = 0; // null signifies implicit access if (IsKnownInstance) { SourceLocation Loc = R.getNameLoc(); if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); - This = new (Context) CXXThisExpr(Loc, ThisType, /*isImplicit=*/true); + baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true); } - return BuildMemberReferenceExpr(This, ThisType, + return BuildMemberReferenceExpr(baseExpr, thisType, /*OpLoc*/ SourceLocation(), /*IsArrow*/ true, SS, @@ -1762,10 +2290,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // we've picked a target. R.suppressDiagnostics(); - bool Dependent - = UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), 0); UnresolvedLookupExpr *ULE - = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(), + = UnresolvedLookupExpr::Create(Context, R.getNamingClass(), (NestedNameSpecifier*) SS.getScopeRep(), SS.getRange(), R.getLookupNameInfo(), NeedsADL, R.isOverloadedResult(), @@ -1774,7 +2300,6 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return Owned(ULE); } - /// \brief Complete semantic analysis for a reference to the given declaration. ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, @@ -1817,6 +2342,14 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, if (VD->isInvalidDecl()) return ExprError(); + // Handle members of anonymous structs and unions. If we got here, + // and the reference is to a class member indirect field, then this + // must be the subject of a pointer-to-member expression. + if (IndirectFieldDecl *indirectField = dyn_cast<IndirectFieldDecl>(VD)) + if (!indirectField->isCXXClassMember()) + return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(), + indirectField); + // If the identifier reference is inside a block, and it refers to a value // that is outside the block, create a BlockDeclRefExpr instead of a // DeclRefExpr. This ensures the value is treated as a copy-in snapshot when @@ -1825,59 +2358,140 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // We do not do this for things like enum constants, global variables, etc, // as they do not get snapshotted. // - if (getCurBlock() && - ShouldSnapshotBlockValueReference(*this, getCurBlock(), VD)) { - if (VD->getType().getTypePtr()->isVariablyModifiedType()) { - Diag(Loc, diag::err_ref_vm_type); - Diag(D->getLocation(), diag::note_declared_at); + switch (shouldCaptureValueReference(*this, NameInfo.getLoc(), VD)) { + case CR_Error: + return ExprError(); + + case CR_Capture: + assert(!SS.isSet() && "referenced local variable with scope specifier?"); + return BuildBlockDeclRefExpr(*this, VD, NameInfo, /*byref*/ false); + + case CR_CaptureByRef: + assert(!SS.isSet() && "referenced local variable with scope specifier?"); + return BuildBlockDeclRefExpr(*this, VD, NameInfo, /*byref*/ true); + + case CR_NoCapture: { + // If this reference is not in a block or if the referenced + // variable is within the block, create a normal DeclRefExpr. + + QualType type = VD->getType(); + ExprValueKind valueKind = VK_RValue; + + switch (D->getKind()) { + // Ignore all the non-ValueDecl kinds. +#define ABSTRACT_DECL(kind) +#define VALUE(type, base) +#define DECL(type, base) \ + case Decl::type: +#include "clang/AST/DeclNodes.inc" + llvm_unreachable("invalid value decl kind"); return ExprError(); - } - if (VD->getType()->isArrayType()) { - Diag(Loc, diag::err_ref_array_type); - Diag(D->getLocation(), diag::note_declared_at); + // These shouldn't make it here. + case Decl::ObjCAtDefsField: + case Decl::ObjCIvar: + llvm_unreachable("forming non-member reference to ivar?"); return ExprError(); + + // Enum constants are always r-values and never references. + // Unresolved using declarations are dependent. + case Decl::EnumConstant: + case Decl::UnresolvedUsingValue: + valueKind = VK_RValue; + break; + + // Fields and indirect fields that got here must be for + // pointer-to-member expressions; we just call them l-values for + // internal consistency, because this subexpression doesn't really + // exist in the high-level semantics. + case Decl::Field: + case Decl::IndirectField: + assert(getLangOptions().CPlusPlus && + "building reference to field in C?"); + + // These can't have reference type in well-formed programs, but + // for internal consistency we do this anyway. + type = type.getNonReferenceType(); + valueKind = VK_LValue; + break; + + // Non-type template parameters are either l-values or r-values + // depending on the type. + case Decl::NonTypeTemplateParm: { + if (const ReferenceType *reftype = type->getAs<ReferenceType>()) { + type = reftype->getPointeeType(); + valueKind = VK_LValue; // even if the parameter is an r-value reference + break; + } + + // For non-references, we need to strip qualifiers just in case + // the template parameter was declared as 'const int' or whatever. + valueKind = VK_RValue; + type = type.getUnqualifiedType(); + break; } - MarkDeclarationReferenced(Loc, VD); - QualType ExprTy = VD->getType().getNonReferenceType(); - // The BlocksAttr indicates the variable is bound by-reference. - if (VD->getAttr<BlocksAttr>()) - return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, true)); - // 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(); - QualType T = VD->getType(); - BlockDeclRefExpr *BDRE = new (Context) BlockDeclRefExpr(VD, - ExprTy, Loc, false, - constAdded); - if (getLangOptions().CPlusPlus) { - if (!T->isDependentType() && !T->isReferenceType()) { - Expr *E = new (Context) - DeclRefExpr(const_cast<ValueDecl*>(BDRE->getDecl()), T, - SourceLocation()); + case Decl::Var: + // In C, "extern void blah;" is valid and is an r-value. + if (!getLangOptions().CPlusPlus && + !type.hasQualifiers() && + type->isVoidType()) { + valueKind = VK_RValue; + break; + } + // fallthrough + + case Decl::ImplicitParam: + case Decl::ParmVar: + // These are always l-values. + valueKind = VK_LValue; + type = type.getNonReferenceType(); + break; + + case Decl::Function: { + // Functions are l-values in C++. + if (getLangOptions().CPlusPlus) { + valueKind = VK_LValue; + break; + } - ExprResult Res = PerformCopyInitialization( - InitializedEntity::InitializeBlock(VD->getLocation(), - T, false), - SourceLocation(), - Owned(E)); - if (!Res.isInvalid()) { - Res = MaybeCreateCXXExprWithTemporaries(Res.get()); - Expr *Init = Res.takeAs<Expr>(); - BDRE->setCopyConstructorExpr(Init); - } + // C99 DR 316 says that, if a function type comes from a + // function definition (without a prototype), that type is only + // used for checking compatibility. Therefore, when referencing + // the function, we pretend that we don't have the full function + // type. + if (!cast<FunctionDecl>(VD)->hasPrototype()) + if (const FunctionProtoType *proto = type->getAs<FunctionProtoType>()) + type = Context.getFunctionNoProtoType(proto->getResultType(), + proto->getExtInfo()); + + // Functions are r-values in C. + valueKind = VK_RValue; + break; + } + + case Decl::CXXMethod: + // C++ methods are l-values if static, r-values if non-static. + if (cast<CXXMethodDecl>(VD)->isStatic()) { + valueKind = VK_LValue; + break; } + // fallthrough + + case Decl::CXXConversion: + case Decl::CXXDestructor: + case Decl::CXXConstructor: + valueKind = VK_RValue; + break; } - return Owned(BDRE); + + return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS); } - // If this reference is not in a block or if the referenced variable is - // within the block, create a normal DeclRefExpr. - return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), - NameInfo, &SS); + } + + llvm_unreachable("unknown capture result"); + return ExprError(); } ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, @@ -2008,6 +2622,9 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { bool isExact = (result == APFloat::opOK); Res = FloatingLiteral::Create(Context, Val, isExact, Ty, Tok.getLocation()); + if (getLangOptions().SinglePrecisionConstants && Ty == Context.DoubleTy) + ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast); + } else if (!Literal.isIntegerLiteral()) { return ExprError(); } else { @@ -2074,7 +2691,10 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // Does it fit in a unsigned long long? if (ResultVal.isIntN(LongLongSize)) { // Does it fit in a signed long long? - if (!Literal.isUnsigned && ResultVal[LongLongSize-1] == 0) + // To be compatible with MSVC, hex integer literals ending with the + // LL or i64 suffix are always signed in Microsoft mode. + if (!Literal.isUnsigned && (ResultVal[LongLongSize-1] == 0 || + (getLangOptions().Microsoft && Literal.isLongLong))) Ty = Context.LongLongTy; else if (AllowUnsigned) Ty = Context.UnsignedLongLongTy; @@ -2091,7 +2711,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { } if (ResultVal.getBitWidth() != Width) - ResultVal.trunc(Width); + ResultVal = ResultVal.trunc(Width); } Res = IntegerLiteral::Create(Context, ResultVal, Ty, Tok.getLocation()); } @@ -2114,7 +2734,7 @@ ExprResult Sema::ActOnParenExpr(SourceLocation L, /// See C99 6.3.2.1p[2-4] for more details. bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, SourceLocation OpLoc, - const SourceRange &ExprRange, + SourceRange ExprRange, bool isSizeof) { if (exprType->isDependentType()) return false; @@ -2153,17 +2773,11 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, return true; } - if (Context.hasSameUnqualifiedType(exprType, Context.OverloadTy)) { - Diag(OpLoc, diag::err_sizeof_alignof_overloaded_function_type) - << !isSizeof << ExprRange; - return true; - } - return false; } -bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, - const SourceRange &ExprRange) { +static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc, + SourceRange ExprRange) { E = E->IgnoreParens(); // alignof decl is always ok. @@ -2175,7 +2789,7 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, return false; if (E->getBitField()) { - Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange; + S. Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange; return true; } @@ -2185,7 +2799,7 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, if (isa<FieldDecl>(ME->getMemberDecl())) return false; - return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false); + return S.CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false); } /// \brief Build a sizeof or alignof expression given a type operand. @@ -2218,10 +2832,14 @@ Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, if (E->isTypeDependent()) { // Delay type-checking for type-dependent expressions. } else if (!isSizeOf) { - isInvalid = CheckAlignOfExpr(E, OpLoc, R); + isInvalid = CheckAlignOfExpr(*this, E, OpLoc, R); } else if (E->getBitField()) { // C99 6.5.3.4p1. Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; + } else if (E->getType()->isPlaceholderType()) { + ExprResult PE = CheckPlaceholderExpr(E, OpLoc); + if (PE.isInvalid()) return ExprError(); + return CreateSizeOfAlignOfExpr(PE.take(), OpLoc, isSizeOf, R); } else { isInvalid = CheckSizeOfAlignOfOperand(E->getType(), OpLoc, R, true); } @@ -2257,9 +2875,14 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, return move(Result); } -QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) { +static QualType CheckRealImagOperand(Sema &S, Expr *&V, SourceLocation Loc, + bool isReal) { if (V->isTypeDependent()) - return Context.DependentTy; + return S.Context.DependentTy; + + // _Real and _Imag are only l-values for normal l-values. + if (V->getObjectKind() != OK_Ordinary) + S.DefaultLvalueConversion(V); // These operators return the element type of a complex type. if (const ComplexType *CT = V->getType()->getAs<ComplexType>()) @@ -2269,8 +2892,16 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) { if (V->getType()->isArithmeticType()) return V->getType(); + // Test for placeholders. + ExprResult PR = S.CheckPlaceholderExpr(V, Loc); + if (PR.isInvalid()) return QualType(); + if (PR.take() != V) { + V = PR.take(); + return CheckRealImagOperand(S, V, Loc, isReal); + } + // Reject anything else. - Diag(Loc, diag::err_realimag_invalid_type) << V->getType() + S.Diag(Loc, diag::err_realimag_invalid_type) << V->getType() << (isReal ? "__real" : "__imag"); return QualType(); } @@ -2290,6 +2921,19 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, return BuildUnaryOp(S, OpLoc, Opc, Input); } +/// Expressions of certain arbitrary types are forbidden by C from +/// having l-value type. These are: +/// - 'void', but not qualified void +/// - function types +/// +/// The exact rule here is C99 6.3.2.1: +/// An lvalue is an expression with an object type or an incomplete +/// type other than void. +static bool IsCForbiddenLValueType(ASTContext &C, QualType T) { + return ((T->isVoidType() && !T.hasQualifiers()) || + T->isFunctionType()); +} + ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc) { @@ -2303,7 +2947,9 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, if (getLangOptions().CPlusPlus && (LHSExp->isTypeDependent() || RHSExp->isTypeDependent())) { return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, - Context.DependentTy, RLoc)); + Context.DependentTy, + VK_LValue, OK_Ordinary, + RLoc)); } if (getLangOptions().CPlusPlus && @@ -2330,6 +2976,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, DefaultFunctionArrayLvalueConversion(RHSExp); QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType(); + ExprValueKind VK = VK_LValue; + ExprObjectKind OK = OK_Ordinary; // C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent // to the expression *((e1)+(e2)). This means the array "Base" may actually be @@ -2364,6 +3012,9 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, } else if (const VectorType *VTy = LHSTy->getAs<VectorType>()) { BaseExpr = LHSExp; // vectors: V[123] IndexExpr = RHSExp; + VK = LHSExp->getValueKind(); + if (VK != VK_RValue) + OK = OK_VectorComponent; // FIXME: need to deal with const... ResultType = VTy->getElementType(); @@ -2417,7 +3068,15 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, return ExprError(); } - if (!ResultType->isDependentType() && + if (ResultType->isVoidType() && !getLangOptions().CPlusPlus) { + // GNU extension: subscripting on pointer to void + Diag(LLoc, diag::ext_gnu_void_ptr) + << BaseExpr->getSourceRange(); + + // C forbids expressions of unqualified void type from being l-values. + // See IsCForbiddenLValueType. + if (!ResultType.hasQualifiers()) VK = VK_RValue; + } else if (!ResultType->isDependentType() && RequireCompleteType(LLoc, ResultType, PDiag(diag::err_subscript_incomplete_type) << BaseExpr->getSourceRange())) @@ -2430,13 +3089,20 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, return ExprError(); } + assert(VK == VK_RValue || LangOpts.CPlusPlus || + !IsCForbiddenLValueType(Context, ResultType)); + return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, - ResultType, RLoc)); + ResultType, VK, OK, RLoc)); } -QualType Sema:: -CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, - const IdentifierInfo *CompName, +/// Check an ext-vector component access expression. +/// +/// VK should be set in advance to the value kind of the base +/// expression. +static QualType +CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, + SourceLocation OpLoc, const IdentifierInfo *CompName, SourceLocation CompLoc) { // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements, // see FIXME there. @@ -2457,25 +3123,36 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, // indicating that it is a string of hex values to be used as vector indices. bool HexSwizzle = *compStr == 's' || *compStr == 'S'; + bool HasRepeated = false; + bool HasIndex[16] = {}; + + int Idx; + // Check that we've found one of the special components, or that the component // names must come from the same set. if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || !strcmp(compStr, "even") || !strcmp(compStr, "odd")) { HalvingSwizzle = true; - } else if (vecType->getPointAccessorIdx(*compStr) != -1) { - do + } else if (!HexSwizzle && + (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) { + do { + if (HasIndex[Idx]) HasRepeated = true; + HasIndex[Idx] = true; compStr++; - while (*compStr && vecType->getPointAccessorIdx(*compStr) != -1); - } else if (HexSwizzle || vecType->getNumericAccessorIdx(*compStr) != -1) { - do + } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1); + } else { + if (HexSwizzle) compStr++; + while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) { + if (HasIndex[Idx]) HasRepeated = true; + HasIndex[Idx] = true; compStr++; - while (*compStr && vecType->getNumericAccessorIdx(*compStr) != -1); + } } if (!HalvingSwizzle && *compStr) { // We didn't get to the end of the string. This means the component names // didn't come from the same set *or* we encountered an illegal name. - Diag(OpLoc, diag::err_ext_vector_component_name_illegal) + S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal) << llvm::StringRef(compStr, 1) << SourceRange(CompLoc); return QualType(); } @@ -2490,7 +3167,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, while (*compStr) { if (!vecType->isAccessorWithinNumElements(*compStr++)) { - Diag(OpLoc, diag::err_ext_vector_component_exceeds_length) + S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length) << baseType << SourceRange(CompLoc); return QualType(); } @@ -2510,48 +3187,51 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, if (CompSize == 1) return vecType->getElementType(); - QualType VT = Context.getExtVectorType(vecType->getElementType(), CompSize); + if (HasRepeated) VK = VK_RValue; + + QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize); // Now look up the TypeDefDecl from the vector type. Without this, // diagostics look bad. We want extended vector types to appear built-in. - for (unsigned i = 0, E = ExtVectorDecls.size(); i != E; ++i) { - if (ExtVectorDecls[i]->getUnderlyingType() == VT) - return Context.getTypedefType(ExtVectorDecls[i]); + for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) { + if (S.ExtVectorDecls[i]->getUnderlyingType() == VT) + return S.Context.getTypedefType(S.ExtVectorDecls[i]); } return VT; // should never get here (a typedef type should always be found). } -static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, +static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, IdentifierInfo *Member, const Selector &Sel, ASTContext &Context) { - - if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member)) - return PD; + if (Member) + if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member)) + return PD; if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel)) return OMD; for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), E = PDecl->protocol_end(); I != E; ++I) { - if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel, - Context)) + if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, + Context)) return D; } return 0; } -static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, - IdentifierInfo *Member, - const Selector &Sel, - ASTContext &Context) { +static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy, + IdentifierInfo *Member, + const Selector &Sel, + ASTContext &Context) { // Check protocols on qualified interfaces. Decl *GDecl = 0; for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), E = QIdTy->qual_end(); I != E; ++I) { - if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { - GDecl = PD; - break; - } - // Also must look for a getter name which uses property syntax. + if (Member) + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { + GDecl = PD; + break; + } + // Also must look for a getter or setter name which uses property syntax. if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) { GDecl = OMD; break; @@ -2561,7 +3241,8 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), E = QIdTy->qual_end(); I != E; ++I) { // Search in the protocol-qualifier list of current protocol. - GDecl = FindGetterNameDeclFromProtocolList(*I, Member, Sel, Context); + GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, + Context); if (GDecl) return GDecl; } @@ -2617,14 +3298,15 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef, Expr *BaseExpr, QualType BaseType, const CXXScopeSpec &SS, - const LookupResult &R) { + NamedDecl *rep, + const DeclarationNameInfo &nameInfo) { // If this is an implicit member access, use a different set of // diagnostics. if (!BaseExpr) - return DiagnoseInstanceReference(SemaRef, SS, R); + return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo); - SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_of_unrelated) - << SS.getRange() << R.getRepresentativeDecl() << BaseType; + SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated) + << SS.getRange() << rep << BaseType; } // Check whether the declarations we found through a nested-name @@ -2673,7 +3355,9 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, return false; } - DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, R); + DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, + R.getRepresentativeDecl(), + R.getLookupNameInfo()); return true; } @@ -2846,18 +3530,12 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // Construct an unresolved result if we in fact got an unresolved // result. if (R.isOverloadedResult() || R.isUnresolvableResult()) { - bool Dependent = - BaseExprType->isDependentType() || - R.isUnresolvableResult() || - OverloadExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs); - // Suppress any lookup-related diagnostics; we'll do these when we // pick a member. R.suppressDiagnostics(); UnresolvedMemberExpr *MemExpr - = UnresolvedMemberExpr::Create(Context, Dependent, - R.isUnresolvableResult(), + = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(), BaseExpr, BaseExprType, IsArrow, OpLoc, Qualifier, SS.getRange(), @@ -2905,58 +3583,44 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, return ExprError(); } - if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) { - // We may have found a field within an anonymous union or struct - // (C++ [class.union]). - if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion() && - !BaseType->getAs<RecordType>()->getDecl()->isAnonymousStructOrUnion()) - return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, - BaseExpr, OpLoc); - - // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] - QualType MemberType = FD->getType(); - if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) - MemberType = Ref->getPointeeType(); - else { - Qualifiers BaseQuals = BaseType.getQualifiers(); - BaseQuals.removeObjCGCAttr(); - if (FD->isMutable()) BaseQuals.removeConst(); + // Perform a property load on the base regardless of whether we + // actually need it for the declaration. + if (BaseExpr->getObjectKind() == OK_ObjCProperty) + ConvertPropertyForRValue(BaseExpr); - Qualifiers MemberQuals - = Context.getCanonicalType(MemberType).getQualifiers(); + if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) + return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, + SS, FD, FoundDecl, MemberNameInfo); - Qualifiers Combined = BaseQuals + MemberQuals; - if (Combined != MemberQuals) - MemberType = Context.getQualifiedType(MemberType, Combined); - } - - MarkDeclarationReferenced(MemberLoc, FD); - if (PerformObjectMemberConversion(BaseExpr, Qualifier, FoundDecl, FD)) - return ExprError(); - return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - FD, FoundDecl, MemberNameInfo, - MemberType)); - } + if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) + // We may have found a field within an anonymous union or struct + // (C++ [class.union]). + return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD, + BaseExpr, OpLoc); if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, Var); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, Var, FoundDecl, MemberNameInfo, - Var->getType().getNonReferenceType())); + Var->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary)); } - if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) { + if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, MemberFn, FoundDecl, MemberNameInfo, - MemberFn->getType())); + MemberFn->getType(), + MemberFn->isInstance() ? VK_RValue : VK_LValue, + OK_Ordinary)); } + assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?"); if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, Enum, FoundDecl, MemberNameInfo, - Enum->getType())); + Enum->getType(), VK_RValue, OK_Ordinary)); } Owned(BaseExpr); @@ -2975,6 +3639,38 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, return ExprError(); } +/// Given that normal member access failed on the given expression, +/// and given that the expression's type involves builtin-id or +/// builtin-Class, decide whether substituting in the redefinition +/// types would be profitable. The redefinition type is whatever +/// this translation unit tried to typedef to id/Class; we store +/// it to the side and then re-use it in places like this. +static bool ShouldTryAgainWithRedefinitionType(Sema &S, Expr *&base) { + const ObjCObjectPointerType *opty + = base->getType()->getAs<ObjCObjectPointerType>(); + if (!opty) return false; + + const ObjCObjectType *ty = opty->getObjectType(); + + QualType redef; + if (ty->isObjCId()) { + redef = S.Context.ObjCIdRedefinitionType; + } else if (ty->isObjCClass()) { + redef = S.Context.ObjCClassRedefinitionType; + } else { + return false; + } + + // Do the substitution as long as the redefinition type isn't just a + // possibly-qualified pointer to builtin-id or builtin-Class again. + opty = redef->getAs<ObjCObjectPointerType>(); + if (opty && !opty->getObjectType()->getInterface() != 0) + return false; + + S.ImpCastExprToType(base, redef, CK_BitCast); + return true; +} + /// Look up the given member of the given non-type-dependent /// expression. This can return in one of two ways: /// * If it returns a sentinel null-but-valid result, the caller will @@ -2994,6 +3690,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Perform default conversions. DefaultFunctionArrayConversion(BaseExpr); + if (IsArrow) DefaultLvalueConversion(BaseExpr); QualType BaseType = BaseExpr->getType(); assert(!BaseType->isDependentType()); @@ -3001,96 +3698,235 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, DeclarationName MemberName = R.getLookupName(); SourceLocation MemberLoc = R.getNameLoc(); - // If the user is trying to apply -> or . to a function pointer - // type, it's probably because they forgot parentheses to call that - // function. Suggest the addition of those parentheses, build the - // call, and continue on. - if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { - if (const FunctionProtoType *Fun - = Ptr->getPointeeType()->getAs<FunctionProtoType>()) { - QualType ResultTy = Fun->getResultType(); - if (Fun->getNumArgs() == 0 && - ((!IsArrow && ResultTy->isRecordType()) || - (IsArrow && ResultTy->isPointerType() && - ResultTy->getAs<PointerType>()->getPointeeType() - ->isRecordType()))) { - SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); - Diag(Loc, diag::err_member_reference_needs_call) - << QualType(Fun, 0) - << FixItHint::CreateInsertion(Loc, "()"); + // For later type-checking purposes, turn arrow accesses into dot + // accesses. The only access type we support that doesn't follow + // the C equivalence "a->b === (*a).b" is ObjC property accesses, + // and those never use arrows, so this is unaffected. + if (IsArrow) { + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) + BaseType = Ptr->getPointeeType(); + else if (const ObjCObjectPointerType *Ptr + = BaseType->getAs<ObjCObjectPointerType>()) + BaseType = Ptr->getPointeeType(); + else if (BaseType->isRecordType()) { + // Recover from arrow accesses to records, e.g.: + // struct MyRecord foo; + // foo->bar + // This is actually well-formed in C++ if MyRecord has an + // overloaded operator->, but that should have been dealt with + // by now. + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << BaseType << int(IsArrow) << BaseExpr->getSourceRange() + << FixItHint::CreateReplacement(OpLoc, "."); + IsArrow = false; + } else { + Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) + << BaseType << BaseExpr->getSourceRange(); + return ExprError(); + } + } - ExprResult NewBase - = ActOnCallExpr(0, BaseExpr, Loc, - MultiExprArg(*this, 0, 0), 0, Loc); - BaseExpr = 0; - if (NewBase.isInvalid()) - return ExprError(); + // Handle field access to simple records. + if (const RecordType *RTy = BaseType->getAs<RecordType>()) { + if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(), + RTy, OpLoc, SS, HasTemplateArgs)) + return ExprError(); - BaseExpr = NewBase.takeAs<Expr>(); - DefaultFunctionArrayConversion(BaseExpr); - BaseType = BaseExpr->getType(); - } - } + // Returning valid-but-null is how we indicate to the caller that + // the lookup result was filled in. + return Owned((Expr*) 0); } - // If this is an Objective-C pseudo-builtin and a definition is provided then - // use that. - if (BaseType->isObjCIdType()) { - if (IsArrow) { - // Handle the following exceptional case PObj->isa. - if (const ObjCObjectPointerType *OPT = - BaseType->getAs<ObjCObjectPointerType>()) { - if (OPT->getObjectType()->isObjCId() && - MemberName.getAsIdentifierInfo()->isStr("isa")) - return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc, - Context.getObjCClassType())); - } + // Handle ivar access to Objective-C objects. + if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) { + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + + // There are three cases for the base type: + // - builtin id (qualified or unqualified) + // - builtin Class (qualified or unqualified) + // - an interface + ObjCInterfaceDecl *IDecl = OTy->getInterface(); + if (!IDecl) { + // There's an implicit 'isa' ivar on all objects. + // But we only actually find it this way on objects of type 'id', + // apparently. + if (OTy->isObjCId() && Member->isStr("isa")) + return Owned(new (Context) ObjCIsaExpr(BaseExpr, IsArrow, MemberLoc, + Context.getObjCClassType())); + + if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + goto fail; } - // 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, CK_BitCast); + + ObjCInterfaceDecl *ClassDeclared; + ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); + + if (!IV) { + // Attempt to correct for typos in ivar names. + LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), + LookupMemberName); + if (CorrectTypo(Res, 0, 0, IDecl, false, + IsArrow ? CTC_ObjCIvarLookup + : CTC_ObjCPropertyLookup) && + (IV = Res.getAsSingle<ObjCIvarDecl>())) { + Diag(R.getNameLoc(), + diag::err_typecheck_member_reference_ivar_suggest) + << IDecl->getDeclName() << MemberName << IV->getDeclName() + << FixItHint::CreateReplacement(R.getNameLoc(), + IV->getNameAsString()); + Diag(IV->getLocation(), diag::note_previous_decl) + << IV->getDeclName(); + } else { + Res.clear(); + Res.setLookupName(Member); + + Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) + << IDecl->getDeclName() << MemberName + << BaseExpr->getSourceRange(); + return ExprError(); + } } - } - // If this is an Objective-C pseudo-builtin and a definition is provided then - // use that. - if (Context.isObjCSelType(BaseType)) { - // We have an 'SEL' type. Rather than fall through, we check if this - // is a reference to 'sel_id'. - if (BaseType != Context.ObjCSelRedefinitionType) { - BaseType = Context.ObjCSelRedefinitionType; - ImpCastExprToType(BaseExpr, BaseType, CK_BitCast); + // If the decl being referenced had an error, return an error for this + // sub-expr without emitting another error, in order to avoid cascading + // error cases. + if (IV->isInvalidDecl()) + return ExprError(); + + // Check whether we can reference this field. + if (DiagnoseUseOfDecl(IV, MemberLoc)) + return ExprError(); + if (IV->getAccessControl() != ObjCIvarDecl::Public && + IV->getAccessControl() != ObjCIvarDecl::Package) { + ObjCInterfaceDecl *ClassOfMethodDecl = 0; + if (ObjCMethodDecl *MD = getCurMethodDecl()) + ClassOfMethodDecl = MD->getClassInterface(); + else if (ObjCImpDecl && getCurFunctionDecl()) { + // Case of a c-function declared inside an objc implementation. + // FIXME: For a c-style function nested inside an objc implementation + // class, there is no implementation context available, so we pass + // down the context as argument to this routine. Ideally, this context + // need be passed down in the AST node and somehow calculated from the + // AST for a function decl. + if (ObjCImplementationDecl *IMPD = + dyn_cast<ObjCImplementationDecl>(ObjCImpDecl)) + ClassOfMethodDecl = IMPD->getClassInterface(); + else if (ObjCCategoryImplDecl* CatImplClass = + dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl)) + ClassOfMethodDecl = CatImplClass->getClassInterface(); + } + + if (IV->getAccessControl() == ObjCIvarDecl::Private) { + if (ClassDeclared != IDecl || + ClassOfMethodDecl != ClassDeclared) + Diag(MemberLoc, diag::error_private_ivar_access) + << IV->getDeclName(); + } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl)) + // @protected + Diag(MemberLoc, diag::error_protected_ivar_access) + << IV->getDeclName(); } + + return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), + MemberLoc, BaseExpr, + IsArrow)); } - assert(!BaseType.isNull() && "no type for member expression"); + // Objective-C property access. + const ObjCObjectPointerType *OPT; + if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) { + // This actually uses the base as an r-value. + DefaultLvalueConversion(BaseExpr); + assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr->getType())); - // Handle properties on ObjC 'Class' types. - if (!IsArrow && 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()) { + + const ObjCObjectType *OT = OPT->getObjectType(); + + // id, with and without qualifiers. + if (OT->isObjCId()) { + // Check protocols on qualified interfaces. + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); + if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) { + if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) { + // Check the use of this declaration + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + VK_LValue, + OK_ObjCProperty, + MemberLoc, + BaseExpr)); + } + + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { + // Check the use of this method. + if (DiagnoseUseOfDecl(OMD, MemberLoc)) + return ExprError(); + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), Member); + ObjCMethodDecl *SMD = 0; + if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0, + SetterSel, Context)) + SMD = dyn_cast<ObjCMethodDecl>(SDecl); + QualType PType = OMD->getSendResultType(); + + ExprValueKind VK = VK_LValue; + if (!getLangOptions().CPlusPlus && + IsCForbiddenLValueType(Context, PType)) + VK = VK_RValue; + ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); + + return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType, + VK, OK, + MemberLoc, BaseExpr)); + } + } + + if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + + return ExprError(Diag(MemberLoc, diag::err_property_not_found) + << MemberName << BaseType); + } + + // 'Class', unqualified only. + if (OT->isObjCClass()) { + // Only works in a method declaration (??!). + ObjCMethodDecl *MD = getCurMethodDecl(); + if (!MD) { + if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + + goto fail; + } + + // Also must look for a getter name which uses property syntax. + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCInterfaceDecl *IFace = MD->getClassInterface(); ObjCMethodDecl *Getter; - // 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(); - } + } else + Getter = IFace->lookupPrivateMethod(Sel, false); // If we found a getter then this may be a valid dot-reference, we // will look for the matching setter, in case it is needed. Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), Member); + 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); + Setter = IFace->lookupPrivateMethod(SetterSel, false); } // Look through local category implementations associated with the class. if (!Setter) @@ -3102,49 +3938,73 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (Getter || Setter) { QualType PType; - if (Getter) + ExprValueKind VK = VK_LValue; + if (Getter) { PType = Getter->getSendResultType(); - else + if (!getLangOptions().CPlusPlus && + IsCForbiddenLValueType(Context, PType)) + VK = VK_RValue; + } else { // Get the expression type from Setter's incoming parameter. PType = (*(Setter->param_end() -1))->getType(); + } + ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); + // FIXME: we must check that the setter has property type. - return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, - PType, - Setter, MemberLoc, BaseExpr)); + return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, + PType, VK, OK, + MemberLoc, BaseExpr)); } + + if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << MemberName << BaseType); + << MemberName << BaseType); } - } - if (BaseType->isObjCClassType() && - BaseType != Context.ObjCClassRedefinitionType) { - BaseType = Context.ObjCClassRedefinitionType; - ImpCastExprToType(BaseExpr, BaseType, CK_BitCast); + // Normal property access. + return HandleExprPropertyRefExpr(OPT, BaseExpr, MemberName, MemberLoc, + SourceLocation(), QualType(), false); } - if (IsArrow) { - if (const PointerType *PT = BaseType->getAs<PointerType>()) - BaseType = PT->getPointeeType(); - else if (BaseType->isObjCObjectPointerType()) - ; - else if (BaseType->isRecordType()) { - // Recover from arrow accesses to records, e.g.: - // struct MyRecord foo; - // foo->bar - // This is actually well-formed in C++ if MyRecord has an - // overloaded operator->, but that should have been dealt with - // by now. - Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << int(IsArrow) << BaseExpr->getSourceRange() - << FixItHint::CreateReplacement(OpLoc, "."); - IsArrow = false; - } else { - Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) - << BaseType << BaseExpr->getSourceRange(); + // Handle 'field access' to vectors, such as 'V.xx'. + if (BaseType->isExtVectorType()) { + // FIXME: this expr should store IsArrow. + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr->getValueKind()); + QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc, + Member, MemberLoc); + if (ret.isNull()) return ExprError(); - } - } else { + + return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr, + *Member, MemberLoc)); + } + + // Adjust builtin-sel to the appropriate redefinition type if that's + // not just a pointer to builtin-sel again. + if (IsArrow && + BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) && + !Context.ObjCSelRedefinitionType->isObjCSelType()) { + ImpCastExprToType(BaseExpr, Context.ObjCSelRedefinitionType, CK_BitCast); + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + } + + // Failure cases. + fail: + + // There's a possible road to recovery for function types. + const FunctionType *Fun = 0; + SourceLocation ParenInsertionLoc = + PP.getLocForEndOfToken(BaseExpr->getLocEnd()); + + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { + if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) { + // fall out, handled below. + // Recover from dot accesses to pointers, e.g.: // type *foo; // foo.bar @@ -3152,165 +4012,113 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // - 'type' is an Objective C type // - 'bar' is a pseudo-destructor name which happens to refer to // the appropriate pointer type - if (MemberName.getNameKind() != DeclarationName::CXXDestructorName) { - const PointerType *PT = BaseType->getAs<PointerType>(); - if (PT && PT->getPointeeType()->isRecordType()) { - Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << int(IsArrow) << BaseExpr->getSourceRange() - << FixItHint::CreateReplacement(OpLoc, "->"); - BaseType = PT->getPointeeType(); - IsArrow = true; - } - } - } + } else if (!IsArrow && Ptr->getPointeeType()->isRecordType() && + MemberName.getNameKind() != DeclarationName::CXXDestructorName) { + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << BaseType << int(IsArrow) << BaseExpr->getSourceRange() + << FixItHint::CreateReplacement(OpLoc, "->"); - // Handle field access to simple records. - if (const RecordType *RTy = BaseType->getAs<RecordType>()) { - if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(), - RTy, OpLoc, SS, HasTemplateArgs)) - return ExprError(); - return Owned((Expr*) 0); + // Recurse as an -> access. + IsArrow = true; + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + } + } else { + Fun = BaseType->getAs<FunctionType>(); } - // Handle access to Objective-C instance variables, such as "Obj->ivar" and - // (*Obj).ivar. - if ((IsArrow && BaseType->isObjCObjectPointerType()) || - (!IsArrow && BaseType->isObjCObjectType())) { - const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>(); - ObjCInterfaceDecl *IDecl = - OPT ? OPT->getInterfaceDecl() - : BaseType->getAs<ObjCObjectType>()->getInterface(); - if (IDecl) { - IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - - ObjCInterfaceDecl *ClassDeclared; - ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); - - if (!IV) { - // Attempt to correct for typos in ivar names. - LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), - LookupMemberName); - if (CorrectTypo(Res, 0, 0, IDecl, false, CTC_MemberLookup) && - (IV = Res.getAsSingle<ObjCIvarDecl>())) { - Diag(R.getNameLoc(), - diag::err_typecheck_member_reference_ivar_suggest) - << IDecl->getDeclName() << MemberName << IV->getDeclName() - << FixItHint::CreateReplacement(R.getNameLoc(), - IV->getNameAsString()); - Diag(IV->getLocation(), diag::note_previous_decl) - << IV->getDeclName(); - } else { - Res.clear(); - Res.setLookupName(Member); + // If the user is trying to apply -> or . to a function pointer + // type, it's probably because they forgot parentheses to call that + // function. Suggest the addition of those parentheses, build the + // call, and continue on. + if (Fun || BaseType == Context.OverloadTy) { + bool TryCall; + if (BaseType == Context.OverloadTy) { + // Plunder the overload set for something that would make the member + // expression valid. + const OverloadExpr *Overloads = cast<OverloadExpr>(BaseExpr); + UnresolvedSet<4> CandidateOverloads; + bool HasZeroArgCandidateOverload = false; + for (OverloadExpr::decls_iterator it = Overloads->decls_begin(), + DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) { + const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*it); + QualType ResultTy = OverloadDecl->getResultType(); + if ((!IsArrow && ResultTy->isRecordType()) || + (IsArrow && ResultTy->isPointerType() && + ResultTy->getPointeeType()->isRecordType())) { + CandidateOverloads.addDecl(*it); + if (OverloadDecl->getNumParams() == 0) { + HasZeroArgCandidateOverload = true; + } } } - - 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. - if (ObjCImplementationDecl *IMPD = - dyn_cast<ObjCImplementationDecl>(ObjCImpDecl)) - ClassOfMethodDecl = IMPD->getClassInterface(); - else if (ObjCCategoryImplDecl* CatImplClass = - dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl)) - ClassOfMethodDecl = CatImplClass->getClassInterface(); + if (HasZeroArgCandidateOverload && CandidateOverloads.size() == 1) { + // We have one reasonable overload, and there's only one way to call it, + // so emit a fixit and try to recover + Diag(ParenInsertionLoc, diag::err_member_reference_needs_call) + << 1 + << BaseExpr->getSourceRange() + << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); + TryCall = true; + } else { + Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call) + << 0 + << BaseExpr->getSourceRange(); + int CandidateOverloadCount = CandidateOverloads.size(); + int I; + for (I = 0; I < CandidateOverloadCount; ++I) { + // FIXME: Magic number for max shown overloads stolen from + // OverloadCandidateSet::NoteCandidates. + if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) { + break; } - - 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(); + Diag(CandidateOverloads[I].getDecl()->getSourceRange().getBegin(), + diag::note_member_ref_possible_intended_overload); + } + if (I != CandidateOverloadCount) { + Diag(BaseExpr->getExprLoc(), diag::note_ovl_too_many_candidates) + << int(CandidateOverloadCount - I); } + return ExprError(); + } + } else { + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) { + TryCall = (FPT->getNumArgs() == 0); + } else { + TryCall = true; + } - return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), - MemberLoc, BaseExpr, - IsArrow)); + if (TryCall) { + QualType ResultTy = Fun->getResultType(); + TryCall = (!IsArrow && ResultTy->isRecordType()) || + (IsArrow && ResultTy->isPointerType() && + ResultTy->getAs<PointerType>()->getPointeeType()->isRecordType()); } - return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) - << IDecl->getDeclName() << MemberName - << BaseExpr->getSourceRange()); } - } - // Handle properties on 'id' and qualified "id". - if (!IsArrow && (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(ObjCMessageExpr::Create(Context, - OMD->getSendResultType(), - OpLoc, BaseExpr, Sel, - OMD, NULL, 0, MemberLoc)); + if (TryCall) { + if (Fun) { + Diag(BaseExpr->getExprLoc(), + diag::err_member_reference_needs_call_zero_arg) + << QualType(Fun, 0) + << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); } - } - return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << MemberName << BaseType); - } + ExprResult NewBase + = ActOnCallExpr(0, BaseExpr, ParenInsertionLoc, + MultiExprArg(*this, 0, 0), ParenInsertionLoc); + if (NewBase.isInvalid()) + return ExprError(); + BaseExpr = NewBase.takeAs<Expr>(); - // Handle Objective-C property access, which is "Obj.property" where Obj is a - // pointer to a (potentially qualified) interface type. - if (!IsArrow) - if (const ObjCObjectPointerType *OPT = - BaseType->getAsObjCInterfacePointerType()) - return HandleExprPropertyRefExpr(OPT, BaseExpr, MemberName, MemberLoc); - // Handle the following exceptional case (*Obj).isa. - if (!IsArrow && - BaseType->isObjCObjectType() && - BaseType->getAs<ObjCObjectType>()->isObjCId() && - MemberName.getAsIdentifierInfo()->isStr("isa")) - return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc, - Context.getObjCClassType())); + DefaultFunctionArrayConversion(BaseExpr); + BaseType = BaseExpr->getType(); - // 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, - MemberLoc)); + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + } } Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) @@ -3333,15 +4141,21 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, /// this is an ugly hack around the fact that ObjC @implementations /// aren't properly put in the context chain ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - CXXScopeSpec &SS, - UnqualifiedId &Id, - Decl *ObjCImpDecl, - bool HasTrailingLParen) { + SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + UnqualifiedId &Id, + Decl *ObjCImpDecl, + bool HasTrailingLParen) { if (SS.isSet() && SS.isInvalid()) return ExprError(); + // Warn about the explicit constructor calls Microsoft extension. + if (getLangOptions().Microsoft && + Id.getKind() == UnqualifiedId::IK_ConstructorName) + Diag(Id.getSourceRange().getBegin(), + diag::ext_ms_explicit_constructor_call); + TemplateArgumentListInfo TemplateArgsBuffer; // Decompose the name into its component parts. @@ -3399,60 +4213,76 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, } ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, - FunctionDecl *FD, - ParmVarDecl *Param) { + FunctionDecl *FD, + ParmVarDecl *Param) { if (Param->hasUnparsedDefaultArg()) { - Diag (CallLoc, - diag::err_use_of_default_argument_to_function_declared_later) << + 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, 0, /*RelativeToPrimary=*/true); - - std::pair<const TemplateArgument *, unsigned> Innermost - = ArgList.getInnermost(); - InstantiatingTemplate Inst(*this, CallLoc, Param, Innermost.first, - Innermost.second); - - ExprResult Result = SubstExpr(UninstExpr, ArgList); - if (Result.isInvalid()) - return ExprError(); + diag::note_default_argument_declared_here); + return ExprError(); + } + + if (Param->hasUninstantiatedDefaultArg()) { + Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); + + // Instantiate the expression. + MultiLevelTemplateArgumentList ArgList + = getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true); + + std::pair<const TemplateArgument *, unsigned> Innermost + = ArgList.getInnermost(); + InstantiatingTemplate Inst(*this, CallLoc, Param, Innermost.first, + Innermost.second); + + ExprResult Result; + { + // C++ [dcl.fct.default]p5: + // The names in the [default argument] expression are bound, and + // the semantic constraints are checked, at the point where the + // default argument expression appears. + ContextRAII SavedContext(*this, FD); + Result = SubstExpr(UninstExpr, ArgList); + } + if (Result.isInvalid()) + return ExprError(); - // Check the expression as an initializer for the parameter. - InitializedEntity Entity - = InitializedEntity::InitializeParameter(Param); - InitializationKind Kind - = InitializationKind::CreateCopy(Param->getLocation(), - /*FIXME:EqualLoc*/UninstExpr->getSourceRange().getBegin()); - Expr *ResultE = Result.takeAs<Expr>(); - - InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); - Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, &ResultE, 1)); - if (Result.isInvalid()) - return ExprError(); + // Check the expression as an initializer for the parameter. + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Context, Param); + InitializationKind Kind + = InitializationKind::CreateCopy(Param->getLocation(), + /*FIXME:EqualLoc*/UninstExpr->getSourceRange().getBegin()); + Expr *ResultE = Result.takeAs<Expr>(); + + InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); + Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, &ResultE, 1)); + if (Result.isInvalid()) + return ExprError(); - // Build the default argument expression. - return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, - Result.takeAs<Expr>())); - } + // Build the default argument expression. + return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, + Result.takeAs<Expr>())); + } - // If the default expression creates temporaries, we need to - // push them to the current stack of expression temporaries so they'll - // be properly destroyed. - // FIXME: We should really be rebuilding the default argument with new - // bound temporaries; see the comment in PR5810. - for (unsigned i = 0, e = Param->getNumDefaultArgTemporaries(); i != e; ++i) - ExprTemporaries.push_back(Param->getDefaultArgTemporary(i)); + // If the default expression creates temporaries, we need to + // push them to the current stack of expression temporaries so they'll + // be properly destroyed. + // FIXME: We should really be rebuilding the default argument with new + // bound temporaries; see the comment in PR5810. + for (unsigned i = 0, e = Param->getNumDefaultArgTemporaries(); i != e; ++i) { + CXXTemporary *Temporary = Param->getDefaultArgTemporary(i); + MarkDeclarationReferenced(Param->getDefaultArg()->getLocStart(), + const_cast<CXXDestructorDecl*>(Temporary->getDestructor())); + ExprTemporaries.push_back(Temporary); } - // We already type-checked the argument, so we know it works. + // We already type-checked the argument, so we know it works. + // Just mark all of the declarations in this potentially-evaluated expression + // as being "referenced". + MarkDeclarationsReferencedInExpr(Param->getDefaultArg()); return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param)); } @@ -3549,13 +4379,12 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, if (FDecl && i < FDecl->getNumParams()) Param = FDecl->getParamDecl(i); - InitializedEntity Entity = - Param? InitializedEntity::InitializeParameter(Param) - : InitializedEntity::InitializeParameter(ProtoArgType); + Param? InitializedEntity::InitializeParameter(Context, Param) + : InitializedEntity::InitializeParameter(Context, ProtoArgType); ExprResult ArgE = PerformCopyInitialization(Entity, - SourceLocation(), - Owned(Arg)); + SourceLocation(), + Owned(Arg)); if (ArgE.isInvalid()) return true; @@ -3590,8 +4419,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, /// locations. ExprResult Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, - MultiExprArg args, - SourceLocation *CommaLocs, SourceLocation RParenLoc) { + MultiExprArg args, SourceLocation RParenLoc, + Expr *ExecConfig) { unsigned NumArgs = args.size(); // Since this might be a postfix expression, get rid of ParenListExprs. @@ -3615,7 +4444,7 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, } return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy, - RParenLoc)); + VK_RValue, RParenLoc)); } // Determine whether this is a dependent call inside a C++ template, @@ -3628,14 +4457,22 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, else if (Expr::hasAnyTypeDependentArguments(Args, NumArgs)) Dependent = true; - if (Dependent) - return Owned(new (Context) CallExpr(Context, Fn, Args, NumArgs, - Context.DependentTy, RParenLoc)); + if (Dependent) { + if (ExecConfig) { + return Owned(new (Context) CUDAKernelCallExpr( + Context, Fn, cast<CallExpr>(ExecConfig), Args, NumArgs, + Context.DependentTy, VK_RValue, RParenLoc)); + } else { + return Owned(new (Context) CallExpr(Context, Fn, Args, NumArgs, + Context.DependentTy, VK_RValue, + RParenLoc)); + } + } // Determine whether this is a call to an object (C++ [over.call.object]). if (Fn->getType()->isRecordType()) return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc)); + RParenLoc)); Expr *NakedFn = Fn->IgnoreParens(); @@ -3652,7 +4489,7 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, (void)MemE; return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc); + RParenLoc); } // Determine whether this is a call to a member function. @@ -3660,7 +4497,7 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, NamedDecl *MemDecl = MemExpr->getMemberDecl(); if (isa<CXXMethodDecl>(MemDecl)) return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc); + RParenLoc); } // Determine whether this is a call to a pointer-to-member function. @@ -3670,10 +4507,31 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (const FunctionProtoType *FPT = BO->getType()->getAs<FunctionProtoType>()) { QualType ResultTy = FPT->getCallResultType(Context); - + ExprValueKind VK = Expr::getValueKindForType(FPT->getResultType()); + + // Check that the object type isn't more qualified than the + // member function we're calling. + Qualifiers FuncQuals = Qualifiers::fromCVRMask(FPT->getTypeQuals()); + Qualifiers ObjectQuals + = BO->getOpcode() == BO_PtrMemD + ? BO->getLHS()->getType().getQualifiers() + : BO->getLHS()->getType()->getAs<PointerType>() + ->getPointeeType().getQualifiers(); + + Qualifiers Difference = ObjectQuals - FuncQuals; + Difference.removeObjCGCAttr(); + Difference.removeAddressSpace(); + if (Difference) { + std::string QualsString = Difference.getAsString(); + Diag(LParenLoc, diag::err_pointer_to_member_call_drops_quals) + << BO->getType().getUnqualifiedType() + << QualsString + << (QualsString.find(' ') == std::string::npos? 1 : 2); + } + CXXMemberCallExpr *TheCall - = new (Context) CXXMemberCallExpr(Context, BO, Args, - NumArgs, ResultTy, + = new (Context) CXXMemberCallExpr(Context, Fn, Args, + NumArgs, ResultTy, VK, RParenLoc); if (CheckCallReturnType(FPT->getResultType(), @@ -3702,14 +4560,34 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (isa<UnresolvedLookupExpr>(NakedFn)) { UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(NakedFn); return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc); + RParenLoc, ExecConfig); } NamedDecl *NDecl = 0; + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn)) + if (UnOp->getOpcode() == UO_AddrOf) + NakedFn = UnOp->getSubExpr()->IgnoreParens(); + if (isa<DeclRefExpr>(NakedFn)) NDecl = cast<DeclRefExpr>(NakedFn)->getDecl(); - return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc); + return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc, + ExecConfig); +} + +ExprResult +Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, + MultiExprArg execConfig, SourceLocation GGGLoc) { + FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl(); + if (!ConfigDecl) + return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) + << "cudaConfigureCall"); + QualType ConfigQTy = ConfigDecl->getType(); + + DeclRefExpr *ConfigDR = new (Context) DeclRefExpr( + ConfigDecl, ConfigQTy, VK_LValue, LLLLoc); + + return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0); } /// BuildResolvedCallExpr - Build a call to a resolved expression, @@ -3722,7 +4600,8 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + Expr *Config) { FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl); // Promote the function operand. @@ -3730,10 +4609,21 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // Make the call expr early, before semantic checks. This guarantees cleanup // of arguments and function on error. - CallExpr *TheCall = new (Context) CallExpr(Context, Fn, - Args, NumArgs, - Context.BoolTy, - RParenLoc); + CallExpr *TheCall; + if (Config) { + TheCall = new (Context) CUDAKernelCallExpr(Context, Fn, + cast<CallExpr>(Config), + Args, NumArgs, + Context.BoolTy, + VK_RValue, + RParenLoc); + } else { + TheCall = new (Context) CallExpr(Context, Fn, + Args, NumArgs, + Context.BoolTy, + VK_RValue, + RParenLoc); + } const FunctionType *FuncT; if (!Fn->getType()->isBlockPointerType()) { @@ -3760,6 +4650,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // We know the result type of the call, set it. TheCall->setType(FuncT->getCallResultType(Context)); + TheCall->setValueKind(Expr::getValueKindForType(FuncT->getResultType())); if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) { if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs, @@ -3773,24 +4664,45 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // on our knowledge of the function definition. const FunctionDecl *Def = 0; if (FDecl->hasBody(Def) && NumArgs != Def->param_size()) { - const FunctionProtoType *Proto = - Def->getType()->getAs<FunctionProtoType>(); - if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size())) { + const FunctionProtoType *Proto + = 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(); - } } + + // If the function we're calling isn't a function prototype, but we have + // a function prototype from a prior declaratiom, use that prototype. + if (!FDecl->hasPrototype()) + Proto = FDecl->getType()->getAs<FunctionProtoType>(); } // Promote the arguments (C99 6.5.2.2p6). for (unsigned i = 0; i != NumArgs; i++) { Expr *Arg = Args[i]; - DefaultArgumentPromotion(Arg); + + if (Proto && i < Proto->getNumArgs()) { + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Context, + Proto->getArgType(i)); + ExprResult ArgE = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(Arg)); + if (ArgE.isInvalid()) + return true; + + Arg = ArgE.takeAs<Expr>(); + + } else { + DefaultArgumentPromotion(Arg); + } + if (RequireCompleteType(Arg->getSourceRange().getBegin(), Arg->getType(), PDiag(diag::err_call_incomplete_argument) << Arg->getSourceRange())) return ExprError(); + TheCall->setArg(i, Arg); } } @@ -3840,6 +4752,11 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, QualType literalType = TInfo->getType(); if (literalType->isArrayType()) { + if (RequireCompleteType(LParenLoc, Context.getBaseElementType(literalType), + PDiag(diag::err_illegal_decl_array_incomplete_type) + << SourceRange(LParenLoc, + literalExpr->getSourceRange().getEnd()))) + return ExprError(); if (literalType->isVariableArrayType()) return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init) << SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd())); @@ -3869,8 +4786,11 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, return ExprError(); } + // In C, compound literals are l-values for some reason. + ExprValueKind VK = getLangOptions().CPlusPlus ? VK_RValue : VK_LValue; + return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, - literalExpr, isFileScope)); + VK, literalExpr, isFileScope)); } ExprResult @@ -3888,60 +4808,171 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, return Owned(E); } -static CastKind getScalarCastKind(ASTContext &Context, - QualType SrcTy, QualType DestTy) { - if (Context.hasSameUnqualifiedType(SrcTy, DestTy)) +/// Prepares for a scalar cast, performing all the necessary stages +/// except the final cast and returning the kind required. +static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) { + // Both Src and Dest are scalar types, i.e. arithmetic or pointer. + // Also, callers should have filtered out the invalid cases with + // pointers. Everything else should be possible. + + QualType SrcTy = Src->getType(); + if (S.Context.hasSameUnqualifiedType(SrcTy, DestTy)) return CK_NoOp; - if (SrcTy->hasPointerRepresentation()) { - if (DestTy->hasPointerRepresentation()) + switch (SrcTy->getScalarTypeKind()) { + case Type::STK_MemberPointer: + llvm_unreachable("member pointer type in C"); + + case Type::STK_Pointer: + switch (DestTy->getScalarTypeKind()) { + case Type::STK_Pointer: return DestTy->isObjCObjectPointerType() ? CK_AnyPointerToObjCPointerCast : CK_BitCast; - if (DestTy->isIntegerType()) + case Type::STK_Bool: + return CK_PointerToBoolean; + case Type::STK_Integral: return CK_PointerToIntegral; - } + case Type::STK_Floating: + case Type::STK_FloatingComplex: + case Type::STK_IntegralComplex: + case Type::STK_MemberPointer: + llvm_unreachable("illegal cast from pointer"); + } + break; - if (SrcTy->isIntegerType()) { - if (DestTy->isIntegerType()) - return CK_IntegralCast; - if (DestTy->hasPointerRepresentation()) + case Type::STK_Bool: // casting from bool is like casting from an integer + case Type::STK_Integral: + switch (DestTy->getScalarTypeKind()) { + case Type::STK_Pointer: + if (Src->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) + return CK_NullToPointer; return CK_IntegralToPointer; - if (DestTy->isRealFloatingType()) + case Type::STK_Bool: + return CK_IntegralToBoolean; + case Type::STK_Integral: + return CK_IntegralCast; + case Type::STK_Floating: return CK_IntegralToFloating; - } + case Type::STK_IntegralComplex: + S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(), + CK_IntegralCast); + return CK_IntegralRealToComplex; + case Type::STK_FloatingComplex: + S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(), + CK_IntegralToFloating); + return CK_FloatingRealToComplex; + case Type::STK_MemberPointer: + llvm_unreachable("member pointer type in C"); + } + break; - if (SrcTy->isRealFloatingType()) { - if (DestTy->isRealFloatingType()) + case Type::STK_Floating: + switch (DestTy->getScalarTypeKind()) { + case Type::STK_Floating: return CK_FloatingCast; - if (DestTy->isIntegerType()) + case Type::STK_Bool: + return CK_FloatingToBoolean; + case Type::STK_Integral: return CK_FloatingToIntegral; + case Type::STK_FloatingComplex: + S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(), + CK_FloatingCast); + return CK_FloatingRealToComplex; + case Type::STK_IntegralComplex: + S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(), + CK_FloatingToIntegral); + return CK_IntegralRealToComplex; + case Type::STK_Pointer: + llvm_unreachable("valid float->pointer cast?"); + case Type::STK_MemberPointer: + llvm_unreachable("member pointer type in C"); + } + break; + + case Type::STK_FloatingComplex: + switch (DestTy->getScalarTypeKind()) { + case Type::STK_FloatingComplex: + return CK_FloatingComplexCast; + case Type::STK_IntegralComplex: + return CK_FloatingComplexToIntegralComplex; + case Type::STK_Floating: { + QualType ET = SrcTy->getAs<ComplexType>()->getElementType(); + if (S.Context.hasSameType(ET, DestTy)) + return CK_FloatingComplexToReal; + S.ImpCastExprToType(Src, ET, CK_FloatingComplexToReal); + return CK_FloatingCast; + } + case Type::STK_Bool: + return CK_FloatingComplexToBoolean; + case Type::STK_Integral: + S.ImpCastExprToType(Src, SrcTy->getAs<ComplexType>()->getElementType(), + CK_FloatingComplexToReal); + return CK_FloatingToIntegral; + case Type::STK_Pointer: + llvm_unreachable("valid complex float->pointer cast?"); + case Type::STK_MemberPointer: + llvm_unreachable("member pointer type in C"); + } + break; + + case Type::STK_IntegralComplex: + switch (DestTy->getScalarTypeKind()) { + case Type::STK_FloatingComplex: + return CK_IntegralComplexToFloatingComplex; + case Type::STK_IntegralComplex: + return CK_IntegralComplexCast; + case Type::STK_Integral: { + QualType ET = SrcTy->getAs<ComplexType>()->getElementType(); + if (S.Context.hasSameType(ET, DestTy)) + return CK_IntegralComplexToReal; + S.ImpCastExprToType(Src, ET, CK_IntegralComplexToReal); + return CK_IntegralCast; + } + case Type::STK_Bool: + return CK_IntegralComplexToBoolean; + case Type::STK_Floating: + S.ImpCastExprToType(Src, SrcTy->getAs<ComplexType>()->getElementType(), + CK_IntegralComplexToReal); + return CK_IntegralToFloating; + case Type::STK_Pointer: + llvm_unreachable("valid complex int->pointer cast?"); + case Type::STK_MemberPointer: + llvm_unreachable("member pointer type in C"); + } + break; } - // FIXME: Assert here. - // assert(false && "Unhandled cast combination!"); - return CK_Unknown; + llvm_unreachable("Unhandled scalar cast"); + return CK_BitCast; } /// CheckCastTypes - Check type constraints for casting between types. -bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, - CastKind& Kind, - CXXCastPath &BasePath, - bool FunctionalStyle) { +bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, + Expr *&castExpr, CastKind& Kind, ExprValueKind &VK, + CXXCastPath &BasePath, bool FunctionalStyle) { if (getLangOptions().CPlusPlus) - return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, BasePath, + return CXXCheckCStyleCast(SourceRange(TyR.getBegin(), + castExpr->getLocEnd()), + castType, VK, castExpr, Kind, BasePath, FunctionalStyle); - DefaultFunctionArrayLvalueConversion(castExpr); + // We only support r-value casts in C. + VK = VK_RValue; // C99 6.5.4p2: the cast type needs to be void or scalar and the expression // type needs to be scalar. if (castType->isVoidType()) { + // We don't necessarily do lvalue-to-rvalue conversions on this. + IgnoredValueConversions(castExpr); + // Cast to void allows any expr type. Kind = CK_ToVoid; return false; } + DefaultFunctionArrayLvalueConversion(castExpr); + if (RequireCompleteType(TyR.getBegin(), castType, diag::err_typecheck_cast_to_incomplete)) return true; @@ -3964,7 +4995,8 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, for (Field = RD->field_begin(), FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { if (Context.hasSameUnqualifiedType(Field->getType(), - castExpr->getType())) { + castExpr->getType()) && + !Field->isUnnamedBitfield()) { Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union) << castExpr->getSourceRange(); break; @@ -3982,6 +5014,9 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, << castType << castExpr->getSourceRange(); } + // The type we're casting to is known to be a scalar or vector. + + // Require the operand to be a scalar or vector. if (!castExpr->getType()->isScalarType() && !castExpr->getType()->isVectorType()) { return Diag(castExpr->getLocStart(), @@ -3997,9 +5032,16 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, if (castExpr->getType()->isVectorType()) return CheckVectorCast(TyR, castExpr->getType(), castType, Kind); + // The source and target types are both scalars, i.e. + // - arithmetic types (fundamental, enum, and complex) + // - all kinds of pointers + // Note that member pointers were filtered out with C++, above. + if (isa<ObjCSelectorExpr>(castExpr)) return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); + // If either type is a pointer, the other type has to be either an + // integer or a pointer. if (!castType->isArithmeticType()) { QualType castExprType = castExpr->getType(); if (!castExprType->isIntegralType(Context) && @@ -4014,9 +5056,9 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, << castType << castExpr->getSourceRange(); } - Kind = getScalarCastKind(Context, castExpr->getType(), castType); + Kind = PrepareScalarCast(*this, castExpr, castType); - if (Kind == CK_Unknown || Kind == CK_BitCast) + if (Kind == CK_BitCast) CheckCastAlign(castExpr, castType, TyR); return false; @@ -4068,7 +5110,7 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType(); ImpCastExprToType(CastExpr, DestElemTy, - getScalarCastKind(Context, SrcTy, DestElemTy)); + PrepareScalarCast(*this, CastExpr, DestElemTy)); Kind = CK_VectorSplat; return false; @@ -4096,15 +5138,16 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, ParsedType Ty, ExprResult Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, SourceLocation RParenLoc, Expr *castExpr) { - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Invalid; + ExprValueKind VK = VK_RValue; CXXCastPath BasePath; if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, - Kind, BasePath)) + Kind, VK, BasePath)) return ExprError(); return Owned(CStyleCastExpr::Create(Context, Ty->getType().getNonLValueExprType(Context), - Kind, castExpr, &BasePath, Ty, + VK, Kind, castExpr, &BasePath, Ty, LParenLoc, RParenLoc)); } @@ -4188,14 +5231,73 @@ ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, return Owned(expr); } +/// \brief Emit a specialized diagnostic when one expression is a null pointer +/// constant and the other is not a pointer. +bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS, + SourceLocation QuestionLoc) { + Expr *NullExpr = LHS; + Expr *NonPointerExpr = RHS; + Expr::NullPointerConstantKind NullKind = + NullExpr->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull); + + if (NullKind == Expr::NPCK_NotNull) { + NullExpr = RHS; + NonPointerExpr = LHS; + NullKind = + NullExpr->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull); + } + + if (NullKind == Expr::NPCK_NotNull) + return false; + + if (NullKind == Expr::NPCK_ZeroInteger) { + // In this case, check to make sure that we got here from a "NULL" + // string in the source code. + NullExpr = NullExpr->IgnoreParenImpCasts(); + SourceManager& SM = Context.getSourceManager(); + SourceLocation Loc = SM.getInstantiationLoc(NullExpr->getExprLoc()); + unsigned Len = + Lexer::MeasureTokenLength(Loc, SM, Context.getLangOptions()); + if (Len != 4 || memcmp(SM.getCharacterData(Loc), "NULL", 4)) + return false; + } + + int DiagType = (NullKind == Expr::NPCK_CXX0X_nullptr); + Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands_null) + << NonPointerExpr->getType() << DiagType + << NonPointerExpr->getSourceRange(); + return true; +} + /// 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 QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { + // If both LHS and RHS are overloaded functions, try to resolve them. + if (Context.hasSameType(LHS->getType(), RHS->getType()) && + LHS->getType()->isSpecificBuiltinType(BuiltinType::Overload)) { + ExprResult LHSResult = CheckPlaceholderExpr(LHS, QuestionLoc); + if (LHSResult.isInvalid()) + return QualType(); + + ExprResult RHSResult = CheckPlaceholderExpr(RHS, QuestionLoc); + if (RHSResult.isInvalid()) + return QualType(); + + LHS = LHSResult.take(); + RHS = RHSResult.take(); + } + // C++ is sufficiently different to merit its own checker. if (getLangOptions().CPlusPlus) - return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc); + return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); + + VK = VK_RValue; + OK = OK_Ordinary; UsualUnaryConversions(Cond); UsualUnaryConversions(LHS); @@ -4206,15 +5308,47 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // first, check the condition. if (!CondTy->isScalarType()) { // C99 6.5.15p2 - Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar) - << CondTy; - return QualType(); + // OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar. + // Throw an error if its not either. + if (getLangOptions().OpenCL) { + if (!CondTy->isVectorType()) { + Diag(Cond->getLocStart(), + diag::err_typecheck_cond_expect_scalar_or_vector) + << CondTy; + return QualType(); + } + } + else { + Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar) + << CondTy; + return QualType(); + } } // Now check the two expressions. if (LHSTy->isVectorType() || RHSTy->isVectorType()) return CheckVectorOperands(QuestionLoc, LHS, RHS); + // OpenCL: If the condition is a vector, and both operands are scalar, + // attempt to implicity convert them to the vector type to act like the + // built in select. + if (getLangOptions().OpenCL && CondTy->isVectorType()) { + // Both operands should be of scalar type. + if (!LHSTy->isScalarType()) { + Diag(LHS->getLocStart(), diag::err_typecheck_cond_expect_scalar) + << CondTy; + return QualType(); + } + if (!RHSTy->isScalarType()) { + Diag(RHS->getLocStart(), diag::err_typecheck_cond_expect_scalar) + << CondTy; + return QualType(); + } + // Implicity convert these scalars to the type of the condition. + ImpCastExprToType(LHS, CondTy, CK_IntegralCast); + ImpCastExprToType(RHS, CondTy, CK_IntegralCast); + } + // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) { @@ -4251,12 +5385,12 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) && RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { // promote the null to a pointer. - ImpCastExprToType(RHS, LHSTy, CK_Unknown); + ImpCastExprToType(RHS, LHSTy, CK_NullToPointer); return LHSTy; } if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) && LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(LHS, RHSTy, CK_Unknown); + ImpCastExprToType(LHS, RHSTy, CK_NullToPointer); return RHSTy; } @@ -4364,7 +5498,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return LHSTy; } - // GCC compatibility: soften pointer/integer mismatch. + // GCC compatibility: soften pointer/integer mismatch. Note that + // null pointers have been filtered out by this point. if (RHSTy->isPointerType() && LHSTy->isIntegerType()) { Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); @@ -4378,6 +5513,12 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return LHSTy; } + // Emit a better diagnostic if one of the expressions is a null pointer + // constant and the other is not a pointer type. In this case, the user most + // likely forgot to take the address of the other expression. + if (DiagnoseConditionalForNull(LHS, RHS, QuestionLoc)) + return QualType(); + // Otherwise, the operands are not compatible. Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); @@ -4395,34 +5536,34 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, // 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)) { + (Context.hasSameType(RHSTy, Context.ObjCClassRedefinitionType))) { ImpCastExprToType(RHS, LHSTy, CK_BitCast); return LHSTy; } if (RHSTy->isObjCClassType() && - (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { + (Context.hasSameType(LHSTy, Context.ObjCClassRedefinitionType))) { ImpCastExprToType(LHS, RHSTy, CK_BitCast); return RHSTy; } // And the same for struct objc_object* / id if (LHSTy->isObjCIdType() && - (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { + (Context.hasSameType(RHSTy, Context.ObjCIdRedefinitionType))) { ImpCastExprToType(RHS, LHSTy, CK_BitCast); return LHSTy; } if (RHSTy->isObjCIdType() && - (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { + (Context.hasSameType(LHSTy, Context.ObjCIdRedefinitionType))) { ImpCastExprToType(LHS, RHSTy, CK_BitCast); return RHSTy; } // And the same for struct objc_selector* / SEL if (Context.isObjCSelType(LHSTy) && - (RHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { + (Context.hasSameType(RHSTy, Context.ObjCSelRedefinitionType))) { ImpCastExprToType(RHS, LHSTy, CK_BitCast); return LHSTy; } if (Context.isObjCSelType(RHSTy) && - (LHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { + (Context.hasSameType(LHSTy, Context.ObjCSelRedefinitionType))) { ImpCastExprToType(LHS, RHSTy, CK_BitCast); return RHSTy; } @@ -4512,60 +5653,84 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, - SourceLocation ColonLoc, - Expr *CondExpr, Expr *LHSExpr, - Expr *RHSExpr) { + SourceLocation ColonLoc, + Expr *CondExpr, Expr *LHSExpr, + Expr *RHSExpr) { // If this is the gnu "x ?: y" extension, analyze the types as though the LHS // was the condition. - bool isLHSNull = LHSExpr == 0; - Expr *SAVEExpr = 0; - if (isLHSNull) { - LHSExpr = SAVEExpr = CondExpr; - } - - QualType result = CheckConditionalOperands(CondExpr, LHSExpr, - RHSExpr, QuestionLoc); + OpaqueValueExpr *opaqueValue = 0; + Expr *commonExpr = 0; + if (LHSExpr == 0) { + commonExpr = CondExpr; + + // We usually want to apply unary conversions *before* saving, except + // in the special case of a C++ l-value conditional. + if (!(getLangOptions().CPlusPlus + && !commonExpr->isTypeDependent() + && commonExpr->getValueKind() == RHSExpr->getValueKind() + && commonExpr->isGLValue() + && commonExpr->isOrdinaryOrBitFieldObject() + && RHSExpr->isOrdinaryOrBitFieldObject() + && Context.hasSameType(commonExpr->getType(), RHSExpr->getType()))) { + UsualUnaryConversions(commonExpr); + } + + opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(), + commonExpr->getType(), + commonExpr->getValueKind(), + commonExpr->getObjectKind()); + LHSExpr = CondExpr = opaqueValue; + } + + ExprValueKind VK = VK_RValue; + ExprObjectKind OK = OK_Ordinary; + QualType result = CheckConditionalOperands(CondExpr, LHSExpr, RHSExpr, + VK, OK, QuestionLoc); if (result.isNull()) return ExprError(); - return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc, - LHSExpr, ColonLoc, - RHSExpr, SAVEExpr, - result)); + if (!commonExpr) + return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc, + LHSExpr, ColonLoc, + RHSExpr, result, VK, OK)); + + return Owned(new (Context) + BinaryConditionalOperator(commonExpr, opaqueValue, CondExpr, LHSExpr, + RHSExpr, QuestionLoc, ColonLoc, result, VK, OK)); } -// CheckPointerTypesForAssignment - This is a very tricky routine (despite +// 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. // This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3]. // FIXME: add a couple examples in this comment. -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; - } +static Sema::AssignConvertType +checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { + assert(lhsType.isCanonical() && "LHS not canonicalized!"); + assert(rhsType.isCanonical() && "RHS not canonicalized!"); // get the "pointed to" type (ignoring qualifiers at the top level) - lhptee = lhsType->getAs<PointerType>()->getPointeeType(); - rhptee = rhsType->getAs<PointerType>()->getPointeeType(); + const Type *lhptee, *rhptee; + Qualifiers lhq, rhq; + llvm::tie(lhptee, lhq) = cast<PointerType>(lhsType)->getPointeeType().split(); + llvm::tie(rhptee, rhq) = cast<PointerType>(rhsType)->getPointeeType().split(); - // make sure we operate on the canonical type - lhptee = Context.getCanonicalType(lhptee); - rhptee = Context.getCanonicalType(rhptee); - - AssignConvertType ConvTy = Compatible; + Sema::AssignConvertType ConvTy = Sema::Compatible; // C99 6.5.16.1p1: This following citation is common to constraints // 3 & 4 (below). ...and the type *pointed to* by the left has all the // qualifiers of the type *pointed to* by the right; - // FIXME: Handle ExtQualType - if (!lhptee.isAtLeastAsQualifiedAs(rhptee)) - ConvTy = CompatiblePointerDiscardsQualifiers; + Qualifiers lq; + + if (!lhq.compatiblyIncludes(rhq)) { + // Treat address-space mismatches as fatal. TODO: address subspaces + if (lhq.getAddressSpace() != rhq.getAddressSpace()) + ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; + + // For GCC compatibility, other qualifier mismatches are treated + // as still compatible in C. + else ConvTy = Sema::CompatiblePointerDiscardsQualifiers; + } // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or // incomplete type and the other is a pointer to a qualified or unqualified @@ -4576,7 +5741,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { // As an extension, we allow cast to/from void* to function pointer. assert(rhptee->isFunctionType()); - return FunctionVoidPointer; + return Sema::FunctionVoidPointer; } if (rhptee->isVoidType()) { @@ -4585,123 +5750,136 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { // As an extension, we allow cast to/from void* to function pointer. assert(lhptee->isFunctionType()); - return FunctionVoidPointer; + return Sema::FunctionVoidPointer; } + // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or // unqualified versions of compatible types, ... - lhptee = lhptee.getUnqualifiedType(); - rhptee = rhptee.getUnqualifiedType(); - if (!Context.typesAreCompatible(lhptee, rhptee)) { + QualType ltrans = QualType(lhptee, 0), rtrans = QualType(rhptee, 0); + if (!S.Context.typesAreCompatible(ltrans, rtrans)) { // Check if the pointee types are compatible ignoring the sign. // We explicitly check for char so that we catch "char" vs // "unsigned char" on systems where "char" is unsigned. if (lhptee->isCharType()) - lhptee = Context.UnsignedCharTy; + ltrans = S.Context.UnsignedCharTy; else if (lhptee->hasSignedIntegerRepresentation()) - lhptee = Context.getCorrespondingUnsignedType(lhptee); + ltrans = S.Context.getCorrespondingUnsignedType(ltrans); if (rhptee->isCharType()) - rhptee = Context.UnsignedCharTy; + rtrans = S.Context.UnsignedCharTy; else if (rhptee->hasSignedIntegerRepresentation()) - rhptee = Context.getCorrespondingUnsignedType(rhptee); + rtrans = S.Context.getCorrespondingUnsignedType(rtrans); - if (lhptee == rhptee) { + if (ltrans == rtrans) { // Types are compatible ignoring the sign. Qualifier incompatibility // takes priority over sign incompatibility because the sign // warning can be disabled. - if (ConvTy != Compatible) + if (ConvTy != Sema::Compatible) return ConvTy; - return IncompatiblePointerSign; + + return Sema::IncompatiblePointerSign; } // If we are a multi-level pointer, it's possible that our issue is simply // one of qualification - e.g. char ** -> const char ** is not allowed. If // the eventual target type is the same and the pointers have the same // level of indirection, this must be the issue. - if (lhptee->isPointerType() && rhptee->isPointerType()) { + if (isa<PointerType>(lhptee) && isa<PointerType>(rhptee)) { do { - lhptee = lhptee->getAs<PointerType>()->getPointeeType(); - rhptee = rhptee->getAs<PointerType>()->getPointeeType(); - - lhptee = Context.getCanonicalType(lhptee); - rhptee = Context.getCanonicalType(rhptee); - } while (lhptee->isPointerType() && rhptee->isPointerType()); + lhptee = cast<PointerType>(lhptee)->getPointeeType().getTypePtr(); + rhptee = cast<PointerType>(rhptee)->getPointeeType().getTypePtr(); + } while (isa<PointerType>(lhptee) && isa<PointerType>(rhptee)); - if (Context.hasSameUnqualifiedType(lhptee, rhptee)) - return IncompatibleNestedPointerQualifiers; + if (lhptee == rhptee) + return Sema::IncompatibleNestedPointerQualifiers; } // General pointer incompatibility takes priority over qualifiers. - return IncompatiblePointer; + return Sema::IncompatiblePointer; } return ConvTy; } -/// CheckBlockPointerTypesForAssignment - This routine determines whether two +/// checkBlockPointerTypesForAssignment - This routine determines whether two /// block pointer types are compatible or whether a block and normal pointer /// are compatible. It is more restrict than comparing two function pointer // types. -Sema::AssignConvertType -Sema::CheckBlockPointerTypesForAssignment(QualType lhsType, - QualType rhsType) { +static Sema::AssignConvertType +checkBlockPointerTypesForAssignment(Sema &S, QualType lhsType, + QualType rhsType) { + assert(lhsType.isCanonical() && "LHS not canonicalized!"); + assert(rhsType.isCanonical() && "RHS not canonicalized!"); + QualType lhptee, rhptee; // get the "pointed to" type (ignoring qualifiers at the top level) - lhptee = lhsType->getAs<BlockPointerType>()->getPointeeType(); - rhptee = rhsType->getAs<BlockPointerType>()->getPointeeType(); + lhptee = cast<BlockPointerType>(lhsType)->getPointeeType(); + rhptee = cast<BlockPointerType>(rhsType)->getPointeeType(); - // make sure we operate on the canonical type - lhptee = Context.getCanonicalType(lhptee); - rhptee = Context.getCanonicalType(rhptee); + // In C++, the types have to match exactly. + if (S.getLangOptions().CPlusPlus) + return Sema::IncompatibleBlockPointer; - AssignConvertType ConvTy = Compatible; + Sema::AssignConvertType ConvTy = Sema::Compatible; // For blocks we enforce that qualifiers are identical. - if (lhptee.getLocalCVRQualifiers() != rhptee.getLocalCVRQualifiers()) - ConvTy = CompatiblePointerDiscardsQualifiers; + if (lhptee.getLocalQualifiers() != rhptee.getLocalQualifiers()) + ConvTy = Sema::CompatiblePointerDiscardsQualifiers; + + if (!S.Context.typesAreBlockPointerCompatible(lhsType, rhsType)) + return Sema::IncompatibleBlockPointer; - if (!getLangOptions().CPlusPlus) { - if (!Context.typesAreBlockPointerCompatible(lhsType, rhsType)) - return IncompatibleBlockPointer; - } - else if (!Context.typesAreCompatible(lhptee, rhptee)) - return IncompatibleBlockPointer; return ConvTy; } -/// CheckObjCPointerTypesForAssignment - Compares two objective-c pointer types +/// checkObjCPointerTypesForAssignment - Compares two objective-c pointer types /// for assignment compatibility. -Sema::AssignConvertType -Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) { +static Sema::AssignConvertType +checkObjCPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { + assert(lhsType.isCanonical() && "LHS was not canonicalized!"); + assert(rhsType.isCanonical() && "RHS was not canonicalized!"); + if (lhsType->isObjCBuiltinType()) { // Class is not compatible with ObjC object pointers. if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType() && !rhsType->isObjCQualifiedClassType()) - return IncompatiblePointer; - return Compatible; + return Sema::IncompatiblePointer; + return Sema::Compatible; } if (rhsType->isObjCBuiltinType()) { // Class is not compatible with ObjC object pointers. if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType() && !lhsType->isObjCQualifiedClassType()) - return IncompatiblePointer; - return Compatible; + return Sema::IncompatiblePointer; + return Sema::Compatible; } QualType lhptee = lhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); QualType rhptee = rhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); - // make sure we operate on the canonical type - lhptee = Context.getCanonicalType(lhptee); - rhptee = Context.getCanonicalType(rhptee); + if (!lhptee.isAtLeastAsQualifiedAs(rhptee)) - return CompatiblePointerDiscardsQualifiers; + return Sema::CompatiblePointerDiscardsQualifiers; - if (Context.typesAreCompatible(lhsType, rhsType)) - return Compatible; + if (S.Context.typesAreCompatible(lhsType, rhsType)) + return Sema::Compatible; if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) - return IncompatibleObjCQualifiedId; - return IncompatiblePointer; + return Sema::IncompatibleObjCQualifiedId; + return Sema::IncompatiblePointer; +} + +Sema::AssignConvertType +Sema::CheckAssignmentConstraints(SourceLocation Loc, + QualType lhsType, QualType rhsType) { + // Fake up an opaque expression. We don't actually care about what + // cast operations are required, so if CheckAssignmentConstraints + // adds casts to this they'll be wasted, but fortunately that doesn't + // usually happen on valid code. + OpaqueValueExpr rhs(Loc, rhsType, VK_RValue); + Expr *rhsPtr = &rhs; + CastKind K = CK_Invalid; + + return CheckAssignmentConstraints(lhsType, rhsPtr, K); } /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently @@ -4720,21 +5898,21 @@ Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) { /// As a result, the code for dealing with pointers is more complex than the /// C99 spec dictates. /// +/// Sets 'Kind' for any result kind except Incompatible. Sema::AssignConvertType -Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { +Sema::CheckAssignmentConstraints(QualType lhsType, Expr *&rhs, + CastKind &Kind) { + QualType rhsType = rhs->getType(); + // Get canonical types. We're not formatting these types, just comparing // them. lhsType = Context.getCanonicalType(lhsType).getUnqualifiedType(); rhsType = Context.getCanonicalType(rhsType).getUnqualifiedType(); - 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; + // Common case: no conversion required. + if (lhsType == rhsType) { + Kind = CK_NoOp; + return Compatible; } // If the left-hand side is a reference type, then we are in a @@ -4745,144 +5923,220 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { // lhsType so that the resulting expression does not have reference // type. if (const ReferenceType *lhsTypeRef = lhsType->getAs<ReferenceType>()) { - if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType)) + if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType)) { + Kind = CK_LValueBitCast; return Compatible; + } return Incompatible; } + // Allow scalar to ExtVector assignments, and assignments of an ExtVector type // to the same ExtVector type. if (lhsType->isExtVectorType()) { if (rhsType->isExtVectorType()) - return lhsType == rhsType ? Compatible : Incompatible; - if (rhsType->isArithmeticType()) + return Incompatible; + if (rhsType->isArithmeticType()) { + // CK_VectorSplat does T -> vector T, so first cast to the + // element type. + QualType elType = cast<ExtVectorType>(lhsType)->getElementType(); + if (elType != rhsType) { + Kind = PrepareScalarCast(*this, rhs, elType); + ImpCastExprToType(rhs, elType, Kind); + } + Kind = CK_VectorSplat; return Compatible; + } } + // Conversions to or from vector type. if (lhsType->isVectorType() || rhsType->isVectorType()) { if (lhsType->isVectorType() && rhsType->isVectorType()) { + // Allow assignments of an AltiVec vector type to an equivalent GCC + // vector type and vice versa + if (Context.areCompatibleVectorTypes(lhsType, rhsType)) { + Kind = CK_BitCast; + return Compatible; + } + // If we are allowing lax vector conversions, and LHS and RHS are both // vectors, the total size only needs to be the same. This is a bitcast; // no bits are changed but the result type is different. if (getLangOptions().LaxVectorConversions && - (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType))) + (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType))) { + Kind = CK_BitCast; return IncompatibleVectors; - - // Allow assignments of an AltiVec vector type to an equivalent GCC - // vector type and vice versa - if (Context.areCompatibleVectorTypes(lhsType, rhsType)) - return Compatible; + } } return Incompatible; } + // Arithmetic conversions. if (lhsType->isArithmeticType() && rhsType->isArithmeticType() && - !(getLangOptions().CPlusPlus && lhsType->isEnumeralType())) + !(getLangOptions().CPlusPlus && lhsType->isEnumeralType())) { + Kind = PrepareScalarCast(*this, rhs, lhsType); return Compatible; + } - if (isa<PointerType>(lhsType)) { - if (rhsType->isIntegerType()) - return IntToPointer; + // Conversions to normal pointers. + if (const PointerType *lhsPointer = dyn_cast<PointerType>(lhsType)) { + // U* -> T* + if (isa<PointerType>(rhsType)) { + Kind = CK_BitCast; + return checkPointerTypesForAssignment(*this, lhsType, rhsType); + } - if (isa<PointerType>(rhsType)) - return CheckPointerTypesForAssignment(lhsType, rhsType); + // int -> T* + if (rhsType->isIntegerType()) { + Kind = CK_IntegralToPointer; // FIXME: null? + return IntToPointer; + } - // In general, C pointers are not compatible with ObjC object pointers. + // C pointers are not compatible with ObjC object pointers, + // with two exceptions: if (isa<ObjCObjectPointerType>(rhsType)) { - if (lhsType->isVoidPointerType()) // an exception to the rule. + // - conversions to void* + if (lhsPointer->getPointeeType()->isVoidType()) { + Kind = CK_AnyPointerToObjCPointerCast; return Compatible; + } + + // - conversions from 'Class' to the redefinition type + if (rhsType->isObjCClassType() && + Context.hasSameType(lhsType, Context.ObjCClassRedefinitionType)) { + Kind = CK_BitCast; + return Compatible; + } + + Kind = CK_BitCast; return IncompatiblePointer; } - if (rhsType->getAs<BlockPointerType>()) { - if (lhsType->getAs<PointerType>()->getPointeeType()->isVoidType()) - return Compatible; - // Treat block pointers as objects. - if (getLangOptions().ObjC1 && lhsType->isObjCIdType()) + // U^ -> void* + if (rhsType->getAs<BlockPointerType>()) { + if (lhsPointer->getPointeeType()->isVoidType()) { + Kind = CK_BitCast; return Compatible; + } } + return Incompatible; } + // Conversions to block pointers. if (isa<BlockPointerType>(lhsType)) { - if (rhsType->isIntegerType()) + // U^ -> T^ + if (rhsType->isBlockPointerType()) { + Kind = CK_AnyPointerToBlockPointerCast; + return checkBlockPointerTypesForAssignment(*this, lhsType, rhsType); + } + + // int or null -> T^ + if (rhsType->isIntegerType()) { + Kind = CK_IntegralToPointer; // FIXME: null return IntToBlockPointer; + } - // Treat block pointers as objects. - if (getLangOptions().ObjC1 && rhsType->isObjCIdType()) + // id -> T^ + if (getLangOptions().ObjC1 && rhsType->isObjCIdType()) { + Kind = CK_AnyPointerToBlockPointerCast; return Compatible; + } - if (rhsType->isBlockPointerType()) - return CheckBlockPointerTypesForAssignment(lhsType, rhsType); - - if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) { - if (RHSPT->getPointeeType()->isVoidType()) + // void* -> T^ + if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) + if (RHSPT->getPointeeType()->isVoidType()) { + Kind = CK_AnyPointerToBlockPointerCast; return Compatible; - } + } + return Incompatible; } + // Conversions to Objective-C pointers. if (isa<ObjCObjectPointerType>(lhsType)) { - if (rhsType->isIntegerType()) + // A* -> B* + if (rhsType->isObjCObjectPointerType()) { + Kind = CK_BitCast; + return checkObjCPointerTypesForAssignment(*this, lhsType, rhsType); + } + + // int or null -> A* + if (rhsType->isIntegerType()) { + Kind = CK_IntegralToPointer; // FIXME: null return IntToPointer; + } - // In general, C pointers are not compatible with ObjC object pointers. + // In general, C pointers are not compatible with ObjC object pointers, + // with two exceptions: if (isa<PointerType>(rhsType)) { - if (rhsType->isVoidPointerType()) // an exception to the rule. + // - conversions from 'void*' + if (rhsType->isVoidPointerType()) { + Kind = CK_AnyPointerToObjCPointerCast; return Compatible; - return IncompatiblePointer; - } - if (rhsType->isObjCObjectPointerType()) { - return CheckObjCPointerTypesForAssignment(lhsType, rhsType); - } - if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) { - if (RHSPT->getPointeeType()->isVoidType()) + } + + // - conversions to 'Class' from its redefinition type + if (lhsType->isObjCClassType() && + Context.hasSameType(rhsType, Context.ObjCClassRedefinitionType)) { + Kind = CK_BitCast; return Compatible; + } + + Kind = CK_AnyPointerToObjCPointerCast; + return IncompatiblePointer; } - // Treat block pointers as objects. - if (rhsType->isBlockPointerType()) + + // T^ -> A* + if (rhsType->isBlockPointerType()) { + Kind = CK_AnyPointerToObjCPointerCast; return Compatible; + } + return Incompatible; } + + // Conversions from pointers that are not covered by the above. if (isa<PointerType>(rhsType)) { - // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer. - if (lhsType == Context.BoolTy) + // T* -> _Bool + if (lhsType == Context.BoolTy) { + Kind = CK_PointerToBoolean; return Compatible; + } - if (lhsType->isIntegerType()) + // T* -> int + if (lhsType->isIntegerType()) { + Kind = CK_PointerToIntegral; return PointerToInt; + } - if (isa<PointerType>(lhsType)) - return CheckPointerTypesForAssignment(lhsType, rhsType); - - if (isa<BlockPointerType>(lhsType) && - rhsType->getAs<PointerType>()->getPointeeType()->isVoidType()) - return Compatible; return Incompatible; } + + // Conversions from Objective-C pointers that are not covered by the above. if (isa<ObjCObjectPointerType>(rhsType)) { - // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer. - if (lhsType == Context.BoolTy) + // T* -> _Bool + if (lhsType == Context.BoolTy) { + Kind = CK_PointerToBoolean; return Compatible; + } - if (lhsType->isIntegerType()) + // T* -> int + if (lhsType->isIntegerType()) { + Kind = CK_PointerToIntegral; 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; } + // struct A -> struct B if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) { - if (Context.typesAreCompatible(lhsType, rhsType)) + if (Context.typesAreCompatible(lhsType, rhsType)) { + Kind = CK_NoOp; return Compatible; + } } + return Incompatible; } @@ -4902,7 +6156,7 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E, // union type from this initializer list. TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType); E = new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType, - Initializer, false); + VK_RValue, Initializer, false); } Sema::AssignConvertType @@ -4935,14 +6189,18 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { if (rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(rExpr, it->getType(), CK_IntegralToPointer); + ImpCastExprToType(rExpr, it->getType(), CK_NullToPointer); InitField = *it; break; } } - if (CheckAssignmentConstraints(it->getType(), rExpr->getType()) + Expr *rhs = rExpr; + CastKind Kind = CK_Invalid; + if (CheckAssignmentConstraints(it->getType(), rhs, Kind) == Compatible) { + ImpCastExprToType(rhs, it->getType(), Kind); + rExpr = rhs; InitField = *it; break; } @@ -4970,7 +6228,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // FIXME: Currently, we fall through and treat C++ classes like C // structures. - } + } // C99 6.5.16.1p1: the left operand is a pointer and the right is // a null pointer constant. @@ -4979,7 +6237,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { lhsType->isBlockPointerType()) && rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(rExpr, lhsType, CK_Unknown); + ImpCastExprToType(rExpr, lhsType, CK_NullToPointer); return Compatible; } @@ -4992,8 +6250,9 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { if (!lhsType->isReferenceType()) DefaultFunctionArrayLvalueConversion(rExpr); + CastKind Kind = CK_Invalid; Sema::AssignConvertType result = - CheckAssignmentConstraints(lhsType, rExpr->getType()); + CheckAssignmentConstraints(lhsType, rExpr, Kind); // C99 6.5.16.1p2: The value of the right operand is converted to the // type of the assignment expression. @@ -5002,8 +6261,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // The getNonReferenceType() call makes sure that the resulting expression // does not have reference type. if (result != Incompatible && rExpr->getType() != lhsType) - ImpCastExprToType(rExpr, lhsType.getNonLValueExprType(Context), - CK_Unknown); + ImpCastExprToType(rExpr, lhsType.getNonLValueExprType(Context), Kind); return result; } @@ -5071,16 +6329,22 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { if (const ExtVectorType *LV = lhsType->getAs<ExtVectorType>()) { QualType EltTy = LV->getElementType(); if (EltTy->isIntegralType(Context) && rhsType->isIntegralType(Context)) { - if (Context.getIntegerTypeOrder(EltTy, rhsType) >= 0) { - ImpCastExprToType(rex, lhsType, CK_IntegralCast); + int order = Context.getIntegerTypeOrder(EltTy, rhsType); + if (order > 0) + ImpCastExprToType(rex, EltTy, CK_IntegralCast); + if (order >= 0) { + ImpCastExprToType(rex, lhsType, CK_VectorSplat); if (swapped) std::swap(rex, lex); return lhsType; } } if (EltTy->isRealFloatingType() && rhsType->isScalarType() && rhsType->isRealFloatingType()) { - if (Context.getFloatingTypeOrder(EltTy, rhsType) >= 0) { - ImpCastExprToType(rex, lhsType, CK_FloatingCast); + int order = Context.getFloatingTypeOrder(EltTy, rhsType); + if (order > 0) + ImpCastExprToType(rex, EltTy, CK_FloatingCast); + if (order >= 0) { + ImpCastExprToType(rex, lhsType, CK_VectorSplat); if (swapped) std::swap(rex, lex); return lhsType; } @@ -5359,6 +6623,12 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, return InvalidOperands(Loc, lex, rex); } +static bool isScopedEnumerationType(QualType T) { + if (const EnumType *ET = dyn_cast<EnumType>(T)) + return ET->getDecl()->isScoped(); + return false; +} + // C99 6.5.7 QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { @@ -5367,21 +6637,28 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, !rex->getType()->hasIntegerRepresentation()) return InvalidOperands(Loc, lex, rex); + // C++0x: Don't allow scoped enums. FIXME: Use something better than + // hasIntegerRepresentation() above instead of this. + if (isScopedEnumerationType(lex->getType()) || + isScopedEnumerationType(rex->getType())) { + return InvalidOperands(Loc, lex, rex); + } + // Vector shifts promote their scalar inputs to vector type. if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorOperands(Loc, lex, rex); // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 - QualType LHSTy = Context.isPromotableBitField(lex); - if (LHSTy.isNull()) { - LHSTy = lex->getType(); - if (LHSTy->isPromotableIntegerType()) - LHSTy = Context.getPromotedIntegerType(LHSTy); - } - if (!isCompAssign) - ImpCastExprToType(lex, LHSTy, CK_IntegralCast); + // For the LHS, do usual unary conversions, but then reset them away + // if this is a compound assignment. + Expr *old_lex = lex; + UsualUnaryConversions(lex); + QualType LHSTy = lex->getType(); + if (isCompAssign) lex = old_lex; + + // The RHS is simpler. UsualUnaryConversions(rex); // Sanity-check shift operands @@ -5425,8 +6702,28 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, QualType lType = lex->getType(); QualType rType = rex->getType(); + Expr *LHSStripped = lex->IgnoreParenImpCasts(); + Expr *RHSStripped = rex->IgnoreParenImpCasts(); + QualType LHSStrippedType = LHSStripped->getType(); + QualType RHSStrippedType = RHSStripped->getType(); + + // Two different enums will raise a warning when compared. + if (const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>()) { + if (const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>()) { + if (LHSEnumType->getDecl()->getIdentifier() && + RHSEnumType->getDecl()->getIdentifier() && + !Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) { + Diag(Loc, diag::warn_comparison_of_mixed_enum_types) + << LHSStrippedType << RHSStrippedType + << lex->getSourceRange() << rex->getSourceRange(); + } + } + } + if (!lType->hasFloatingRepresentation() && - !(lType->isBlockPointerType() && isRelational)) { + !(lType->isBlockPointerType() && isRelational) && + !lex->getLocStart().isMacroID() && + !rex->getLocStart().isMacroID()) { // 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. @@ -5437,11 +6734,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // obvious cases in the definition of the template anyways. The idea is to // warn when the typed comparison operator will always evaluate to the same // result. - Expr *LHSStripped = lex->IgnoreParens(); - Expr *RHSStripped = rex->IgnoreParens(); if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped)) { if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) { - if (DRL->getDecl() == DRR->getDecl() && !Loc.isMacroID() && + if (DRL->getDecl() == DRR->getDecl() && !IsWithinTemplateSpecialization(DRL->getDecl())) { DiagRuntimeBehavior(Loc, PDiag(diag::warn_comparison_always) << 0 // self- @@ -5525,7 +6820,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, rType = rex->getType(); // The result of comparisons is 'bool' in C++, 'int' in C. - QualType ResultTy = getLangOptions().CPlusPlus ? Context.BoolTy:Context.IntTy; + QualType ResultTy = Context.getLogicalOperationType(); if (isRelational) { if (lType->isRealType() && rType->isRealType()) @@ -5576,6 +6871,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return ResultTy; } } + // C++ [expr.rel]p2: // [...] Pointer conversions (4.10) and qualification // conversions (4.4) are performed on pointer operands (or on @@ -5629,24 +6925,28 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, } if (getLangOptions().CPlusPlus) { + // Comparison of nullptr_t with itself. + if (lType->isNullPtrType() && rType->isNullPtrType()) + return ResultTy; + // Comparison of pointers with null pointer constants and equality // comparisons of member pointers to null pointer constants. if (RHSIsNull && - (lType->isPointerType() || + ((lType->isPointerType() || lType->isNullPtrType()) || (!isRelational && lType->isMemberPointerType()))) { ImpCastExprToType(rex, lType, lType->isMemberPointerType() ? CK_NullToMemberPointer - : CK_IntegralToPointer); + : CK_NullToPointer); return ResultTy; } if (LHSIsNull && - (rType->isPointerType() || + ((rType->isPointerType() || rType->isNullPtrType()) || (!isRelational && rType->isMemberPointerType()))) { ImpCastExprToType(lex, rType, rType->isMemberPointerType() ? CK_NullToMemberPointer - : CK_IntegralToPointer); + : CK_NullToPointer); return ResultTy; } @@ -5681,10 +6981,6 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, ImpCastExprToType(rex, T, CK_BitCast); return ResultTy; } - - // Comparison of nullptr_t with itself. - if (lType->isNullPtrType() && rType->isNullPtrType()) - return ResultTy; } // Handle block pointer types. @@ -5765,21 +7061,23 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, } if (lType->isIntegerType()) - ImpCastExprToType(lex, rType, CK_IntegralToPointer); + ImpCastExprToType(lex, rType, + LHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); else - ImpCastExprToType(rex, lType, CK_IntegralToPointer); + ImpCastExprToType(rex, lType, + RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); return ResultTy; } // Handle block pointers. if (!isRelational && RHSIsNull && lType->isBlockPointerType() && rType->isIntegerType()) { - ImpCastExprToType(rex, lType, CK_IntegralToPointer); + ImpCastExprToType(rex, lType, CK_NullToPointer); return ResultTy; } if (!isRelational && LHSIsNull && lType->isIntegerType() && rType->isBlockPointerType()) { - ImpCastExprToType(lex, rType, CK_IntegralToPointer); + ImpCastExprToType(lex, rType, CK_NullToPointer); return ResultTy; } return InvalidOperands(Loc, lex, rex); @@ -5798,6 +7096,11 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, if (vType.isNull()) return vType; + // If AltiVec, the comparison results in a numeric type, i.e. + // bool for C++, int for C + if (getLangOptions().AltiVec) + return Context.getLogicalOperationType(); + QualType lType = lex->getType(); QualType rType = rex->getType(); @@ -5851,7 +7154,8 @@ inline QualType Sema::CheckBitwiseOperands( QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) + if (lex->getType()->isIntegralOrUnscopedEnumerationType() && + rex->getType()->isIntegralOrUnscopedEnumerationType()) return compType; return InvalidOperands(Loc, lex, rex); } @@ -5912,14 +7216,18 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] 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 ObjCObjectPointerType *OPT = - BaseType->getAsObjCInterfacePointerType()) - if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl()) - if (S.isPropertyReadonly(PDecl, IFace)) - return true; - } + if (PropExpr->isImplicitProperty()) return false; + + ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty(); + QualType BaseType = PropExpr->isSuperReceiver() ? + PropExpr->getSuperReceiverType() : + PropExpr->getBase()->getType(); + + if (const ObjCObjectPointerType *OPT = + BaseType->getAsObjCInterfacePointerType()) + if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl()) + if (S.isPropertyReadonly(PDecl, IFace)) + return true; } return false; } @@ -6005,17 +7313,8 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, if (CompoundType.isNull()) { QualType LHSTy(LHSType); // Simple assignment "x = y". - if (const ObjCImplicitSetterGetterRefExpr *OISGE = - dyn_cast<ObjCImplicitSetterGetterRefExpr>(LHS)) { - // If using property-dot syntax notation for assignment, and there is a - // setter, RHS expression is being passed to the setter argument. So, - // type conversion (and comparison) is RHS to setter's argument type. - if (const ObjCMethodDecl *SetterMD = OISGE->getSetterMethod()) { - ObjCMethodDecl::param_iterator P = SetterMD->param_begin(); - LHSTy = (*P)->getType(); - } - } - + if (LHS->getObjectKind() == OK_ObjCProperty) + ConvertPropertyForLValue(LHS, RHS, LHSTy); ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); // Special case of NSObject attributes on c-style pointer types. if (ConvTy == IncompatiblePointer && @@ -6025,6 +7324,12 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, LHSType->isObjCObjectPointerType()))) ConvTy = Compatible; + if (ConvTy == Compatible && + getLangOptions().ObjCNonFragileABI && + LHSType->isObjCObjectType()) + Diag(Loc, diag::err_assignment_requires_nonfragile_object) + << LHSType; + // If the RHS is a unary plus or minus, check to see if they = and + are // right next to each other. If so, the user may have typo'd "x =+ 4" // instead of "x += 4". @@ -6048,7 +7353,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, } } else { // Compound assignment "x += y" - ConvTy = CheckAssignmentConstraints(LHSType, RHSType); + ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType); } if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, @@ -6072,6 +7377,11 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, Diag(UO->getOperatorLoc(), diag::note_indirection_through_null); } + // Check for trivial buffer overflows. + if (const ArraySubscriptExpr *ae + = dyn_cast<ArraySubscriptExpr>(LHS->IgnoreParenCasts())) + CheckArrayAccess(ae); + // C99 6.5.16p3: The type of an assignment expression is the type of the // left operand unless the left operand has qualified type, in which case // it is the unqualified version of the type of the left operand. @@ -6079,42 +7389,61 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, // is converted to the type of the assignment expression (above). // C++ 5.17p1: the type of the assignment expression is that of its left // operand. - return LHSType.getUnqualifiedType(); + return (getLangOptions().CPlusPlus + ? LHSType : LHSType.getUnqualifiedType()); } // C99 6.5.17 -QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) { - DiagnoseUnusedExprResult(LHS); +static QualType CheckCommaOperands(Sema &S, Expr *&LHS, Expr *&RHS, + SourceLocation Loc) { + S.DiagnoseUnusedExprResult(LHS); - // Comma performs lvalue conversion (C99 6.3.2.1), but not unary conversions. - // C++ does not perform this conversion (C++ [expr.comma]p1). - if (!getLangOptions().CPlusPlus) - DefaultFunctionArrayLvalueConversion(RHS); + ExprResult LHSResult = S.CheckPlaceholderExpr(LHS, Loc); + if (LHSResult.isInvalid()) + return QualType(); + + ExprResult RHSResult = S.CheckPlaceholderExpr(RHS, Loc); + if (RHSResult.isInvalid()) + return QualType(); + RHS = RHSResult.take(); - // FIXME: Check that RHS type is complete in C mode (it's legal for it to be - // incomplete in C++). + // C's comma performs lvalue conversion (C99 6.3.2.1) on both its + // operands, but not unary promotions. + // C++'s comma does not do any conversions at all (C++ [expr.comma]p1). + + // So we treat the LHS as a ignored value, and in C++ we allow the + // containing site to determine what should be done with the RHS. + S.IgnoredValueConversions(LHS); + + if (!S.getLangOptions().CPlusPlus) { + S.DefaultFunctionArrayLvalueConversion(RHS); + if (!RHS->getType()->isVoidType()) + S.RequireCompleteType(Loc, RHS->getType(), diag::err_incomplete_type); + } return RHS->getType(); } /// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine /// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions. -QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, - bool isInc, bool isPrefix) { +static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, + ExprValueKind &VK, + SourceLocation OpLoc, + bool isInc, bool isPrefix) { if (Op->isTypeDependent()) - return Context.DependentTy; + return S.Context.DependentTy; QualType ResType = Op->getType(); assert(!ResType.isNull() && "no type for increment/decrement expression"); - if (getLangOptions().CPlusPlus && ResType->isBooleanType()) { + if (S.getLangOptions().CPlusPlus && ResType->isBooleanType()) { // Decrement of bool is not allowed. if (!isInc) { - Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange(); + S.Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange(); return QualType(); } // Increment of bool sets it to true, but is deprecated. - Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange(); + S.Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange(); } else if (ResType->isRealType()) { // OK! } else if (ResType->isAnyPointerType()) { @@ -6122,53 +7451,128 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, // C99 6.5.2.4p2, 6.5.6p2 if (PointeeTy->isVoidType()) { - if (getLangOptions().CPlusPlus) { - Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type) + if (S.getLangOptions().CPlusPlus) { + S.Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type) << Op->getSourceRange(); return QualType(); } // Pointer to void is a GNU extension in C. - Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); + S.Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); } else if (PointeeTy->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) + if (S.getLangOptions().CPlusPlus) { + S.Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) << Op->getType() << Op->getSourceRange(); return QualType(); } - Diag(OpLoc, diag::ext_gnu_ptr_func_arith) + S.Diag(OpLoc, diag::ext_gnu_ptr_func_arith) << ResType << Op->getSourceRange(); - } else if (RequireCompleteType(OpLoc, PointeeTy, - PDiag(diag::err_typecheck_arithmetic_incomplete_type) + } else if (S.RequireCompleteType(OpLoc, PointeeTy, + S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) << Op->getSourceRange() << ResType)) return QualType(); // Diagnose bad cases where we step over interface counts. - else if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { - Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) + else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) { + S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) << PointeeTy << Op->getSourceRange(); return QualType(); } } else if (ResType->isAnyComplexType()) { // C99 does not support ++/-- on complex types, we allow as an extension. - Diag(OpLoc, diag::ext_integer_increment_complex) + S.Diag(OpLoc, diag::ext_integer_increment_complex) << ResType << Op->getSourceRange(); + } else if (ResType->isPlaceholderType()) { + ExprResult PR = S.CheckPlaceholderExpr(Op, OpLoc); + if (PR.isInvalid()) return QualType(); + return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc, + isInc, isPrefix); + } else if (S.getLangOptions().AltiVec && ResType->isVectorType()) { + // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) } else { - Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) + S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) << ResType << int(isInc) << Op->getSourceRange(); return QualType(); } // At this point, we know we have a real, complex or pointer type. // Now make sure the operand is a modifiable lvalue. - if (CheckForModifiableLvalue(Op, OpLoc, *this)) + if (CheckForModifiableLvalue(Op, OpLoc, S)) return QualType(); // In C++, a prefix increment is the same type as the operand. Otherwise // (in C or with postfix), the increment is the unqualified type of the // operand. - return isPrefix && getLangOptions().CPlusPlus - ? ResType : ResType.getUnqualifiedType(); + if (isPrefix && S.getLangOptions().CPlusPlus) { + VK = VK_LValue; + return ResType; + } else { + VK = VK_RValue; + return ResType.getUnqualifiedType(); + } +} + +void Sema::ConvertPropertyForRValue(Expr *&E) { + assert(E->getValueKind() == VK_LValue && + E->getObjectKind() == OK_ObjCProperty); + const ObjCPropertyRefExpr *PRE = E->getObjCProperty(); + + ExprValueKind VK = VK_RValue; + if (PRE->isImplicitProperty()) { + if (const ObjCMethodDecl *GetterMethod = + PRE->getImplicitPropertyGetter()) { + QualType Result = GetterMethod->getResultType(); + VK = Expr::getValueKindForType(Result); + } + else { + Diag(PRE->getLocation(), diag::err_getter_not_found) + << PRE->getBase()->getType(); + } + } + + E = ImplicitCastExpr::Create(Context, E->getType(), CK_GetObjCProperty, + E, 0, VK); + + ExprResult Result = MaybeBindToTemporary(E); + if (!Result.isInvalid()) + E = Result.take(); +} + +void Sema::ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType &LHSTy) { + assert(LHS->getValueKind() == VK_LValue && + LHS->getObjectKind() == OK_ObjCProperty); + const ObjCPropertyRefExpr *PRE = LHS->getObjCProperty(); + + if (PRE->isImplicitProperty()) { + // If using property-dot syntax notation for assignment, and there is a + // setter, RHS expression is being passed to the setter argument. So, + // type conversion (and comparison) is RHS to setter's argument type. + if (const ObjCMethodDecl *SetterMD = PRE->getImplicitPropertySetter()) { + ObjCMethodDecl::param_iterator P = SetterMD->param_begin(); + LHSTy = (*P)->getType(); + + // Otherwise, if the getter returns an l-value, just call that. + } else { + QualType Result = PRE->getImplicitPropertyGetter()->getResultType(); + ExprValueKind VK = Expr::getValueKindForType(Result); + if (VK == VK_LValue) { + LHS = ImplicitCastExpr::Create(Context, LHS->getType(), + CK_GetObjCProperty, LHS, 0, VK); + return; + } + } + } + + if (getLangOptions().CPlusPlus && LHSTy->isRecordType()) { + InitializedEntity Entity = + InitializedEntity::InitializeParameter(Context, LHSTy); + Expr *Arg = RHS; + ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), + Owned(Arg)); + if (!ArgE.isInvalid()) + RHS = ArgE.takeAs<Expr>(); + } } + /// getPrimaryDecl - Helper function for CheckAddressOfOperand(). /// This routine allows us to typecheck complex/recursive expressions @@ -6182,7 +7586,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, /// - *(x + 1) -> x, if x is an array /// - &"123"[2] -> 0 /// - & __real__ x -> x -static NamedDecl *getPrimaryDecl(Expr *E) { +static ValueDecl *getPrimaryDecl(Expr *E) { switch (E->getStmtClass()) { case Stmt::DeclRefExprClass: return cast<DeclRefExpr>(E)->getDecl(); @@ -6234,16 +7638,21 @@ static NamedDecl *getPrimaryDecl(Expr *E) { /// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. /// In C++, the operand might be an overloaded function name, in which case /// we allow the '&' but retain the overloaded-function type. -QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { +static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, + SourceLocation OpLoc) { if (OrigOp->isTypeDependent()) - return Context.DependentTy; - if (OrigOp->getType() == Context.OverloadTy) - return Context.OverloadTy; + return S.Context.DependentTy; + if (OrigOp->getType() == S.Context.OverloadTy) + return S.Context.OverloadTy; + + ExprResult PR = S.CheckPlaceholderExpr(OrigOp, OpLoc); + if (PR.isInvalid()) return QualType(); + OrigOp = PR.take(); // Make sure to ignore parentheses in subsequent checks Expr *op = OrigOp->IgnoreParens(); - if (getLangOptions().C99) { + if (S.getLangOptions().C99) { // Implement C99-only parts of addressof rules. if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) { if (uOp->getOpcode() == UO_Deref) @@ -6254,24 +7663,25 @@ QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { // Technically, there should be a check for array subscript // expressions here, but the result of one is always an lvalue anyway. } - NamedDecl *dcl = getPrimaryDecl(op); - Expr::isLvalueResult lval = op->isLvalue(Context); + ValueDecl *dcl = getPrimaryDecl(op); + Expr::LValueClassification lval = op->ClassifyLValue(S.Context); if (lval == Expr::LV_ClassTemporary) { - Diag(OpLoc, isSFINAEContext()? diag::err_typecheck_addrof_class_temporary - : diag::ext_typecheck_addrof_class_temporary) + bool sfinae = S.isSFINAEContext(); + S.Diag(OpLoc, sfinae ? diag::err_typecheck_addrof_class_temporary + : diag::ext_typecheck_addrof_class_temporary) << op->getType() << op->getSourceRange(); - if (isSFINAEContext()) + if (sfinae) return QualType(); } else if (isa<ObjCSelectorExpr>(op)) { - return Context.getPointerType(op->getType()); + return S.Context.getPointerType(op->getType()); } else if (lval == Expr::LV_MemberFunction) { // If it's an instance method, make a member pointer. // The expression must have exactly the form &A::foo. // If the underlying expression isn't a decl ref, give up. if (!isa<DeclRefExpr>(op)) { - Diag(OpLoc, diag::err_invalid_form_pointer_member_function) + S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function) << OrigOp->getSourceRange(); return QualType(); } @@ -6280,45 +7690,41 @@ QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { // The id-expression was parenthesized. if (OrigOp != DRE) { - Diag(OpLoc, diag::err_parens_pointer_member_function) + S.Diag(OpLoc, diag::err_parens_pointer_member_function) << OrigOp->getSourceRange(); // The method was named without a qualifier. } else if (!DRE->getQualifier()) { - Diag(OpLoc, diag::err_unqualified_pointer_member_function) + S.Diag(OpLoc, diag::err_unqualified_pointer_member_function) << op->getSourceRange(); } - return Context.getMemberPointerType(op->getType(), - Context.getTypeDeclType(MD->getParent()).getTypePtr()); + return S.Context.getMemberPointerType(op->getType(), + S.Context.getTypeDeclType(MD->getParent()).getTypePtr()); } else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { // C99 6.5.3.2p1 // The operand must be either an l-value or a function designator if (!op->getType()->isFunctionType()) { // FIXME: emit more specific diag... - Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) + S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) << op->getSourceRange(); return QualType(); } - } else if (op->getBitField()) { // C99 6.5.3.2p1 + } else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1 // The operand cannot be a bit-field - Diag(OpLoc, diag::err_typecheck_address_of) + S.Diag(OpLoc, diag::err_typecheck_address_of) << "bit-field" << op->getSourceRange(); return QualType(); - } else if (op->refersToVectorElement()) { + } else if (op->getObjectKind() == OK_VectorComponent) { // The operand cannot be an element of a vector - Diag(OpLoc, diag::err_typecheck_address_of) + S.Diag(OpLoc, diag::err_typecheck_address_of) << "vector element" << op->getSourceRange(); return QualType(); - } else if (isa<ObjCPropertyRefExpr>(op)) { + } else if (op->getObjectKind() == OK_ObjCProperty) { // cannot take address of a property expression. - Diag(OpLoc, diag::err_typecheck_address_of) + S.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. @@ -6326,29 +7732,31 @@ QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { // in C++ it is not error to take address of a register // variable (c++03 7.1.1P3) if (vd->getStorageClass() == SC_Register && - !getLangOptions().CPlusPlus) { - Diag(OpLoc, diag::err_typecheck_address_of) + !S.getLangOptions().CPlusPlus) { + S.Diag(OpLoc, diag::err_typecheck_address_of) << "register variable" << op->getSourceRange(); return QualType(); } } else if (isa<FunctionTemplateDecl>(dcl)) { - return Context.OverloadTy; - } else if (FieldDecl *FD = dyn_cast<FieldDecl>(dcl)) { + return S.Context.OverloadTy; + } else if (isa<FieldDecl>(dcl) || isa<IndirectFieldDecl>(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<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier()) { DeclContext *Ctx = dcl->getDeclContext(); if (Ctx && Ctx->isRecord()) { - if (FD->getType()->isReferenceType()) { - Diag(OpLoc, - diag::err_cannot_form_pointer_to_member_of_reference_type) - << FD->getDeclName() << FD->getType(); + if (dcl->getType()->isReferenceType()) { + S.Diag(OpLoc, + diag::err_cannot_form_pointer_to_member_of_reference_type) + << dcl->getDeclName() << dcl->getType(); return QualType(); } - return Context.getMemberPointerType(op->getType(), - Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr()); + while (cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion()) + Ctx = Ctx->getParent(); + return S.Context.getMemberPointerType(op->getType(), + S.Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr()); } } } else if (!isa<FunctionDecl>(dcl)) @@ -6359,21 +7767,22 @@ QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { // Taking the address of a void variable is technically illegal, but we // allow it in cases which are otherwise valid. // Example: "extern void x; void* y = &x;". - Diag(OpLoc, diag::ext_typecheck_addrof_void) << op->getSourceRange(); + S.Diag(OpLoc, diag::ext_typecheck_addrof_void) << op->getSourceRange(); } // If the operand has type "type", the result has type "pointer to type". if (op->getType()->isObjCObjectType()) - return Context.getObjCObjectPointerType(op->getType()); - return Context.getPointerType(op->getType()); + return S.Context.getObjCObjectPointerType(op->getType()); + return S.Context.getPointerType(op->getType()); } /// CheckIndirectionOperand - Type check unary indirection (prefix '*'). -QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) { +static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, + SourceLocation OpLoc) { if (Op->isTypeDependent()) - return Context.DependentTy; + return S.Context.DependentTy; - UsualUnaryConversions(Op); + S.UsualUnaryConversions(Op); QualType OpTy = Op->getType(); QualType Result; @@ -6386,12 +7795,26 @@ QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) { else if (const ObjCObjectPointerType *OPT = OpTy->getAs<ObjCObjectPointerType>()) Result = OPT->getPointeeType(); + else { + ExprResult PR = S.CheckPlaceholderExpr(Op, OpLoc); + if (PR.isInvalid()) return QualType(); + if (PR.take() != Op) + return CheckIndirectionOperand(S, PR.take(), VK, OpLoc); + } if (Result.isNull()) { - Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer) + S.Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer) << OpTy << Op->getSourceRange(); return QualType(); } + + // Dereferences are usually l-values... + VK = VK_LValue; + + // ...except that certain expressions are never l-values in C. + if (!S.getLangOptions().CPlusPlus && + IsCForbiddenLValueType(S.Context, Result)) + VK = VK_RValue; return Result; } @@ -6457,25 +7880,67 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( return Opc; } +/// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself. +/// This warning is only emitted for builtin assignment operations. It is also +/// suppressed in the event of macro expansions. +static void DiagnoseSelfAssignment(Sema &S, Expr *lhs, Expr *rhs, + SourceLocation OpLoc) { + if (!S.ActiveTemplateInstantiations.empty()) + return; + if (OpLoc.isInvalid() || OpLoc.isMacroID()) + return; + lhs = lhs->IgnoreParenImpCasts(); + rhs = rhs->IgnoreParenImpCasts(); + const DeclRefExpr *LeftDeclRef = dyn_cast<DeclRefExpr>(lhs); + const DeclRefExpr *RightDeclRef = dyn_cast<DeclRefExpr>(rhs); + if (!LeftDeclRef || !RightDeclRef || + LeftDeclRef->getLocation().isMacroID() || + RightDeclRef->getLocation().isMacroID()) + return; + const ValueDecl *LeftDecl = + cast<ValueDecl>(LeftDeclRef->getDecl()->getCanonicalDecl()); + const ValueDecl *RightDecl = + cast<ValueDecl>(RightDeclRef->getDecl()->getCanonicalDecl()); + if (LeftDecl != RightDecl) + return; + if (LeftDecl->getType().isVolatileQualified()) + return; + if (const ReferenceType *RefTy = LeftDecl->getType()->getAs<ReferenceType>()) + if (RefTy->getPointeeType().isVolatileQualified()) + return; + + S.Diag(OpLoc, diag::warn_self_assignment) + << LeftDeclRef->getType() + << lhs->getSourceRange() << rhs->getSourceRange(); +} + /// CreateBuiltinBinOp - Creates a new built-in binary operation with /// operator @p Opc at location @c TokLoc. This routine only supports /// built-in operations; ActOnBinOp handles overloaded operators. ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, - unsigned Op, + BinaryOperatorKind Opc, Expr *lhs, Expr *rhs) { QualType ResultTy; // Result type of the binary operator. - BinaryOperatorKind Opc = (BinaryOperatorKind) Op; // The following two variables are used for compound assignment operators QualType CompLHSTy; // Type of LHS after promotions for computation QualType CompResultTy; // Type of computation result + ExprValueKind VK = VK_RValue; + ExprObjectKind OK = OK_Ordinary; switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType()); + if (getLangOptions().CPlusPlus && + lhs->getObjectKind() != OK_ObjCProperty) { + VK = lhs->getValueKind(); + OK = lhs->getObjectKind(); + } + if (!ResultTy.isNull()) + DiagnoseSelfAssignment(*this, lhs, rhs, OpLoc); break; case BO_PtrMemD: case BO_PtrMemI: - ResultTy = CheckPointerToMemberOperands(lhs, rhs, OpLoc, + ResultTy = CheckPointerToMemberOperands(lhs, rhs, VK, OpLoc, Opc == BO_PtrMemI); break; case BO_Mul: @@ -6518,7 +7983,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BO_MulAssign: case BO_DivAssign: CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true, - Opc == BO_DivAssign); + Opc == BO_DivAssign); CompLHSTy = CompResultTy; if (!CompResultTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); @@ -6555,22 +8020,26 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); break; case BO_Comma: - ResultTy = CheckCommaOperands(lhs, rhs, OpLoc); + ResultTy = CheckCommaOperands(*this, lhs, rhs, OpLoc); + if (getLangOptions().CPlusPlus) { + VK = rhs->getValueKind(); + OK = rhs->getObjectKind(); + } break; } if (ResultTy.isNull()) return ExprError(); - if (ResultTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { - if (Opc >= BO_Assign && Opc <= BO_OrAssign) - Diag(OpLoc, diag::err_assignment_requires_nonfragile_object) - << ResultTy; - } if (CompResultTy.isNull()) - return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy, OpLoc)); - else - return Owned(new (Context) CompoundAssignOperator(lhs, rhs, Opc, ResultTy, - CompLHSTy, CompResultTy, - OpLoc)); + return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy, + VK, OK, OpLoc)); + + if (getLangOptions().CPlusPlus && lhs->getObjectKind() != OK_ObjCProperty) { + VK = VK_LValue; + OK = lhs->getObjectKind(); + } + return Owned(new (Context) CompoundAssignOperator(lhs, rhs, Opc, ResultTy, + VK, OK, CompLHSTy, + CompResultTy, OpLoc)); } /// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps @@ -6660,13 +8129,87 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, rhs->getSourceRange()); } +/// \brief It accepts a '&&' expr that is inside a '||' one. +/// Emit a diagnostic together with a fixit hint that wraps the '&&' expression +/// in parentheses. +static void +EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc, + Expr *E) { + assert(isa<BinaryOperator>(E) && + cast<BinaryOperator>(E)->getOpcode() == BO_LAnd); + SuggestParentheses(Self, OpLoc, + Self.PDiag(diag::warn_logical_and_in_logical_or) + << E->getSourceRange(), + Self.PDiag(diag::note_logical_and_in_logical_or_silence), + E->getSourceRange(), + Self.PDiag(0), SourceRange()); +} + +/// \brief Returns true if the given expression can be evaluated as a constant +/// 'true'. +static bool EvaluatesAsTrue(Sema &S, Expr *E) { + bool Res; + return E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && Res; +} + +/// \brief Returns true if the given expression can be evaluated as a constant +/// 'false'. +static bool EvaluatesAsFalse(Sema &S, Expr *E) { + bool Res; + return E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && !Res; +} + +/// \brief Look for '&&' in the left hand of a '||' expr. +static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc, + Expr *OrLHS, Expr *OrRHS) { + if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrLHS)) { + if (Bop->getOpcode() == BO_LAnd) { + // If it's "a && b || 0" don't warn since the precedence doesn't matter. + if (EvaluatesAsFalse(S, OrRHS)) + return; + // If it's "1 && a || b" don't warn since the precedence doesn't matter. + if (!EvaluatesAsTrue(S, Bop->getLHS())) + return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop); + } else if (Bop->getOpcode() == BO_LOr) { + if (BinaryOperator *RBop = dyn_cast<BinaryOperator>(Bop->getRHS())) { + // If it's "a || b && 1 || c" we didn't warn earlier for + // "a || b && 1", but warn now. + if (RBop->getOpcode() == BO_LAnd && EvaluatesAsTrue(S, RBop->getRHS())) + return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, RBop); + } + } + } +} + +/// \brief Look for '&&' in the right hand of a '||' expr. +static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, + Expr *OrLHS, Expr *OrRHS) { + if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrRHS)) { + if (Bop->getOpcode() == BO_LAnd) { + // If it's "0 || a && b" don't warn since the precedence doesn't matter. + if (EvaluatesAsFalse(S, OrLHS)) + return; + // If it's "a || b && 1" don't warn since the precedence doesn't matter. + if (!EvaluatesAsTrue(S, Bop->getRHS())) + return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop); + } + } +} + /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky -/// precedence. This currently diagnoses only "arg1 'bitwise' arg2 'eq' arg3". -/// But it could also warn about arg1 && arg2 || arg3, as GCC 4.3+ does. +/// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, SourceLocation OpLoc, Expr *lhs, Expr *rhs){ + // Diagnose "arg1 'bitwise' arg2 'eq' arg3". if (BinaryOperator::isBitwiseOp(Opc)) - DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); + return DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); + + // Warn about arg1 || arg2 && arg3, as GCC 4.3+ does. + // We don't warn for 'assert(a || b && "bad")' since this is safe. + if (Opc == BO_LOr && !OpLoc.isMacroID()/* Don't warn in macros. */) { + DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, lhs, rhs); + DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, lhs, rhs); + } } // Binary Operators. 'Tok' is the token for the operator. @@ -6686,22 +8229,34 @@ ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *lhs, Expr *rhs) { - if (getLangOptions().CPlusPlus && - (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 - // scope and an argument-dependent lookup based on the types of - // the arguments. - UnresolvedSet<16> Functions; - OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc); - if (S && OverOp != OO_None) - LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), - Functions); + if (getLangOptions().CPlusPlus) { + bool UseBuiltinOperator; - // Build the (potentially-overloaded, potentially-dependent) - // binary operation. - return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs); + if (lhs->isTypeDependent() || rhs->isTypeDependent()) { + UseBuiltinOperator = false; + } else if (Opc == BO_Assign && lhs->getObjectKind() == OK_ObjCProperty) { + UseBuiltinOperator = true; + } else { + UseBuiltinOperator = !lhs->getType()->isOverloadableType() && + !rhs->getType()->isOverloadableType(); + } + + if (!UseBuiltinOperator) { + // Find all of the overloaded operators visible from this + // point. We perform both an operator-name lookup from the local + // scope and an argument-dependent lookup based on the types of + // the arguments. + UnresolvedSet<16> Functions; + OverloadedOperatorKind OverOp + = BinaryOperator::getOverloadedOperator(Opc); + if (S && OverOp != OO_None) + LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), + Functions); + + // Build the (potentially-overloaded, potentially-dependent) + // binary operation. + return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs); + } } // Build a built-in binary operation. @@ -6709,28 +8264,28 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, } ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, - unsigned OpcIn, - Expr *Input) { - UnaryOperatorKind Opc = static_cast<UnaryOperatorKind>(OpcIn); - + UnaryOperatorKind Opc, + Expr *Input) { + ExprValueKind VK = VK_RValue; + ExprObjectKind OK = OK_Ordinary; QualType resultType; switch (Opc) { case UO_PreInc: case UO_PreDec: case UO_PostInc: case UO_PostDec: - resultType = CheckIncrementDecrementOperand(Input, OpLoc, + resultType = CheckIncrementDecrementOperand(*this, Input, VK, OpLoc, Opc == UO_PreInc || Opc == UO_PostInc, Opc == UO_PreInc || Opc == UO_PreDec); break; case UO_AddrOf: - resultType = CheckAddressOfOperand(Input, OpLoc); + resultType = CheckAddressOfOperand(*this, Input, OpLoc); break; case UO_Deref: DefaultFunctionArrayLvalueConversion(Input); - resultType = CheckIndirectionOperand(Input, OpLoc); + resultType = CheckIndirectionOperand(*this, Input, VK, OpLoc); break; case UO_Plus: case UO_Minus: @@ -6748,6 +8303,11 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, Opc == UO_Plus && resultType->isPointerType()) break; + else if (resultType->isPlaceholderType()) { + ExprResult PR = CheckPlaceholderExpr(Input, OpLoc); + if (PR.isInvalid()) return ExprError(); + return CreateBuiltinUnaryOp(OpLoc, Opc, PR.take()); + } return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input->getSourceRange()); @@ -6761,9 +8321,16 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // C99 does not support '~' for complex conjugation. Diag(OpLoc, diag::ext_integer_complement_complex) << resultType << Input->getSourceRange(); - else if (!resultType->hasIntegerRepresentation()) + else if (resultType->hasIntegerRepresentation()) + break; + else if (resultType->isPlaceholderType()) { + ExprResult PR = CheckPlaceholderExpr(Input, OpLoc); + if (PR.isInvalid()) return ExprError(); + return CreateBuiltinUnaryOp(OpLoc, Opc, PR.take()); + } else { return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input->getSourceRange()); + } break; case UO_LNot: // logical negation // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5). @@ -6771,25 +8338,40 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType = Input->getType(); if (resultType->isDependentType()) break; - if (!resultType->isScalarType()) // C99 6.5.3.3p1 + if (resultType->isScalarType()) { // C99 6.5.3.3p1 + // ok, fallthrough + } else if (resultType->isPlaceholderType()) { + ExprResult PR = CheckPlaceholderExpr(Input, OpLoc); + if (PR.isInvalid()) return ExprError(); + return CreateBuiltinUnaryOp(OpLoc, Opc, PR.take()); + } else { return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input->getSourceRange()); + } + // LNot always has type int. C99 6.5.3.3p5. // In C++, it's bool. C++ 5.3.1p8 - resultType = getLangOptions().CPlusPlus ? Context.BoolTy : Context.IntTy; + resultType = Context.getLogicalOperationType(); break; case UO_Real: case UO_Imag: - resultType = CheckRealImagOperand(Input, OpLoc, Opc == UO_Real); + resultType = CheckRealImagOperand(*this, Input, OpLoc, Opc == UO_Real); + // _Real and _Imag map ordinary l-values into ordinary l-values. + if (Input->getValueKind() != VK_RValue && + Input->getObjectKind() == OK_Ordinary) + VK = Input->getValueKind(); break; case UO_Extension: resultType = Input->getType(); + VK = Input->getValueKind(); + OK = Input->getObjectKind(); break; } if (resultType.isNull()) return ExprError(); - return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc)); + return Owned(new (Context) UnaryOperator(Input, Opc, resultType, + VK, OK, OpLoc)); } ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, @@ -6815,24 +8397,16 @@ ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, // Unary Operators. 'Tok' is the token for the operator. ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Op, Expr *Input) { + tok::TokenKind Op, Expr *Input) { return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input); } /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". -ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, - SourceLocation LabLoc, - IdentifierInfo *LabelII) { - // Look up the record for this label identifier. - LabelStmt *&LabelDecl = getCurFunction()->LabelMap[LabelII]; - - // If we haven't seen this label yet, create a forward reference. It - // will be validated and/or cleaned up in ActOnFinishFunctionBody. - if (LabelDecl == 0) - LabelDecl = new (Context) LabelStmt(LabLoc, LabelII, 0); - +ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, + LabelDecl *TheDecl) { + TheDecl->setUsed(); // Create the AST node. The address of a label always has type 'void*'. - return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, LabelDecl, + return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy))); } @@ -6854,28 +8428,54 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, // If there are sub stmts in the compound stmt, take the type of the last one // as the type of the stmtexpr. QualType Ty = Context.VoidTy; - + bool StmtExprMayBindToTemp = false; if (!Compound->body_empty()) { Stmt *LastStmt = Compound->body_back(); + LabelStmt *LastLabelStmt = 0; // If LastStmt is a label, skip down through into the body. - while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt)) + while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt)) { + LastLabelStmt = Label; LastStmt = Label->getSubStmt(); + } + if (Expr *LastExpr = dyn_cast<Expr>(LastStmt)) { + // Do function/array conversion on the last expression, but not + // lvalue-to-rvalue. However, initialize an unqualified type. + DefaultFunctionArrayConversion(LastExpr); + Ty = LastExpr->getType().getUnqualifiedType(); - if (Expr *LastExpr = dyn_cast<Expr>(LastStmt)) - Ty = LastExpr->getType(); + if (!Ty->isDependentType() && !LastExpr->isTypeDependent()) { + ExprResult Res = PerformCopyInitialization( + InitializedEntity::InitializeResult(LPLoc, + Ty, + false), + SourceLocation(), + Owned(LastExpr)); + if (Res.isInvalid()) + return ExprError(); + if ((LastExpr = Res.takeAs<Expr>())) { + if (!LastLabelStmt) + Compound->setLastStmt(LastExpr); + else + LastLabelStmt->setSubStmt(LastExpr); + StmtExprMayBindToTemp = true; + } + } + } } // FIXME: Check that expression type is complete/non-abstract; statement // expressions are not lvalues. - - return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc)); + Expr *ResStmtExpr = new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc); + if (StmtExprMayBindToTemp) + return MaybeBindToTemporary(ResStmtExpr); + return Owned(ResStmtExpr); } ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, - TypeSourceInfo *TInfo, - OffsetOfComponent *CompPtr, - unsigned NumComponents, - SourceLocation RParenLoc) { + TypeSourceInfo *TInfo, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc) { QualType ArgTy = TInfo->getType(); bool Dependent = ArgTy->isDependentType(); SourceRange TypeRange = TInfo->getTypeLoc().getLocalSourceRange(); @@ -6974,6 +8574,12 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); LookupQualifiedName(R, RD); FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>(); + IndirectFieldDecl *IndirectMemberDecl = 0; + if (!MemberDecl) { + if ((IndirectMemberDecl = R.getAsSingle<IndirectFieldDecl>())) + MemberDecl = IndirectMemberDecl->getAnonField(); + } + if (!MemberDecl) return ExprError(Diag(BuiltinLoc, diag::err_no_member) << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, @@ -6992,12 +8598,8 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, } RecordDecl *Parent = MemberDecl->getParent(); - bool AnonStructUnion = Parent->isAnonymousStructOrUnion(); - if (AnonStructUnion) { - do { - Parent = cast<RecordDecl>(Parent->getParent()); - } while (Parent->isAnonymousStructOrUnion()); - } + if (IndirectMemberDecl) + Parent = cast<RecordDecl>(IndirectMemberDecl->getDeclContext()); // If the member was found in a base class, introduce OffsetOfNodes for // the base class indirections. @@ -7010,15 +8612,17 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, Comps.push_back(OffsetOfNode(B->Base)); } - if (AnonStructUnion) { - llvm::SmallVector<FieldDecl*, 4> Path; - BuildAnonymousStructUnionMemberPath(MemberDecl, Path); - unsigned n = Path.size(); - for (int j = n - 1; j > -1; --j) - Comps.push_back(OffsetOfNode(OC.LocStart, Path[j], OC.LocEnd)); - } else { + if (IndirectMemberDecl) { + for (IndirectFieldDecl::chain_iterator FI = + IndirectMemberDecl->chain_begin(), + FEnd = IndirectMemberDecl->chain_end(); FI != FEnd; FI++) { + assert(isa<FieldDecl>(*FI)); + Comps.push_back(OffsetOfNode(OC.LocStart, + cast<FieldDecl>(*FI), OC.LocEnd)); + } + } else Comps.push_back(OffsetOfNode(OC.LocStart, MemberDecl, OC.LocEnd)); - } + CurrentType = MemberDecl->getType().getNonReferenceType(); } @@ -7028,13 +8632,13 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, } ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, - SourceLocation BuiltinLoc, - SourceLocation TypeLoc, - ParsedType argty, - OffsetOfComponent *CompPtr, - unsigned NumComponents, - SourceLocation RPLoc) { - + SourceLocation BuiltinLoc, + SourceLocation TypeLoc, + ParsedType argty, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RPLoc) { + TypeSourceInfo *ArgTInfo; QualType ArgTy = GetTypeFromParser(argty, &ArgTInfo); if (ArgTy.isNull()) @@ -7048,41 +8652,14 @@ ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, } -ExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, - ParsedType arg1,ParsedType arg2, - SourceLocation RPLoc) { - TypeSourceInfo *argTInfo1; - QualType argT1 = GetTypeFromParser(arg1, &argTInfo1); - TypeSourceInfo *argTInfo2; - QualType argT2 = GetTypeFromParser(arg2, &argTInfo2); - - assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)"); - - return BuildTypesCompatibleExpr(BuiltinLoc, argTInfo1, argTInfo2, RPLoc); -} - -ExprResult -Sema::BuildTypesCompatibleExpr(SourceLocation BuiltinLoc, - TypeSourceInfo *argTInfo1, - TypeSourceInfo *argTInfo2, - SourceLocation RPLoc) { - if (getLangOptions().CPlusPlus) { - Diag(BuiltinLoc, diag::err_types_compatible_p_in_cplusplus) - << SourceRange(BuiltinLoc, RPLoc); - return ExprError(); - } - - return Owned(new (Context) TypesCompatibleExpr(Context.IntTy, BuiltinLoc, - argTInfo1, argTInfo2, RPLoc)); -} - - ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, - Expr *CondExpr, - Expr *LHSExpr, Expr *RHSExpr, - SourceLocation RPLoc) { + Expr *CondExpr, + Expr *LHSExpr, Expr *RHSExpr, + SourceLocation RPLoc) { assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)"); + ExprValueKind VK = VK_RValue; + ExprObjectKind OK = OK_Ordinary; QualType resType; bool ValueDependent = false; if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) { @@ -7098,13 +8675,16 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, << CondExpr->getSourceRange()); // 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(); + Expr *ActiveExpr = condEval.getZExtValue() ? LHSExpr : RHSExpr; + + resType = ActiveExpr->getType(); + ValueDependent = ActiveExpr->isValueDependent(); + VK = ActiveExpr->getValueKind(); + OK = ActiveExpr->getObjectKind(); } return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, - resType, RPLoc, + resType, VK, OK, RPLoc, resType->isDependentType(), ValueDependent)); } @@ -7126,32 +8706,51 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!"); + assert(ParamInfo.getContext() == Declarator::BlockLiteralContext); BlockScopeInfo *CurBlock = getCurBlock(); TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo, CurScope); - CurBlock->TheDecl->setSignatureAsWritten(Sig); QualType T = Sig->getType(); - bool isVariadic; - QualType RetTy; - if (const FunctionType *Fn = T->getAs<FunctionType>()) { - CurBlock->FunctionType = T; - RetTy = Fn->getResultType(); - isVariadic = - !isa<FunctionProtoType>(Fn) || cast<FunctionProtoType>(Fn)->isVariadic(); - } else { - RetTy = T; - isVariadic = false; - } + // GetTypeForDeclarator always produces a function type for a block + // literal signature. Furthermore, it is always a FunctionProtoType + // unless the function was written with a typedef. + assert(T->isFunctionType() && + "GetTypeForDeclarator made a non-function block signature"); - CurBlock->TheDecl->setIsVariadic(isVariadic); + // Look for an explicit signature in that function type. + FunctionProtoTypeLoc ExplicitSignature; - // Don't allow returning an array by value. - if (RetTy->isArrayType()) { - Diag(ParamInfo.getSourceRange().getBegin(), diag::err_block_returns_array); - return; + TypeLoc tmp = Sig->getTypeLoc().IgnoreParens(); + if (isa<FunctionProtoTypeLoc>(tmp)) { + ExplicitSignature = cast<FunctionProtoTypeLoc>(tmp); + + // Check whether that explicit signature was synthesized by + // GetTypeForDeclarator. If so, don't save that as part of the + // written signature. + if (ExplicitSignature.getLParenLoc() == + ExplicitSignature.getRParenLoc()) { + // This would be much cheaper if we stored TypeLocs instead of + // TypeSourceInfos. + TypeLoc Result = ExplicitSignature.getResultLoc(); + unsigned Size = Result.getFullDataSize(); + Sig = Context.CreateTypeSourceInfo(Result.getType(), Size); + Sig->getTypeLoc().initializeFullCopy(Result, Size); + + ExplicitSignature = FunctionProtoTypeLoc(); + } } + CurBlock->TheDecl->setSignatureAsWritten(Sig); + CurBlock->FunctionType = T; + + const FunctionType *Fn = T->getAs<FunctionType>(); + QualType RetTy = Fn->getResultType(); + bool isVariadic = + (isa<FunctionProtoType>(Fn) && cast<FunctionProtoType>(Fn)->isVariadic()); + + CurBlock->TheDecl->setIsVariadic(isVariadic); + // Don't allow returning a objc interface by value. if (RetTy->isObjCObjectType()) { Diag(ParamInfo.getSourceRange().getBegin(), @@ -7168,10 +8767,9 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { // Push block parameters from the declarator if we had them. llvm::SmallVector<ParmVarDecl*, 8> Params; - if (isa<FunctionProtoType>(T)) { - FunctionProtoTypeLoc TL = cast<FunctionProtoTypeLoc>(Sig->getTypeLoc()); - for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { - ParmVarDecl *Param = TL.getArg(I); + if (ExplicitSignature) { + for (unsigned I = 0, E = ExplicitSignature.getNumArgs(); I != E; ++I) { + ParmVarDecl *Param = ExplicitSignature.getArg(I); if (Param->getIdentifier() == 0 && !Param->isImplicit() && !Param->isInvalidDecl() && @@ -7194,9 +8792,13 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { } // Set the parameters on the block decl. - if (!Params.empty()) + if (!Params.empty()) { CurBlock->TheDecl->setParams(Params.data(), Params.size()); - + CheckParmsForFunctionDef(CurBlock->TheDecl->param_begin(), + CurBlock->TheDecl->param_end(), + /*CheckParameterNames=*/false); + } + // Finally we can process decl attributes. ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); @@ -7211,17 +8813,13 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { if (Params.empty()) return; - bool ShouldCheckShadow = - Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored; - for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(), E = CurBlock->TheDecl->param_end(); AI != E; ++AI) { (*AI)->setOwningFunction(CurBlock->TheDecl); // If this has an identifier, add it to the scope stack. if ((*AI)->getIdentifier()) { - if (ShouldCheckShadow) - CheckShadow(CurBlock->TheScope, *AI); + CheckShadow(CurBlock->TheScope, *AI); PushOnScopeChains(*AI, CurBlock->TheScope); } @@ -7234,13 +8832,12 @@ void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) { // Pop off CurBlock, handle nested blocks. PopDeclContext(); PopFunctionOrBlockScope(); - // FIXME: Delete the ParmVarDecl objects as well??? } /// ActOnBlockStmtExpr - This is called when the body of a block statement /// literal was successfully completed. ^(int x){...} ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, - Stmt *Body, Scope *CurScope) { + Stmt *Body, Scope *CurScope) { // If blocks are disabled, emit an error. if (!LangOpts.Blocks) Diag(CaretLoc, diag::err_blocks_disable); @@ -7256,6 +8853,10 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>(); QualType BlockTy; + // Set the captured variables on the block. + BSI->TheDecl->setCaptures(Context, BSI->Captures.begin(), BSI->Captures.end(), + BSI->CapturesCXXThis); + // If the user wrote a function type in some form, try to use that. if (!BSI->FunctionType.isNull()) { const FunctionType *FTy = BSI->FunctionType->getAs<FunctionType>(); @@ -7265,8 +8866,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, // Turn protoless block types into nullary block types. if (isa<FunctionNoProtoType>(FTy)) { - BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, - false, false, 0, 0, Ext); + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExtInfo = Ext; + BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI); // Otherwise, if we don't need to change anything about the function type, // preserve its sugar structure. @@ -7277,26 +8879,22 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, // Otherwise, make the minimal modifications to the function type. } else { const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.TypeQuals = 0; // FIXME: silently? + EPI.ExtInfo = Ext; BlockTy = Context.getFunctionType(RetTy, FPT->arg_type_begin(), FPT->getNumArgs(), - FPT->isVariadic(), - /*quals*/ 0, - FPT->hasExceptionSpec(), - FPT->hasAnyExceptionSpec(), - FPT->getNumExceptions(), - FPT->exception_begin(), - Ext); + EPI); } // If we don't have a function type, just build one from nothing. } else { - BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, - false, false, 0, 0, - FunctionType::ExtInfo(NoReturn, 0, CC_Default)); + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, 0, CC_Default); + BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI); } - // FIXME: Check that return/parameter types are complete/non-abstract DiagnoseUnusedParameters(BSI->TheDecl->param_begin(), BSI->TheDecl->param_end()); BlockTy = Context.getBlockPointerType(BlockTy); @@ -7307,28 +8905,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, BSI->TheDecl->setBody(cast<CompoundStmt>(Body)); - bool Good = true; - // Check goto/label use. - for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator - I = BSI->LabelMap.begin(), E = BSI->LabelMap.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. - if (L->getSubStmt() != 0) - continue; - - // Emit error. - Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName(); - Good = false; - } - if (!Good) { - PopFunctionOrBlockScope(); - return ExprError(); - } - - BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, - BSI->hasBlockDeclRefExprs); + BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy); // Issue any analysis-based warnings. const sema::AnalysisBasedWarnings::Policy &WP = @@ -7343,17 +8920,15 @@ ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, Expr *expr, ParsedType type, SourceLocation RPLoc) { TypeSourceInfo *TInfo; - QualType T = GetTypeFromParser(type, &TInfo); + GetTypeFromParser(type, &TInfo); return BuildVAArgExpr(BuiltinLoc, expr, TInfo, RPLoc); } ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, - Expr *E, TypeSourceInfo *TInfo, - SourceLocation RPLoc) { + Expr *E, TypeSourceInfo *TInfo, + SourceLocation RPLoc) { Expr *OrigExpr = E; - InitBuiltinVaListType(); - // Get the va_list type QualType VaListType = Context.getBuiltinVaListType(); if (VaListType->isArrayType()) { @@ -7389,10 +8964,17 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { // The type of __null will be int or long, depending on the size of // pointers on the target. QualType Ty; - if (Context.Target.getPointerWidth(0) == Context.Target.getIntWidth()) + unsigned pw = Context.Target.getPointerWidth(0); + if (pw == Context.Target.getIntWidth()) Ty = Context.IntTy; - else + else if (pw == Context.Target.getLongWidth()) Ty = Context.LongTy; + else if (pw == Context.Target.getLongLongWidth()) + Ty = Context.LongLongTy; + else { + assert(!"I don't know size of pointer!"); + Ty = Context.IntTy; + } return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); } @@ -7454,15 +9036,29 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, case FunctionVoidPointer: DiagKind = diag::ext_typecheck_convert_pointer_void_func; break; + case IncompatiblePointerDiscardsQualifiers: { + // Perform array-to-pointer decay if necessary. + if (SrcType->isArrayType()) SrcType = Context.getArrayDecayedType(SrcType); + + Qualifiers lhq = SrcType->getPointeeType().getQualifiers(); + Qualifiers rhq = DstType->getPointeeType().getQualifiers(); + if (lhq.getAddressSpace() != rhq.getAddressSpace()) { + DiagKind = diag::err_typecheck_incompatible_address_space; + break; + } + + llvm_unreachable("unknown error case for discarding qualifiers!"); + // fallthrough + } case CompatiblePointerDiscardsQualifiers: // If the qualifiers lost were because we were applying the // (deprecated) C++ conversion from a string literal to a char* // (or wchar_t*), then there was no error (C++ 4.2p2). FIXME: // Ideally, this check would be performed in - // CheckPointerTypesForAssignment. However, that would require a + // checkPointerTypesForAssignment. However, that would require a // bit of refactoring (so that the second argument is an // expression, rather than a type), which should be done as part - // of a larger effort to fix CheckPointerTypesForAssignment for + // of a larger effort to fix checkPointerTypesForAssignment for // C++ semantics. if (getLangOptions().CPlusPlus && IsStringLiteralToNonConstPointerConversion(SrcExpr, DstType)) @@ -7548,7 +9144,8 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ E->getSourceRange(); if (EvalResult.Diag && - Diags.getDiagnosticLevel(diag::ext_expr_not_ice) != Diagnostic::Ignored) + Diags.getDiagnosticLevel(diag::ext_expr_not_ice, EvalResult.DiagLoc) + != Diagnostic::Ignored) Diag(EvalResult.DiagLoc, EvalResult.Diag); if (Result) @@ -7625,7 +9222,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // -Wunused-parameters) if (isa<ParmVarDecl>(D) || (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) { - D->setUsed(true); + D->setUsed(); return; } @@ -7653,6 +9250,11 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // potentially evaluated. ExprEvalContexts.back().addReferencedDecl(Loc, D); return; + + case PotentiallyEvaluatedIfUsed: + // Referenced declarations will only be used if the construct in the + // containing expression is used. + return; } // Note that this declaration has been used. @@ -7684,6 +9286,9 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { MarkVTableUsed(Loc, MethodDecl->getParent()); } if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + // Recursive functions should be marked when used from another function. + if (CurContext == Function) return; + // Implicit instantiation of function templates and member functions of // class templates. if (Function->isImplicitlyInstantiable()) { @@ -7712,19 +9317,23 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { else PendingInstantiations.push_back(std::make_pair(Function, Loc)); } - } else // Walk redefinitions, as some of them may be instantiable. + } else { + // Walk redefinitions, as some of them may be instantiable. for (FunctionDecl::redecl_iterator i(Function->redecls_begin()), e(Function->redecls_end()); i != e; ++i) { if (!i->isUsed(false) && i->isImplicitlyInstantiable()) MarkDeclarationReferenced(Loc, *i); } + } - // FIXME: keep track of references to static functions - - // Recursive functions should be marked when used from another function. - if (CurContext != Function) - Function->setUsed(true); + // Keep track of used but undefined functions. + if (!Function->isPure() && !Function->hasBody() && + Function->getLinkage() != ExternalLinkage) { + SourceLocation &old = UndefinedInternals[Function->getCanonicalDecl()]; + if (old.isInvalid()) old = Loc; + } + Function->setUsed(true); return; } @@ -7741,7 +9350,12 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { } } - // FIXME: keep track of references to static data? + // Keep track of used but undefined variables. + if (Var->hasDefinition() == VarDecl::DeclarationOnly + && Var->getLinkage() != ExternalLinkage) { + SourceLocation &old = UndefinedInternals[Var->getCanonicalDecl()]; + if (old.isInvalid()) old = Loc; + } D->setUsed(true); return; @@ -7779,8 +9393,7 @@ bool MarkReferencedDecls::TraverseRecordType(RecordType *T) { if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) { const TemplateArgumentList &Args = Spec->getTemplateArgs(); - return TraverseTemplateArguments(Args.getFlatArgumentList(), - Args.flat_size()); + return TraverseTemplateArguments(Args.data(), Args.size()); } return true; @@ -7791,6 +9404,70 @@ void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) { Marker.TraverseType(Context.getCanonicalType(T)); } +namespace { + /// \brief Helper class that marks all of the declarations referenced by + /// potentially-evaluated subexpressions as "referenced". + class EvaluatedExprMarker : public EvaluatedExprVisitor<EvaluatedExprMarker> { + Sema &S; + + public: + typedef EvaluatedExprVisitor<EvaluatedExprMarker> Inherited; + + explicit EvaluatedExprMarker(Sema &S) : Inherited(S.Context), S(S) { } + + void VisitDeclRefExpr(DeclRefExpr *E) { + S.MarkDeclarationReferenced(E->getLocation(), E->getDecl()); + } + + void VisitMemberExpr(MemberExpr *E) { + S.MarkDeclarationReferenced(E->getMemberLoc(), E->getMemberDecl()); + Inherited::VisitMemberExpr(E); + } + + void VisitCXXNewExpr(CXXNewExpr *E) { + if (E->getConstructor()) + S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor()); + if (E->getOperatorNew()) + S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorNew()); + if (E->getOperatorDelete()) + S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete()); + Inherited::VisitCXXNewExpr(E); + } + + void VisitCXXDeleteExpr(CXXDeleteExpr *E) { + if (E->getOperatorDelete()) + S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete()); + QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType()); + if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl()); + S.MarkDeclarationReferenced(E->getLocStart(), + S.LookupDestructor(Record)); + } + + Inherited::VisitCXXDeleteExpr(E); + } + + void VisitCXXConstructExpr(CXXConstructExpr *E) { + S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor()); + Inherited::VisitCXXConstructExpr(E); + } + + void VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { + S.MarkDeclarationReferenced(E->getLocation(), E->getDecl()); + } + + void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + Visit(E->getExpr()); + } + }; +} + +/// \brief Mark any declarations that appear within this expression or any +/// potentially-evaluated subexpressions as "referenced". +void Sema::MarkDeclarationsReferencedInExpr(Expr *E) { + EvaluatedExprMarker(*this).Visit(E); +} + /// \brief Emit a diagnostic that describes an effect on the run-time behavior /// of the program being compiled. /// @@ -7815,6 +9492,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, break; case PotentiallyEvaluated: + case PotentiallyEvaluatedIfUsed: Diag(Loc, PD); return true; @@ -7848,40 +9526,42 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, return false; } -// Diagnose the common s/=/==/ typo. Note that adding parentheses +// Diagnose the s/=/==/ and s/\|=/!=/ typos. Note that adding parentheses // will prevent this condition from triggering, which is what we want. void Sema::DiagnoseAssignmentAsCondition(Expr *E) { SourceLocation Loc; unsigned diagnostic = diag::warn_condition_is_assignment; + bool IsOrAssign = false; if (isa<BinaryOperator>(E)) { BinaryOperator *Op = cast<BinaryOperator>(E); - if (Op->getOpcode() != BO_Assign) + if (Op->getOpcode() != BO_Assign && Op->getOpcode() != BO_OrAssign) return; + IsOrAssign = Op->getOpcode() == BO_OrAssign; + // Greylist some idioms by putting them into a warning subcategory. if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Op->getRHS()->IgnoreParenCasts())) { Selector Sel = ME->getSelector(); // self = [<foo> init...] - if (isSelfExpr(Op->getLHS()) - && Sel.getIdentifierInfoForSlot(0)->getName().startswith("init")) + if (isSelfExpr(Op->getLHS()) && Sel.getNameForSlot(0).startswith("init")) diagnostic = diag::warn_condition_is_idiomatic_assignment; // <foo> = [<bar> nextObject] - else if (Sel.isUnarySelector() && - Sel.getIdentifierInfoForSlot(0)->getName() == "nextObject") + else if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "nextObject") diagnostic = diag::warn_condition_is_idiomatic_assignment; } Loc = Op->getOperatorLoc(); } else if (isa<CXXOperatorCallExpr>(E)) { CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(E); - if (Op->getOperator() != OO_Equal) + if (Op->getOperator() != OO_Equal && Op->getOperator() != OO_PipeEqual) return; + IsOrAssign = Op->getOperator() == OO_PipeEqual; Loc = Op->getOperatorLoc(); } else { // Not an assignment. @@ -7892,29 +9572,63 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd()); Diag(Loc, diagnostic) << E->getSourceRange(); - Diag(Loc, diag::note_condition_assign_to_comparison) - << FixItHint::CreateReplacement(Loc, "=="); + + if (IsOrAssign) + Diag(Loc, diag::note_condition_or_assign_to_comparison) + << FixItHint::CreateReplacement(Loc, "!="); + else + Diag(Loc, diag::note_condition_assign_to_comparison) + << FixItHint::CreateReplacement(Loc, "=="); + Diag(Loc, diag::note_condition_assign_silence) << FixItHint::CreateInsertion(Open, "(") << FixItHint::CreateInsertion(Close, ")"); } +/// \brief Redundant parentheses over an equality comparison can indicate +/// that the user intended an assignment used as condition. +void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) { + // Don't warn if the parens came from a macro. + SourceLocation parenLoc = parenE->getLocStart(); + if (parenLoc.isInvalid() || parenLoc.isMacroID()) + return; + + Expr *E = parenE->IgnoreParens(); + + if (BinaryOperator *opE = dyn_cast<BinaryOperator>(E)) + if (opE->getOpcode() == BO_EQ && + opE->getLHS()->IgnoreParenImpCasts()->isModifiableLvalue(Context) + == Expr::MLV_Valid) { + SourceLocation Loc = opE->getOperatorLoc(); + + Diag(Loc, diag::warn_equality_with_extra_parens) << E->getSourceRange(); + Diag(Loc, diag::note_equality_comparison_to_assign) + << FixItHint::CreateReplacement(Loc, "="); + Diag(Loc, diag::note_equality_comparison_silence) + << FixItHint::CreateRemoval(parenE->getSourceRange().getBegin()) + << FixItHint::CreateRemoval(parenE->getSourceRange().getEnd()); + } +} + bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { DiagnoseAssignmentAsCondition(E); + if (ParenExpr *parenE = dyn_cast<ParenExpr>(E)) + DiagnoseEqualityWithExtraParens(parenE); if (!E->isTypeDependent()) { + if (E->isBoundMemberFunction(Context)) + return Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func) + << E->getSourceRange(); + + if (getLangOptions().CPlusPlus) + return CheckCXXBooleanCondition(E); // C++ 6.4p4 + DefaultFunctionArrayLvalueConversion(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; - } + if (!T->isScalarType()) // C99 6.8.4.1p1 + return Diag(Loc, diag::err_typecheck_statement_requires_scalar) + << T << E->getSourceRange(); } return false; @@ -7930,3 +9644,26 @@ ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, return Owned(Sub); } + +/// Check for operands with placeholder types and complain if found. +/// Returns true if there was an error and no recovery was possible. +ExprResult Sema::CheckPlaceholderExpr(Expr *E, SourceLocation Loc) { + const BuiltinType *BT = E->getType()->getAs<BuiltinType>(); + if (!BT || !BT->isPlaceholderType()) return Owned(E); + + // If this is overload, check for a single overload. + assert(BT->getKind() == BuiltinType::Overload); + + if (FunctionDecl *Specialization + = ResolveSingleFunctionTemplateSpecialization(E)) { + // The access doesn't really matter in this case. + DeclAccessPair Found = DeclAccessPair::make(Specialization, + Specialization->getAccess()); + E = FixOverloadedFunctionReference(E, Found, Specialization); + if (!E) return ExprError(); + return Owned(E); + } + + Diag(Loc, diag::err_ovl_unresolvable) << E->getSourceRange(); + return ExprError(); +} diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 5720d93..f9c2c9a 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -31,7 +32,7 @@ using namespace clang; using namespace sema; ParsedType Sema::getDestructorName(SourceLocation TildeLoc, - IdentifierInfo &II, + IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectTypePtr, @@ -71,26 +72,26 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (SS.isSet()) { NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); - + bool AlreadySearched = false; bool LookAtPrefix = true; // C++ [basic.lookup.qual]p6: - // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, + // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, // the type-names are looked up as types in the scope designated by the // nested-name-specifier. In a qualified-id of the form: - // - // ::[opt] nested-name-specifier ̃ class-name + // + // ::[opt] nested-name-specifier ~ class-name // // where the nested-name-specifier designates a namespace scope, and in // a qualified-id of the form: // - // ::opt nested-name-specifier class-name :: ̃ class-name + // ::opt nested-name-specifier class-name :: ~ class-name // - // the class-names are looked up as types in the scope designated by + // the class-names are looked up as types in the scope designated by // the nested-name-specifier. // // Here, we check the first case (completely) and determine whether the - // code below is permitted to look at the prefix of the + // code below is permitted to look at the prefix of the // nested-name-specifier. DeclContext *DC = computeDeclContext(SS, EnteringContext); if (DC && DC->isFileContext()) { @@ -99,7 +100,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, isDependent = false; } else if (DC && isa<CXXRecordDecl>(DC)) LookAtPrefix = false; - + // The second case from the C++03 rules quoted further above. NestedNameSpecifier *Prefix = 0; if (AlreadySearched) { @@ -116,7 +117,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = LookupCtx && LookupCtx->isDependentContext(); } - + LookInScope = false; } else if (ObjectTypePtr) { // C++ [basic.lookup.classref]p3: @@ -128,7 +129,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // cv-qualified) T. LookupCtx = computeDeclContext(SearchType); isDependent = SearchType->isDependentType(); - assert((isDependent || !SearchType->isIncompleteType()) && + assert((isDependent || !SearchType->isIncompleteType()) && "Caller should have completed object type"); LookInScope = true; @@ -170,7 +171,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // nested-name-specifier (if present) or the object type, then // this is the destructor for that class. // FIXME: This is a workaround until we get real drafting for core - // issue 399, for which there isn't even an obvious direction. + // issue 399, for which there isn't even an obvious direction. if (ClassTemplateDecl *Template = Found.getAsSingle<ClassTemplateDecl>()) { QualType MemberOfType; if (SS.isSet()) { @@ -182,7 +183,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, } if (MemberOfType.isNull()) MemberOfType = SearchType; - + if (MemberOfType.isNull()) continue; @@ -199,7 +200,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, continue; } - + // We're referring to an unresolved class template // specialization. Determine whether we class template we found // is the same as the template being specialized or, if we don't @@ -220,7 +221,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // The class template we found has the same name as the // (dependent) template name being specialized. - if (DependentTemplateName *DepTemplate + if (DependentTemplateName *DepTemplate = SpecName.getAsDependentTemplateName()) { if (DepTemplate->isIdentifier() && DepTemplate->getIdentifier() == Template->getIdentifier()) @@ -253,7 +254,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (ObjectTypePtr) Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) - << &II; + << &II; else Diag(NameLoc, diag::err_destructor_class_name); @@ -262,13 +263,13 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, /// \brief Build a C++ typeid expression with a type operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, - SourceLocation TypeidLoc, - TypeSourceInfo *Operand, - SourceLocation RParenLoc) { + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { // C++ [expr.typeid]p4: - // The top-level cv-qualifiers of the lvalue expression or the type-id + // The top-level cv-qualifiers of the lvalue expression or the type-id // that is the operand of typeid are always ignored. - // If the type of the type-id is a class type or a reference to a class + // If the type of the type-id is a class type or a reference to a class // type, the class shall be completely-defined. Qualifiers Quals; QualType T @@ -277,7 +278,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, if (T->getAs<RecordType>() && RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); - + return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand, SourceRange(TypeidLoc, RParenLoc))); @@ -285,9 +286,9 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, /// \brief Build a C++ typeid expression with an expression operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, - SourceLocation TypeidLoc, - Expr *E, - SourceLocation RParenLoc) { + SourceLocation TypeidLoc, + Expr *E, + SourceLocation RParenLoc) { bool isUnevaluatedOperand = true; if (E && !E->isTypeDependent()) { QualType T = E->getType(); @@ -298,7 +299,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, // shall be completely-defined. if (RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); - + // C++ [expr.typeid]p3: // When typeid is applied to an expression other than an glvalue of a // polymorphic class type [...] [the] expression is an unevaluated @@ -310,11 +311,11 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, MarkVTableUsed(TypeidLoc, RecordD); } } - + // C++ [expr.typeid]p4: // [...] If the type of the type-id is a reference to a possibly - // cv-qualified type, the result of the typeid expression refers to a - // std::type_info object representing the cv-unqualified referenced + // cv-qualified type, the result of the typeid expression refers to a + // std::type_info object representing the cv-unqualified referenced // type. Qualifiers Quals; QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); @@ -323,16 +324,16 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E)); } } - + // If this is an unevaluated operand, clear out the set of // declaration references we have been computing and eliminate any // temporaries introduced in its computation. if (isUnevaluatedOperand) ExprEvalContexts.back().Context = Unevaluated; - + return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), E, - SourceRange(TypeidLoc, RParenLoc))); + SourceRange(TypeidLoc, RParenLoc))); } /// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression); @@ -343,15 +344,17 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, if (!StdNamespace) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); - LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); - LookupQualifiedName(R, getStdNamespace()); - RecordDecl *TypeInfoRecordDecl = R.getAsSingle<RecordDecl>(); - if (!TypeInfoRecordDecl) - return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - - QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl); - + if (!CXXTypeInfoDecl) { + IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); + LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); + LookupQualifiedName(R, getStdNamespace()); + CXXTypeInfoDecl = R.getAsSingle<RecordDecl>(); + if (!CXXTypeInfoDecl) + return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); + } + + QualType TypeInfoType = Context.getTypeDeclType(CXXTypeInfoDecl); + if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = 0; @@ -359,17 +362,102 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, &TInfo); if (T.isNull()) return ExprError(); - + if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc); } - // The operand is an expression. + // The operand is an expression. return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } +/// Retrieve the UuidAttr associated with QT. +static UuidAttr *GetUuidAttrOfType(QualType QT) { + // Optionally remove one level of pointer, reference or array indirection. + const Type *Ty = QT.getTypePtr();; + if (QT->isPointerType() || QT->isReferenceType()) + Ty = QT->getPointeeType().getTypePtr(); + else if (QT->isArrayType()) + Ty = cast<ArrayType>(QT)->getElementType().getTypePtr(); + + // Loop all class definition and declaration looking for an uuid attribute. + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + while (RD) { + if (UuidAttr *Uuid = RD->getAttr<UuidAttr>()) + return Uuid; + RD = RD->getPreviousDeclaration(); + } + return 0; +} + +/// \brief Build a Microsoft __uuidof expression with a type operand. +ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { + if (!Operand->getType()->isDependentType()) { + if (!GetUuidAttrOfType(Operand->getType())) + return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); + } + + // FIXME: add __uuidof semantic analysis for type operand. + return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(), + Operand, + SourceRange(TypeidLoc, RParenLoc))); +} + +/// \brief Build a Microsoft __uuidof expression with an expression operand. +ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *E, + SourceLocation RParenLoc) { + if (!E->getType()->isDependentType()) { + if (!GetUuidAttrOfType(E->getType()) && + !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) + return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); + } + // FIXME: add __uuidof semantic analysis for type operand. + return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(), + E, + SourceRange(TypeidLoc, RParenLoc))); +} + +/// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression); +ExprResult +Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, + bool isType, void *TyOrExpr, SourceLocation RParenLoc) { + // If MSVCGuidDecl has not been cached, do the lookup. + if (!MSVCGuidDecl) { + IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID"); + LookupResult R(*this, GuidII, SourceLocation(), LookupTagName); + LookupQualifiedName(R, Context.getTranslationUnitDecl()); + MSVCGuidDecl = R.getAsSingle<RecordDecl>(); + if (!MSVCGuidDecl) + return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof)); + } + + QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl); + + if (isType) { + // The operand is a type; handle it as such. + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr), + &TInfo); + if (T.isNull()) + return ExprError(); + + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); + + return BuildCXXUuidof(GuidType, OpLoc, TInfo, RParenLoc); + } + + // The operand is an expression. + return BuildCXXUuidof(GuidType, OpLoc, (Expr*)TyOrExpr, RParenLoc); +} + /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { @@ -388,6 +476,9 @@ Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { /// ActOnCXXThrow - Parse throw expressions. ExprResult Sema::ActOnCXXThrow(SourceLocation OpLoc, Expr *Ex) { + if (!getLangOptions().Exceptions) + Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; + if (Ex && !Ex->isTypeDependent() && CheckCXXThrowOperand(OpLoc, Ex)) return ExprError(); return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc)); @@ -399,12 +490,12 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // A throw-expression initializes a temporary object, called the exception // object, the type of which is determined by removing any top-level // cv-qualifiers from the static type of the operand of throw and adjusting - // the type from "array of T" or "function returning T" to "pointer to T" + // the type from "array of T" or "function returning T" to "pointer to T" // or "pointer to function returning T", [...] if (E->getType().hasQualifiers()) ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, CastCategory(E)); - + DefaultFunctionArrayConversion(E); // If the type of the exception would be an incomplete type or a pointer @@ -430,13 +521,14 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // Initialize the exception result. This implicitly weeds out // abstract types or types with inaccessible copy constructors. - // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p34. + const VarDecl *NRVOVariable = getCopyElisionCandidate(QualType(), E, false); + + // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p32. InitializedEntity Entity = - InitializedEntity::InitializeException(ThrowLoc, E->getType(), - /*NRVO=*/false); - ExprResult Res = PerformCopyInitialization(Entity, - SourceLocation(), - Owned(E)); + InitializedEntity::InitializeException(ThrowLoc, E->getType(), + /*NRVO=*/false); + ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable, + QualType(), E); if (Res.isInvalid()) return true; E = Res.takeAs<Expr>(); @@ -451,11 +543,15 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // exception handling will make use of the vtable. MarkVTableUsed(ThrowLoc, RD); + // If a pointer is thrown, the referenced object will not be destroyed. + if (isPointer) + return false; + // If the class has a non-trivial destructor, we must be able to call it. if (RD->hasTrivialDestructor()) return false; - CXXDestructorDecl *Destructor + CXXDestructorDecl *Destructor = const_cast<CXXDestructorDecl*>(LookupDestructor(RD)); if (!Destructor) return false; @@ -466,30 +562,48 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { return false; } -ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { +CXXMethodDecl *Sema::tryCaptureCXXThis() { + // Ignore block scopes: we can capture through them. + // Ignore nested enum scopes: we'll diagnose non-constant expressions + // where they're invalid, and other uses are legitimate. + // Don't ignore nested class scopes: you can't use 'this' in a local class. + DeclContext *DC = CurContext; + while (true) { + if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext(); + else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext(); + else break; + } + + // If we're not in an instance method, error out. + CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC); + if (!method || !method->isInstance()) + return 0; + + // Mark that we're closing on 'this' in all the block scopes, if applicable. + for (unsigned idx = FunctionScopes.size() - 1; + isa<BlockScopeInfo>(FunctionScopes[idx]); + --idx) + cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true; + + return method; +} + +ExprResult Sema::ActOnCXXThis(SourceLocation loc) { /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. - DeclContext *DC = getFunctionLevelDeclContext(); - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) - if (MD->isInstance()) - return Owned(new (Context) CXXThisExpr(ThisLoc, - MD->getThisType(Context), - /*isImplicit=*/false)); + CXXMethodDecl *method = tryCaptureCXXThis(); + if (!method) return Diag(loc, diag::err_invalid_this_use); - return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); + return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context), + /*isImplicit=*/false)); } -/// ActOnCXXTypeConstructExpr - Parse construction of a specified type. -/// Can be interpreted either as function-style casting ("int(x)") -/// or class type construction ("ClassType(x,y,z)") -/// or creation of a value-initialized type ("int()"). ExprResult -Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, +Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenLoc, MultiExprArg exprs, - SourceLocation *CommaLocs, SourceLocation RParenLoc) { if (!TypeRep) return ExprError(); @@ -498,17 +612,30 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, QualType Ty = GetTypeFromParser(TypeRep, &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); + + return BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc); +} + +/// ActOnCXXTypeConstructExpr - Parse construction of a specified type. +/// Can be interpreted either as function-style casting ("int(x)") +/// or class type construction ("ClassType(x,y,z)") +/// or creation of a value-initialized type ("int()"). +ExprResult +Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, + SourceLocation LParenLoc, + MultiExprArg exprs, + SourceLocation RParenLoc) { + QualType Ty = TInfo->getType(); unsigned NumExprs = exprs.size(); Expr **Exprs = (Expr**)exprs.get(); - SourceLocation TyBeginLoc = TypeRange.getBegin(); + SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); SourceRange FullRange = SourceRange(TyBeginLoc, RParenLoc); if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) { exprs.release(); - return Owned(CXXUnresolvedConstructExpr::Create(Context, - TypeRange.getBegin(), Ty, + return Owned(CXXUnresolvedConstructExpr::Create(Context, TInfo, LParenLoc, Exprs, NumExprs, RParenLoc)); @@ -522,7 +649,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, PDiag(diag::err_invalid_incomplete_type_use) << FullRange)) return ExprError(); - + if (RequireNonAbstractType(TyBeginLoc, Ty, diag::err_allocation_of_abstract_type)) return ExprError(); @@ -534,55 +661,91 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, // corresponding cast expression. // if (NumExprs == 1) { - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Invalid; + ExprValueKind VK = VK_RValue; CXXCastPath BasePath; - if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, BasePath, + if (CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0], + Kind, VK, BasePath, /*FunctionalStyle=*/true)) return ExprError(); exprs.release(); return Owned(CXXFunctionalCastExpr::Create(Context, - Ty.getNonLValueExprType(Context), - TInfo, TyBeginLoc, Kind, + Ty.getNonLValueExprType(Context), + VK, TInfo, TyBeginLoc, Kind, Exprs[0], &BasePath, RParenLoc)); } - if (Ty->isRecordType()) { - InitializedEntity Entity = InitializedEntity::InitializeTemporary(Ty); - InitializationKind Kind - = NumExprs ? InitializationKind::CreateDirect(TypeRange.getBegin(), - LParenLoc, RParenLoc) - : InitializationKind::CreateValue(TypeRange.getBegin(), - LParenLoc, RParenLoc); - InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - move(exprs)); + InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); + InitializationKind Kind + = NumExprs ? InitializationKind::CreateDirect(TyBeginLoc, + LParenLoc, RParenLoc) + : InitializationKind::CreateValue(TyBeginLoc, + LParenLoc, RParenLoc); + InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs)); + + // FIXME: Improve AST representation? + return move(Result); +} + +/// doesUsualArrayDeleteWantSize - Answers whether the usual +/// operator delete[] for the given type has a size_t parameter. +static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, + QualType allocType) { + const RecordType *record = + allocType->getBaseElementTypeUnsafe()->getAs<RecordType>(); + if (!record) return false; + + // Try to find an operator delete[] in class scope. + + DeclarationName deleteName = + S.Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete); + LookupResult ops(S, deleteName, loc, Sema::LookupOrdinaryName); + S.LookupQualifiedName(ops, record->getDecl()); + + // We're just doing this for information. + ops.suppressDiagnostics(); + + // Very likely: there's no operator delete[]. + if (ops.empty()) return false; + + // If it's ambiguous, it should be illegal to call operator delete[] + // on this thing, so it doesn't matter if we allocate extra space or not. + if (ops.isAmbiguous()) return false; + + LookupResult::Filter filter = ops.makeFilter(); + while (filter.hasNext()) { + NamedDecl *del = filter.next()->getUnderlyingDecl(); - // FIXME: Improve AST representation? - return move(Result); + // C++0x [basic.stc.dynamic.deallocation]p2: + // A template instance is never a usual deallocation function, + // regardless of its signature. + if (isa<FunctionTemplateDecl>(del)) { + filter.erase(); + continue; + } + + // C++0x [basic.stc.dynamic.deallocation]p2: + // If class T does not declare [an operator delete[] with one + // parameter] but does declare a member deallocation function + // named operator delete[] with exactly two parameters, the + // second of which has type std::size_t, then this function + // is a usual deallocation function. + if (!cast<CXXMethodDecl>(del)->isUsualDeallocationFunction()) { + filter.erase(); + continue; + } } + filter.done(); - // C++ [expr.type.conv]p1: - // If the expression list specifies more than a single value, the type shall - // be a class with a suitably declared constructor. - // - if (NumExprs > 1) - return ExprError(Diag(CommaLocs[0], - diag::err_builtin_func_cast_more_than_one_arg) - << FullRange); - - assert(NumExprs == 0 && "Expected 0 expressions"); - // C++ [expr.type.conv]p2: - // The expression T(), where T is a simple-type-specifier for a non-array - // complete object type or the (possibly cv-qualified) void type, creates an - // rvalue of the specified type, which is value-initialized. - // - exprs.release(); - return Owned(new (Context) CXXScalarValueInitExpr(Ty, TyBeginLoc, RParenLoc)); -} + if (!ops.isSingleResult()) return false; + const FunctionDecl *del = cast<FunctionDecl>(ops.getFoundDecl()); + return (del->getNumParams() == 2); +} /// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.: /// @code new (memory) int[size][4] @endcode @@ -592,15 +755,20 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, ExprResult Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, - SourceLocation PlacementRParen, SourceRange TypeIdParens, + SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, SourceLocation ConstructorRParen) { + bool TypeContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + Expr *ArraySize = 0; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { DeclaratorChunk &Chunk = D.getTypeObject(0); + if (TypeContainsAuto) + return ExprError(Diag(Chunk.Loc, diag::err_new_array_of_auto) + << D.getSourceRange()); if (Chunk.Arr.hasStatic) return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new) << D.getSourceRange()); @@ -630,25 +798,24 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - //FIXME: Store TypeSourceInfo in CXXNew expression. - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0, /*OwnedDecl=*/0, + /*AllowAuto=*/true); QualType AllocType = TInfo->getType(); if (D.isInvalidType()) return ExprError(); - - SourceRange R = TInfo->getTypeLoc().getSourceRange(); + return BuildCXXNew(StartLoc, UseGlobal, PlacementLParen, move(PlacementArgs), PlacementRParen, TypeIdParens, AllocType, - D.getSourceRange().getBegin(), - R, + TInfo, ArraySize, ConstructorLParen, move(ConstructorArgs), - ConstructorRParen); + ConstructorRParen, + TypeContainsAuto); } ExprResult @@ -658,15 +825,37 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, - SourceLocation TypeLoc, - SourceRange TypeRange, + TypeSourceInfo *AllocTypeInfo, Expr *ArraySize, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, - SourceLocation ConstructorRParen) { - if (CheckAllocatedType(AllocType, TypeLoc, TypeRange)) - return ExprError(); + SourceLocation ConstructorRParen, + bool TypeMayContainAuto) { + SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange(); + + // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. + if (TypeMayContainAuto && AllocType->getContainedAutoType()) { + if (ConstructorArgs.size() == 0) + return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) + << AllocType << TypeRange); + if (ConstructorArgs.size() != 1) { + Expr *FirstBad = ConstructorArgs.get()[1]; + return ExprError(Diag(FirstBad->getSourceRange().getBegin(), + diag::err_auto_new_ctor_multiple_expressions) + << AllocType << TypeRange); + } + QualType DeducedType; + if (!DeduceAutoType(AllocType, ConstructorArgs.get()[0], DeducedType)) + return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) + << AllocType + << ConstructorArgs.get()[0]->getType() + << TypeRange + << ConstructorArgs.get()[0]->getSourceRange()); + AllocType = DeducedType; + AllocTypeInfo = Context.getTrivialTypeSourceInfo(AllocType, StartLoc); + } + // Per C++0x [expr.new]p5, the type being constructed may be a // typedef of an array type. if (!ArraySize) { @@ -679,14 +868,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } + if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange)) + return ExprError(); + QualType ResultType = Context.getPointerType(AllocType); // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral // or enumeration type with a non-negative value." if (ArraySize && !ArraySize->isTypeDependent()) { - + QualType SizeType = ArraySize->getType(); - + ExprResult ConvertedSize = ConvertToIntegralOrEnumerationType(StartLoc, ArraySize, PDiag(diag::err_array_size_not_integral), @@ -696,16 +888,16 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, PDiag(diag::note_array_size_conversion), PDiag(diag::err_array_size_ambiguous_conversion), PDiag(diag::note_array_size_conversion), - PDiag(getLangOptions().CPlusPlus0x? 0 + PDiag(getLangOptions().CPlusPlus0x? 0 : diag::ext_array_size_conversion)); if (ConvertedSize.isInvalid()) return ExprError(); - + ArraySize = ConvertedSize.take(); SizeType = ArraySize->getType(); - if (!SizeType->isIntegralOrEnumerationType()) + if (!SizeType->isIntegralOrUnscopedEnumerationType()) return ExprError(); - + // Let's see if this is a constant < 0. If so, we reject it out of hand. // We don't care about special rules, so we tell the machinery it's not // evaluated - it gives us a result in more cases. @@ -713,17 +905,17 @@ 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()), + llvm::APInt::getNullValue(Value.getBitWidth()), Value.isUnsigned())) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); - + if (!AllocType->isDependentType()) { unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { - Diag(ArraySize->getSourceRange().getBegin(), + Diag(ArraySize->getSourceRange().getBegin(), diag::err_array_too_large) << Value.toString(10) << ArraySize->getSourceRange(); @@ -736,11 +928,11 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, << ArraySize->getSourceRange() << FixItHint::CreateRemoval(TypeIdParens.getBegin()) << FixItHint::CreateRemoval(TypeIdParens.getEnd()); - + TypeIdParens = SourceRange(); } } - + ImpCastExprToType(ArraySize, Context.getSizeType(), CK_IntegralCast); } @@ -749,7 +941,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, FunctionDecl *OperatorDelete = 0; Expr **PlaceArgs = (Expr**)PlacementArgs.get(); unsigned NumPlaceArgs = PlacementArgs.size(); - + if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) && FindAllocationFunctions(StartLoc, @@ -757,24 +949,32 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, UseGlobal, AllocType, ArraySize, PlaceArgs, NumPlaceArgs, OperatorNew, OperatorDelete)) return ExprError(); + + // If this is an array allocation, compute whether the usual array + // deallocation function for the type has a size_t parameter. + bool UsualArrayDeleteWantsSize = false; + if (ArraySize && !AllocType->isDependentType()) + UsualArrayDeleteWantsSize + = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); + llvm::SmallVector<Expr *, 8> AllPlaceArgs; if (OperatorNew) { // Add default arguments, if any. - const FunctionProtoType *Proto = + const FunctionProtoType *Proto = OperatorNew->getType()->getAs<FunctionProtoType>(); - VariadicCallType CallType = + VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; - + if (GatherArgumentsForCall(PlacementLParen, OperatorNew, - Proto, 1, PlaceArgs, NumPlaceArgs, + Proto, 1, PlaceArgs, NumPlaceArgs, AllPlaceArgs, CallType)) return ExprError(); - + NumPlaceArgs = AllPlaceArgs.size(); if (NumPlaceArgs > 0) PlaceArgs = &AllPlaceArgs[0]; } - + bool Init = ConstructorLParen.isValid(); // --- Choosing a constructor --- CXXConstructorDecl *Constructor = 0; @@ -786,7 +986,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, if (NumConsArgs && (ResultType->isArrayType() || ArraySize)) { SourceRange InitRange(ConsArgs[0]->getLocStart(), ConsArgs[NumConsArgs - 1]->getLocEnd()); - + Diag(StartLoc, diag::err_new_array_init_args) << InitRange; return ExprError(); } @@ -800,22 +1000,22 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, // - If the new-initializer is omitted, the object is default- // initialized (8.5); if no initialization is performed, // the object has indeterminate value - = !Init? InitializationKind::CreateDefault(TypeLoc) - // - Otherwise, the new-initializer is interpreted according to the + = !Init? InitializationKind::CreateDefault(TypeRange.getBegin()) + // - Otherwise, the new-initializer is interpreted according to the // initialization rules of 8.5 for direct-initialization. - : InitializationKind::CreateDirect(TypeLoc, - ConstructorLParen, + : InitializationKind::CreateDirect(TypeRange.getBegin(), + ConstructorLParen, ConstructorRParen); - + InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType); InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs); - ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, + ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, move(ConstructorArgs)); if (FullInit.isInvalid()) return ExprError(); - - // FullInit is our initializer; walk through it to determine if it's a + + // FullInit is our initializer; walk through it to determine if it's a // constructor call, which CXXNewExpr handles directly. if (Expr *FullInitExpr = (Expr *)FullInit.get()) { if (CXXBindTemporaryExpr *Binder @@ -827,7 +1027,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, for (CXXConstructExpr::arg_iterator A = Construct->arg_begin(), AEnd = Construct->arg_end(); A != AEnd; ++A) - ConvertedConstructorArgs.push_back(A->Retain()); + ConvertedConstructorArgs.push_back(*A); } else { // Take the converted initializer. ConvertedConstructorArgs.push_back(FullInit.release()); @@ -835,12 +1035,12 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } else { // No initialization required. } - + // Take the converted arguments and use them for the new expression. NumConsArgs = ConvertedConstructorArgs.size(); ConsArgs = (Expr **)ConvertedConstructorArgs.take(); } - + // Mark the new and delete operators as referenced. if (OperatorNew) MarkDeclarationReferenced(StartLoc, OperatorNew); @@ -848,18 +1048,20 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, MarkDeclarationReferenced(StartLoc, OperatorDelete); // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) - + PlacementArgs.release(); ConstructorArgs.release(); - - // FIXME: The TypeSourceInfo should also be included in CXXNewExpr. + return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, TypeIdParens, ArraySize, Constructor, Init, ConsArgs, NumConsArgs, OperatorDelete, - ResultType, StartLoc, + UsualArrayDeleteWantsSize, + ResultType, AllocTypeInfo, + StartLoc, Init ? ConstructorRParen : - TypeRange.getEnd())); + TypeRange.getEnd(), + ConstructorLParen, ConstructorRParen)); } /// CheckAllocatedType - Checks that a type is suitable as the allocated type @@ -883,6 +1085,9 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, else if (RequireNonAbstractType(Loc, AllocType, diag::err_allocation_of_abstract_type)) return true; + else if (AllocType->isVariablyModifiedType()) + return Diag(Loc, diag::err_variably_modified_new_type) + << AllocType; return false; } @@ -931,10 +1136,10 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // C++ [expr.new]p8: // If the allocated type is a non-array type, the allocation - // function’s name is operator new and the deallocation function’s + // function's name is operator new and the deallocation function's // name is operator delete. If the allocated type is an array - // type, the allocation function’s name is operator new[] and the - // deallocation function’s name is operator delete[]. + // type, the allocation function's name is operator new[] and the + // deallocation function's name is operator delete[]. DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( @@ -975,12 +1180,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // C++ [expr.new]p19: // // If the new-expression begins with a unary :: operator, the - // deallocation function’s name is looked up in the global + // deallocation function's name is looked up in the global // scope. Otherwise, if the allocated type is a class type T or an - // array thereof, the deallocation function’s name is looked up in + // array thereof, the deallocation function's name is looked up in // the scope of T. If this lookup fails to find the name, or if // the allocated type is not a class type or array thereof, the - // deallocation function’s name is looked up in the global scope. + // deallocation function's name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && !UseGlobal) { CXXRecordDecl *RD @@ -999,39 +1204,49 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, llvm::SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches; - if (NumPlaceArgs > 0) { + // Whether we're looking for a placement operator delete is dictated + // by whether we selected a placement operator new, not by whether + // we had explicit placement arguments. This matters for things like + // struct A { void *operator new(size_t, int = 0); ... }; + // A *a = new A() + bool isPlacementNew = (NumPlaceArgs > 0 || OperatorNew->param_size() != 1); + + if (isPlacementNew) { // C++ [expr.new]p20: // A declaration of a placement deallocation function matches the // declaration of a placement allocation function if it has the // same number of parameters and, after parameter transformations // (8.3.5), all parameter types except the first are // identical. [...] - // + // // To perform this comparison, we compute the function type that // the deallocation function should have, and use that type both // for template argument deduction and for comparison purposes. + // + // FIXME: this comparison should ignore CC and the like. QualType ExpectedFunctionType; { const FunctionProtoType *Proto = OperatorNew->getType()->getAs<FunctionProtoType>(); + llvm::SmallVector<QualType, 4> ArgTypes; - ArgTypes.push_back(Context.VoidPtrTy); + ArgTypes.push_back(Context.VoidPtrTy); for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I) ArgTypes.push_back(Proto->getArgType(I)); + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = Proto->isVariadic(); + ExpectedFunctionType = Context.getFunctionType(Context.VoidTy, ArgTypes.data(), - ArgTypes.size(), - Proto->isVariadic(), - 0, false, false, 0, 0, - FunctionType::ExtInfo()); + ArgTypes.size(), EPI); } - for (LookupResult::iterator D = FoundDelete.begin(), + for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { FunctionDecl *Fn = 0; - if (FunctionTemplateDecl *FnTmpl + if (FunctionTemplateDecl *FnTmpl = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { // Perform template argument deduction to try to match the // expected function type. @@ -1048,7 +1263,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // C++ [expr.new]p20: // [...] Any non-placement deallocation function matches a // non-placement allocation function. [...] - for (LookupResult::iterator D = FoundDelete.begin(), + for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl())) @@ -1073,7 +1288,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, if (NumPlaceArgs && getLangOptions().CPlusPlus0x && isNonPlacementDeallocationFunction(OperatorDelete)) { Diag(StartLoc, diag::err_placement_new_non_placement_delete) - << SourceRange(PlaceArgs[0]->getLocStart(), + << SourceRange(PlaceArgs[0]->getLocStart(), PlaceArgs[NumPlaceArgs - 1]->getLocEnd()); Diag(OperatorDelete->getLocation(), diag::note_previous_decl) << DeleteName; @@ -1107,7 +1322,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, R.suppressDiagnostics(); OverloadCandidateSet Candidates(StartLoc); - for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); + 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. @@ -1140,12 +1355,13 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { ExprResult Result = PerformCopyInitialization(InitializedEntity::InitializeParameter( + Context, FnDecl->getParamDecl(i)), SourceLocation(), - Owned(Args[i]->Retain())); + Owned(Args[i])); if (Result.isInvalid()) return true; - + Args[i] = Result.takeAs<Expr>(); } Operator = FnDecl; @@ -1190,18 +1406,18 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, 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 + // [...] 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 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 + // 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 @@ -1211,14 +1427,14 @@ void Sema::DeclareGlobalNewDelete() { if (!StdBadAlloc) { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. - StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, - getOrCreateStdNamespace(), - SourceLocation(), - &PP.getIdentifierTable().get("bad_alloc"), + StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, + getOrCreateStdNamespace(), + SourceLocation(), + &PP.getIdentifierTable().get("bad_alloc"), SourceLocation(), 0); getStdBadAlloc()->setImplicit(true); } - + GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); @@ -1268,28 +1484,31 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, } QualType BadAllocType; - bool HasBadAllocExceptionSpec + bool HasBadAllocExceptionSpec = (Name.getCXXOverloadedOperator() == OO_New || Name.getCXXOverloadedOperator() == OO_Array_New); if (HasBadAllocExceptionSpec) { assert(StdBadAlloc && "Must have std::bad_alloc declared"); BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); } - - QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0, - true, false, - HasBadAllocExceptionSpec? 1 : 0, - &BadAllocType, - FunctionType::ExtInfo()); + + FunctionProtoType::ExtProtoInfo EPI; + EPI.HasExceptionSpec = true; + if (HasBadAllocExceptionSpec) { + EPI.NumExceptions = 1; + EPI.Exceptions = &BadAllocType; + } + + QualType FnType = Context.getFunctionType(Return, &Argument, 1, EPI); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, FnType, /*TInfo=*/0, SC_None, SC_None, false, true); Alloc->setImplicit(); - + if (AddMallocAttr) Alloc->addAttr(::new (Context) MallocAttr(SourceLocation(), Context)); - + ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), 0, Argument, /*TInfo=*/0, SC_None, @@ -1308,7 +1527,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); - + if (Found.isAmbiguous()) return true; @@ -1352,7 +1571,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, if (!Found.empty()) { Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) << Name << RD; - + for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) Diag((*F)->getUnderlyingDecl()->getLocation(), @@ -1364,7 +1583,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, // Look for a global declaration. DeclareGlobalNewDelete(); DeclContext *TUDecl = Context.getTranslationUnitDecl(); - + CXXNullPtrLiteralExpr Null(Context.VoidPtrTy, SourceLocation()); Expr* DeallocArgs[1]; DeallocArgs[0] = &Null; @@ -1391,19 +1610,21 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // DR599 amends "pointer type" to "pointer to object type" in both cases. FunctionDecl *OperatorDelete = 0; + bool ArrayFormAsWritten = ArrayForm; + bool UsualArrayDeleteWantsSize = false; if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); if (const RecordType *Record = Type->getAs<RecordType>()) { - if (RequireCompleteType(StartLoc, Type, + if (RequireCompleteType(StartLoc, Type, PDiag(diag::err_delete_incomplete_class_type))) return ExprError(); - + llvm::SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions; CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); - const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); + const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = I.getDecl(); @@ -1413,9 +1634,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // Skip over templated conversion functions; they aren't considered. if (isa<FunctionTemplateDecl>(D)) continue; - + CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); - + QualType ConvType = Conv->getConversionType().getNonReferenceType(); if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType()) @@ -1446,7 +1667,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); if (Pointee->isVoidType() && !isSFINAEContext()) { - // The C++ standard bans deleting a pointer to a non-object type, which + // The C++ standard bans deleting a pointer to a non-object type, which // effectively bans deletion of "void*". However, most compilers support // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) @@ -1461,13 +1682,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, return ExprError(); // 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 + // [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), + ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy), CK_NoOp); - + + if (Pointee->isArrayType() && !ArrayForm) { + Diag(StartLoc, diag::warn_delete_array_type) + << Type << Ex->getSourceRange() + << FixItHint::CreateInsertion(PP.getLocForEndOfToken(StartLoc), "[]"); + ArrayForm = true; + } + DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( ArrayForm ? OO_Array_Delete : OO_Delete); @@ -1475,16 +1703,33 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (const RecordType *RT = PointeeElem->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (!UseGlobal && + if (!UseGlobal && FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete)) return ExprError(); - + + // If we're allocating an array of records, check whether the + // usual operator delete[] has a size_t parameter. + if (ArrayForm) { + // If the user specifically asked to use the global allocator, + // we'll need to do the lookup into the class. + if (UseGlobal) + UsualArrayDeleteWantsSize = + doesUsualArrayDeleteWantSize(*this, StartLoc, PointeeElem); + + // Otherwise, the usual operator delete[] should be the + // function we just found. + else if (isa<CXXMethodDecl>(OperatorDelete)) + UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2); + } + if (!RD->hasTrivialDestructor()) - if (const CXXDestructorDecl *Dtor = LookupDestructor(RD)) + if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { MarkDeclarationReferenced(StartLoc, const_cast<CXXDestructorDecl*>(Dtor)); + DiagnoseUseOfDecl(Dtor, StartLoc); + } } - + if (!OperatorDelete) { // Look for a global declaration. DeclareGlobalNewDelete(); @@ -1496,38 +1741,49 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, } MarkDeclarationReferenced(StartLoc, OperatorDelete); + + // Check access and ambiguity of operator delete and destructor. + if (const RecordType *RT = PointeeElem->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { + CheckDestructorAccess(Ex->getExprLoc(), Dtor, + PDiag(diag::err_access_dtor) << PointeeElem); + } + } - // FIXME: Check access and ambiguity of operator delete and destructor. } return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, + ArrayFormAsWritten, + UsualArrayDeleteWantsSize, OperatorDelete, Ex, StartLoc)); } /// \brief Check the use of the given variable as a C++ condition in an if, /// while, do-while, or switch statement. ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, - SourceLocation StmtLoc, - bool ConvertToBoolean) { + SourceLocation StmtLoc, + bool ConvertToBoolean) { QualType T = ConditionVar->getType(); - + // C++ [stmt.select]p2: // The declarator shall not specify a function or an array. if (T->isFunctionType()) - return ExprError(Diag(ConditionVar->getLocation(), + return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_function_type) << ConditionVar->getSourceRange()); else if (T->isArrayType()) - return ExprError(Diag(ConditionVar->getLocation(), + return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_array_type) << ConditionVar->getSourceRange()); Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, - ConditionVar->getLocation(), - ConditionVar->getType().getNonReferenceType()); + ConditionVar->getLocation(), + ConditionVar->getType().getNonReferenceType(), + VK_LValue); if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) return ExprError(); - + return Owned(Condition); } @@ -1575,42 +1831,46 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { return false; } -static ExprResult BuildCXXCastArgument(Sema &S, +static ExprResult BuildCXXCastArgument(Sema &S, SourceLocation CastLoc, QualType Ty, CastKind Kind, CXXMethodDecl *Method, + NamedDecl *FoundDecl, Expr *From) { switch (Kind) { default: assert(0 && "Unhandled cast kind!"); case CK_ConstructorConversion: { ASTOwningVector<Expr*> ConstructorArgs(S); - + if (S.CompleteConstructorCall(cast<CXXConstructorDecl>(Method), MultiExprArg(&From, 1), CastLoc, ConstructorArgs)) return ExprError(); - - ExprResult Result = - S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), + + ExprResult Result = + S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), move_arg(ConstructorArgs), - /*ZeroInit*/ false, CXXConstructExpr::CK_Complete); + /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, + SourceRange()); if (Result.isInvalid()) return ExprError(); - + return S.MaybeBindToTemporary(Result.takeAs<Expr>()); } - + case CK_UserDefinedConversion: { assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); - + // Create an implicit call expr that calls it. - // FIXME: pass the FoundDecl for the user-defined conversion here - CXXMemberCallExpr *CE = S.BuildCXXMemberCallExpr(From, Method, Method); - return S.MaybeBindToTemporary(CE); + ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Method); + if (Result.isInvalid()) + return ExprError(); + + return S.MaybeBindToTemporary(Result.get()); } } -} +} /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit @@ -1621,52 +1881,51 @@ static ExprResult BuildCXXCastArgument(Sema &S, bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence &ICS, - AssignmentAction Action, bool IgnoreBaseAccess) { + AssignmentAction Action, bool CStyle) { switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: if (PerformImplicitConversion(From, ToType, ICS.Standard, Action, - IgnoreBaseAccess)) + CStyle)) return true; break; case ImplicitConversionSequence::UserDefinedConversion: { - + FunctionDecl *FD = ICS.UserDefined.ConversionFunction; - CastKind CastKind = CK_Unknown; + CastKind CastKind; QualType BeforeToType; if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(FD)) { CastKind = 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)) { + } else { + const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(FD); CastKind = CK_ConstructorConversion; // Do no conversion if dealing with ... for the first conversion. if (!ICS.UserDefined.EllipsisConversion) { - // If the user-defined conversion is specified by a constructor, the + // 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().getNonReferenceType(); } - } - else - assert(0 && "Unknown conversion function kind!"); - // Whatch out for elipsis conversion. + } + // Watch out for elipsis conversion. if (!ICS.UserDefined.EllipsisConversion) { - if (PerformImplicitConversion(From, BeforeToType, + if (PerformImplicitConversion(From, BeforeToType, ICS.UserDefined.Before, AA_Converting, - IgnoreBaseAccess)) + CStyle)) return true; } - - ExprResult CastArg + + ExprResult CastArg = BuildCXXCastArgument(*this, From->getLocStart(), ToType.getNonReferenceType(), - CastKind, cast<CXXMethodDecl>(FD), + CastKind, cast<CXXMethodDecl>(FD), + ICS.UserDefined.FoundConversionFunction, From); if (CastArg.isInvalid()) @@ -1675,7 +1934,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, From = CastArg.takeAs<Expr>(); return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, - AA_Converting, IgnoreBaseAccess); + AA_Converting, CStyle); } case ImplicitConversionSequence::AmbiguousConversion: @@ -1683,7 +1942,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); return true; - + case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); return false; @@ -1705,7 +1964,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, - AssignmentAction Action, bool IgnoreBaseAccess) { + AssignmentAction Action, bool CStyle) { // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, @@ -1719,7 +1978,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ASTOwningVector<Expr*> ConstructorArgs(*this); if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor), MultiExprArg(*this, &From, 1), - /*FIXME:ConstructLoc*/SourceLocation(), + /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) return true; ExprResult FromResult = @@ -1727,7 +1986,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ToType, SCS.CopyConstructor, move_arg(ConstructorArgs), /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete); + CXXConstructExpr::CK_Complete, + SourceRange()); if (FromResult.isInvalid()) return true; From = FromResult.takeAs<Expr>(); @@ -1738,7 +1998,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ToType, SCS.CopyConstructor, MultiExprArg(*this, &From, 1), /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete); + CXXConstructExpr::CK_Complete, + SourceRange()); if (FromResult.isInvalid()) return true; @@ -1765,10 +2026,25 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Perform the first implicit conversion. switch (SCS.First) { case ICK_Identity: - case ICK_Lvalue_To_Rvalue: // Nothing to do. break; + case ICK_Lvalue_To_Rvalue: + // Should this get its own ICK? + if (From->getObjectKind() == OK_ObjCProperty) { + ConvertPropertyForRValue(From); + if (!From->isGLValue()) break; + } + + // Check for trivial buffer overflows. + if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(From)) + CheckArrayAccess(AE); + + FromType = FromType.getUnqualifiedType(); + From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue, + From, 0, VK_RValue); + break; + case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay); @@ -1798,12 +2074,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // If both sides are functions (or pointers/references to them), there could // be incompatible exception declarations. if (CheckExceptionSpecCompatibility(From, ToType)) - return true; - - ImpCastExprToType(From, Context.getNoReturnType(From->getType(), false), - CK_NoOp); + return true; + + ImpCastExprToType(From, ToType, CK_NoOp); break; - + case ICK_Integral_Promotion: case ICK_Integral_Conversion: ImpCastExprToType(From, ToType, CK_IntegralCast); @@ -1815,9 +2090,23 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; case ICK_Complex_Promotion: - case ICK_Complex_Conversion: - ImpCastExprToType(From, ToType, CK_Unknown); + case ICK_Complex_Conversion: { + QualType FromEl = From->getType()->getAs<ComplexType>()->getElementType(); + QualType ToEl = ToType->getAs<ComplexType>()->getElementType(); + CastKind CK; + if (FromEl->isRealFloatingType()) { + if (ToEl->isRealFloatingType()) + CK = CK_FloatingComplexCast; + else + CK = CK_FloatingComplexToIntegralComplex; + } else if (ToEl->isRealFloatingType()) { + CK = CK_IntegralComplexToFloatingComplex; + } else { + CK = CK_IntegralComplexCast; + } + ImpCastExprToType(From, ToType, CK); break; + } case ICK_Floating_Integral: if (ToType->isRealFloatingType()) @@ -1831,7 +2120,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; case ICK_Pointer_Conversion: { - if (SCS.IncompatibleObjC) { + if (SCS.IncompatibleObjC && Action != AA_Casting) { // Diagnose incompatible Objective-C conversions Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) @@ -1839,20 +2128,18 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, << From->getSourceRange(); } - - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Invalid; CXXCastPath BasePath; - if (CheckPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess)) + if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return true; ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath); break; } - + case ICK_Pointer_Member: { - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Invalid; CXXCastPath BasePath; - if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, - IgnoreBaseAccess)) + if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle)) return true; if (CheckExceptionSpecCompatibility(From, ToType)) return true; @@ -1860,22 +2147,29 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; } case ICK_Boolean_Conversion: { - CastKind Kind = CK_Unknown; - if (FromType->isMemberPointerType()) - Kind = CK_MemberPointerToBoolean; - + CastKind Kind = CK_Invalid; + switch (FromType->getScalarTypeKind()) { + case Type::STK_Pointer: Kind = CK_PointerToBoolean; break; + case Type::STK_MemberPointer: Kind = CK_MemberPointerToBoolean; break; + case Type::STK_Bool: llvm_unreachable("bool -> bool conversion?"); + case Type::STK_Integral: Kind = CK_IntegralToBoolean; break; + case Type::STK_Floating: Kind = CK_FloatingToBoolean; break; + case Type::STK_IntegralComplex: Kind = CK_IntegralComplexToBoolean; break; + case Type::STK_FloatingComplex: Kind = CK_FloatingComplexToBoolean; break; + } + ImpCastExprToType(From, Context.BoolTy, Kind); break; } case ICK_Derived_To_Base: { CXXCastPath BasePath; - if (CheckDerivedToBaseConversion(From->getType(), + if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), - From->getSourceRange(), + From->getSourceRange(), &BasePath, - IgnoreBaseAccess)) + CStyle)) return true; ImpCastExprToType(From, ToType.getNonReferenceType(), @@ -1891,10 +2185,60 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Vector_Splat: ImpCastExprToType(From, ToType, CK_VectorSplat); break; - + case ICK_Complex_Real: - ImpCastExprToType(From, ToType, CK_Unknown); + // Case 1. x -> _Complex y + if (const ComplexType *ToComplex = ToType->getAs<ComplexType>()) { + QualType ElType = ToComplex->getElementType(); + bool isFloatingComplex = ElType->isRealFloatingType(); + + // x -> y + if (Context.hasSameUnqualifiedType(ElType, From->getType())) { + // do nothing + } else if (From->getType()->isRealFloatingType()) { + ImpCastExprToType(From, ElType, + isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral); + } else { + assert(From->getType()->isIntegerType()); + ImpCastExprToType(From, ElType, + isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast); + } + // y -> _Complex y + ImpCastExprToType(From, ToType, + isFloatingComplex ? CK_FloatingRealToComplex + : CK_IntegralRealToComplex); + + // Case 2. _Complex x -> y + } else { + const ComplexType *FromComplex = From->getType()->getAs<ComplexType>(); + assert(FromComplex); + + QualType ElType = FromComplex->getElementType(); + bool isFloatingComplex = ElType->isRealFloatingType(); + + // _Complex x -> x + ImpCastExprToType(From, ElType, + isFloatingComplex ? CK_FloatingComplexToReal + : CK_IntegralComplexToReal); + + // x -> y + if (Context.hasSameUnqualifiedType(ElType, ToType)) { + // do nothing + } else if (ToType->isRealFloatingType()) { + ImpCastExprToType(From, ToType, + isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating); + } else { + assert(ToType->isIntegerType()); + ImpCastExprToType(From, ToType, + isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast); + } + } break; + + case ICK_Block_Pointer_Conversion: { + ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, VK_RValue); + break; + } case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: @@ -1933,31 +2277,409 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return false; } -ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT, - SourceLocation KWLoc, - SourceLocation LParen, - ParsedType Ty, - SourceLocation RParen) { - QualType T = GetTypeFromParser(Ty); +ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait UTT, + SourceLocation KWLoc, + ParsedType Ty, + SourceLocation RParen) { + TypeSourceInfo *TSInfo; + QualType T = GetTypeFromParser(Ty, &TSInfo); + + if (!TSInfo) + TSInfo = Context.getTrivialTypeSourceInfo(T); + return BuildUnaryTypeTrait(UTT, KWLoc, TSInfo, RParen); +} + +static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T, + SourceLocation KeyLoc) { + // FIXME: For many of these traits, we need a complete type before we can + // check these properties. + assert(!T->isDependentType() && + "Cannot evaluate traits for dependent types."); + ASTContext &C = Self.Context; + switch(UTT) { + default: assert(false && "Unknown type trait or not implemented"); + case UTT_IsPOD: return T->isPODType(); + case UTT_IsLiteral: return T->isLiteralType(); + case UTT_IsClass: // Fallthrough + case UTT_IsUnion: + if (const RecordType *Record = T->getAs<RecordType>()) { + bool Union = Record->getDecl()->isUnion(); + return UTT == UTT_IsUnion ? Union : !Union; + } + return false; + case UTT_IsEnum: return T->isEnumeralType(); + case UTT_IsPolymorphic: + if (const RecordType *Record = T->getAs<RecordType>()) { + // Type traits are only parsed in C++, so we've got CXXRecords. + return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic(); + } + return false; + case UTT_IsAbstract: + if (const RecordType *RT = T->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->isAbstract(); + return false; + case UTT_IsEmpty: + if (const RecordType *Record = T->getAs<RecordType>()) { + return !Record->getDecl()->isUnion() + && cast<CXXRecordDecl>(Record->getDecl())->isEmpty(); + } + return false; + case UTT_HasTrivialConstructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true then the trait is true, else if type is + // a cv class or union type (or array thereof) with a trivial default + // constructor ([class.ctor]) then the trait is true, else it is false. + if (T->isPODType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(T)->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor(); + return false; + case UTT_HasTrivialCopy: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true or type is a reference type then + // the trait is true, else if type is a cv class or union type + // with a trivial copy constructor ([class.copy]) then the trait + // is true, else it is false. + if (T->isPODType() || T->isReferenceType()) + return true; + if (const RecordType *RT = T->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor(); + return false; + case UTT_HasTrivialAssign: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is const qualified or is a reference type then the + // trait is false. Otherwise if __is_pod (type) is true then the + // trait is true, else if type is a cv class or union type with + // a trivial copy assignment ([class.copy]) then the trait is + // true, else it is false. + // Note: the const and reference restrictions are interesting, + // given that const and reference members don't prevent a class + // from having a trivial copy assignment operator (but do cause + // errors if the copy assignment operator is actually used, q.v. + // [class.copy]p12). + + if (C.getBaseElementType(T).isConstQualified()) + return false; + if (T->isPODType()) + return true; + if (const RecordType *RT = T->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment(); + return false; + case UTT_HasTrivialDestructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true or type is a reference type + // then the trait is true, else if type is a cv class or union + // type (or array thereof) with a trivial destructor + // ([class.dtor]) then the trait is true, else it is + // false. + if (T->isPODType() || T->isReferenceType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(T)->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor(); + return false; + // TODO: Propagate nothrowness for implicitly declared special members. + case UTT_HasNothrowAssign: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is const qualified or is a reference type then the + // trait is false. Otherwise if __has_trivial_assign (type) + // is true then the trait is true, else if type is a cv class + // or union type with copy assignment operators that are known + // not to throw an exception then the trait is true, else it is + // false. + if (C.getBaseElementType(T).isConstQualified()) + return false; + if (T->isReferenceType()) + return false; + if (T->isPODType()) + return true; + if (const RecordType *RT = T->getAs<RecordType>()) { + CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialCopyAssignment()) + return true; + + bool FoundAssign = false; + bool AllNoThrow = true; + DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal); + LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc), + Sema::LookupOrdinaryName); + if (Self.LookupQualifiedName(Res, RD)) { + for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end(); + Op != OpEnd; ++Op) { + CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op); + if (Operator->isCopyAssignmentOperator()) { + FoundAssign = true; + const FunctionProtoType *CPT + = Operator->getType()->getAs<FunctionProtoType>(); + if (!CPT->hasEmptyExceptionSpec()) { + AllNoThrow = false; + break; + } + } + } + } + + return FoundAssign && AllNoThrow; + } + return false; + case UTT_HasNothrowCopy: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __has_trivial_copy (type) is true then the trait is true, else + // if type is a cv class or union type with copy constructors that are + // known not to throw an exception then the trait is true, else it is + // false. + if (T->isPODType() || T->isReferenceType()) + return true; + if (const RecordType *RT = T->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialCopyConstructor()) + return true; + + bool FoundConstructor = false; + bool AllNoThrow = true; + unsigned FoundTQs; + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD); + Con != ConEnd; ++Con) { + // A template constructor is never a copy constructor. + // FIXME: However, it may actually be selected at the actual overload + // resolution point. + if (isa<FunctionTemplateDecl>(*Con)) + continue; + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isCopyConstructor(FoundTQs)) { + FoundConstructor = true; + const FunctionProtoType *CPT + = Constructor->getType()->getAs<FunctionProtoType>(); + // TODO: check whether evaluating default arguments can throw. + // For now, we'll be conservative and assume that they can throw. + if (!CPT->hasEmptyExceptionSpec() || CPT->getNumArgs() > 1) { + AllNoThrow = false; + break; + } + } + } + + return FoundConstructor && AllNoThrow; + } + return false; + case UTT_HasNothrowConstructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __has_trivial_constructor (type) is true then the trait is + // true, else if type is a cv class or union type (or array + // thereof) with a default constructor that is known not to + // throw an exception then the trait is true, else it is false. + if (T->isPODType()) + return true; + if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialConstructor()) + return true; + + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD); + Con != ConEnd; ++Con) { + // FIXME: In C++0x, a constructor template can be a default constructor. + if (isa<FunctionTemplateDecl>(*Con)) + continue; + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isDefaultConstructor()) { + const FunctionProtoType *CPT + = Constructor->getType()->getAs<FunctionProtoType>(); + // TODO: check whether evaluating default arguments can throw. + // For now, we'll be conservative and assume that they can throw. + return CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0; + } + } + } + return false; + case UTT_HasVirtualDestructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is a class type with a virtual destructor ([class.dtor]) + // then the trait is true, else it is false. + if (const RecordType *Record = T->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); + if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD)) + return Destructor->isVirtual(); + } + return false; + } +} + +ExprResult Sema::BuildUnaryTypeTrait(UnaryTypeTrait UTT, + SourceLocation KWLoc, + TypeSourceInfo *TSInfo, + SourceLocation RParen) { + QualType T = TSInfo->getType(); // 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, + // to be complete, an array of unknown bound, or void. + if (UTT != UTT_IsClass && UTT != UTT_IsEnum && UTT != UTT_IsUnion) { + QualType E = T; + if (T->isIncompleteArrayType()) + E = Context.getAsArrayType(T)->getElementType(); + if (!T->isVoidType() && + RequireCompleteType(KWLoc, E, 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, T, + bool Value = false; + if (!T->isDependentType()) + Value = EvaluateUnaryTypeTrait(*this, UTT, T, KWLoc); + + return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, UTT, TSInfo, Value, RParen, Context.BoolTy)); } -QualType Sema::CheckPointerToMemberOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) { +ExprResult Sema::ActOnBinaryTypeTrait(BinaryTypeTrait BTT, + SourceLocation KWLoc, + ParsedType LhsTy, + ParsedType RhsTy, + SourceLocation RParen) { + TypeSourceInfo *LhsTSInfo; + QualType LhsT = GetTypeFromParser(LhsTy, &LhsTSInfo); + if (!LhsTSInfo) + LhsTSInfo = Context.getTrivialTypeSourceInfo(LhsT); + + TypeSourceInfo *RhsTSInfo; + QualType RhsT = GetTypeFromParser(RhsTy, &RhsTSInfo); + if (!RhsTSInfo) + RhsTSInfo = Context.getTrivialTypeSourceInfo(RhsT); + + return BuildBinaryTypeTrait(BTT, KWLoc, LhsTSInfo, RhsTSInfo, RParen); +} + +static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, + QualType LhsT, QualType RhsT, + SourceLocation KeyLoc) { + assert((!LhsT->isDependentType() || RhsT->isDependentType()) && + "Cannot evaluate traits for dependent types."); + + switch(BTT) { + case BTT_IsBaseOf: { + // C++0x [meta.rel]p2 + // Base is a base class of Derived without regard to cv-qualifiers or + // Base and Derived are not unions and name the same class type without + // regard to cv-qualifiers. + + const RecordType *lhsRecord = LhsT->getAs<RecordType>(); + if (!lhsRecord) return false; + + const RecordType *rhsRecord = RhsT->getAs<RecordType>(); + if (!rhsRecord) return false; + + assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT) + == (lhsRecord == rhsRecord)); + + if (lhsRecord == rhsRecord) + return !lhsRecord->getDecl()->isUnion(); + + // C++0x [meta.rel]p2: + // If Base and Derived are class types and are different types + // (ignoring possible cv-qualifiers) then Derived shall be a + // complete type. + if (Self.RequireCompleteType(KeyLoc, RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) + return false; + + return cast<CXXRecordDecl>(rhsRecord->getDecl()) + ->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl())); + } + + case BTT_TypeCompatible: + return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(), + RhsT.getUnqualifiedType()); + + case BTT_IsConvertibleTo: { + // C++0x [meta.rel]p4: + // Given the following function prototype: + // + // template <class T> + // typename add_rvalue_reference<T>::type create(); + // + // the predicate condition for a template specialization + // is_convertible<From, To> shall be satisfied if and only if + // the return expression in the following code would be + // well-formed, including any implicit conversions to the return + // type of the function: + // + // To test() { + // return create<From>(); + // } + // + // Access checking is performed as if in a context unrelated to To and + // From. Only the validity of the immediate context of the expression + // of the return-statement (including conversions to the return type) + // is considered. + // + // We model the initialization as a copy-initialization of a temporary + // of the appropriate type, which for this expression is identical to the + // return statement (since NRVO doesn't apply). + if (LhsT->isObjectType() || LhsT->isFunctionType()) + LhsT = Self.Context.getRValueReferenceType(LhsT); + + InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT)); + OpaqueValueExpr From(KeyLoc, LhsT.getNonLValueExprType(Self.Context), + Expr::getValueKindForType(LhsT)); + Expr *FromPtr = &From; + InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, + SourceLocation())); + + // Perform the initialization within a SFINAE trap at translation unit + // scope. + Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); + InitializationSequence Init(Self, To, Kind, &FromPtr, 1); + if (Init.getKind() == InitializationSequence::FailedSequence) + return false; + + ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1)); + return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); + } + } + llvm_unreachable("Unknown type trait or not implemented"); +} + +ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT, + SourceLocation KWLoc, + TypeSourceInfo *LhsTSInfo, + TypeSourceInfo *RhsTSInfo, + SourceLocation RParen) { + QualType LhsT = LhsTSInfo->getType(); + QualType RhsT = RhsTSInfo->getType(); + + if (BTT == BTT_TypeCompatible) { + if (getLangOptions().CPlusPlus) { + Diag(KWLoc, diag::err_types_compatible_p_in_cplusplus) + << SourceRange(KWLoc, RParen); + return ExprError(); + } + } + + bool Value = false; + if (!LhsT->isDependentType() && !RhsT->isDependentType()) + Value = EvaluateBinaryTypeTrait(*this, BTT, LhsT, RhsT, KWLoc); + + // Select trait result type. + QualType ResultType; + switch (BTT) { + case BTT_IsBaseOf: ResultType = Context.BoolTy; break; + case BTT_TypeCompatible: ResultType = Context.IntTy; break; + case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break; + } + + return Owned(new (Context) BinaryTypeTraitExpr(KWLoc, BTT, LhsTSInfo, + RhsTSInfo, Value, RParen, + ResultType)); +} + +QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex, + ExprValueKind &VK, + SourceLocation Loc, + bool isIndirect) { const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall @@ -1973,8 +2695,11 @@ QualType Sema::CheckPointerToMemberOperands( QualType Class(MemPtr->getClass(), 0); - if (RequireCompleteType(Loc, Class, diag::err_memptr_rhs_to_incomplete)) - return QualType(); + // Note: C++ [expr.mptr.oper]p2-3 says that the class type into which the + // member pointer points must be completely-defined. However, there is no + // reason for this semantic distinction, and the rule is not enforced by + // other compilers. Therefore, we do not check this property, as it is + // likely to be considered a defect. // C++ 5.5p2 // [...] to its first operand, which shall be of class T or of a class of @@ -1983,7 +2708,7 @@ QualType Sema::CheckPointerToMemberOperands( QualType LType = lex->getType(); if (isIndirect) { if (const PointerType *Ptr = LType->getAs<PointerType>()) - LType = Ptr->getPointeeType().getNonReferenceType(); + LType = Ptr->getPointeeType(); else { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << 1 << LType @@ -2024,6 +2749,7 @@ QualType Sema::CheckPointerToMemberOperands( Diag(Loc, diag::err_pointer_to_member_type) << isIndirect; return QualType(); } + // C++ 5.5p2 // The result is an object or a function of the type specified by the // second operand. @@ -2038,6 +2764,47 @@ QualType Sema::CheckPointerToMemberOperands( // We probably need a "MemberFunctionClosureType" or something like that. QualType Result = MemPtr->getPointeeType(); Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers()); + + // C++0x [expr.mptr.oper]p6: + // In a .* expression whose object expression is an rvalue, the program is + // ill-formed if the second operand is a pointer to member function with + // ref-qualifier &. In a ->* expression or in a .* expression whose object + // expression is an lvalue, the program is ill-formed if the second operand + // is a pointer to member function with ref-qualifier &&. + if (const FunctionProtoType *Proto = Result->getAs<FunctionProtoType>()) { + switch (Proto->getRefQualifier()) { + case RQ_None: + // Do nothing + break; + + case RQ_LValue: + if (!isIndirect && !lex->Classify(Context).isLValue()) + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RType << 1 << lex->getSourceRange(); + break; + + case RQ_RValue: + if (isIndirect || !lex->Classify(Context).isRValue()) + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RType << 0 << lex->getSourceRange(); + break; + } + } + + // C++ [expr.mptr.oper]p6: + // The result of a .* expression whose second operand is a pointer + // to a data member is of the same value category as its + // first operand. The result of a .* expression whose second + // operand is a pointer to a member function is a prvalue. The + // result of an ->* expression is an lvalue if its second operand + // is a pointer to data member and a prvalue otherwise. + if (Result->isFunctionType()) + VK = VK_RValue; + else if (isIndirect) + VK = VK_LValue; + else + VK = lex->getValueKind(); + return Result; } @@ -2054,29 +2821,29 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, QualType &ToType) { HaveConversion = false; ToType = To->getType(); - - InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), + + InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), SourceLocation()); // 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 // as follows: // -- If E2 is an lvalue: - bool ToIsLvalue = (To->isLvalue(Self.Context) == Expr::LV_Valid); + bool ToIsLvalue = To->isLValue(); if (ToIsLvalue) { // E1 can be converted to match E2 if E1 can be implicitly converted to // type "lvalue reference to T2", subject to the constraint that in the // conversion the reference must bind directly to E1. QualType T = Self.Context.getLValueReferenceType(ToType); InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); - + InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); if (InitSeq.isDirectReferenceBinding()) { ToType = T; HaveConversion = true; return false; } - + if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); } @@ -2088,9 +2855,9 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, QualType TTy = To->getType(); const RecordType *FRec = FTy->getAs<RecordType>(); const RecordType *TRec = TTy->getAs<RecordType>(); - bool FDerivedFromT = FRec && TRec && FRec != TRec && + bool FDerivedFromT = FRec && TRec && FRec != TRec && Self.IsDerivedFrom(FTy, TTy); - if (FRec && TRec && + if (FRec && TRec && (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) { // E1 can be converted to match E2 if the class of T2 is the // same type as, or a base class of, the class of T1, and @@ -2103,28 +2870,28 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, HaveConversion = true; return false; } - + if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); - } + } } - + return false; } - + // -- Otherwise: E1 can be converted to match E2 if E1 can be // implicitly converted to the type that expression E2 would have - // if E2 were converted to an rvalue (or the type it has, if E2 is + // if E2 were converted to an rvalue (or the type it has, if E2 is // an rvalue). // // This actually refers very narrowly to the lvalue-to-rvalue conversion, not // to the array-to-pointer or function-to-pointer conversions. if (!TTy->getAs<TagType>()) TTy = TTy.getUnqualifiedType(); - + InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); - HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence; + HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence; ToType = TTy; if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); @@ -2138,13 +2905,14 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, /// value operand is a class type, overload resolution is used to find a /// conversion to a common type. static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, - SourceLocation Loc) { + SourceLocation QuestionLoc) { Expr *Args[2] = { LHS, RHS }; - OverloadCandidateSet CandidateSet(Loc); - Self.AddBuiltinOperatorCandidates(OO_Conditional, Loc, Args, 2, CandidateSet); + OverloadCandidateSet CandidateSet(QuestionLoc); + Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, 2, + CandidateSet); OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(Self, Loc, Best)) { + switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) { case OR_Success: // We found a match. Perform the conversions on the arguments and move on. if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], @@ -2155,13 +2923,20 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, return false; case OR_No_Viable_Function: - Self.Diag(Loc, diag::err_typecheck_cond_incompatible_operands) + + // Emit a better diagnostic if one of the expressions is a null pointer + // constant and the other is a pointer type. In this case, the user most + // likely forgot to take the address of the other expression. + if (Self.DiagnoseConditionalForNull(LHS, RHS, QuestionLoc)) + return true; + + Self.Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); return true; case OR_Ambiguous: - Self.Diag(Loc, diag::err_conditional_ambiguous_ovl) + Self.Diag(QuestionLoc, diag::err_conditional_ambiguous_ovl) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); // FIXME: Print the possible common types by printing the return types of @@ -2185,7 +2960,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) { ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&E, 1)); if (Result.isInvalid()) return true; - + E = Result.takeAs<Expr>(); return false; } @@ -2195,6 +2970,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) { /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y /// extension. In this case, LHS == Cond. (But they're not aliases.) QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++ // interface pointers. @@ -2206,6 +2982,10 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return QualType(); } + // Assume r-value. + VK = VK_RValue; + OK = OK_Ordinary; + // Either of the arguments dependent? if (LHS->isTypeDependent() || RHS->isTypeDependent()) return Context.DependentTy; @@ -2252,7 +3032,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // Otherwise, if the second and third operand have different types, and // either has (cv) class type, and attempt is made to convert each of those // operands to the other. - if (!Context.hasSameType(LTy, RTy) && + if (!Context.hasSameType(LTy, RTy) && (LTy->isRecordType() || RTy->isRecordType())) { ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft; // These return true if a single direction is already ambiguous. @@ -2262,7 +3042,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return QualType(); if (TryClassUnification(*this, RHS, LHS, QuestionLoc, HaveR2L, R2LType)) return QualType(); - + // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) @@ -2285,12 +3065,24 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, } // C++0x 5.16p4 - // If the second and third operands are lvalues and have the same type, - // the result is of that type [...] + // If the second and third operands are glvalues of the same value + // category and have the same type, the result is of that type and + // value category and it is a bit-field if the second or the third + // operand is a bit-field, or if both are bit-fields. + // We only extend this to bitfields, not to the crazy other kinds of + // l-values. bool Same = Context.hasSameType(LTy, RTy); - if (Same && LHS->isLvalue(Context) == Expr::LV_Valid && - RHS->isLvalue(Context) == Expr::LV_Valid) + if (Same && + LHS->isGLValue() && + LHS->getValueKind() == RHS->getValueKind() && + LHS->isOrdinaryOrBitFieldObject() && + RHS->isOrdinaryOrBitFieldObject()) { + VK = LHS->getValueKind(); + if (LHS->getObjectKind() == OK_BitField || + RHS->getObjectKind() == OK_BitField) + OK = OK_BitField; return LTy; + } // C++0x 5.16p5 // Otherwise, the result is an rvalue. If the second and third operands @@ -2321,18 +3113,18 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); - ExprResult LHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), - Owned(LHS)); + ExprResult LHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(LHS)); if (LHSCopy.isInvalid()) return QualType(); - - ExprResult RHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), - Owned(RHS)); + + ExprResult RHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(RHS)); if (RHSCopy.isInvalid()) return QualType(); - + LHS = LHSCopy.takeAs<Expr>(); RHS = RHSCopy.takeAs<Expr>(); } @@ -2341,7 +3133,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, } // Extension: conditional operator involving vector types. - if (LTy->isVectorType() || RTy->isVectorType()) + if (LTy->isVectorType() || RTy->isVectorType()) return CheckVectorOperands(QuestionLoc, LHS, RHS); // -- The second and third operands have arithmetic or enumeration type; @@ -2367,19 +3159,23 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, isSFINAEContext()? 0 : &NonStandardCompositeType); if (!Composite.isNull()) { if (NonStandardCompositeType) - Diag(QuestionLoc, + Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands_nonstandard) << LTy << RTy << Composite << LHS->getSourceRange() << RHS->getSourceRange(); - + return Composite; } - + // Similarly, attempt to find composite type of two objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (!Composite.isNull()) return Composite; + // Check if we are using a null with a non-pointer type. + if (DiagnoseConditionalForNull(LHS, RHS, QuestionLoc)) + return QualType(); + Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); @@ -2400,12 +3196,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, /// a non-standard (but still sane) composite type to which both expressions /// can be converted. When such a type is chosen, \c *NonStandardCompositeType /// will be set true. -QualType Sema::FindCompositePointerType(SourceLocation Loc, +QualType Sema::FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool *NonStandardCompositeType) { if (NonStandardCompositeType) *NonStandardCompositeType = false; - + assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); @@ -2422,14 +3218,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, if (T2->isMemberPointerType()) ImpCastExprToType(E1, T2, CK_NullToMemberPointer); else - ImpCastExprToType(E1, T2, CK_IntegralToPointer); + ImpCastExprToType(E1, T2, CK_NullToPointer); return T2; } if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (T1->isMemberPointerType()) ImpCastExprToType(E2, T1, CK_NullToMemberPointer); else - ImpCastExprToType(E2, T1, CK_IntegralToPointer); + ImpCastExprToType(E2, T1, CK_NullToPointer); return T1; } @@ -2456,20 +3252,20 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, ContainingClassVector MemberOfClass; QualType Composite1 = Context.getCanonicalType(T1), Composite2 = Context.getCanonicalType(T2); - unsigned NeedConstBefore = 0; + unsigned NeedConstBefore = 0; do { const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs<PointerType>()) && (Ptr2 = Composite2->getAs<PointerType>())) { Composite1 = Ptr1->getPointeeType(); Composite2 = Ptr2->getPointeeType(); - + // If we're allowed to create a non-standard composite type, keep track - // of where we need to fill in additional 'const' qualifiers. + // of where we need to fill in additional 'const' qualifiers. if (NonStandardCompositeType && Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); - + QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0)); @@ -2481,13 +3277,13 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, (MemPtr2 = Composite2->getAs<MemberPointerType>())) { Composite1 = MemPtr1->getPointeeType(); Composite2 = MemPtr2->getPointeeType(); - + // If we're allowed to create a non-standard composite type, keep track - // of where we need to fill in additional 'const' qualifiers. + // of where we need to fill in additional 'const' qualifiers. if (NonStandardCompositeType && Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); - + QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), @@ -2503,7 +3299,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, if (NeedConstBefore && NonStandardCompositeType) { // Extension: Add 'const' to qualifiers that come before the first qualifier - // mismatch, so that our (non-standard!) composite type meets the + // mismatch, so that our (non-standard!) composite type meets the // requirements of C++ [conv.qual]p4 bullet 3. for (unsigned I = 0; I != NeedConstBefore; ++I) { if ((QualifierUnion[I] & Qualifiers::Const) == 0) { @@ -2512,7 +3308,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, } } } - + // Rewrap the composites as pointers or member pointers with the union CVRs. ContainingClassVector::reverse_iterator MOC = MemberOfClass.rbegin(); @@ -2575,7 +3371,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, if (E2Result.isInvalid()) return QualType(); E2 = E2Result.takeAs<Expr>(); - + return Composite1; } @@ -2586,25 +3382,28 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); if (!E1ToC2 || !E2ToC2) return QualType(); - + // Convert E1 to Composite2 ExprResult E1Result = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E1, 1)); if (E1Result.isInvalid()) return QualType(); E1 = E1Result.takeAs<Expr>(); - + // Convert E2 to Composite2 ExprResult E2Result = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E2, 1)); if (E2Result.isInvalid()) return QualType(); E2 = E2Result.takeAs<Expr>(); - + return Composite2; } ExprResult Sema::MaybeBindToTemporary(Expr *E) { + if (!E) + return ExprError(); + if (!Context.getLangOptions().CPlusPlus) return Owned(E); @@ -2614,17 +3413,9 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!RT) return Owned(E); - // If this is the result of a call or an Objective-C message send expression, - // our source might actually be a reference, in which case we shouldn't bind. - if (CallExpr *CE = dyn_cast<CallExpr>(E)) { - if (CE->getCallReturnType()->isReferenceType()) - return Owned(E); - } else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) { - if (const ObjCMethodDecl *MD = ME->getMethodDecl()) { - if (MD->getResultType()->isReferenceType()) - return Owned(E); - } - } + // If the result is a glvalue, we shouldn't bind it. + if (E->Classify(Context).isGLValue()) + return Owned(E); // That should be enough to guarantee that this type is complete. // If it has a trivial destructor, we can avoid the extra copy. @@ -2644,48 +3435,49 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E)); } -Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr) { +Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) { assert(SubExpr && "sub expression can't be null!"); - // Check any implicit conversions within the expression. - CheckImplicitConversions(SubExpr); - unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; assert(ExprTemporaries.size() >= FirstTemporary); if (ExprTemporaries.size() == FirstTemporary) return SubExpr; - Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr, - &ExprTemporaries[FirstTemporary], - ExprTemporaries.size() - FirstTemporary); + Expr *E = ExprWithCleanups::Create(Context, SubExpr, + &ExprTemporaries[FirstTemporary], + ExprTemporaries.size() - FirstTemporary); ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary, ExprTemporaries.end()); return E; } -ExprResult -Sema::MaybeCreateCXXExprWithTemporaries(ExprResult SubExpr) { +ExprResult +Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) { if (SubExpr.isInvalid()) return ExprError(); - - return Owned(MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs<Expr>())); + + return Owned(MaybeCreateExprWithCleanups(SubExpr.take())); } -FullExpr Sema::CreateFullExpr(Expr *SubExpr) { +Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { + assert(SubStmt && "sub statement can't be null!"); + unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; assert(ExprTemporaries.size() >= FirstTemporary); - - unsigned NumTemporaries = ExprTemporaries.size() - FirstTemporary; - CXXTemporary **Temporaries = - NumTemporaries == 0 ? 0 : &ExprTemporaries[FirstTemporary]; - - FullExpr E = FullExpr::Create(Context, SubExpr, Temporaries, NumTemporaries); - - ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary, - ExprTemporaries.end()); - - return E; + if (ExprTemporaries.size() == FirstTemporary) + return SubStmt; + + // FIXME: In order to attach the temporaries, wrap the statement into + // a StmtExpr; currently this is only used for asm statements. + // This is hacky, either create a new CXXStmtWithTemporaries statement or + // a new AsmStmtWithTemporaries. + CompoundStmt *CompStmt = new (Context) CompoundStmt(Context, &SubStmt, 1, + SourceLocation(), + SourceLocation()); + Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), + SourceLocation()); + return MaybeCreateExprWithCleanups(E); } ExprResult @@ -2706,7 +3498,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, if (OpKind == tok::arrow) if (const PointerType *Ptr = BaseType->getAs<PointerType>()) BaseType = Ptr->getPointeeType(); - + ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Owned(Base); @@ -2720,7 +3512,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, llvm::SmallPtrSet<CanQualType,8> CTypes; llvm::SmallVector<SourceLocation, 8> Locations; CTypes.insert(Context.getCanonicalType(BaseType)); - + while (BaseType->isRecordType()) { Result = BuildOverloadedArrowExpr(S, Base, OpLoc); if (Result.isInvalid()) @@ -2760,10 +3552,10 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, // The object type must be complete (or dependent). if (!BaseType->isDependentType() && - RequireCompleteType(OpLoc, BaseType, + RequireCompleteType(OpLoc, BaseType, PDiag(diag::err_incomplete_member_access))) return ExprError(); - + // 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 expression is of a class @@ -2779,12 +3571,11 @@ ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, Diag(MemExpr->getLocStart(), diag::err_dtor_expr_without_call) << isa<CXXPseudoDestructorExpr>(MemExpr) << FixItHint::CreateInsertion(ExpectedLParenLoc, "()"); - + return ActOnCallExpr(/*Scope*/ 0, MemExpr, /*LPLoc*/ ExpectedLParenLoc, MultiExprArg(), - /*CommaLocs*/ 0, /*RPLoc*/ ExpectedLParenLoc); } @@ -2798,11 +3589,11 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, PseudoDestructorTypeStorage Destructed, bool HasTrailingLParen) { TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo(); - + // C++ [expr.pseudo]p2: - // The left-hand side of the dot operator shall be of scalar type. The + // 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. - // This scalar type is the object type. + // This scalar type is the object type. QualType ObjectType = Base->getType(); if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) { @@ -2814,11 +3605,11 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, << FixItHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); - + OpKind = tok::period; } } - + if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) { Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) << ObjectType << Base->getSourceRange(); @@ -2826,7 +3617,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, } // C++ [expr.pseudo]p2: - // [...] The cv-unqualified versions of the object type and of the type + // [...] The cv-unqualified versions of the object type and of the type // designated by the pseudo-destructor-name shall be the same type. if (DestructedTypeInfo) { QualType DestructedType = DestructedTypeInfo->getType(); @@ -2837,7 +3628,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); - + // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, @@ -2845,29 +3636,29 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } } - + // C++ [expr.pseudo]p2: // [...] Furthermore, the two type-names in a pseudo-destructor-name of the // form // - // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name + // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name // // shall designate the same scalar type. if (ScopeTypeInfo) { QualType ScopeType = ScopeTypeInfo->getType(); if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(ScopeType, ObjectType)) { - + Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(), diag::err_pseudo_dtor_type_mismatch) << ObjectType << ScopeType << Base->getSourceRange() << ScopeTypeInfo->getTypeLoc().getLocalSourceRange(); - + ScopeType = QualType(); ScopeTypeInfo = 0; } } - + Expr *Result = new (Context) CXXPseudoDestructorExpr(Context, Base, OpKind == tok::arrow, OpLoc, @@ -2876,10 +3667,10 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, CCLoc, TildeLoc, Destructed); - + if (HasTrailingLParen) return Owned(Result); - + return DiagnoseDtorReference(Destructed.getLocation(), Result); } @@ -2900,9 +3691,9 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, "Invalid second type name in pseudo-destructor"); // C++ [expr.pseudo]p2: - // The left-hand side of the dot operator shall be of scalar type. The + // 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. - // This scalar type is the object type. + // This scalar type is the object type. QualType ObjectType = Base->getType(); if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) { @@ -2914,7 +3705,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, << FixItHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); - + OpKind = tok::period; } } @@ -2928,32 +3719,32 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, else if (ObjectType->isDependentType()) ObjectTypePtrForLookup = ParsedType::make(Context.DependentTy); } - - // Convert the name of the type being destructed (following the ~) into a + + // Convert the name of the type being destructed (following the ~) into a // type (with source-location information). QualType DestructedType; TypeSourceInfo *DestructedTypeInfo = 0; PseudoDestructorTypeStorage Destructed; if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { - ParsedType T = getTypeName(*SecondTypeName.Identifier, + ParsedType T = getTypeName(*SecondTypeName.Identifier, SecondTypeName.StartLocation, - S, &SS, true, ObjectTypePtrForLookup); - if (!T && + S, &SS, true, false, ObjectTypePtrForLookup); + if (!T && ((SS.isSet() && !computeDeclContext(SS, false)) || (!SS.isSet() && ObjectType->isDependentType()))) { - // The name of the type being destroyed is a dependent name, and we + // The name of the type being destroyed is a dependent name, and we // couldn't find anything useful in scope. Just store the identifier and // it's location, and we'll perform (qualified) name lookup again at // template instantiation time. Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier, SecondTypeName.StartLocation); } else if (!T) { - Diag(SecondTypeName.StartLocation, + Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << SecondTypeName.Identifier << ObjectType; if (isSFINAEContext()) return ExprError(); - + // Recover by assuming we had the right type all along. DestructedType = ObjectType; } else @@ -2975,8 +3766,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, } else DestructedType = GetTypeFromParser(T.get(), &DestructedTypeInfo); } - - // If we've performed some kind of recovery, (re-)build the type source + + // If we've performed some kind of recovery, (re-)build the type source // information. if (!DestructedType.isNull()) { if (!DestructedTypeInfo) @@ -2984,24 +3775,24 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SecondTypeName.StartLocation); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } - + // Convert the name of the scope type (the type prior to '::') into a type. TypeSourceInfo *ScopeTypeInfo = 0; QualType ScopeType; - if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || + if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || FirstTypeName.Identifier) { if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { - ParsedType T = getTypeName(*FirstTypeName.Identifier, + ParsedType T = getTypeName(*FirstTypeName.Identifier, FirstTypeName.StartLocation, - S, &SS, false, ObjectTypePtrForLookup); + S, &SS, false, false, ObjectTypePtrForLookup); if (!T) { - Diag(FirstTypeName.StartLocation, + Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << FirstTypeName.Identifier << ObjectType; - + if (isSFINAEContext()) return ExprError(); - + // Just drop this type. It's unnecessary anyway. ScopeType = QualType(); } else @@ -3021,39 +3812,100 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, // Recover by dropping this type. ScopeType = QualType(); } else - ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); + ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); } } - + if (!ScopeType.isNull() && !ScopeTypeInfo) ScopeTypeInfo = Context.getTrivialTypeSourceInfo(ScopeType, FirstTypeName.StartLocation); - + return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, SS, ScopeTypeInfo, CCLoc, TildeLoc, Destructed, HasTrailingLParen); } -CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, - NamedDecl *FoundDecl, - CXXMethodDecl *Method) { +ExprResult Sema::BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, + CXXMethodDecl *Method) { if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, FoundDecl, Method)) - assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?"); + return true; - MemberExpr *ME = + MemberExpr *ME = new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, - SourceLocation(), Method->getType()); - QualType ResultType = Method->getCallResultType(); + SourceLocation(), Method->getType(), + VK_RValue, OK_Ordinary); + QualType ResultType = Method->getResultType(); + ExprValueKind VK = Expr::getValueKindForType(ResultType); + ResultType = ResultType.getNonLValueExprType(Context); + MarkDeclarationReferenced(Exp->getLocStart(), Method); CXXMemberCallExpr *CE = - new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, + new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, VK, Exp->getLocEnd()); return CE; } +ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, + SourceLocation RParen) { + return Owned(new (Context) CXXNoexceptExpr(Context.BoolTy, Operand, + Operand->CanThrow(Context), + KeyLoc, RParen)); +} + +ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, + Expr *Operand, SourceLocation RParen) { + return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen); +} + +/// Perform the conversions required for an expression used in a +/// context that ignores the result. +void Sema::IgnoredValueConversions(Expr *&E) { + // C99 6.3.2.1: + // [Except in specific positions,] an lvalue that does not have + // array type is converted to the value stored in the + // designated object (and is no longer an lvalue). + if (E->isRValue()) return; + + // We always want to do this on ObjC property references. + if (E->getObjectKind() == OK_ObjCProperty) { + ConvertPropertyForRValue(E); + if (E->isRValue()) return; + } + + // Otherwise, this rule does not apply in C++, at least not for the moment. + if (getLangOptions().CPlusPlus) return; + + // GCC seems to also exclude expressions of incomplete enum type. + if (const EnumType *T = E->getType()->getAs<EnumType>()) { + if (!T->getDecl()->isComplete()) { + // FIXME: stupid workaround for a codegen bug! + ImpCastExprToType(E, Context.VoidTy, CK_ToVoid); + return; + } + } + + DefaultFunctionArrayLvalueConversion(E); + if (!E->getType()->isVoidType()) + RequireCompleteType(E->getExprLoc(), E->getType(), + diag::err_incomplete_type); +} + ExprResult Sema::ActOnFinishFullExpr(Expr *FullExpr) { - if (!FullExpr) return ExprError(); - return MaybeCreateCXXExprWithTemporaries(FullExpr); + if (!FullExpr) + return ExprError(); + + if (DiagnoseUnexpandedParameterPack(FullExpr)) + return ExprError(); + + IgnoredValueConversions(FullExpr); + CheckImplicitConversions(FullExpr); + return MaybeCreateExprWithCleanups(FullExpr); +} + +StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { + if (!FullStmt) return StmtError(); + + return MaybeCreateStmtWithCleanups(FullStmt); } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index b56159c..4d03b06 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -14,6 +14,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Initialization.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -23,6 +24,7 @@ #include "clang/Lex/Preprocessor.h" using namespace clang; +using namespace sema; ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, Expr **strings, @@ -77,7 +79,14 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, if (!Ty.isNull()) { Ty = Context.getObjCObjectPointerType(Ty); } else if (getLangOptions().NoConstantCFStrings) { - IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString"); + IdentifierInfo *NSIdent=0; + std::string StringClass(getLangOptions().ObjCConstantStringClass); + + if (StringClass.empty()) + NSIdent = &Context.Idents.get("NSConstantString"); + else + NSIdent = &Context.Idents.get(StringClass); + NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0], LookupOrdinaryName); if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { @@ -188,11 +197,49 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc); } +/// Try to capture an implicit reference to 'self'. +ObjCMethodDecl *Sema::tryCaptureObjCSelf() { + // Ignore block scopes: we can capture through them. + DeclContext *DC = CurContext; + while (true) { + if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext(); + else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext(); + else break; + } + + // If we're not in an ObjC method, error out. Note that, unlike the + // C++ case, we don't require an instance method --- class methods + // still have a 'self', and we really do still need to capture it! + ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(DC); + if (!method) + return 0; + + ImplicitParamDecl *self = method->getSelfDecl(); + assert(self && "capturing 'self' in non-definition?"); + + // Mark that we're closing on 'this' in all the block scopes, if applicable. + for (unsigned idx = FunctionScopes.size() - 1; + isa<BlockScopeInfo>(FunctionScopes[idx]); + --idx) { + BlockScopeInfo *blockScope = cast<BlockScopeInfo>(FunctionScopes[idx]); + unsigned &captureIndex = blockScope->CaptureMap[self]; + if (captureIndex) break; + + bool nested = isa<BlockScopeInfo>(FunctionScopes[idx-1]); + blockScope->Captures.push_back( + BlockDecl::Capture(self, /*byref*/ false, nested, /*copy*/ 0)); + captureIndex = blockScope->Captures.size(); // +1 + } + + return method; +} + + bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Selector Sel, ObjCMethodDecl *Method, bool isClassMessage, SourceLocation lbrac, SourceLocation rbrac, - QualType &ReturnType) { + QualType &ReturnType, ExprValueKind &VK) { if (!Method) { // Apply default argument promotion as for (C99 6.5.2.2p6). for (unsigned i = 0; i != NumArgs; i++) { @@ -207,10 +254,12 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Diag(lbrac, DiagID) << Sel << isClassMessage << SourceRange(lbrac, rbrac); ReturnType = Context.getObjCIdType(); + VK = VK_RValue; return false; } ReturnType = Method->getSendResultType(); + VK = Expr::getValueKindForType(Method->getResultType()); unsigned NumNamedArgs = Sel.getNumArgs(); // Method might have more arguments than selector indicates. This is due @@ -219,8 +268,8 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, NumNamedArgs = Method->param_size(); // FIXME. This need be cleaned up. if (NumArgs < NumNamedArgs) { - Diag(lbrac, diag::err_typecheck_call_too_few_args) << 2 - << NumNamedArgs << NumArgs; + Diag(lbrac, diag::err_typecheck_call_too_few_args) + << 2 << NumNamedArgs << NumArgs; return false; } @@ -241,10 +290,9 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, << argExpr->getSourceRange())) return true; - InitializedEntity Entity = InitializedEntity::InitializeParameter(Param); - ExprResult ArgE = PerformCopyInitialization(Entity, - SourceLocation(), - Owned(argExpr->Retain())); + InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, + Param); + ExprResult ArgE = PerformCopyInitialization(Entity, lbrac, Owned(argExpr)); if (ArgE.isInvalid()) IsError = true; else @@ -276,6 +324,9 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, } bool Sema::isSelfExpr(Expr *RExpr) { + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RExpr)) + if (ICE->getCastKind() == CK_LValueToRValue) + RExpr = ICE->getSubExpr(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RExpr)) if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self")) return true; @@ -335,11 +386,19 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel, ExprResult Sema:: HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Expr *BaseExpr, DeclarationName MemberName, - SourceLocation MemberLoc) { + SourceLocation MemberLoc, + SourceLocation SuperLoc, QualType SuperType, + bool Super) { const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); ObjCInterfaceDecl *IFace = IFaceT->getDecl(); IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + if (IFace->isForwardDecl()) { + Diag(MemberLoc, diag::err_property_not_found_forward_class) + << MemberName << QualType(OPT, 0); + Diag(IFace->getLocation(), diag::note_forward_class); + return ExprError(); + } // Search for a declared property first. if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { // Check whether we can reference this property. @@ -349,9 +408,17 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) - ResTy = Getter->getSendResultType(); - return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, - MemberLoc, BaseExpr)); + ResTy = Getter->getResultType(); + + if (Super) + return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, + VK_LValue, OK_ObjCProperty, + MemberLoc, + SuperLoc, SuperType)); + else + return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, + VK_LValue, OK_ObjCProperty, + MemberLoc, BaseExpr)); } // Check protocols on qualified interfaces. for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), @@ -360,9 +427,18 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); - - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), - MemberLoc, BaseExpr)); + if (Super) + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + VK_LValue, + OK_ObjCProperty, + MemberLoc, + SuperLoc, SuperType)); + else + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + VK_LValue, + OK_ObjCProperty, + MemberLoc, + BaseExpr)); } // If that failed, look for an "implicit" property by seeing if the nullary // selector is implemented. @@ -375,7 +451,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // If this reference is in an @implementation, check for 'private' methods. if (!Getter) - Getter = IFace->lookupPrivateInstanceMethod(Sel); + Getter = IFace->lookupPrivateMethod(Sel); // Look through local category implementations associated with the class. if (!Getter) @@ -394,7 +470,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (!Setter) { // If this reference is in an @implementation, also check for 'private' // methods. - Setter = IFace->lookupPrivateInstanceMethod(SetterSel); + Setter = IFace->lookupPrivateMethod(SetterSel); } // Look through local category implementations associated with the class. if (!Setter) @@ -403,11 +479,31 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); - if (Getter) { + if (Getter || Setter) { QualType PType; - PType = Getter->getSendResultType(); - return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, - Setter, MemberLoc, BaseExpr)); + if (Getter) + PType = Getter->getSendResultType(); + else { + ParmVarDecl *ArgDecl = *Setter->param_begin(); + PType = ArgDecl->getType(); + } + + ExprValueKind VK = VK_LValue; + ExprObjectKind OK = OK_ObjCProperty; + if (!getLangOptions().CPlusPlus && !PType.hasQualifiers() && + PType->isVoidType()) + VK = VK_RValue, OK = OK_Ordinary; + + if (Super) + return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, + PType, VK, OK, + MemberLoc, + SuperLoc, SuperType)); + else + return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, + PType, VK, OK, + MemberLoc, BaseExpr)); + } // Attempt to correct for typos in property names. @@ -421,14 +517,31 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); Diag(Property->getLocation(), diag::note_previous_decl) << Property->getDeclName(); - return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc); + return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc, + SuperLoc, SuperType, Super); + } + ObjCInterfaceDecl *ClassDeclared; + if (ObjCIvarDecl *Ivar = + IFace->lookupInstanceVariable(Member, ClassDeclared)) { + QualType T = Ivar->getType(); + if (const ObjCObjectPointerType * OBJPT = + T->getAsObjCInterfacePointerType()) { + const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType(); + if (ObjCInterfaceDecl *IFace = IFaceT->getDecl()) + if (IFace->isForwardDecl()) { + Diag(MemberLoc, diag::err_property_not_as_forward_class) + << MemberName << IFace; + Diag(IFace->getLocation(), diag::note_forward_class); + return ExprError(); + } + } } Diag(MemberLoc, diag::err_property_not_found) << MemberName << QualType(OPT, 0); - if (Setter && !Getter) + if (Setter) Diag(Setter->getLocation(), diag::note_getter_unavailable) - << MemberName << BaseExpr->getSourceRange(); + << MemberName << BaseExpr->getSourceRange(); return ExprError(); } @@ -446,23 +559,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, if (IFace == 0) { // If the "receiver" is 'super' in a method, handle it as an expression-like // property reference. - if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) - if (receiverNamePtr->isStr("super")) { + if (receiverNamePtr->isStr("super")) { + if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) { if (CurMethod->isInstanceMethod()) { QualType T = Context.getObjCInterfaceType(CurMethod->getClassInterface()); T = Context.getObjCObjectPointerType(T); - Expr *SuperExpr = new (Context) ObjCSuperExpr(receiverNameLoc, T); return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(), - SuperExpr, &propertyName, - propertyNameLoc); + /*BaseExpr*/0, &propertyName, + propertyNameLoc, + receiverNameLoc, T, true); } // Otherwise, if this is a class method, try dispatching to our // superclass. IFace = CurMethod->getClassInterface()->getSuperClass(); } + } if (IFace == 0) { Diag(receiverNameLoc, diag::err_expected_ident_or_lparen); @@ -512,16 +626,25 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, if (Getter || Setter) { QualType PType; - if (Getter) + ExprValueKind VK = VK_LValue; + if (Getter) { PType = Getter->getSendResultType(); - else { + if (!getLangOptions().CPlusPlus && + !PType.hasQualifiers() && PType->isVoidType()) + VK = VK_RValue; + } else { for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(), E = Setter->param_end(); PI != E; ++PI) PType = (*PI)->getType(); + VK = VK_LValue; } - return Owned(new (Context) ObjCImplicitSetterGetterRefExpr( - Getter, PType, Setter, - propertyNameLoc, IFace, receiverNameLoc)); + + ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); + + return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, + PType, VK, OK, + propertyNameLoc, + receiverNameLoc, IFace)); } return ExprError(Diag(propertyNameLoc, diag::err_property_not_found) << &propertyName << Context.getObjCInterfaceType(IFace)); @@ -536,9 +659,10 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, ReceiverType = ParsedType(); // If the identifier is "super" and there is no trailing dot, we're - // messaging super. - if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope()) - return ObjCSuperMessage; + // messaging super. If the identifier is "super" and there is a + // trailing dot, it's an instance message. + if (IsSuper && S->isInObjcMethodScope()) + return HasTrailingDot? ObjCInstanceMessage : ObjCSuperMessage; LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); LookupName(Result, S); @@ -547,14 +671,15 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, case LookupResult::NotFound: // Normal name lookup didn't find anything. If we're in an // Objective-C method, look for ivars. If we find one, we're done! - // FIXME: This is a hack. Ivar lookup should be part of normal lookup. + // FIXME: This is a hack. Ivar lookup should be part of normal + // lookup. if (ObjCMethodDecl *Method = getCurMethodDecl()) { ObjCInterfaceDecl *ClassDeclared; if (Method->getClassInterface()->lookupInstanceVariable(Name, ClassDeclared)) return ObjCInstanceMessage; } - + // Break out; we'll perform typo correction below. break; @@ -566,6 +691,10 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, return ObjCInstanceMessage; case LookupResult::Found: { + // If the identifier is a class or not, and there is a trailing dot, + // it's an instance message. + if (HasTrailingDot) + return ObjCInstanceMessage; // We found something. If it's a type, then we have a class // message. Otherwise, it's an instance message. NamedDecl *ND = Result.getFoundDecl(); @@ -616,7 +745,6 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, Diag(NameLoc, diag::err_unknown_receiver_suggest) << Name << Corrected << FixItHint::CreateReplacement(SourceRange(NameLoc), "super"); - Name = Corrected.getAsIdentifierInfo(); return ObjCSuperMessage; } } @@ -626,14 +754,14 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, } ExprResult Sema::ActOnSuperMessage(Scope *S, - SourceLocation SuperLoc, - Selector Sel, - SourceLocation LBracLoc, - SourceLocation SelectorLoc, - SourceLocation RBracLoc, - MultiExprArg Args) { + SourceLocation SuperLoc, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { // Determine whether we are inside a method or not. - ObjCMethodDecl *Method = getCurMethodDecl(); + ObjCMethodDecl *Method = tryCaptureObjCSelf(); if (!Method) { Diag(SuperLoc, diag::err_invalid_receiver_to_message_super); return ExprError(); @@ -649,7 +777,8 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, ObjCInterfaceDecl *Super = Class->getSuperClass(); if (!Super) { // The current class does not have a superclass. - Diag(SuperLoc, diag::error_no_super_class) << Class->getIdentifier(); + Diag(SuperLoc, diag::error_root_class_cannot_use_super) + << Class->getIdentifier(); return ExprError(); } @@ -661,16 +790,16 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, QualType SuperTy = Context.getObjCInterfaceType(Super); SuperTy = Context.getObjCObjectPointerType(SuperTy); return BuildInstanceMessage(0, SuperTy, SuperLoc, - Sel, /*Method=*/0, LBracLoc, RBracLoc, - move(Args)); + Sel, /*Method=*/0, + LBracLoc, SelectorLoc, RBracLoc, move(Args)); } // Since we are in a class method, this is a class message to // the superclass. return BuildClassMessage(/*ReceiverTypeInfo=*/0, Context.getObjCInterfaceType(Super), - SuperLoc, Sel, /*Method=*/0, LBracLoc, RBracLoc, - move(Args)); + SuperLoc, Sel, /*Method=*/0, + LBracLoc, SelectorLoc, RBracLoc, move(Args)); } /// \brief Build an Objective-C class message expression. @@ -702,27 +831,34 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, /// /// \param Args The message arguments. ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, - QualType ReceiverType, - SourceLocation SuperLoc, - Selector Sel, - ObjCMethodDecl *Method, - SourceLocation LBracLoc, - SourceLocation RBracLoc, - MultiExprArg ArgsIn) { + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg ArgsIn) { + SourceLocation Loc = SuperLoc.isValid()? SuperLoc + : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin(); + if (LBracLoc.isInvalid()) { + Diag(Loc, diag::err_missing_open_square_message_send) + << FixItHint::CreateInsertion(Loc, "["); + LBracLoc = Loc; + } + if (ReceiverType->isDependentType()) { // If the receiver type is dependent, we can't type-check anything // at this point. Build a dependent expression. unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); assert(SuperLoc.isInvalid() && "Message to super with dependent type"); - return Owned(ObjCMessageExpr::Create(Context, ReceiverType, LBracLoc, - ReceiverTypeInfo, Sel, /*Method=*/0, + return Owned(ObjCMessageExpr::Create(Context, ReceiverType, + VK_RValue, LBracLoc, ReceiverTypeInfo, + Sel, SelectorLoc, /*Method=*/0, Args, NumArgs, RBracLoc)); } - SourceLocation Loc = SuperLoc.isValid()? SuperLoc - : ReceiverTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); - // Find the class to which we are sending this message. ObjCInterfaceDecl *Class = 0; const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>(); @@ -757,23 +893,30 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, // Check the argument types and determine the result type. QualType ReturnType; + ExprValueKind VK = VK_RValue; + unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true, - LBracLoc, RBracLoc, ReturnType)) + LBracLoc, RBracLoc, ReturnType, VK)) + return ExprError(); + + if (Method && !Method->getResultType()->isVoidType() && + RequireCompleteType(LBracLoc, Method->getResultType(), + diag::err_illegal_message_expr_incomplete_type)) return ExprError(); // Construct the appropriate ObjCMessageExpr. Expr *Result; if (SuperLoc.isValid()) - Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/false, - ReceiverType, Sel, Method, Args, - NumArgs, RBracLoc); + ReceiverType, Sel, SelectorLoc, + Method, Args, NumArgs, RBracLoc); else - Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, - ReceiverTypeInfo, Sel, Method, Args, - NumArgs, RBracLoc); + Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, + ReceiverTypeInfo, Sel, SelectorLoc, + Method, Args, NumArgs, RBracLoc); return MaybeBindToTemporary(Result); } @@ -781,12 +924,12 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). ExprResult Sema::ActOnClassMessage(Scope *S, - ParsedType Receiver, - Selector Sel, - SourceLocation LBracLoc, - SourceLocation SelectorLoc, - SourceLocation RBracLoc, - MultiExprArg Args) { + ParsedType Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { TypeSourceInfo *ReceiverTypeInfo; QualType ReceiverType = GetTypeFromParser(Receiver, &ReceiverTypeInfo); if (ReceiverType.isNull()) @@ -798,7 +941,7 @@ ExprResult Sema::ActOnClassMessage(Scope *S, return BuildClassMessage(ReceiverTypeInfo, ReceiverType, /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, - LBracLoc, RBracLoc, move(Args)); + LBracLoc, SelectorLoc, RBracLoc, move(Args)); } /// \brief Build an Objective-C instance message expression. @@ -830,13 +973,23 @@ ExprResult Sema::ActOnClassMessage(Scope *S, /// /// \param Args The message arguments. ExprResult Sema::BuildInstanceMessage(Expr *Receiver, - QualType ReceiverType, - SourceLocation SuperLoc, - Selector Sel, - ObjCMethodDecl *Method, - SourceLocation LBracLoc, - SourceLocation RBracLoc, - MultiExprArg ArgsIn) { + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg ArgsIn) { + // The location of the receiver. + SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); + + if (LBracLoc.isInvalid()) { + Diag(Loc, diag::err_missing_open_square_message_send) + << FixItHint::CreateInsertion(Loc, "["); + LBracLoc = Loc; + } + // If we have a receiver expression, perform appropriate promotions // and determine receiver type. if (Receiver) { @@ -847,9 +1000,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy, - LBracLoc, Receiver, Sel, - /*Method=*/0, Args, NumArgs, - RBracLoc)); + VK_RValue, LBracLoc, Receiver, Sel, + SelectorLoc, /*Method=*/0, + Args, NumArgs, RBracLoc)); } // If necessary, apply function/array conversion to the receiver. @@ -858,9 +1011,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, ReceiverType = Receiver->getType(); } - // The location of the receiver. - SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); - if (!Method) { // Handle messages to id. bool receiverIsId = ReceiverType->isObjCIdType(); @@ -946,6 +1096,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, break; } } + bool forwardClass = false; if (!Method) { // If we have implementations in scope, check "private" methods. Method = LookupPrivateInstanceMethod(Sel, ClassDecl); @@ -956,14 +1107,15 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // compatibility. FIXME: should we deviate?? if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); - if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) + SourceRange(LBracLoc, RBracLoc)); + forwardClass = OCIType->getInterfaceDecl()->isForwardDecl(); + if (Method && !forwardClass) Diag(Loc, diag::warn_maynot_respond) << OCIType->getInterfaceDecl()->getIdentifier() << Sel; } } } - if (Method && DiagnoseUseOfDecl(Method, Loc)) + if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass)) return ExprError(); } else if (!Context.getObjCIdType().isNull() && (ReceiverType->isPointerType() || @@ -975,9 +1127,13 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (ReceiverType->isPointerType()) ImpCastExprToType(Receiver, Context.getObjCIdType(), CK_BitCast); - else + else { + // TODO: specialized warning on null receivers? + bool IsNull = Receiver->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull); ImpCastExprToType(Receiver, Context.getObjCIdType(), - CK_IntegralToPointer); + IsNull ? CK_NullToPointer : CK_IntegralToPointer); + } ReceiverType = Receiver->getType(); } else if (getLangOptions().CPlusPlus && @@ -991,7 +1147,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, SuperLoc, Sel, Method, - LBracLoc, + LBracLoc, + SelectorLoc, RBracLoc, move(ArgsIn)); } else { @@ -1007,26 +1164,29 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); QualType ReturnType; - if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, false, - LBracLoc, RBracLoc, ReturnType)) + ExprValueKind VK = VK_RValue; + bool ClassMessage = (ReceiverType->isObjCClassType() || + ReceiverType->isObjCQualifiedClassType()); + if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, ClassMessage, + LBracLoc, RBracLoc, ReturnType, VK)) return ExprError(); - if (!ReturnType->isVoidType()) { - if (RequireCompleteType(LBracLoc, ReturnType, - diag::err_illegal_message_expr_incomplete_type)) - return ExprError(); - } + if (Method && !Method->getResultType()->isVoidType() && + RequireCompleteType(LBracLoc, Method->getResultType(), + diag::err_illegal_message_expr_incomplete_type)) + return ExprError(); // Construct the appropriate ObjCMessageExpr instance. Expr *Result; if (SuperLoc.isValid()) - Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true, - ReceiverType, Sel, Method, + ReceiverType, Sel, SelectorLoc, Method, Args, NumArgs, RBracLoc); else - Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, - Sel, Method, Args, NumArgs, RBracLoc); + Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, + Receiver, Sel, SelectorLoc, Method, + Args, NumArgs, RBracLoc); return MaybeBindToTemporary(Result); } @@ -1045,6 +1205,6 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S, return BuildInstanceMessage(Receiver, Receiver->getType(), /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, - LBracLoc, RBracLoc, move(Args)); + LBracLoc, SelectorLoc, RBracLoc, move(Args)); } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index a28fd7f..b9a6a57 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -11,8 +11,6 @@ // point is Sema::CheckInitList(), but all of the work is performed // within the InitListChecker class. // -// This file also implements Sema::CheckInitializerTypes. -// //===----------------------------------------------------------------------===// #include "clang/Sema/Designator.h" @@ -122,7 +120,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) { /// responsible for moving that Index forward as it consumes elements. /// /// Each Check* routine also has a StructuredList/StructuredIndex -/// arguments, which contains the current the "structured" (semantic) +/// arguments, which contains the current "structured" (semantic) /// initializer list and the index into that initializer list where we /// are copying initializers as we map them over to the semantic /// list. Once we have completed our recursive walk of the subobject @@ -231,11 +229,11 @@ public: void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity, - InitListExpr *ILE, + InitListExpr *ILE, bool &RequiresSecondPass) { SourceLocation Loc = ILE->getSourceRange().getBegin(); unsigned NumInits = ILE->getNumInits(); - InitializedEntity MemberEntity + InitializedEntity MemberEntity = InitializedEntity::InitializeMember(Field, &ParentEntity); if (Init >= NumInits || !ILE->getInit(Init)) { // FIXME: We probably don't need to handle references @@ -254,7 +252,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, hadError = true; return; } - + InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, 0, 0); @@ -263,14 +261,14 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, hadError = true; return; } - + ExprResult MemberInit = InitSeq.Perform(SemaRef, MemberEntity, Kind, MultiExprArg()); if (MemberInit.isInvalid()) { hadError = true; return; } - + if (hadError) { // Do nothing } else if (Init < NumInits) { @@ -286,14 +284,14 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, } } else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init))) - FillInValueInitializations(MemberEntity, InnerILE, - RequiresSecondPass); + FillInValueInitializations(MemberEntity, InnerILE, + RequiresSecondPass); } /// Recursively replaces NULL values within the given initializer list /// with expressions that perform value-initialization of the /// appropriate type. -void +void InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, InitListExpr *ILE, bool &RequiresSecondPass) { @@ -344,17 +342,17 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, ElementType = AType->getElementType(); if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) NumElements = CAType->getSize().getZExtValue(); - ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, + ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); } else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) { ElementType = VType->getElementType(); NumElements = VType->getNumElements(); - ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, + ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); } else ElementType = ILE->getType(); - + for (unsigned Init = 0; Init != NumElements; ++Init) { if (hadError) return; @@ -409,7 +407,7 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, unsigned newStructuredIndex = 0; FullyStructuredList = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange()); - CheckExplicitInitList(Entity, IL, T, newIndex, + CheckExplicitInitList(Entity, IL, T, newIndex, FullyStructuredList, newStructuredIndex, /*TopLevelObject=*/true); @@ -417,7 +415,7 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, bool RequiresSecondPass = false; FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass); if (RequiresSecondPass && !hadError) - FillInValueInitializations(Entity, FullyStructuredList, + FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass); } } @@ -482,7 +480,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, // Check the element types and build the structural subobject. unsigned StartIndex = Index; - CheckListElementTypes(Entity, ParentIList, T, + CheckListElementTypes(Entity, ParentIList, T, /*SubobjectIsDesignatorContext=*/false, Index, StructuredSubobjectInitList, StructuredSubobjectInitIndex, @@ -497,16 +495,16 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, = ParentIList->getInit(EndIndex)->getSourceRange().getEnd(); StructuredSubobjectInitList->setRBraceLoc(EndLoc); } - + // Warn about missing braces. if (T->isArrayType() || T->isRecordType()) { SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), diag::warn_missing_braces) << StructuredSubobjectInitList->getSourceRange() - << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(), + << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(), "{") << FixItHint::CreateInsertion(SemaRef.PP.getLocForEndOfToken( - StructuredSubobjectInitList->getLocEnd()), + StructuredSubobjectInitList->getLocEnd()), "}"); } } @@ -520,7 +518,7 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); SyntacticToSemantic[IList] = StructuredList; StructuredList->setSyntacticForm(IList); - CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, + CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, Index, StructuredList, StructuredIndex, TopLevelObject); QualType ExprTy = T.getNonLValueExprType(SemaRef.Context); IList->setType(ExprTy); @@ -585,7 +583,7 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, CheckScalarType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isVectorType()) { - CheckVectorType(Entity, IList, DeclType, Index, + CheckVectorType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isAggregateType()) { if (DeclType->isRecordType()) { @@ -598,7 +596,7 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, llvm::APSInt Zero( SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()), false); - CheckArrayType(Entity, IList, DeclType, Zero, + CheckArrayType(Entity, IList, DeclType, Zero, SubobjectIsDesignatorContext, Index, StructuredList, StructuredIndex); } else @@ -658,7 +656,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, UpdateStructuredListElement(StructuredList, StructuredIndex, Str); ++Index; } else if (ElemType->isScalarType()) { - CheckScalarType(Entity, IList, ElemType, Index, + CheckScalarType(Entity, IList, ElemType, Index, StructuredList, StructuredIndex); } else if (ElemType->isReferenceType()) { CheckReferenceType(Entity, IList, ElemType, Index, @@ -672,17 +670,17 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // member, the member is initialized. [...] // FIXME: Better EqualLoc? - InitializationKind Kind = + InitializationKind Kind = InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation()); InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1); - + if (Seq) { - ExprResult Result = + ExprResult Result = Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1)); if (Result.isInvalid()) hadError = true; - - UpdateStructuredListElement(StructuredList, StructuredIndex, + + UpdateStructuredListElement(StructuredList, StructuredIndex, Result.takeAs<Expr>()); ++Index; return; @@ -699,7 +697,9 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // initial value of the object, including unnamed members, is // that of the expression. if ((ElemType->isRecordType() || ElemType->isVectorType()) && - SemaRef.Context.hasSameUnqualifiedType(expr->getType(), ElemType)) { + SemaRef.CheckSingleAssignmentConstraints(ElemType, expr) + == Sema::Compatible) { + SemaRef.DefaultFunctionArrayLvalueConversion(expr); UpdateStructuredListElement(StructuredList, StructuredIndex, expr); ++Index; return; @@ -721,9 +721,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, } else { // We cannot initialize this element, so let // PerformCopyInitialization produce the appropriate diagnostic. - SemaRef.PerformCopyInitialization(Entity, SourceLocation(), + SemaRef.PerformCopyInitialization(Entity, SourceLocation(), SemaRef.Owned(expr)); - IList->setInit(Index, 0); hadError = true; ++Index; ++StructuredIndex; @@ -736,48 +735,7 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { - if (Index < IList->getNumInits()) { - Expr *expr = IList->getInit(Index); - if (InitListExpr *SubIList = dyn_cast<InitListExpr>(expr)) { - SemaRef.Diag(SubIList->getLocStart(), - diag::warn_many_braces_around_scalar_init) - << SubIList->getSourceRange(); - - CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList, - StructuredIndex); - return; - } else if (isa<DesignatedInitExpr>(expr)) { - SemaRef.Diag(expr->getSourceRange().getBegin(), - diag::err_designator_for_scalar_init) - << DeclType << expr->getSourceRange(); - hadError = true; - ++Index; - ++StructuredIndex; - return; - } - - ExprResult Result = - SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), - SemaRef.Owned(expr)); - - Expr *ResultExpr = 0; - - if (Result.isInvalid()) - hadError = true; // types weren't compatible. - else { - ResultExpr = Result.takeAs<Expr>(); - - if (ResultExpr != expr) { - // The type was promoted, update initializer list. - IList->setInit(Index, ResultExpr); - } - } - if (hadError) - ++StructuredIndex; - else - UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr); - ++Index; - } else { + if (Index >= IList->getNumInits()) { SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer) << IList->getSourceRange(); hadError = true; @@ -785,6 +743,47 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, ++StructuredIndex; return; } + + Expr *expr = IList->getInit(Index); + if (InitListExpr *SubIList = dyn_cast<InitListExpr>(expr)) { + SemaRef.Diag(SubIList->getLocStart(), + diag::warn_many_braces_around_scalar_init) + << SubIList->getSourceRange(); + + CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList, + StructuredIndex); + return; + } else if (isa<DesignatedInitExpr>(expr)) { + SemaRef.Diag(expr->getSourceRange().getBegin(), + diag::err_designator_for_scalar_init) + << DeclType << expr->getSourceRange(); + hadError = true; + ++Index; + ++StructuredIndex; + return; + } + + ExprResult Result = + SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), + SemaRef.Owned(expr)); + + Expr *ResultExpr = 0; + + if (Result.isInvalid()) + hadError = true; // types weren't compatible. + else { + ResultExpr = Result.takeAs<Expr>(); + + if (ResultExpr != expr) { + // The type was promoted, update initializer list. + IList->setInit(Index, ResultExpr); + } + } + if (hadError) + ++StructuredIndex; + else + UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr); + ++Index; } void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, @@ -839,66 +838,95 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { - if (Index < IList->getNumInits()) { - const VectorType *VT = DeclType->getAs<VectorType>(); - unsigned maxElements = VT->getNumElements(); - unsigned numEltsInit = 0; - QualType elementType = VT->getElementType(); - - if (!SemaRef.getLangOptions().OpenCL) { - InitializedEntity ElementEntity = - InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); - - 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; - - ElementEntity.setElementIndex(Index); - CheckSubElementType(ElementEntity, IList, elementType, Index, - StructuredList, StructuredIndex); - } - } else { - InitializedEntity ElementEntity = - InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); - - // 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; - - ElementEntity.setElementIndex(Index); - - QualType IType = IList->getInit(Index)->getType(); - if (!IType->isVectorType()) { - CheckSubElementType(ElementEntity, IList, elementType, Index, - StructuredList, StructuredIndex); - ++numEltsInit; - } else { - QualType VecType; - const VectorType *IVT = IType->getAs<VectorType>(); - unsigned numIElts = IVT->getNumElements(); - - if (IType->isExtVectorType()) - VecType = SemaRef.Context.getExtVectorType(elementType, numIElts); - else - VecType = SemaRef.Context.getVectorType(elementType, numIElts, - IVT->getAltiVecSpecific()); - CheckSubElementType(ElementEntity, IList, VecType, Index, - StructuredList, StructuredIndex); - numEltsInit += numIElts; + if (Index >= IList->getNumInits()) + return; + + const VectorType *VT = DeclType->getAs<VectorType>(); + unsigned maxElements = VT->getNumElements(); + unsigned numEltsInit = 0; + QualType elementType = VT->getElementType(); + + if (!SemaRef.getLangOptions().OpenCL) { + // If the initializing element is a vector, try to copy-initialize + // instead of breaking it apart (which is doomed to failure anyway). + Expr *Init = IList->getInit(Index); + if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) { + ExprResult Result = + SemaRef.PerformCopyInitialization(Entity, Init->getLocStart(), + SemaRef.Owned(Init)); + + Expr *ResultExpr = 0; + if (Result.isInvalid()) + hadError = true; // types weren't compatible. + else { + ResultExpr = Result.takeAs<Expr>(); + + if (ResultExpr != Init) { + // The type was promoted, update initializer list. + IList->setInit(Index, ResultExpr); } } + if (hadError) + ++StructuredIndex; + else + UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr); + ++Index; + return; } - // OpenCL requires all elements to be initialized. - if (numEltsInit != maxElements) - if (SemaRef.getLangOptions().OpenCL) - SemaRef.Diag(IList->getSourceRange().getBegin(), - diag::err_vector_incorrect_num_initializers) - << (numEltsInit < maxElements) << maxElements << numEltsInit; + InitializedEntity ElementEntity = + InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); + + 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; + + ElementEntity.setElementIndex(Index); + CheckSubElementType(ElementEntity, IList, elementType, Index, + StructuredList, StructuredIndex); + } + return; + } + + InitializedEntity ElementEntity = + InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); + + // 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; + + ElementEntity.setElementIndex(Index); + + QualType IType = IList->getInit(Index)->getType(); + if (!IType->isVectorType()) { + CheckSubElementType(ElementEntity, IList, elementType, Index, + StructuredList, StructuredIndex); + ++numEltsInit; + } else { + QualType VecType; + const VectorType *IVT = IType->getAs<VectorType>(); + unsigned numIElts = IVT->getNumElements(); + + if (IType->isExtVectorType()) + VecType = SemaRef.Context.getExtVectorType(elementType, numIElts); + else + VecType = SemaRef.Context.getVectorType(elementType, numIElts, + IVT->getVectorKind()); + CheckSubElementType(ElementEntity, IList, VecType, Index, + StructuredList, StructuredIndex); + numEltsInit += numIElts; + } } + + // OpenCL requires all elements to be initialized. + if (numEltsInit != maxElements) + if (SemaRef.getLangOptions().OpenCL) + SemaRef.Diag(IList->getSourceRange().getBegin(), + diag::err_vector_incorrect_num_initializers) + << (numEltsInit < maxElements) << maxElements << numEltsInit; } void InitListChecker::CheckArrayType(const InitializedEntity &Entity, @@ -945,7 +973,7 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, if (const ConstantArrayType *CAT = SemaRef.Context.getAsConstantArrayType(DeclType)) { maxElements = CAT->getSize(); - elementIndex.extOrTrunc(maxElements.getBitWidth()); + elementIndex = elementIndex.extOrTrunc(maxElements.getBitWidth()); elementIndex.setIsUnsigned(maxElements.isUnsigned()); maxElementsKnown = true; } @@ -972,9 +1000,9 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, } if (elementIndex.getBitWidth() > maxElements.getBitWidth()) - maxElements.extend(elementIndex.getBitWidth()); + maxElements = maxElements.extend(elementIndex.getBitWidth()); else if (elementIndex.getBitWidth() < maxElements.getBitWidth()) - elementIndex.extend(maxElements.getBitWidth()); + elementIndex = elementIndex.extend(maxElements.getBitWidth()); elementIndex.setIsUnsigned(maxElements.isUnsigned()); // If the array is of incomplete type, keep track of the number of @@ -991,7 +1019,7 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, break; InitializedEntity ElementEntity = - InitializedEntity::InitializeElement(SemaRef.Context, StructuredIndex, + InitializedEntity::InitializeElement(SemaRef.Context, StructuredIndex, Entity); // Check this element. CheckSubElementType(ElementEntity, IList, elementType, Index, @@ -1118,7 +1146,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } // Emit warnings for missing struct field initializers. - if (InitializedSomething && CheckForMissingFields && Field != FieldEnd && + if (InitializedSomething && CheckForMissingFields && Field != FieldEnd && !Field->getType()->isIncompleteArrayType() && !DeclType->isUnionType()) { // It is possible we have one or more unnamed bitfields remaining. // Find first (if any) named field and emit warning. @@ -1158,12 +1186,12 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, InitializedEntity MemberEntity = InitializedEntity::InitializeMember(*Field, &Entity); - + if (isa<InitListExpr>(IList->getInit(Index))) - CheckSubElementType(MemberEntity, IList, Field->getType(), Index, + CheckSubElementType(MemberEntity, IList, Field->getType(), Index, StructuredList, StructuredIndex); else - CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index, + CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index, StructuredList, StructuredIndex); } @@ -1171,34 +1199,25 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, /// anonymous struct or union into a series of field designators that /// refers to the field within the appropriate subobject. /// -/// Field/FieldIndex will be updated to point to the (new) -/// currently-designated field. static void ExpandAnonymousFieldDesignator(Sema &SemaRef, DesignatedInitExpr *DIE, unsigned DesigIdx, - FieldDecl *Field, - RecordDecl::field_iterator &FieldIter, - unsigned &FieldIndex) { + IndirectFieldDecl *IndirectField) { typedef DesignatedInitExpr::Designator Designator; - // Build the path from the current object to the member of the - // 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) + for (IndirectFieldDecl::chain_iterator PI = IndirectField->chain_begin(), + PE = IndirectField->chain_end(); PI != PE; ++PI) { + if (PI + 1 == PE) Replacements.push_back(Designator((IdentifierInfo *)0, DIE->getDesignator(DesigIdx)->getDotLoc(), DIE->getDesignator(DesigIdx)->getFieldLoc())); else Replacements.push_back(Designator((IdentifierInfo *)0, SourceLocation(), SourceLocation())); - Replacements.back().setField(*FI); + assert(isa<FieldDecl>(*PI)); + Replacements.back().setField(cast<FieldDecl>(*PI)); } // Expand the current designator into the set of replacement @@ -1206,23 +1225,20 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, // member of the anonymous struct/union is actually stored. DIE->ExpandDesignator(SemaRef.Context, DesigIdx, &Replacements[0], &Replacements[0] + Replacements.size()); +} - // Update FieldIter/FieldIndex; - RecordDecl *Record = cast<RecordDecl>(Path.back()->getDeclContext()); - FieldIter = Record->field_begin(); - FieldIndex = 0; - for (RecordDecl::field_iterator FEnd = Record->field_end(); - FieldIter != FEnd; ++FieldIter) { - if (FieldIter->isUnnamedBitfield()) - continue; - - if (*FieldIter == Path.back()) - return; - - ++FieldIndex; +/// \brief Given an implicit anonymous field, search the IndirectField that +/// corresponds to FieldName. +static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField, + IdentifierInfo *FieldName) { + assert(AnonField->isAnonymousStructOrUnion()); + Decl *NextDecl = AnonField->getNextDeclInContext(); + while (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(NextDecl)) { + if (FieldName && FieldName == IF->getAnonField()->getIdentifier()) + return IF; + NextDecl = NextDecl->getNextDeclInContext(); } - - assert(false && "Unable to find anonymous struct/union field"); + return 0; } /// @brief Check the well-formedness of a C99 designated initializer. @@ -1343,7 +1359,19 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, if (Field->isUnnamedBitfield()) continue; - if (KnownField == *Field || Field->getIdentifier() == FieldName) + // If we find a field representing an anonymous field, look in the + // IndirectFieldDecl that follow for the designated initializer. + if (!KnownField && Field->isAnonymousStructOrUnion()) { + if (IndirectFieldDecl *IF = + FindIndirectFieldDesignator(*Field, FieldName)) { + ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IF); + D = DIE->getDesignator(DesigIdx); + break; + } + } + if (KnownField && KnownField == *Field) + break; + if (FieldName && FieldName == Field->getIdentifier()) break; ++FieldIndex; @@ -1360,19 +1388,19 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, if (Lookup.first == Lookup.second) { // Name lookup didn't find anything. Determine whether this // was a typo for another field name. - LookupResult R(SemaRef, FieldName, D->getFieldLoc(), + LookupResult R(SemaRef, FieldName, D->getFieldLoc(), Sema::LookupMemberName); if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false, - Sema::CTC_NoKeywords) && + Sema::CTC_NoKeywords) && (ReplacementField = R.getAsSingle<FieldDecl>()) && ReplacementField->getDeclContext()->getRedeclContext() ->Equals(RT->getDecl())) { - SemaRef.Diag(D->getFieldLoc(), + SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown_suggest) << FieldName << CurrentObjectType << R.getLookupName() << FixItHint::CreateReplacement(D->getFieldLoc(), R.getLookupName().getAsString()); - SemaRef.Diag(ReplacementField->getLocation(), + SemaRef.Diag(ReplacementField->getLocation(), diag::note_previous_decl) << ReplacementField->getDeclName(); } else { @@ -1381,9 +1409,6 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, ++Index; return true; } - } else if (!KnownField) { - // Determine whether we found a field at all. - ReplacementField = dyn_cast<FieldDecl>(*Lookup.first); } if (!ReplacementField) { @@ -1396,16 +1421,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, return true; } - if (!KnownField && - cast<RecordDecl>((ReplacementField)->getDeclContext()) - ->isAnonymousStructOrUnion()) { - // Handle an field designator that refers to a member of an - // anonymous struct or union. - ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, - ReplacementField, - Field, FieldIndex); - D = DIE->getDesignator(DesigIdx); - } else if (!KnownField) { + if (!KnownField) { // The replacement field comes from typo correction; find it // in the list of fields. FieldIndex = 0; @@ -1414,19 +1430,13 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, if (Field->isUnnamedBitfield()) continue; - if (ReplacementField == *Field || + if (ReplacementField == *Field || Field->getIdentifier() == ReplacementField->getIdentifier()) break; ++FieldIndex; } } - } else if (!KnownField && - cast<RecordDecl>((*Field)->getDeclContext()) - ->isAnonymousStructOrUnion()) { - ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, *Field, - Field, FieldIndex); - D = DIE->getDesignator(DesigIdx); } // All of the fields of a union are located at the same place in @@ -1461,7 +1471,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, Invalid = true; } - if (!hadError && !isa<InitListExpr>(DIE->getInit())) { + if (!hadError && !isa<InitListExpr>(DIE->getInit()) && + !isa<StringLiteral>(DIE->getInit())) { // The initializer is not an initializer list. SemaRef.Diag(DIE->getInit()->getSourceRange().getBegin(), diag::err_flexible_array_init_needs_braces) @@ -1511,11 +1522,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Recurse to check later designated subobjects. QualType FieldType = (*Field)->getType(); unsigned newStructuredIndex = FieldIndex; - + InitializedEntity MemberEntity = InitializedEntity::InitializeMember(*Field, &Entity); - if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1, - FieldType, 0, 0, Index, + if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1, + FieldType, 0, 0, Index, StructuredList, newStructuredIndex, true, false)) return true; @@ -1544,7 +1555,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Check the remaining fields within this class/struct/union subobject. bool prevHadError = hadError; - + CheckStructUnionTypes(Entity, IList, CurrentObjectType, Field, false, Index, StructuredList, FieldIndex); return hadError && !prevHadError; @@ -1582,22 +1593,29 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, } else { assert(D->isArrayRangeDesignator() && "Need array-range designator"); - DesignatedStartIndex = DIE->getArrayRangeStart(*D)->EvaluateAsInt(SemaRef.Context); DesignatedEndIndex = DIE->getArrayRangeEnd(*D)->EvaluateAsInt(SemaRef.Context); IndexExpr = DIE->getArrayRangeEnd(*D); - if (DesignatedStartIndex.getZExtValue() !=DesignatedEndIndex.getZExtValue()) + // Codegen can't handle evaluating array range designators that have side + // effects, because we replicate the AST value for each initialized element. + // As such, set the sawArrayRangeDesignator() bit if we initialize multiple + // elements with something that has a side effect, so codegen can emit an + // "error unsupported" error instead of miscompiling the app. + if (DesignatedStartIndex.getZExtValue()!=DesignatedEndIndex.getZExtValue()&& + DIE->getInit()->HasSideEffects(SemaRef.Context)) FullyStructuredList->sawArrayRangeDesignator(); } if (isa<ConstantArrayType>(AT)) { llvm::APSInt MaxElements(cast<ConstantArrayType>(AT)->getSize(), false); - DesignatedStartIndex.extOrTrunc(MaxElements.getBitWidth()); + DesignatedStartIndex + = DesignatedStartIndex.extOrTrunc(MaxElements.getBitWidth()); DesignatedStartIndex.setIsUnsigned(MaxElements.isUnsigned()); - DesignatedEndIndex.extOrTrunc(MaxElements.getBitWidth()); + DesignatedEndIndex + = DesignatedEndIndex.extOrTrunc(MaxElements.getBitWidth()); DesignatedEndIndex.setIsUnsigned(MaxElements.isUnsigned()); if (DesignatedEndIndex >= MaxElements) { SemaRef.Diag(IndexExpr->getSourceRange().getBegin(), @@ -1610,10 +1628,12 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, } else { // Make sure the bit-widths and signedness match. if (DesignatedStartIndex.getBitWidth() > DesignatedEndIndex.getBitWidth()) - DesignatedEndIndex.extend(DesignatedStartIndex.getBitWidth()); + DesignatedEndIndex + = DesignatedEndIndex.extend(DesignatedStartIndex.getBitWidth()); else if (DesignatedStartIndex.getBitWidth() < DesignatedEndIndex.getBitWidth()) - DesignatedStartIndex.extend(DesignatedEndIndex.getBitWidth()); + DesignatedStartIndex + = DesignatedStartIndex.extend(DesignatedEndIndex.getBitWidth()); DesignatedStartIndex.setIsUnsigned(true); DesignatedEndIndex.setIsUnsigned(true); } @@ -1630,7 +1650,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Move to the next designator unsigned ElementIndex = DesignatedStartIndex.getZExtValue(); unsigned OldIndex = Index; - + InitializedEntity ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); @@ -1638,10 +1658,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Recurse to check later designated subobjects. QualType ElementType = AT->getElementType(); Index = OldIndex; - + ElementEntity.setElementIndex(ElementIndex); - if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1, - ElementType, 0, 0, Index, + if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1, + ElementType, 0, 0, Index, StructuredList, ElementIndex, (DesignatedStartIndex == DesignatedEndIndex), false)) @@ -1666,7 +1686,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Check the remaining elements within this array subobject. bool prevHadError = hadError; - CheckArrayType(Entity, IList, CurrentObjectType, DesignatedStartIndex, + CheckArrayType(Entity, IList, CurrentObjectType, DesignatedStartIndex, /*SubobjectIsDesignatorContext=*/false, Index, StructuredList, ElementIndex); return hadError && !prevHadError; @@ -1812,9 +1832,9 @@ CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) { } ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, - SourceLocation Loc, - bool GNUSyntax, - ExprResult Init) { + SourceLocation Loc, + bool GNUSyntax, + ExprResult Init) { typedef DesignatedInitExpr::Designator ASTDesignator; bool Invalid = false; @@ -1865,9 +1885,9 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, if (StartDependent || EndDependent) { // Nothing to compute. } else if (StartValue.getBitWidth() > EndValue.getBitWidth()) - EndValue.extend(StartValue.getBitWidth()); + EndValue = EndValue.extend(StartValue.getBitWidth()); else if (StartValue.getBitWidth() < EndValue.getBitWidth()) - StartValue.extend(EndValue.getBitWidth()); + StartValue = StartValue.extend(EndValue.getBitWidth()); if (!StartDependent && !EndDependent && EndValue < StartValue) { Diag(D.getEllipsisLoc(), diag::err_array_designator_empty_range) @@ -1899,6 +1919,11 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, Designators.data(), Designators.size(), InitExpressions.data(), InitExpressions.size(), Loc, GNUSyntax, Init.takeAs<Expr>()); + + if (getLangOptions().CPlusPlus) + Diag(DIE->getLocStart(), diag::ext_designated_init) + << DIE->getSourceRange(); + return Owned(DIE); } @@ -1915,9 +1940,9 @@ bool Sema::CheckInitList(const InitializedEntity &Entity, // Initialization entity //===----------------------------------------------------------------------===// -InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, +InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, const InitializedEntity &Parent) - : Parent(&Parent), Index(Index) + : Parent(&Parent), Index(Index) { if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) { Kind = EK_ArrayElement; @@ -1928,7 +1953,7 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, } } -InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, +InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, CXXBaseSpecifier *Base, bool IsInheritedVirtualBase) { @@ -1937,7 +1962,7 @@ InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, Result.Base = reinterpret_cast<uintptr_t>(Base); if (IsInheritedVirtualBase) Result.Base |= 0x01; - + Result.Type = Base->getType(); return Result; } @@ -1963,7 +1988,7 @@ DeclarationName InitializedEntity::getName() const { case EK_BlockElement: return DeclarationName(); } - + // Silence GCC warning return DeclarationName(); } @@ -1985,7 +2010,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_BlockElement: return 0; } - + // Silence GCC warning return 0; } @@ -1995,7 +2020,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_Result: case EK_Exception: return LocAndNRVO.NRVO; - + case EK_Variable: case EK_Parameter: case EK_Member: @@ -2035,7 +2060,7 @@ void InitializationSequence::Step::Destroy() { case SK_StringInit: case SK_ObjCObjectConversion: break; - + case SK_ConversionSequence: delete ICS; } @@ -2048,7 +2073,7 @@ bool InitializationSequence::isDirectReferenceBinding() const { bool InitializationSequence::isAmbiguous() const { if (getKind() != FailedSequence) return false; - + switch (getFailureKind()) { case FK_TooManyInitsForReference: case FK_ArrayNeedsInitList: @@ -2066,13 +2091,13 @@ bool InitializationSequence::isAmbiguous() const { case FK_DefaultInitOfConst: case FK_Incomplete: return false; - + case FK_ReferenceInitOverloadFailed: case FK_UserConversionOverloadFailed: case FK_ConstructorOverloadFailed: return FailedOverloadResult == OR_Ambiguous; } - + return false; } @@ -2091,7 +2116,7 @@ void InitializationSequence::AddAddressOverloadResolutionStep( Steps.push_back(S); } -void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType, +void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType, ExprValueKind VK) { Step S; switch (VK) { @@ -2104,7 +2129,7 @@ void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType, Steps.push_back(S); } -void InitializationSequence::AddReferenceBindingStep(QualType T, +void InitializationSequence::AddReferenceBindingStep(QualType T, bool BindingTemporary) { Step S; S.Kind = BindingTemporary? SK_BindReferenceToTemporary : SK_BindReference; @@ -2166,7 +2191,7 @@ void InitializationSequence::AddListInitializationStep(QualType T) { Steps.push_back(S); } -void +void InitializationSequence::AddConstructorInitializationStep( CXXConstructorDecl *Constructor, AccessSpecifier Access, @@ -2207,7 +2232,7 @@ void InitializationSequence::AddObjCObjectConversionStep(QualType T) { Steps.push_back(S); } -void InitializationSequence::SetOverloadFailure(FailureKind Failure, +void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { SequenceKind = FailedSequence; this->Failure = Failure; @@ -2218,8 +2243,8 @@ void InitializationSequence::SetOverloadFailure(FailureKind Failure, // Attempt initialization //===----------------------------------------------------------------------===// -/// \brief Attempt list initialization (C++0x [dcl.init.list]) -static void TryListInitialization(Sema &S, +/// \brief Attempt list initialization (C++0x [dcl.init.list]) +static void TryListInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, InitListExpr *InitList, @@ -2235,7 +2260,7 @@ static void TryListInitialization(Sema &S, QualType DestType = Entity.getType(); // C++ [dcl.init]p13: - // If T is a scalar type, then a declaration of the form + // If T is a scalar type, then a declaration of the form // // T x = { a }; // @@ -2282,7 +2307,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, bool DerivedToBase; bool ObjCConversion; - assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), + assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), T1, T2, DerivedToBase, ObjCConversion) && "Must have incompatible references when binding via conversion"); @@ -2297,7 +2322,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; - + const RecordType *T1RecordType = 0; if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) && !S.RequireCompleteType(Kind.getLocation(), T1, 0)) { @@ -2319,22 +2344,24 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, ConstructorTmpl->getTemplatedDecl()); else Constructor = cast<CXXConstructorDecl>(D); - + if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, - &Initializer, 1, CandidateSet); + &Initializer, 1, CandidateSet, + /*SuppressUserConversions=*/true); else S.AddOverloadCandidate(Constructor, FoundDecl, - &Initializer, 1, CandidateSet); + &Initializer, 1, CandidateSet, + /*SuppressUserConversions=*/true); } - } + } } if (T1RecordType && T1RecordType->getDecl()->isInvalidDecl()) return OR_No_Viable_Function; - + const RecordType *T2RecordType = 0; if ((T2RecordType = T2->getAs<RecordType>()) && !S.RequireCompleteType(Kind.getLocation(), T2, 0)) { @@ -2342,11 +2369,6 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // functions. CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl()); - // Determine the type we are converting to. If we are allowed to - // convert to an rvalue, take the type that the destination type - // refers to. - QualType ToType = AllowRValues? cv1T1 : DestType; - const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); for (UnresolvedSetImpl::const_iterator I = Conversions->begin(), @@ -2355,41 +2377,41 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); - + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); CXXConversionDecl *Conv; if (ConvTemplate) Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); else Conv = cast<CXXConversionDecl>(D); - + // If the conversion function doesn't return a reference type, // it can't be considered for this conversion unless we're allowed to // consider rvalues. - // FIXME: Do we need to make sure that we only consider conversion - // candidates with reference-compatible results? That might be needed to + // FIXME: Do we need to make sure that we only consider conversion + // candidates with reference-compatible results? That might be needed to // break recursion. if ((AllowExplicit || !Conv->isExplicit()) && (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){ if (ConvTemplate) S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, Initializer, - ToType, CandidateSet); + DestType, CandidateSet); else S.AddConversionCandidate(Conv, I.getPair(), ActingDC, - Initializer, ToType, CandidateSet); + Initializer, DestType, CandidateSet); } } } if (T2RecordType && T2RecordType->getDecl()->isInvalidDecl()) return OR_No_Viable_Function; - + SourceLocation DeclLoc = Initializer->getLocStart(); - // Perform overload resolution. If it fails, return the failed result. + // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; - if (OverloadingResult Result - = CandidateSet.BestViableFunction(S, DeclLoc, Best)) + if (OverloadingResult Result + = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) return Result; FunctionDecl *Function = Best->Function; @@ -2404,7 +2426,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, Sequence.AddUserConversionStep(Function, Best->FoundDecl, T2.getNonLValueExprType(S.Context)); - // Determine whether we need to perform derived-to-base or + // Determine whether we need to perform derived-to-base or // cv-qualification adjustments. ExprValueKind VK = VK_RValue; if (T2->isLValueReferenceType()) @@ -2415,7 +2437,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, bool NewDerivedToBase = false; bool NewObjCConversion = false; Sema::ReferenceCompareResult NewRefRelationship - = S.CompareReferenceRelationship(DeclLoc, T1, + = S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonLValueExprType(S.Context), NewDerivedToBase, NewObjCConversion); if (NewRefRelationship == Sema::Ref_Incompatible) { @@ -2431,7 +2453,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, } else if (NewDerivedToBase) Sequence.AddDerivedToBaseCastStep( S.Context.getQualifiedType(T1, - T2.getNonReferenceType().getQualifiers()), + T2.getNonReferenceType().getQualifiers()), VK); else if (NewObjCConversion) Sequence.AddObjCObjectConversionStep( @@ -2440,13 +2462,13 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers()) Sequence.AddQualificationConversionStep(cv1T1, VK); - + Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType()); return OR_Success; } - -/// \brief Attempt reference initialization (C++0x [dcl.init.ref]) -static void TryReferenceInitialization(Sema &S, + +/// \brief Attempt reference initialization (C++0x [dcl.init.ref]) +static void TryReferenceInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr *Initializer, @@ -2467,18 +2489,17 @@ static void TryReferenceInitialization(Sema &S, // type of the resulting function. if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { DeclAccessPair Found; - FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, - T1, - false, - Found); - if (!Fn) { + if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, + T1, + false, + Found)) { + Sequence.AddAddressOverloadResolutionStep(Fn, Found); + cv2T2 = Fn->getType(); + T2 = cv2T2.getUnqualifiedType(); + } else if (!T1->isRecordType()) { Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); return; } - - Sequence.AddAddressOverloadResolutionStep(Fn, Found); - cv2T2 = Fn->getType(); - T2 = cv2T2.getUnqualifiedType(); } // Compute some basic properties of the types and the initializer. @@ -2492,10 +2513,10 @@ static void TryReferenceInitialization(Sema &S, ObjCConversion); // C++0x [dcl.init.ref]p5: - // A reference to type "cv1 T1" is initialized by an expression of type + // A reference to type "cv1 T1" is initialized by an expression of type // "cv2 T2" as follows: // - // - If the reference is an lvalue reference and the initializer + // - If the reference is an lvalue reference and the initializer // expression // Note the analogous bullet points for rvlaue refs to functions. Because // there are no function rvalues in C++, rvalue refs to functions are treated @@ -2503,19 +2524,21 @@ static void TryReferenceInitialization(Sema &S, OverloadingResult ConvOvlResult = OR_Success; bool T1Function = T1->isFunctionType(); if (isLValueRef || T1Function) { - if (InitCategory.isLValue() && - RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { - // - is an lvalue (but is not a bit-field), and "cv1 T1" is + if (InitCategory.isLValue() && + (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification || + (Kind.isCStyleOrFunctionalCast() && + RefRelationship == Sema::Ref_Related))) { + // - is an lvalue (but is not a bit-field), and "cv1 T1" is // reference-compatible with "cv2 T2," or // - // Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a + // Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a // bit-field when we're determining whether the reference initialization // can occur. However, we do pay attention to whether it is a bit-field // to decide whether we're actually binding to a temporary created from // the bit-field. if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( - S.Context.getQualifiedType(T1, T2Quals), + S.Context.getQualifiedType(T1, T2Quals), VK_LValue); else if (ObjCConversion) Sequence.AddObjCObjectConversionStep( @@ -2528,18 +2551,18 @@ static void TryReferenceInitialization(Sema &S, Sequence.AddReferenceBindingStep(cv1T1, BindingTemporary); return; } - - // - has a class type (i.e., T2 is a class type), where T1 is not - // reference-related to T2, and can be implicitly converted to an - // lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible - // with "cv3 T3" (this conversion is selected by enumerating the + + // - has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to an + // lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible + // with "cv3 T3" (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 we have an rvalue ref to function type here, the rhs must be // an rvalue. if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() && (isLValueRef || InitCategory.isRValue())) { - ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, + ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, Initializer, /*AllowRValues=*/isRValueRef, Sequence); @@ -2553,37 +2576,39 @@ static void TryReferenceInitialization(Sema &S, } } - // - Otherwise, the reference shall be an lvalue reference to a + // - Otherwise, the reference shall be an lvalue reference 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 or have a function type. - // We handled the function type stuff above. - if (!((isLValueRef && T1Quals.hasConst() && !T1Quals.hasVolatile()) || - (isRValueRef && InitCategory.isRValue()))) { - if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) + // shall be an rvalue reference. + if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile())) { + if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) + Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); + else if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) Sequence.SetOverloadFailure( InitializationSequence::FK_ReferenceInitOverloadFailed, ConvOvlResult); - else if (isLValueRef) + else Sequence.SetFailed(InitCategory.isLValue() ? (RefRelationship == Sema::Ref_Related ? InitializationSequence::FK_ReferenceInitDropsQualifiers : InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated) : InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary); - else - Sequence.SetFailed( - InitializationSequence::FK_RValueReferenceBindingToLValue); return; } - // - [If T1 is not a function type], if T2 is a class type and - if (!T1Function && T2->isRecordType()) { - bool isXValue = InitCategory.isXValue(); - // - the initializer expression is an rvalue and "cv1 T1" is - // reference-compatible with "cv2 T2", or - if (InitCategory.isRValue() && - RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // - If the initializer expression + // - is an xvalue, class prvalue, array prvalue, or function lvalue and + // "cv1 T1" is reference-compatible with "cv2 T2" + // Note: functions are handled below. + if (!T1Function && + (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification || + (Kind.isCStyleOrFunctionalCast() && + RefRelationship == Sema::Ref_Related)) && + (InitCategory.isXValue() || + (InitCategory.isPRValue() && T2->isRecordType()) || + (InitCategory.isPRValue() && T2->isArrayType()))) { + ExprValueKind ValueKind = InitCategory.isXValue()? VK_XValue : VK_RValue; + if (InitCategory.isPRValue() && T2->isRecordType()) { // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the // compiler the freedom to perform a copy here or bind to the // object, while C++0x requires that we bind directly to the @@ -2593,29 +2618,29 @@ static void TryReferenceInitialization(Sema &S, // // The constructor that would be used to make the copy shall // be callable whether or not the copy is actually done. - if (!S.getLangOptions().CPlusPlus0x) + if (!S.getLangOptions().CPlusPlus0x && !S.getLangOptions().Microsoft) Sequence.AddExtraneousCopyToTemporary(cv2T2); - - if (DerivedToBase) - Sequence.AddDerivedToBaseCastStep( - S.Context.getQualifiedType(T1, T2Quals), - isXValue ? VK_XValue : VK_RValue); - else if (ObjCConversion) - Sequence.AddObjCObjectConversionStep( - S.Context.getQualifiedType(T1, T2Quals)); - - if (T1Quals != T2Quals) - Sequence.AddQualificationConversionStep(cv1T1, - isXValue ? VK_XValue : VK_RValue); - Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/!isXValue); - return; } - // - T1 is not reference-related to T2 and the initializer expression - // can be implicitly converted to an rvalue of type "cv3 T3" (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 (DerivedToBase) + Sequence.AddDerivedToBaseCastStep(S.Context.getQualifiedType(T1, T2Quals), + ValueKind); + else if (ObjCConversion) + Sequence.AddObjCObjectConversionStep( + S.Context.getQualifiedType(T1, T2Quals)); + + if (T1Quals != T2Quals) + Sequence.AddQualificationConversionStep(cv1T1, ValueKind); + Sequence.AddReferenceBindingStep(cv1T1, + /*bindingTemporary=*/(InitCategory.isPRValue() && !T2->isArrayType())); + return; + } + + // - has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to an + // xvalue, class prvalue, or function lvalue of type "cv3 T3", + // where "cv1 T1" is reference-compatible with "cv3 T3", + if (T2->isRecordType()) { if (RefRelationship == Sema::Ref_Incompatible) { ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, Initializer, @@ -2625,23 +2650,17 @@ static void TryReferenceInitialization(Sema &S, Sequence.SetOverloadFailure( InitializationSequence::FK_ReferenceInitOverloadFailed, ConvOvlResult); - + return; } - + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } - - // - If the initializer expression is an rvalue, with T2 an array type, - // and "cv1 T1" is reference-compatible with "cv2 T2," the reference - // is bound to the object represented by the rvalue (see 3.10). - // FIXME: How can an array type be reference-compatible with anything? - // Don't we mean the element types of T1 and T2? - - // - Otherwise, a temporary of type “cv1 T1” is created and initialized + + // - 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 + // copy initialization (8.5). The reference is then bound to the // temporary. [...] // Determine whether we are allowed to call explicit constructors or @@ -2653,7 +2672,8 @@ static void TryReferenceInitialization(Sema &S, if (S.TryImplicitConversion(Sequence, TempEntity, Initializer, /*SuppressUserConversions*/ false, AllowExplicit, - /*FIXME:InOverloadResolution=*/false)) { + /*FIXME:InOverloadResolution=*/false, + /*CStyle=*/Kind.isCStyleOrFunctionalCast())) { // FIXME: Use the conversion function set stored in ICS to turn // this into an overloading ambiguity diagnostic. However, we need // to keep that set as an OverloadCandidateSet rather than as some @@ -2662,6 +2682,8 @@ static void TryReferenceInitialization(Sema &S, Sequence.SetOverloadFailure( InitializationSequence::FK_ReferenceInitOverloadFailed, ConvOvlResult); + else if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) + Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); else Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed); return; @@ -2672,19 +2694,28 @@ static void TryReferenceInitialization(Sema &S, // than, cv2; otherwise, the program is ill-formed. unsigned T1CVRQuals = T1Quals.getCVRQualifiers(); unsigned T2CVRQuals = T2Quals.getCVRQualifiers(); - if (RefRelationship == Sema::Ref_Related && + if (RefRelationship == Sema::Ref_Related && (T1CVRQuals | T2CVRQuals) != T1CVRQuals) { Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } + // [...] If T1 is reference-related to T2 and the reference is an rvalue + // reference, the initializer expression shall not be an lvalue. + if (RefRelationship >= Sema::Ref_Related && !isLValueRef && + InitCategory.isLValue()) { + Sequence.SetFailed( + InitializationSequence::FK_RValueReferenceBindingToLValue); + return; + } + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); return; } /// \brief Attempt character array initialization from a string literal -/// (C++ [dcl.init.string], C99 6.7.8). -static void TryStringLiteralInitialization(Sema &S, +/// (C++ [dcl.init.string], C99 6.7.8). +static void TryStringLiteralInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr *Initializer, @@ -2696,19 +2727,19 @@ static void TryStringLiteralInitialization(Sema &S, /// \brief Attempt initialization by constructor (C++ [dcl.init]), which /// enumerates the constructors of the initialized entity and performs overload /// resolution to select the best. -static void TryConstructorInitialization(Sema &S, +static void TryConstructorInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr **Args, unsigned NumArgs, QualType DestType, InitializationSequence &Sequence) { Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization); - + // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); CandidateSet.clear(); - + // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct || @@ -2720,21 +2751,21 @@ static void TryConstructorInitialization(Sema &S, Sequence.SetFailed(InitializationSequence::FK_Incomplete); return; } - + // The type we're converting to is a class type. Enumerate its constructors // to see if one is suitable. const RecordType *DestRecordType = DestType->getAs<RecordType>(); - assert(DestRecordType && "Constructor initialization requires record type"); + assert(DestRecordType && "Constructor initialization requires record type"); CXXRecordDecl *DestRecordDecl = cast<CXXRecordDecl>(DestRecordType->getDecl()); - + DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl); Con != ConEnd; ++Con) { NamedDecl *D = *Con; DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); bool SuppressUserConversions = false; - + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); @@ -2744,14 +2775,14 @@ static void TryConstructorInitialization(Sema &S, else { Constructor = cast<CXXConstructorDecl>(D); - // If we're performing copy initialization using a copy constructor, we + // If we're performing copy initialization using a copy constructor, we // suppress user-defined conversions on the arguments. // FIXME: Move constructors? if (Kind.getKind() == InitializationKind::IK_Copy && Constructor->isCopyConstructor()) SuppressUserConversions = true; } - + if (!Constructor->isInvalidDecl() && (AllowExplicit || !Constructor->isExplicit())) { if (ConstructorTmpl) @@ -2764,16 +2795,16 @@ static void TryConstructorInitialization(Sema &S, Args, NumArgs, CandidateSet, SuppressUserConversions); } - } - + } + SourceLocation DeclLoc = Kind.getLocation(); - - // Perform overload resolution. If it fails, return the failed result. + + // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; - if (OverloadingResult Result + if (OverloadingResult Result = CandidateSet.BestViableFunction(S, DeclLoc, Best)) { Sequence.SetOverloadFailure( - InitializationSequence::FK_ConstructorOverloadFailed, + InitializationSequence::FK_ConstructorOverloadFailed, Result); return; } @@ -2792,13 +2823,13 @@ static void TryConstructorInitialization(Sema &S, // Add the constructor initialization step. Any cv-qualification conversion is // subsumed by the initialization. Sequence.AddConstructorInitializationStep( - cast<CXXConstructorDecl>(Best->Function), + cast<CXXConstructorDecl>(Best->Function), Best->FoundDecl.getAccess(), DestType); } /// \brief Attempt value initialization (C++ [dcl.init]p7). -static void TryValueInitialization(Sema &S, +static void TryValueInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, InitializationSequence &Sequence) { @@ -2806,11 +2837,11 @@ static void TryValueInitialization(Sema &S, // // To value-initialize an object of type T means: QualType T = Entity.getType(); - + // -- if T is an array type, then each element is value-initialized; while (const ArrayType *AT = S.Context.getAsArrayType(T)) T = AT->getElementType(); - + if (const RecordType *RT = T->getAs<RecordType>()) { if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { // -- if T is a class type (clause 9) with a user-declared @@ -2822,15 +2853,15 @@ static void TryValueInitialization(Sema &S, // but Entity doesn't have a way to capture that (yet). if (ClassDecl->hasUserDeclaredConstructor()) return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); - + // -- if T is a (possibly cv-qualified) non-union class type // without a user-provided constructor, then the object is - // zero-initialized and, if T’s implicitly-declared default + // zero-initialized and, if T's implicitly-declared default // constructor is non-trivial, that constructor is called. if ((ClassDecl->getTagKind() == TTK_Class || ClassDecl->getTagKind() == TTK_Struct)) { Sequence.AddZeroInitializationStep(Entity.getType()); - return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); + return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); } } } @@ -2845,14 +2876,14 @@ static void TryDefaultInitialization(Sema &S, const InitializationKind &Kind, InitializationSequence &Sequence) { assert(Kind.getKind() == InitializationKind::IK_Default); - + // C++ [dcl.init]p6: // To default-initialize an object of type T means: // - if T is an array type, each element is default-initialized; QualType DestType = Entity.getType(); while (const ArrayType *Array = S.Context.getAsArrayType(DestType)) DestType = Array->getElementType(); - + // - if T is a (possibly cv-qualified) class type (Clause 9), the default // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); @@ -2860,12 +2891,12 @@ static void TryDefaultInitialization(Sema &S, TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, Sequence); return; } - + // - otherwise, no initialization is performed. Sequence.setSequenceKind(InitializationSequence::NoInitialization); - + // If a program calls for the default initialization of an object of - // a const-qualified type T, T shall be a class type with a user-provided + // a const-qualified type T, T shall be a class type with a user-provided // default constructor. if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus) Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); @@ -2874,42 +2905,42 @@ static void TryDefaultInitialization(Sema &S, /// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]), /// which enumerates all conversion functions and performs overload resolution /// to select the best. -static void TryUserDefinedConversion(Sema &S, +static void TryUserDefinedConversion(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr *Initializer, InitializationSequence &Sequence) { Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion); - + QualType DestType = Entity.getType(); assert(!DestType->isReferenceType() && "References are handled elsewhere"); QualType SourceType = Initializer->getType(); assert((DestType->isRecordType() || SourceType->isRecordType()) && "Must have a class type to perform a user-defined conversion"); - + // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); CandidateSet.clear(); - + // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; - + if (const RecordType *DestRecordType = DestType->getAs<RecordType>()) { // The type we're converting to is a class type. Enumerate its constructors // to see if there is a suitable conversion. CXXRecordDecl *DestRecordDecl = cast<CXXRecordDecl>(DestRecordType->getDecl()); - + // Try to complete the type we're converting to. - if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { + if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl); Con != ConEnd; ++Con) { NamedDecl *D = *Con; DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; FunctionTemplateDecl *ConstructorTmpl @@ -2919,7 +2950,7 @@ static void TryUserDefinedConversion(Sema &S, ConstructorTmpl->getTemplatedDecl()); else Constructor = cast<CXXConstructorDecl>(D); - + if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) @@ -2932,7 +2963,7 @@ static void TryUserDefinedConversion(Sema &S, &Initializer, 1, CandidateSet, /*SuppressUserConversions=*/true); } - } + } } } @@ -2947,24 +2978,24 @@ static void TryUserDefinedConversion(Sema &S, if (!S.RequireCompleteType(DeclLoc, SourceType, 0)) { CXXRecordDecl *SourceRecordDecl = cast<CXXRecordDecl>(SourceRecordType->getDecl()); - + const UnresolvedSetImpl *Conversions = SourceRecordDecl->getVisibleConversionFunctions(); for (UnresolvedSetImpl::const_iterator I = Conversions->begin(), - E = Conversions->end(); + E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); - + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); CXXConversionDecl *Conv; if (ConvTemplate) Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); else Conv = cast<CXXConversionDecl>(D); - + if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), @@ -2977,19 +3008,19 @@ static void TryUserDefinedConversion(Sema &S, } } } - - // Perform overload resolution. If it fails, return the failed result. + + // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result - = CandidateSet.BestViableFunction(S, DeclLoc, Best)) { + = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) { Sequence.SetOverloadFailure( - InitializationSequence::FK_UserConversionOverloadFailed, + InitializationSequence::FK_UserConversionOverloadFailed, Result); return; } FunctionDecl *Function = Best->Function; - + if (isa<CXXConstructorDecl>(Function)) { // Add the user-defined conversion step. Any cv-qualification conversion is // subsumed by the initialization. @@ -3011,7 +3042,7 @@ static void TryUserDefinedConversion(Sema &S, } Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType); - + // If the conversion following the call to the conversion function // is interesting, add it as a separate step. if (Best->FinalConversion.First || Best->FinalConversion.Second || @@ -3030,12 +3061,12 @@ InitializationSequence::InitializationSequence(Sema &S, unsigned NumArgs) : FailedCandidateSet(Kind.getLocation()) { ASTContext &Context = S.Context; - + // C++0x [dcl.init]p16: - // The semantics of initializers are as follows. The destination type is - // the type of the object or reference being initialized and the source + // The semantics of initializers are as follows. The destination type is + // the type of the object or reference being initialized and the source // type is the type of the initializer expression. The source type is not - // defined when the initializer is a braced-init-list or when it is a + // defined when the initializer is a braced-init-list or when it is a // parenthesized list of expressions. QualType DestType = Entity.getType(); @@ -3045,6 +3076,10 @@ InitializationSequence::InitializationSequence(Sema &S, return; } + for (unsigned I = 0; I != NumArgs; ++I) + if (Args[I]->getObjectKind() == OK_ObjCProperty) + S.ConvertPropertyForRValue(Args[I]); + QualType SourceType; Expr *Initializer = 0; if (NumArgs == 1) { @@ -3052,14 +3087,14 @@ InitializationSequence::InitializationSequence(Sema &S, if (!isa<InitListExpr>(Initializer)) SourceType = Initializer->getType(); } - - // - If the initializer is a braced-init-list, the object is + + // - If the initializer is a braced-init-list, the object is // list-initialized (8.5.4). if (InitListExpr *InitList = dyn_cast_or_null<InitListExpr>(Initializer)) { TryListInitialization(S, Entity, Kind, InitList, *this); return; } - + // - If the destination type is a reference type, see 8.5.3. if (DestType->isReferenceType()) { // C++0x [dcl.init.ref]p1: @@ -3073,36 +3108,36 @@ InitializationSequence::InitializationSequence(Sema &S, TryReferenceInitialization(S, Entity, Kind, Args[0], *this); return; } - - // - If the destination type is an array of characters, an array of - // char16_t, an array of char32_t, or an array of wchar_t, and the + + // - If the destination type is an array of characters, an array of + // char16_t, an array of char32_t, or an array of wchar_t, and the // initializer is a string literal, see 8.5.2. if (Initializer && IsStringInit(Initializer, DestType, Context)) { TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); return; } - + // - If the initializer is (), the object is value-initialized. if (Kind.getKind() == InitializationKind::IK_Value || (Kind.getKind() == InitializationKind::IK_Direct && NumArgs == 0)) { TryValueInitialization(S, Entity, Kind, *this); return; } - + // Handle default initialization. - if (Kind.getKind() == InitializationKind::IK_Default){ + if (Kind.getKind() == InitializationKind::IK_Default) { TryDefaultInitialization(S, Entity, Kind, *this); return; } - // - Otherwise, if the destination type is an array, the program is + // - Otherwise, if the destination type is an array, the program is // ill-formed. if (const ArrayType *AT = Context.getAsArrayType(DestType)) { if (AT->getElementType()->isAnyCharacterType()) SetFailed(FK_ArrayNeedsInitListOrStringLiteral); else SetFailed(FK_ArrayNeedsInitList); - + return; } @@ -3112,22 +3147,22 @@ InitializationSequence::InitializationSequence(Sema &S, AddCAssignmentStep(DestType); return; } - + // - If the destination type is a (possibly cv-qualified) class type: if (DestType->isRecordType()) { - // - 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 + // - 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 (Kind.getKind() == InitializationKind::IK_Direct || (Kind.getKind() == InitializationKind::IK_Copy && (Context.hasSameUnqualifiedType(SourceType, DestType) || S.IsDerivedFrom(SourceType, DestType)))) - TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, + TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, Entity.getType(), *this); - // - Otherwise (i.e., for the remaining copy-initialization cases), + // - 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 (when a conversion function is + // type to the destination type or (when a conversion function is // used) to a derived class thereof are enumerated as described in // 13.3.1.4, and the best one is chosen through overload resolution // (13.3). @@ -3135,30 +3170,39 @@ InitializationSequence::InitializationSequence(Sema &S, TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); return; } - + if (NumArgs > 1) { SetFailed(FK_TooManyInitsForScalar); return; } assert(NumArgs == 1 && "Zero-argument case handled above"); - - // - Otherwise, if the source type is a (possibly cv-qualified) class + + // - Otherwise, if the source type is a (possibly cv-qualified) class // type, conversion functions are considered. if (!SourceType.isNull() && SourceType->isRecordType()) { TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); return; } - + // - Otherwise, the initial value of the object being initialized is the // (possibly converted) value of the initializer expression. Standard // conversions (Clause 4) will be used, if necessary, to convert the - // initializer expression to the cv-unqualified version of the + // initializer expression to the cv-unqualified version of the // destination type; no user-defined conversions are considered. if (S.TryImplicitConversion(*this, Entity, Initializer, /*SuppressUserConversions*/ true, /*AllowExplicitConversions*/ false, - /*InOverloadResolution*/ false)) - SetFailed(InitializationSequence::FK_ConversionFailed); + /*InOverloadResolution*/ false, + /*CStyle=*/Kind.isCStyleOrFunctionalCast())) + { + DeclAccessPair dap; + if (Initializer->getType() == Context.OverloadTy && + !S.ResolveAddressOfOverloadedFunction(Initializer + , DestType, false, dap)) + SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); + else + SetFailed(InitializationSequence::FK_ConversionFailed); + } else setSequenceKind(StandardConversion); } @@ -3173,15 +3217,17 @@ InitializationSequence::~InitializationSequence() { //===----------------------------------------------------------------------===// // Perform initialization //===----------------------------------------------------------------------===// -static Sema::AssignmentAction +static Sema::AssignmentAction getAssignmentAction(const InitializedEntity &Entity) { switch(Entity.getKind()) { case InitializedEntity::EK_Variable: case InitializedEntity::EK_New: + case InitializedEntity::EK_Exception: + case InitializedEntity::EK_Base: return Sema::AA_Initializing; case InitializedEntity::EK_Parameter: - if (Entity.getDecl() && + if (Entity.getDecl() && isa<ObjCMethodDecl>(Entity.getDecl()->getDeclContext())) return Sema::AA_Sending; @@ -3190,15 +3236,10 @@ getAssignmentAction(const InitializedEntity &Entity) { case InitializedEntity::EK_Result: return Sema::AA_Returning; - case InitializedEntity::EK_Exception: - case InitializedEntity::EK_Base: - llvm_unreachable("No assignment action for C++-specific initialization"); - break; - case InitializedEntity::EK_Temporary: // FIXME: Can we tell apart casting vs. converting? return Sema::AA_Casting; - + case InitializedEntity::EK_Member: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_VectorElement: @@ -3223,12 +3264,12 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: return false; - + case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Temporary: return true; } - + llvm_unreachable("missed an InitializedEntity kind?"); } @@ -3243,7 +3284,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_BlockElement: return false; - + case InitializedEntity::EK_Variable: case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Temporary: @@ -3251,8 +3292,8 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Exception: return true; } - - llvm_unreachable("missed an InitializedEntity kind?"); + + llvm_unreachable("missed an InitializedEntity kind?"); } /// \brief Make a (potentially elidable) temporary copy of the object @@ -3261,7 +3302,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { /// /// \param S The Sema object used for type-checking. /// -/// \param T The type of the temporary object, which must either by +/// \param T The type of the temporary object, which must either be /// the type of the initializer expression or a superclass thereof. /// /// \param Enter The entity being initialized. @@ -3276,19 +3317,19 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { /// a temporary object, or an error expression if a copy could not be /// created. static ExprResult CopyObject(Sema &S, - QualType T, - const InitializedEntity &Entity, - ExprResult CurInit, - bool IsExtraneousCopy) { + QualType T, + const InitializedEntity &Entity, + ExprResult CurInit, + bool IsExtraneousCopy) { // Determine which class type we're copying to. Expr *CurInitExpr = (Expr *)CurInit.get(); - CXXRecordDecl *Class = 0; + CXXRecordDecl *Class = 0; if (const RecordType *Record = T->getAs<RecordType>()) Class = cast<CXXRecordDecl>(Record->getDecl()); if (!Class) return move(CurInit); - // C++0x [class.copy]p34: + // C++0x [class.copy]p32: // When certain criteria are met, an implementation is allowed to // omit the copy/move construction of a class object, even if the // copy/move constructor and/or destructor for the object have @@ -3298,23 +3339,22 @@ static ExprResult CopyObject(Sema &S, // with the same cv-unqualified type, the copy/move operation // can be omitted by constructing the temporary object // directly into the target of the omitted copy/move - // + // // Note that the other three bullets are handled elsewhere. Copy // elision for return statements and throw expressions are handled as part - // of constructor initialization, while copy elision for exception handlers + // of constructor initialization, while copy elision for exception handlers // is handled by the run-time. - bool Elidable = CurInitExpr->isTemporaryObject() && - S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType()); + bool Elidable = CurInitExpr->isTemporaryObject(S.Context, Class); SourceLocation Loc; switch (Entity.getKind()) { case InitializedEntity::EK_Result: Loc = Entity.getReturnLoc(); break; - + case InitializedEntity::EK_Exception: Loc = Entity.getThrowLoc(); break; - + case InitializedEntity::EK_Variable: Loc = Entity.getDecl()->getLocation(); break; @@ -3331,33 +3371,57 @@ static ExprResult CopyObject(Sema &S, break; } - // Make sure that the type we are copying is complete. + // Make sure that the type we are copying is complete. if (S.RequireCompleteType(Loc, T, S.PDiag(diag::err_temp_copy_incomplete))) return move(CurInit); - // Perform overload resolution using the class's copy constructors. + // Perform overload resolution using the class's copy/move constructors. DeclContext::lookup_iterator Con, ConEnd; OverloadCandidateSet CandidateSet(Loc); for (llvm::tie(Con, ConEnd) = S.LookupConstructors(Class); Con != ConEnd; ++Con) { - // Only consider copy constructors. - CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con); - if (!Constructor || Constructor->isInvalidDecl() || - !Constructor->isCopyConstructor() || - !Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) + // Only consider copy/move constructors and constructor templates. Per + // C++0x [dcl.init]p16, second bullet to class types, this + // initialization is direct-initialization. + CXXConstructorDecl *Constructor = 0; + + if ((Constructor = dyn_cast<CXXConstructorDecl>(*Con))) { + // Handle copy/moveconstructors, only. + if (!Constructor || Constructor->isInvalidDecl() || + !Constructor->isCopyOrMoveConstructor() || + !Constructor->isConvertingConstructor(/*AllowExplicit=*/true)) + continue; + + DeclAccessPair FoundDecl + = DeclAccessPair::make(Constructor, Constructor->getAccess()); + S.AddOverloadCandidate(Constructor, FoundDecl, + &CurInitExpr, 1, CandidateSet); + continue; + } + + // Handle constructor templates. + FunctionTemplateDecl *ConstructorTmpl = cast<FunctionTemplateDecl>(*Con); + if (ConstructorTmpl->isInvalidDecl()) + continue; + + Constructor = cast<CXXConstructorDecl>( + ConstructorTmpl->getTemplatedDecl()); + if (!Constructor->isConvertingConstructor(/*AllowExplicit=*/true)) continue; + // FIXME: Do we need to limit this to copy-constructor-like + // candidates? DeclAccessPair FoundDecl - = DeclAccessPair::make(Constructor, Constructor->getAccess()); - S.AddOverloadCandidate(Constructor, FoundDecl, - &CurInitExpr, 1, CandidateSet); + = DeclAccessPair::make(ConstructorTmpl, ConstructorTmpl->getAccess()); + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, 0, + &CurInitExpr, 1, CandidateSet, true); } - + OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(S, Loc, Best)) { case OR_Success: break; - + case OR_No_Viable_Function: S.Diag(Loc, IsExtraneousCopy && !S.isSFINAEContext() ? diag::ext_rvalue_to_reference_temp_copy_no_viable @@ -3368,14 +3432,14 @@ static ExprResult CopyObject(Sema &S, if (!IsExtraneousCopy || S.isSFINAEContext()) return ExprError(); return move(CurInit); - + case OR_Ambiguous: S.Diag(Loc, diag::err_temp_copy_ambiguous) << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); CandidateSet.NoteCandidates(S, OCD_ViableCandidates, &CurInitExpr, 1); return ExprError(); - + case OR_Deleted: S.Diag(Loc, diag::err_temp_copy_deleted) << (int)Entity.getKind() << CurInitExpr->getType() @@ -3417,7 +3481,7 @@ static ExprResult CopyObject(Sema &S, return S.Owned(CurInitExpr); } - + // Determine the arguments required to actually perform the // constructor call (we might have derived-to-base conversions, or // the copy constructor may have default arguments). @@ -3429,8 +3493,9 @@ static ExprResult CopyObject(Sema &S, CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable, move_arg(ConstructorArgs), /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete); - + CXXConstructExpr::CK_Complete, + SourceRange()); + // If we're supposed to bind temporaries, do so. if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); @@ -3451,7 +3516,7 @@ void InitializationSequence::PrintInitLocationNote(Sema &S, } } -ExprResult +ExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -3462,7 +3527,7 @@ InitializationSequence::Perform(Sema &S, Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs); return ExprError(); } - + if (SequenceKind == DependentSequence) { // If the declaration is a non-dependent, incomplete array type // that has an initializer, then its type will be completed once @@ -3512,14 +3577,14 @@ InitializationSequence::Perform(Sema &S, unsigned NumArgs = Args.size(); return S.Owned(new (S.Context) ParenListExpr(S.Context, SourceLocation(), - (Expr **)Args.release(), + (Expr **)Args.release(), NumArgs, SourceLocation())); } if (SequenceKind == NoInitialization) return S.Owned((Expr *)0); - + QualType DestType = Entity.getType().getNonReferenceType(); // FIXME: Ugly hack around the fact that Entity.getType() is not // the same as Entity.getDecl()->getType() in cases involving type merging, @@ -3529,10 +3594,10 @@ InitializationSequence::Perform(Sema &S, Entity.getType(); ExprResult CurInit = S.Owned((Expr *)0); - + assert(!Steps.empty() && "Cannot have an empty initialization sequence"); - - // For initialization steps that start with a single initializer, + + // For initialization steps that start with a single initializer, // grab the only argument out the Args and place it into the "current" // initializer. switch (Steps.front().Kind) { @@ -3551,32 +3616,38 @@ InitializationSequence::Perform(Sema &S, case SK_ListInitialization: case SK_CAssignment: case SK_StringInit: - case SK_ObjCObjectConversion: + case SK_ObjCObjectConversion: { assert(Args.size() == 1); - CurInit = ExprResult(((Expr **)(Args.get()))[0]->Retain()); - if (CurInit.isInvalid()) - return ExprError(); + Expr *CurInitExpr = Args.get()[0]; + if (!CurInitExpr) return ExprError(); + + // Read from a property when initializing something with it. + if (CurInitExpr->getObjectKind() == OK_ObjCProperty) + S.ConvertPropertyForRValue(CurInitExpr); + + CurInit = ExprResult(CurInitExpr); break; - + } + case SK_ConstructorInitialization: case SK_ZeroInitialization: break; } - - // Walk through the computed steps for the initialization sequence, + + // Walk through the computed steps for the initialization sequence, // performing the specified conversions along the way. bool ConstructorInitRequiresZeroInit = false; for (step_iterator Step = step_begin(), StepEnd = step_end(); Step != StepEnd; ++Step) { if (CurInit.isInvalid()) return ExprError(); - - Expr *CurInitExpr = (Expr *)CurInit.get(); + + Expr *CurInitExpr = CurInit.get(); QualType SourceType = CurInitExpr? CurInitExpr->getType() : QualType(); - + switch (Step->Kind) { case SK_ResolveAddressOfOverloadedFunction: - // Overload resolution determined which function invoke; update the + // Overload resolution determined which function invoke; update the // initializer to reflect that choice. S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl); S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation()); @@ -3584,29 +3655,29 @@ InitializationSequence::Perform(Sema &S, Step->Function.FoundDecl, Step->Function.Function); break; - + case SK_CastDerivedToBaseRValue: case SK_CastDerivedToBaseXValue: case SK_CastDerivedToBaseLValue: { // We have a derived-to-base cast that produces either an rvalue or an // lvalue. Perform that cast. - + CXXCastPath BasePath; // Casts to inaccessible base classes are allowed with C-style casts. bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); if (S.CheckDerivedToBaseConversion(SourceType, Step->Type, CurInitExpr->getLocStart(), - CurInitExpr->getSourceRange(), + CurInitExpr->getSourceRange(), &BasePath, IgnoreBaseAccess)) return ExprError(); - + if (S.BasePathInvolvesVirtualBase(BasePath)) { QualType T = SourceType; if (const PointerType *Pointer = T->getAs<PointerType>()) T = Pointer->getPointeeType(); if (const RecordType *RecordTy = T->getAs<RecordType>()) - S.MarkVTableUsed(CurInitExpr->getLocStart(), + S.MarkVTableUsed(CurInitExpr->getLocStart(), cast<CXXRecordDecl>(RecordTy->getDecl())); } @@ -3623,7 +3694,7 @@ InitializationSequence::Perform(Sema &S, &BasePath, VK)); break; } - + case SK_BindReference: if (FieldDecl *BitField = CurInitExpr->getBitField()) { // References cannot bind to bit fields (C++ [dcl.init.ref]p5). @@ -3643,7 +3714,7 @@ InitializationSequence::Perform(Sema &S, PrintInitLocationNote(S, Entity); return ExprError(); } - + // Reference binding does not have any corresponding ASTs. // Check exception specifications @@ -3660,16 +3731,16 @@ InitializationSequence::Perform(Sema &S, return ExprError(); break; - + case SK_ExtraneousCopyToTemporary: - CurInit = CopyObject(S, Step->Type, Entity, move(CurInit), + CurInit = CopyObject(S, Step->Type, Entity, move(CurInit), /*IsExtraneousCopy=*/true); break; case SK_UserConversion: { // We have a user-defined conversion that invokes either a constructor // or a conversion function. - CastKind CastKind = CK_Unknown; + CastKind CastKind; bool IsCopy = false; FunctionDecl *Fn = Step->Function.Function; DeclAccessPair FoundFn = Step->Function.FoundDecl; @@ -3687,25 +3758,26 @@ InitializationSequence::Perform(Sema &S, MultiExprArg(&CurInitExpr, 1), Loc, ConstructorArgs)) return ExprError(); - + // Build the an expression that constructs a temporary. - CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, + CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, move_arg(ConstructorArgs), /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete); + CXXConstructExpr::CK_Complete, + SourceRange()); if (CurInit.isInvalid()) return ExprError(); S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity, FoundFn.getAccess()); S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); - + CastKind = CK_ConstructorConversion; QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); if (S.Context.hasSameUnqualifiedType(SourceType, Class) || S.IsDerivedFrom(SourceType, Class)) IsCopy = true; - + CreatedObject = true; } else { // Build a call to the conversion function. @@ -3714,8 +3786,8 @@ InitializationSequence::Perform(Sema &S, S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, FoundFn); S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); - - // FIXME: Should we move this initialization into a separate + + // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because // we don't want to turn off access control here for c-style casts. if (S.PerformObjectArgumentInitialization(CurInitExpr, /*Qualifier=*/0, @@ -3725,19 +3797,18 @@ InitializationSequence::Perform(Sema &S, // Do a little dance to make sure that CurInit has the proper // pointer. CurInit.release(); - + // Build the actual call to the conversion function. - CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn, - Conversion)); + CurInit = S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn, Conversion); if (CurInit.isInvalid() || !CurInit.get()) return ExprError(); - + CastKind = CK_UserDefinedConversion; - + CreatedObject = Conversion->getResultType()->isRecordType(); } - - bool RequiresCopy = !IsCopy && + + bool RequiresCopy = !IsCopy && getKind() != InitializationSequence::ReferenceBinding; if (RequiresCopy || shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); @@ -3745,21 +3816,22 @@ InitializationSequence::Perform(Sema &S, CurInitExpr = static_cast<Expr *>(CurInit.get()); QualType T = CurInitExpr->getType(); if (const RecordType *Record = T->getAs<RecordType>()) { - CXXDestructorDecl *Destructor + CXXDestructorDecl *Destructor = S.LookupDestructor(cast<CXXRecordDecl>(Record->getDecl())); - S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor, + S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor, S.PDiag(diag::err_access_dtor_temp) << T); S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor); + S.DiagnoseUseOfDecl(Destructor, CurInitExpr->getLocStart()); } } - + CurInitExpr = CurInit.takeAs<Expr>(); // FIXME: xvalues CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, CurInitExpr->getType(), CastKind, CurInitExpr, 0, IsLvalue ? VK_LValue : VK_RValue)); - + if (RequiresCopy) CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, move(CurInit), /*IsExtraneousCopy=*/false); @@ -3784,17 +3856,16 @@ InitializationSequence::Perform(Sema &S, } case SK_ConversionSequence: { - bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); - if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS, - Sema::AA_Converting, IgnoreBaseAccess)) + getAssignmentAction(Entity), + Kind.isCStyleOrFunctionalCast())) return ExprError(); - + CurInit.release(); CurInit = S.Owned(CurInitExpr); break; } - + case SK_ListInitialization: { InitListExpr *InitList = cast<InitListExpr>(CurInitExpr); QualType Ty = Step->Type; @@ -3810,7 +3881,7 @@ InitializationSequence::Perform(Sema &S, unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Step->Function.Function); - + // Build a call to the selected constructor. ASTOwningVector<Expr*> ConstructorArgs(S); SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid()) @@ -3830,11 +3901,11 @@ InitializationSequence::Perform(Sema &S, // Determine the arguments required to actually perform the constructor // call. - if (S.CompleteConstructorCall(Constructor, move(Args), + if (S.CompleteConstructorCall(Constructor, move(Args), Loc, ConstructorArgs)) return ExprError(); - - + + if (Entity.getKind() == InitializedEntity::EK_Temporary && NumArgs != 1 && // FIXME: Hack to work around cast weirdness (Kind.getKind() == InitializationKind::IK_Direct || @@ -3843,24 +3914,34 @@ InitializationSequence::Perform(Sema &S, unsigned NumExprs = ConstructorArgs.size(); Expr **Exprs = (Expr **)ConstructorArgs.take(); S.MarkDeclarationReferenced(Loc, Constructor); + S.DiagnoseUseOfDecl(Constructor, Loc); + + TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); + if (!TSInfo) + TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc); + CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context, Constructor, - Entity.getType(), - Loc, - Exprs, + TSInfo, + Exprs, NumExprs, - Kind.getParenRange().getEnd(), + Kind.getParenRange(), ConstructorInitRequiresZeroInit)); } else { CXXConstructExpr::ConstructionKind ConstructKind = CXXConstructExpr::CK_Complete; - + if (Entity.getKind() == InitializedEntity::EK_Base) { ConstructKind = Entity.getBaseSpecifier()->isVirtual() ? - CXXConstructExpr::CK_VirtualBase : + CXXConstructExpr::CK_VirtualBase : CXXConstructExpr::CK_NonVirtualBase; - } - + } + + // Only get the parenthesis range if it is a direct construction. + SourceRange parenRange = + Kind.getKind() == InitializationKind::IK_Direct ? + Kind.getParenRange() : SourceRange(); + // If the entity allows NRVO, mark the construction as elidable // unconditionally. if (Entity.allowsNRVO()) @@ -3868,13 +3949,15 @@ InitializationSequence::Perform(Sema &S, Constructor, /*Elidable=*/true, move_arg(ConstructorArgs), ConstructorInitRequiresZeroInit, - ConstructKind); + ConstructKind, + parenRange); else CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), - Constructor, + Constructor, move_arg(ConstructorArgs), ConstructorInitRequiresZeroInit, - ConstructKind); + ConstructKind, + parenRange); } if (CurInit.isInvalid()) return ExprError(); @@ -3883,17 +3966,17 @@ InitializationSequence::Perform(Sema &S, S.CheckConstructorAccess(Loc, Constructor, Entity, Step->Function.FoundDecl.getAccess()); S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Loc); - + if (shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); - + break; } - + case SK_ZeroInitialization: { step_iterator NextStep = Step; ++NextStep; - if (NextStep != StepEnd && + if (NextStep != StepEnd && NextStep->Kind == SK_ConstructorInitialization) { // The need for zero-initialization is recorded directly into // the call to the object's constructor within the next step. @@ -3901,8 +3984,14 @@ InitializationSequence::Perform(Sema &S, } else if (Kind.getKind() == InitializationKind::IK_Value && S.getLangOptions().CPlusPlus && !Kind.isImplicitValueInit()) { - CurInit = S.Owned(new (S.Context) CXXScalarValueInitExpr(Step->Type, - Kind.getRange().getBegin(), + TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); + if (!TSInfo) + TSInfo = S.Context.getTrivialTypeSourceInfo(Step->Type, + Kind.getRange().getBegin()); + + CurInit = S.Owned(new (S.Context) CXXScalarValueInitExpr( + TSInfo->getType().getNonLValueExprType(S.Context), + TSInfo, Kind.getRange().getEnd())); } else { CurInit = S.Owned(new (S.Context) ImplicitValueInitExpr(Step->Type)); @@ -3925,7 +4014,7 @@ InitializationSequence::Perform(Sema &S, bool Complained; if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(), Step->Type, SourceType, - CurInitExpr, + CurInitExpr, getAssignmentAction(Entity), &Complained)) { PrintInitLocationNote(S, Entity); @@ -3945,7 +4034,7 @@ InitializationSequence::Perform(Sema &S, } case SK_ObjCObjectConversion: - S.ImpCastExprToType(CurInitExpr, Step->Type, + S.ImpCastExprToType(CurInitExpr, Step->Type, CK_ObjCObjectLValueCast, S.CastCategory(CurInitExpr)); CurInit.release(); @@ -3953,20 +4042,27 @@ InitializationSequence::Perform(Sema &S, break; } } - + + // Diagnose non-fatal problems with the completed initialization. + if (Entity.getKind() == InitializedEntity::EK_Member && + cast<FieldDecl>(Entity.getDecl())->isBitField()) + S.CheckBitFieldInitialization(Kind.getLocation(), + cast<FieldDecl>(Entity.getDecl()), + CurInit.get()); + return move(CurInit); } //===----------------------------------------------------------------------===// // Diagnose initialization failures //===----------------------------------------------------------------------===// -bool InitializationSequence::Diagnose(Sema &S, +bool InitializationSequence::Diagnose(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr **Args, unsigned NumArgs) { if (SequenceKind != FailedSequence) return false; - + QualType DestType = Entity.getType(); switch (Failure) { case FK_TooManyInitsForReference: @@ -3978,22 +4074,22 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits) << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); break; - + case FK_ArrayNeedsInitList: case FK_ArrayNeedsInitListOrStringLiteral: S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << (Failure == FK_ArrayNeedsInitListOrStringLiteral); break; - + case FK_AddressOfOverloadFailed: { DeclAccessPair Found; - S.ResolveAddressOfOverloadedFunction(Args[0], + S.ResolveAddressOfOverloadedFunction(Args[0], DestType.getNonReferenceType(), true, Found); break; } - + case FK_ReferenceInitOverloadFailed: case FK_UserConversionOverloadFailed: switch (FailedOverloadResult) { @@ -4009,21 +4105,22 @@ bool InitializationSequence::Diagnose(Sema &S, FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args, NumArgs); break; - + case OR_No_Viable_Function: S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) << Args[0]->getType() << DestType.getNonReferenceType() << Args[0]->getSourceRange(); FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args, NumArgs); break; - + case OR_Deleted: { S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function) << Args[0]->getType() << DestType.getNonReferenceType() << Args[0]->getSourceRange(); OverloadCandidateSet::iterator Best; OverloadingResult Ovl - = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best); + = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best, + true); if (Ovl == OR_Deleted) { S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) << Best->Function->isDeleted(); @@ -4032,16 +4129,16 @@ bool InitializationSequence::Diagnose(Sema &S, } break; } - + case OR_Success: llvm_unreachable("Conversion did not fail!"); break; } break; - + case FK_NonConstLValueReferenceBindingToTemporary: case FK_NonConstLValueReferenceBindingToUnrelated: - S.Diag(Kind.getLocation(), + S.Diag(Kind.getLocation(), Failure == FK_NonConstLValueReferenceBindingToTemporary ? diag::err_lvalue_reference_bind_to_temporary : diag::err_lvalue_reference_bind_to_unrelated) @@ -4050,47 +4147,54 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->getType() << Args[0]->getSourceRange(); break; - + case FK_RValueReferenceBindingToLValue: S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref) + << DestType.getNonReferenceType() << Args[0]->getType() << Args[0]->getSourceRange(); break; - + case FK_ReferenceInitDropsQualifiers: S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) << DestType.getNonReferenceType() << Args[0]->getType() << Args[0]->getSourceRange(); break; - + case FK_ReferenceInitFailed: S.Diag(Kind.getLocation(), diag::err_reference_bind_failed) << DestType.getNonReferenceType() - << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) + << Args[0]->isLValue() << Args[0]->getType() << Args[0]->getSourceRange(); break; - - case FK_ConversionFailed: + + case FK_ConversionFailed: { + QualType FromType = Args[0]->getType(); S.Diag(Kind.getLocation(), diag::err_init_conversion_failed) << (int)Entity.getKind() << DestType - << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) - << Args[0]->getType() + << Args[0]->isLValue() + << FromType << Args[0]->getSourceRange(); break; - + } case FK_TooManyInitsForScalar: { SourceRange R; if (InitListExpr *InitList = dyn_cast<InitListExpr>(Args[0])) - R = SourceRange(InitList->getInit(1)->getLocStart(), + R = SourceRange(InitList->getInit(0)->getLocEnd(), InitList->getLocEnd()); else - R = SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); + R = SourceRange(Args[0]->getLocEnd(), Args[NumArgs - 1]->getLocEnd()); - S.Diag(Kind.getLocation(), diag::err_excess_initializers) - << /*scalar=*/2 << R; + R.setBegin(S.PP.getLocForEndOfToken(R.getBegin())); + if (Kind.isCStyleOrFunctionalCast()) + S.Diag(Kind.getLocation(), diag::err_builtin_func_cast_more_than_one_arg) + << R; + else + S.Diag(Kind.getLocation(), diag::err_excess_initializers) + << /*scalar=*/2 << R; break; } @@ -4103,13 +4207,13 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Kind.getLocation(), diag::err_init_list_bad_dest_type) << (DestType->isRecordType()) << DestType << Args[0]->getSourceRange(); break; - + case FK_ConstructorOverloadFailed: { SourceRange ArgsRange; if (NumArgs) - ArgsRange = SourceRange(Args[0]->getLocStart(), + ArgsRange = SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); - + // FIXME: Using "DestType" for the entity we're printing is probably // bad. switch (FailedOverloadResult) { @@ -4119,7 +4223,7 @@ bool InitializationSequence::Diagnose(Sema &S, FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args, NumArgs); break; - + case OR_No_Viable_Function: if (Kind.getKind() == InitializationKind::IK_Default && (Entity.getKind() == InitializedEntity::EK_Base || @@ -4153,7 +4257,7 @@ bool InitializationSequence::Diagnose(Sema &S, if (const RecordType *Record = Entity.getType()->getAs<RecordType>()) - S.Diag(Record->getDecl()->getLocation(), + S.Diag(Record->getDecl()->getLocation(), diag::note_previous_decl) << S.Context.getTagDeclType(Record->getDecl()); } @@ -4164,7 +4268,7 @@ bool InitializationSequence::Diagnose(Sema &S, << DestType << ArgsRange; FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args, NumArgs); break; - + case OR_Deleted: { S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) << true << DestType << ArgsRange; @@ -4179,14 +4283,14 @@ bool InitializationSequence::Diagnose(Sema &S, } break; } - + case OR_Success: llvm_unreachable("Conversion did not fail!"); break; } break; } - + case FK_DefaultInitOfConst: if (Entity.getKind() == InitializedEntity::EK_Member && isa<CXXConstructorDecl>(S.CurContext)) { @@ -4206,13 +4310,13 @@ bool InitializationSequence::Diagnose(Sema &S, << DestType << (bool)DestType->getAs<RecordType>(); } break; - + case FK_Incomplete: - S.RequireCompleteType(Kind.getLocation(), DestType, + S.RequireCompleteType(Kind.getLocation(), DestType, diag::err_init_incomplete_type); - break; + break; } - + PrintInitLocationNote(S, Entity); return true; } @@ -4225,95 +4329,95 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case FK_TooManyInitsForReference: OS << "too many initializers for reference"; break; - + case FK_ArrayNeedsInitList: OS << "array requires initializer list"; break; - + case FK_ArrayNeedsInitListOrStringLiteral: OS << "array requires initializer list or string literal"; break; - + case FK_AddressOfOverloadFailed: OS << "address of overloaded function failed"; break; - + case FK_ReferenceInitOverloadFailed: OS << "overload resolution for reference initialization failed"; break; - + case FK_NonConstLValueReferenceBindingToTemporary: OS << "non-const lvalue reference bound to temporary"; break; - + case FK_NonConstLValueReferenceBindingToUnrelated: OS << "non-const lvalue reference bound to unrelated type"; break; - + case FK_RValueReferenceBindingToLValue: OS << "rvalue reference bound to an lvalue"; break; - + case FK_ReferenceInitDropsQualifiers: OS << "reference initialization drops qualifiers"; break; - + case FK_ReferenceInitFailed: OS << "reference initialization failed"; break; - + case FK_ConversionFailed: OS << "conversion failed"; break; - + case FK_TooManyInitsForScalar: OS << "too many initializers for scalar"; break; - + case FK_ReferenceBindingToInitList: OS << "referencing binding to initializer list"; break; - + case FK_InitListBadDestinationType: OS << "initializer list for non-aggregate, non-scalar type"; break; - + case FK_UserConversionOverloadFailed: OS << "overloading failed for user-defined conversion"; break; - + case FK_ConstructorOverloadFailed: OS << "constructor overloading failed"; break; - + case FK_DefaultInitOfConst: OS << "default initialization of a const variable"; break; - + case FK_Incomplete: OS << "initialization of incomplete type"; break; - } + } OS << '\n'; return; } - + case DependentSequence: OS << "Dependent sequence: "; return; - + case UserDefinedConversion: OS << "User-defined conversion sequence: "; break; - + case ConstructorInitialization: OS << "Constructor initialization sequence: "; break; - + case ReferenceBinding: OS << "Reference binding: "; break; - + case ListInitialization: OS << "List initialization: "; break; @@ -4321,54 +4425,54 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case ZeroInitialization: OS << "Zero initialization\n"; return; - + case NoInitialization: OS << "No initialization\n"; return; - + case StandardConversion: OS << "Standard conversion: "; break; - + case CAssignment: OS << "C assignment: "; break; - + case StringInit: OS << "String initialization: "; break; } - + for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) { if (S != step_begin()) { OS << " -> "; } - + switch (S->Kind) { case SK_ResolveAddressOfOverloadedFunction: OS << "resolve address of overloaded function"; break; - + case SK_CastDerivedToBaseRValue: OS << "derived-to-base case (rvalue" << S->Type.getAsString() << ")"; break; - + case SK_CastDerivedToBaseXValue: OS << "derived-to-base case (xvalue" << S->Type.getAsString() << ")"; break; - + case SK_CastDerivedToBaseLValue: OS << "derived-to-base case (lvalue" << S->Type.getAsString() << ")"; break; - + case SK_BindReference: OS << "bind reference to lvalue"; break; - + case SK_BindReferenceToTemporary: OS << "bind reference to a temporary"; break; - + case SK_ExtraneousCopyToTemporary: OS << "extraneous C++03 copy to temporary"; break; @@ -4386,29 +4490,29 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case SK_QualificationConversionLValue: OS << "qualification conversion (lvalue)"; break; - + case SK_ConversionSequence: OS << "implicit conversion sequence ("; S->ICS->DebugPrint(); // FIXME: use OS OS << ")"; break; - + case SK_ListInitialization: OS << "list initialization"; break; - + case SK_ConstructorInitialization: OS << "constructor initialization"; break; - + case SK_ZeroInitialization: OS << "zero initialization"; break; - + case SK_CAssignment: OS << "C assignment"; break; - + case SK_StringInit: OS << "string initialization"; break; @@ -4427,14 +4531,14 @@ void InitializationSequence::dump() const { //===----------------------------------------------------------------------===// // Initialization helper functions //===----------------------------------------------------------------------===// -ExprResult +ExprResult Sema::PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init) { if (Init.isInvalid()) return ExprError(); - Expr *InitE = (Expr *)Init.get(); + Expr *InitE = Init.get(); assert(InitE && "No initialization expression?"); if (EqualLoc.isInvalid()) diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 306e95a..0fd0e08 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -31,7 +31,9 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/ErrorHandling.h" +#include <limits> #include <list> #include <set> #include <vector> @@ -89,7 +91,7 @@ namespace { UnqualUsingDirectiveSet() {} void visitScopeChain(Scope *S, Scope *InnermostFileScope) { - // C++ [namespace.udir]p1: + // C++ [namespace.udir]p1: // During unqualified name lookup, the names appear as if they // were declared in the nearest enclosing namespace which contains // both the using-directive and the nominated namespace. @@ -104,7 +106,7 @@ namespace { } else { Scope::udir_iterator I = S->using_directives_begin(), End = S->using_directives_end(); - + for (; I != End; ++I) visit(*I, InnermostFileDC); } @@ -175,7 +177,7 @@ namespace { while (!Common->Encloses(EffectiveDC)) Common = Common->getParent(); Common = Common->getPrimaryContext(); - + list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common)); } @@ -183,11 +185,8 @@ namespace { std::sort(list.begin(), list.end(), UnqualUsingEntry::Comparator()); } - typedef ListTy::iterator iterator; typedef ListTy::const_iterator const_iterator; - - iterator begin() { return list.begin(); } - iterator end() { return list.end(); } + const_iterator begin() const { return list.begin(); } const_iterator end() const { return list.end(); } @@ -211,7 +210,8 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_Ordinary; if (CPlusPlus) { IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace; - if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend; + if (Redeclaration) + IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend; } break; @@ -237,7 +237,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_Tag; } break; - + case Sema::LookupLabel: + IDNS = Decl::IDNS_Label; + break; + case Sema::LookupMemberName: IDNS = Decl::IDNS_Member; if (CPlusPlus) @@ -260,9 +263,9 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; - + case Sema::LookupAnyName: - IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol | Decl::IDNS_Type; break; @@ -271,8 +274,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, } void LookupResult::configure() { - IDNS = getIDNS(LookupKind, - SemaRef.getLangOptions().CPlusPlus, + IDNS = getIDNS(LookupKind, SemaRef.getLangOptions().CPlusPlus, isForRedeclaration()); // If we're looking for one of the allocation or deallocation @@ -293,7 +295,6 @@ void LookupResult::configure() { } } -#ifndef NDEBUG void LookupResult::sanity() const { assert(ResultKind != NotFound || Decls.size() == 0); assert(ResultKind != Found || Decls.size() == 1); @@ -302,12 +303,12 @@ void LookupResult::sanity() const { isa<FunctionTemplateDecl>((*begin())->getUnderlyingDecl()))); assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); assert(ResultKind != Ambiguous || Decls.size() > 1 || - (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects)); + (Decls.size() == 1 && (Ambiguity == AmbiguousBaseSubobjects || + Ambiguity == AmbiguousBaseSubobjectTypes))); assert((Paths != NULL) == (ResultKind == Ambiguous && (Ambiguity == AmbiguousBaseSubobjectTypes || Ambiguity == AmbiguousBaseSubobjects))); } -#endif // Necessary because CXXBasePaths is not complete in Sema.h void LookupResult::deletePaths(CXXBasePaths *Paths) { @@ -317,7 +318,7 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) { /// Resolves the result kind of this lookup. void LookupResult::resolveKind() { unsigned N = Decls.size(); - + // Fast case: no possible ambiguity. if (N == 0) { assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation); @@ -340,13 +341,13 @@ void LookupResult::resolveKind() { llvm::SmallPtrSet<NamedDecl*, 16> Unique; llvm::SmallPtrSet<QualType, 16> UniqueTypes; - + bool Ambiguous = false; bool HasTag = false, HasFunction = false, HasNonFunction = false; bool HasFunctionTemplate = false, HasUnresolved = false; unsigned UniqueTagIndex = 0; - + unsigned I = 0; while (I < N) { NamedDecl *D = Decls[I]->getUnderlyingDecl(); @@ -367,14 +368,14 @@ void LookupResult::resolveKind() { } } } - + if (!Unique.insert(D)) { // If it's not unique, pull something off the back (and // continue at this index). Decls[I] = Decls[--N]; continue; - } - + } + // Otherwise, do some decl type analysis and then continue. if (isa<UnresolvedUsingValueDecl>(D)) { @@ -407,8 +408,13 @@ void LookupResult::resolveKind() { // But it's still an error if there are distinct tag types found, // even if they're not visible. (ref?) if (HideTags && HasTag && !Ambiguous && - (HasFunction || HasNonFunction || HasUnresolved)) - Decls[UniqueTagIndex] = Decls[--N]; + (HasFunction || HasNonFunction || HasUnresolved)) { + if (Decls[UniqueTagIndex]->getDeclContext()->getRedeclContext()->Equals( + Decls[UniqueTagIndex? 0 : N-1]->getDeclContext()->getRedeclContext())) + Decls[UniqueTagIndex] = Decls[--N]; + else + Ambiguous = true; + } Decls.set_size(N); @@ -453,7 +459,7 @@ void 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); @@ -480,12 +486,21 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return false; - NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, - S.TUScope, R.isForRedeclaration(), - R.getNameLoc()); - if (D) + if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, + BuiltinID, S.TUScope, + R.isForRedeclaration(), + R.getNameLoc())) { R.addDecl(D); - return (D != NULL); + return true; + } + + if (R.isForRedeclaration()) { + // If we're redeclaring this function anyway, forget that + // this was a builtin at all. + S.Context.BuiltinInfo.ForgetBuiltin(BuiltinID, S.Context.Idents); + } + + return false; } } } @@ -500,16 +515,16 @@ static bool CanDeclareSpecialMemberFunction(ASTContext &Context, // Don't do it if the class is invalid. if (Class->isInvalidDecl()) return false; - + // We need to have a definition for the class. if (!Class->getDefinition() || Class->isDependentContext()) return false; - + // We can't be in the middle of defining the class. if (const RecordType *RecordTy = Context.getTypeDeclType(Class)->getAs<RecordType>()) return !RecordTy->isBeingDefined(); - + return false; } @@ -520,46 +535,46 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { // If the default constructor has not yet been declared, do so now. if (!Class->hasDeclaredDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); - + // If the copy constructor has not yet been declared, do so now. if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); - + // If the copy assignment operator has not yet been declared, do so now. if (!Class->hasDeclaredCopyAssignment()) DeclareImplicitCopyAssignment(Class); // If the destructor has not yet been declared, do so now. if (!Class->hasDeclaredDestructor()) - DeclareImplicitDestructor(Class); + DeclareImplicitDestructor(Class); } -/// \brief Determine whether this is the name of an implicitly-declared +/// \brief Determine whether this is the name of an implicitly-declared /// special member function. static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) { switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: return true; - + case DeclarationName::CXXOperatorName: return Name.getCXXOverloadedOperator() == OO_Equal; - + default: - break; + break; } - + return false; } /// \brief If there are any implicit member functions with the given name /// that need to be declared in the given declaration context, do so. -static void DeclareImplicitMemberFunctionsWithName(Sema &S, +static void DeclareImplicitMemberFunctionsWithName(Sema &S, DeclarationName Name, const DeclContext *DC) { if (!DC) return; - + switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) @@ -572,26 +587,26 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S, S.DeclareImplicitCopyConstructor(const_cast<CXXRecordDecl *>(Record)); } break; - + case DeclarationName::CXXDestructorName: if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) if (Record->getDefinition() && !Record->hasDeclaredDestructor() && CanDeclareSpecialMemberFunction(S.Context, Record)) S.DeclareImplicitDestructor(const_cast<CXXRecordDecl *>(Record)); break; - + case DeclarationName::CXXOperatorName: if (Name.getCXXOverloadedOperator() != OO_Equal) break; - + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) if (Record->getDefinition() && !Record->hasDeclaredCopyAssignment() && CanDeclareSpecialMemberFunction(S.Context, Record)) S.DeclareImplicitCopyAssignment(const_cast<CXXRecordDecl *>(Record)); break; - + default: - break; + break; } } @@ -603,7 +618,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // Lazily declare C++ special member functions. if (S.getLangOptions().CPlusPlus) DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC); - + // Perform lookup into this declaration context. DeclContext::lookup_const_iterator I, E; for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) { @@ -624,7 +639,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { return Found; // C++ [temp.mem]p6: - // A specialization of a conversion function template is not found by + // A specialization of a conversion function template is not found by // name lookup. Instead, any conversion function templates visible in the // context of the use are considered. [...] const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); @@ -632,50 +647,51 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { return Found; const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); - for (UnresolvedSetImpl::iterator U = Unresolved->begin(), + for (UnresolvedSetImpl::iterator U = Unresolved->begin(), UEnd = Unresolved->end(); U != UEnd; ++U) { FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U); if (!ConvTemplate) continue; - + // When we're performing lookup for the purposes of redeclaration, just - // add the conversion function template. When we deduce template - // arguments for specializations, we'll end up unifying the return + // add the conversion function template. When we deduce template + // arguments for specializations, we'll end up unifying the return // type of the new declaration with the type of the function template. if (R.isForRedeclaration()) { R.addDecl(ConvTemplate); Found = true; continue; } - + // C++ [temp.mem]p6: - // [...] For each such operator, if argument deduction succeeds - // (14.9.2.3), the resulting specialization is used as if found by + // [...] For each such operator, if argument deduction succeeds + // (14.9.2.3), the resulting specialization is used as if found by // name lookup. // // When referencing a conversion function for any purpose other than // a redeclaration (such that we'll be building an expression with the - // result), perform template argument deduction and place the + // result), perform template argument deduction and place the // specialization into the result set. We do this to avoid forcing all // callers to perform special deduction for conversion functions. TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc()); FunctionDecl *Specialization = 0; - - const FunctionProtoType *ConvProto + + const FunctionProtoType *ConvProto = ConvTemplate->getTemplatedDecl()->getType()->getAs<FunctionProtoType>(); assert(ConvProto && "Nonsensical conversion function template type"); // Compute the type of the function that we would expect the conversion // function to have, if it were to match the name given. // FIXME: Calling convention! - FunctionType::ExtInfo ConvProtoInfo = ConvProto->getExtInfo(); + FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo(); + EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_Default); + EPI.HasExceptionSpec = false; + EPI.HasAnyExceptionSpec = false; + EPI.NumExceptions = 0; QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), - 0, 0, ConvProto->isVariadic(), - ConvProto->getTypeQuals(), - false, false, 0, 0, - ConvProtoInfo.withCallingConv(CC_Default)); - + 0, 0, EPI); + // Perform template argument deduction against the type that we would // expect the function to have. if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType, @@ -691,7 +707,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // Performs C++ unqualified lookup into the given file context. static bool -CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, +CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, DeclContext *NS, UnqualUsingDirectiveSet &UDirs) { assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!"); @@ -729,7 +745,7 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) { static std::pair<DeclContext *, bool> findOuterContext(Scope *S) { DeclContext *DC = static_cast<DeclContext *>(S->getEntity()); DeclContext *Lexical = 0; - for (Scope *OuterS = S->getParent(); OuterS; + for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent()) { if (OuterS->getEntity()) { Lexical = static_cast<DeclContext *>(OuterS->getEntity()); @@ -745,12 +761,12 @@ static std::pair<DeclContext *, bool> findOuterContext(Scope *S) { // // Example: // - // namespace N { - // class C { }; + // namespace N { + // class C { }; // // template<class T> class B { // void f(T); - // }; + // }; // } // // template<class C> void N::B<C>::f(C) { @@ -759,24 +775,24 @@ static std::pair<DeclContext *, bool> findOuterContext(Scope *S) { // // In this example, the lexical context we return is the // TranslationUnit, while the semantic context is the namespace N. - if (!Lexical || !DC || !S->getParent() || + if (!Lexical || !DC || !S->getParent() || !S->getParent()->isTemplateParamScope()) return std::make_pair(Lexical, false); - // Find the outermost template parameter scope. + // Find the outermost template parameter scope. // For the example, this is the scope for the template parameters of // template<class C>. Scope *OutermostTemplateScope = S->getParent(); while (OutermostTemplateScope->getParent() && OutermostTemplateScope->getParent()->isTemplateParamScope()) OutermostTemplateScope = OutermostTemplateScope->getParent(); - + // Find the namespace context in which the original scope occurs. In // the example, this is namespace N. DeclContext *Semantic = DC; while (!Semantic->isFileContext()) Semantic = Semantic->getParent(); - + // Find the declaration context just outside of the template // parameter scope. This is the context in which the template is // being lexically declaration (a namespace context). In the @@ -800,7 +816,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (DeclContext *DC = static_cast<DeclContext *>(PreS->getEntity())) DeclareImplicitMemberFunctionsWithName(*this, Name, DC); } - + // Implicitly declare member functions with the name we're looking for, if in // fact we are in a scope where it matters. @@ -883,7 +899,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (ObjCInterfaceDecl *Class = Method->getClassInterface()) { ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable( - Name.getAsIdentifierInfo(), + Name.getAsIdentifierInfo(), ClassDeclared)) { if (R.isAcceptableDecl(Ivar)) { R.addDecl(Ivar); @@ -913,6 +929,10 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // FIXME: This really, really shouldn't be happening. if (!S) return false; + // If we are looking for members, no need to look into global/namespace scope. + if (R.getLookupKind() == LookupMemberName) + return false; + // Collect UsingDirectiveDecls in all scopes, and recursively all // nominated namespaces by those using-directives. // @@ -958,7 +978,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { Ctx = OutsideOfTemplateParamDC; OutsideOfTemplateParamDC = 0; } - + if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; @@ -972,24 +992,24 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // non-transparent context. if (Ctx->isTransparentContext()) continue; - + // If we have a context, and it's not a context stashed in the // template parameter scope for an out-of-line definition, also // look into that context. if (!(Found && S && S->isTemplateParamScope())) { assert(Ctx->isFileContext() && "We should have been looking only at file context here already."); - + // Look into context considering using-directives. if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) Found = true; } - + if (Found) { R.resolveKind(); return true; } - + if (R.isForRedeclaration() && !Ctx->isTransparentContext()) return false; } @@ -1042,7 +1062,6 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { if (!getLangOptions().CPlusPlus) { // Unqualified name lookup in C/Objective-C is purely lexical, so // search in the declarations attached to the name. - if (NameKind == Sema::LookupRedeclarationWithLinkage) { // Find the nearest non-transparent declaration scope. while (!(S->getFlags() & Scope::DeclScope) || @@ -1228,16 +1247,48 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, } /// \brief Callback that looks for any member of a class with the given name. -static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, +static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); - + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); Path.Decls = BaseRecord->lookup(N); return Path.Decls.first != Path.Decls.second; } +/// \brief Determine whether the given set of member declarations contains only +/// static members, nested types, and enumerators. +template<typename InputIterator> +static bool HasOnlyStaticMembers(InputIterator First, InputIterator Last) { + Decl *D = (*First)->getUnderlyingDecl(); + if (isa<VarDecl>(D) || isa<TypeDecl>(D) || isa<EnumConstantDecl>(D)) + return true; + + if (isa<CXXMethodDecl>(D)) { + // Determine whether all of the methods are static. + bool AllMethodsAreStatic = true; + for(; First != Last; ++First) { + D = (*First)->getUnderlyingDecl(); + + if (!isa<CXXMethodDecl>(D)) { + assert(isa<TagDecl>(D) && "Non-function must be a tag decl"); + break; + } + + if (!cast<CXXMethodDecl>(D)->isStatic()) { + AllMethodsAreStatic = false; + break; + } + } + + if (AllMethodsAreStatic) + return true; + } + + return false; +} + /// \brief Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find @@ -1256,7 +1307,7 @@ static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, /// search. If the lookup criteria permits, name lookup may also search /// in the parent contexts or (for C++ classes) base classes. /// -/// \param InUnqualifiedLookup true if this is qualified name lookup that +/// \param InUnqualifiedLookup true if this is qualified name lookup that /// occurs as part of unqualified name lookup. /// /// \returns true if lookup succeeded, false if it failed. @@ -1307,7 +1358,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // If we're performing qualified name lookup into a dependent class, // then we are actually looking into a current instantiation. If we have any - // dependent base classes, then we either have to delay lookup until + // dependent base classes, then we either have to delay lookup until // template instantiation time (at which point all bases will be available) // or we have to fail. if (!InUnqualifiedLookup && LookupRec->isDependentContext() && @@ -1315,7 +1366,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, R.setNotFoundInCurrentInstantiation(); return false; } - + // Perform lookup into our base classes. CXXBasePaths Paths; Paths.setOrigin(LookupRec); @@ -1328,7 +1379,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, case LookupRedeclarationWithLinkage: BaseCallback = &CXXRecordDecl::FindOrdinaryMember; break; - + case LookupTagName: BaseCallback = &CXXRecordDecl::FindTagMember; break; @@ -1336,21 +1387,22 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, case LookupAnyName: BaseCallback = &LookupAnyMember; break; - + case LookupUsingDeclName: // This lookup is for redeclarations only. - + case LookupOperatorName: case LookupNamespaceName: case LookupObjCProtocolName: + case LookupLabel: // 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, R.getLookupName().getAsOpaquePtr(), Paths)) return false; @@ -1363,10 +1415,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // and includes members from distinct sub-objects, there is an // ambiguity and the program is ill-formed. Otherwise that set is // the result of the lookup. - // FIXME: support using declarations! QualType SubobjectType; int SubobjectNumber = 0; AccessSpecifier SubobjectAccess = AS_none; + for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); @@ -1374,51 +1426,54 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Pick the best (i.e. most permissive i.e. numerically lowest) access // across all paths. SubobjectAccess = std::min(SubobjectAccess, Path->Access); - + // 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 its type. SubobjectType = Context.getCanonicalType(PathElement.Base->getType()); SubobjectNumber = PathElement.SubobjectNumber; - } else if (SubobjectType + continue; + } + + if (SubobjectType != Context.getCanonicalType(PathElement.Base->getType())) { // We found members of the given name in two subobjects of - // different types. This lookup is ambiguous. + // different types. If the declaration sets aren't the same, this + // this lookup is ambiguous. + if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) { + CXXBasePaths::paths_iterator FirstPath = Paths.begin(); + DeclContext::lookup_iterator FirstD = FirstPath->Decls.first; + DeclContext::lookup_iterator CurrentD = Path->Decls.first; + + while (FirstD != FirstPath->Decls.second && + CurrentD != Path->Decls.second) { + if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() != + (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl()) + break; + + ++FirstD; + ++CurrentD; + } + + if (FirstD == FirstPath->Decls.second && + CurrentD == Path->Decls.second) + continue; + } + R.setAmbiguousBaseSubobjectTypes(Paths); return true; - } else if (SubobjectNumber != PathElement.SubobjectNumber) { + } + + 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. - Decl *FirstDecl = *Path->Decls.first; - if (isa<VarDecl>(FirstDecl) || - isa<TypeDecl>(FirstDecl) || - isa<EnumConstantDecl>(FirstDecl)) + if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) continue; - if (isa<CXXMethodDecl>(FirstDecl)) { - // Determine whether all of the methods are static. - bool AllMethodsAreStatic = true; - for (DeclContext::lookup_iterator Func = Path->Decls.first; - Func != Path->Decls.second; ++Func) { - if (!isa<CXXMethodDecl>(*Func)) { - assert(isa<TagDecl>(*Func) && "Non-function must be a tag decl"); - break; - } - - if (!cast<CXXMethodDecl>(*Func)->isStatic()) { - AllMethodsAreStatic = false; - break; - } - } - - if (AllMethodsAreStatic) - continue; - } - // We have found a nonstatic member name in multiple, distinct // subobjects. Name lookup is ambiguous. R.setAmbiguousBaseSubobjects(Paths); @@ -1453,13 +1508,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, /// /// @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 -/// C library functions (like "malloc") are implicitly declared. -/// /// @param EnteringContext Indicates whether we are going to enter the /// context of the scope-specifier SS (if present). /// @@ -1525,21 +1573,21 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { 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 (CXXBasePaths::paths_iterator Path = Paths->begin(), @@ -1582,7 +1630,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { 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; @@ -1648,11 +1696,12 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, addAssociatedClassesAndNamespaces(Result, Arg.getAsType()); break; - case TemplateArgument::Template: { + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { // [...] 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. - TemplateName Template = Arg.getAsTemplate(); + TemplateName Template = Arg.getAsTemplateOrTemplatePattern(); if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(Template.getAsTemplateDecl())) { DeclContext *Ctx = ClassTemplate->getDeclContext(); @@ -1663,7 +1712,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, } break; } - + case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Expression: @@ -1713,7 +1762,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // -- 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 + // 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 @@ -1840,7 +1889,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // -- 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 + // member, its associated class is the member's class; else // it has no associated class. case Type::Enum: { EnumDecl *Enum = cast<EnumType>(T)->getDecl(); @@ -2032,7 +2081,7 @@ NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, } /// \brief Find the protocol with the given name, if any. -ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, +ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc) { Decl *D = LookupSingleName(TUScope, II, IdLoc, LookupObjCProtocolName); @@ -2089,7 +2138,7 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); } - + CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T); return Class->lookup(Name); @@ -2097,7 +2146,7 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { /// \brief Look for the destructor of the given class. /// -/// During semantic analysis, this routine should be used in lieu of +/// During semantic analysis, this routine should be used in lieu of /// CXXRecordDecl::getDestructor(). /// /// \returns The destructor for this class. @@ -2233,7 +2282,7 @@ public: /// of declarations. class ShadowMapEntry { typedef llvm::SmallVector<NamedDecl *, 4> DeclVector; - + /// \brief Contains either the solitary NamedDecl * or a vector /// of declarations. llvm::PointerUnion<NamedDecl *, DeclVector*> DeclOrVector; @@ -2245,7 +2294,7 @@ public: void Destroy(); // Iteration. - typedef NamedDecl **iterator; + typedef NamedDecl * const *iterator; iterator begin(); iterator end(); }; @@ -2315,7 +2364,7 @@ void VisibleDeclsRecord::ShadowMapEntry::Add(NamedDecl *ND) { DeclOrVector = ND; return; } - + if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) { // 1 -> 2 elements: create the vector of results and push in the // existing declaration. @@ -2335,18 +2384,18 @@ void VisibleDeclsRecord::ShadowMapEntry::Destroy() { } } -VisibleDeclsRecord::ShadowMapEntry::iterator +VisibleDeclsRecord::ShadowMapEntry::iterator VisibleDeclsRecord::ShadowMapEntry::begin() { if (DeclOrVector.isNull()) return 0; - if (DeclOrVector.dyn_cast<NamedDecl *>()) - return &reinterpret_cast<NamedDecl*&>(DeclOrVector); + if (DeclOrVector.is<NamedDecl *>()) + return DeclOrVector.getAddrOf<NamedDecl *>(); return DeclOrVector.get<DeclVector *>()->begin(); } -VisibleDeclsRecord::ShadowMapEntry::iterator +VisibleDeclsRecord::ShadowMapEntry::iterator VisibleDeclsRecord::ShadowMapEntry::end() { if (DeclOrVector.isNull()) return 0; @@ -2360,7 +2409,7 @@ VisibleDeclsRecord::ShadowMapEntry::end() { NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { // Look through using declarations. ND = ND->getUnderlyingDecl(); - + unsigned IDNS = ND->getIdentifierNamespace(); std::list<ShadowMap>::reverse_iterator SM = ShadowMaps.rbegin(); for (std::list<ShadowMap>::reverse_iterator SMEnd = ShadowMaps.rend(); @@ -2369,12 +2418,12 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { if (Pos == SM->end()) continue; - for (ShadowMapEntry::iterator I = Pos->second.begin(), + for (ShadowMapEntry::iterator I = Pos->second.begin(), IEnd = Pos->second.end(); I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. if ((*I)->hasTagIdentifierNamespace() && - (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | + (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; @@ -2391,7 +2440,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { ND->isFunctionOrFunctionTemplate() && SM == ShadowMaps.rbegin()) continue; - + // We've found a declaration that hides this one. return *I; } @@ -2411,22 +2460,44 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Make sure we don't visit the same context twice. if (Visited.visitedContext(Ctx->getPrimaryContext())) return; - + if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) Result.getSema().ForceDeclarationOfImplicitMembers(Class); // Enumerate all of the results in this context. - for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; + for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; CurCtx = CurCtx->getNextContext()) { - for (DeclContext::decl_iterator D = CurCtx->decls_begin(), + for (DeclContext::decl_iterator D = CurCtx->decls_begin(), DEnd = CurCtx->decls_end(); D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) + if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) { if (Result.isAcceptableDecl(ND)) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass); Visited.add(ND); } - + } else if (ObjCForwardProtocolDecl *ForwardProto + = dyn_cast<ObjCForwardProtocolDecl>(*D)) { + for (ObjCForwardProtocolDecl::protocol_iterator + P = ForwardProto->protocol_begin(), + PEnd = ForwardProto->protocol_end(); + P != PEnd; + ++P) { + if (Result.isAcceptableDecl(*P)) { + Consumer.FoundDecl(*P, Visited.checkHidden(*P), InBaseClass); + Visited.add(*P); + } + } + } else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) { + for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end(); + I != IEnd; ++I) { + ObjCInterfaceDecl *IFace = I->getInterface(); + if (Result.isAcceptableDecl(IFace)) { + Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), InBaseClass); + Visited.add(IFace); + } + } + } + // Visit transparent contexts and inline namespaces inside this context. if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) { if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) @@ -2441,7 +2512,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, ShadowContextRAII Shadow(Visited); DeclContext::udir_iterator I, E; for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) { - LookupVisibleDecls((*I)->getNominatedNamespace(), Result, + LookupVisibleDecls((*I)->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } } @@ -2455,16 +2526,16 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, 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 // @@ -2483,21 +2554,21 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // or // // c->A::member - + // Find results in this base class (and its bases). ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup, true, Consumer, Visited); } } - + // Traverse the contexts of Objective-C classes. if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) { // Traverse categories. for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category; Category = Category->getNextClassCategory()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Category, Result, QualifiedNameLookup, false, + LookupVisibleDecls(Category, Result, QualifiedNameLookup, false, Consumer, Visited); } @@ -2506,7 +2577,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, I = IFace->all_referenced_protocol_begin(), E = IFace->all_referenced_protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } @@ -2516,35 +2587,35 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, true, Consumer, Visited); } - + // If there is an implementation, traverse it. We do this to find // synthesized ivars. if (IFace->getImplementation()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(IFace->getImplementation(), Result, + LookupVisibleDecls(IFace->getImplementation(), Result, QualifiedNameLookup, true, Consumer, Visited); } } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) { for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(), E = Protocol->protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) { for (ObjCCategoryDecl::protocol_iterator I = Category->protocol_begin(), E = Category->protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } - + // If there is an implementation, traverse it. if (Category->getImplementation()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Category->getImplementation(), Result, + LookupVisibleDecls(Category->getImplementation(), Result, QualifiedNameLookup, true, Consumer, Visited); - } + } } } @@ -2555,8 +2626,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, if (!S) return; - if (!S->getEntity() || - (!S->getParent() && + if (!S->getEntity() || + (!S->getParent() && !Visited.alreadyVisitedContext((DeclContext *)S->getEntity())) || ((DeclContext *)S->getEntity())->isFunctionOrMethod()) { // Walk through the declarations in this Scope. @@ -2569,7 +2640,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, } } } - + // FIXME: C++ [temp.local]p8 DeclContext *Entity = 0; if (S->getEntity()) { @@ -2578,7 +2649,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // where we hit the context stored in the next outer scope. Entity = (DeclContext *)S->getEntity(); DeclContext *OuterCtx = findOuterContext(S).first; // FIXME - + for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) { @@ -2586,9 +2657,27 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // For instance methods, look for ivars in the method's interface. LookupResult IvarResult(Result.getSema(), Result.getLookupName(), Result.getNameLoc(), Sema::LookupMemberName); - if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) - LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, + if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { + LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); + + // Look for properties from which we can synthesize ivars, if + // permitted. + if (Result.getSema().getLangOptions().ObjCNonFragileABI2 && + IFace->getImplementation() && + Result.getLookupKind() == Sema::LookupOrdinaryName) { + for (ObjCInterfaceDecl::prop_iterator + P = IFace->prop_begin(), + PEnd = IFace->prop_end(); + P != PEnd; ++P) { + if (Result.getSema().canSynthesizeProvisionalIvar(*P) && + !IFace->lookupInstanceVariable((*P)->getIdentifier())) { + Consumer.FoundDecl(*P, Visited.checkHidden(*P), false); + Visited.add(*P); + } + } + } + } } // We've already performed all of the name lookup that we need @@ -2599,8 +2688,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, if (Ctx->isFunctionOrMethod()) continue; - - LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, + + LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } } else if (!S->getParent()) { @@ -2610,14 +2699,14 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // 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. + // 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 this. Entity = Result.getSema().Context.getTranslationUnitDecl(); - LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, + LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); - } - + } + if (Entity) { // Lookup visible declarations in any namespaces found by using // directives. @@ -2625,7 +2714,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity); for (; UI != UEnd; ++UI) LookupVisibleDecls(const_cast<DeclContext *>(UI->getNominatedNamespace()), - Result, /*QualifiedNameLookup=*/false, + Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } @@ -2667,13 +2756,41 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, if (!IncludeGlobalScope) Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, + ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, /*InBaseClass=*/false, Consumer, Visited); } -//---------------------------------------------------------------------------- +/// LookupOrCreateLabel - Do a name lookup of a label with the specified name. +/// If isLocalLabel is true, then this is a definition of an __label__ label +/// name, otherwise it is a normal label definition or use. +LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, + bool isLocalLabel) { + // Do a lookup to see if we have a label with this name already. + NamedDecl *Res = 0; + + // Local label definitions always shadow existing labels. + if (!isLocalLabel) + Res = LookupSingleName(CurScope, II, Loc, LookupLabel, NotForRedeclaration); + + // If we found a label, check to see if it is in the same context as us. When + // in a Block, we don't want to reuse a label in an enclosing function. + if (Res && Res->getDeclContext() != CurContext) + Res = 0; + + if (Res == 0) { + // If not forward referenced or defined already, create the backing decl. + Res = LabelDecl::Create(Context, CurContext, Loc, II); + Scope *S = isLocalLabel ? CurScope : CurScope->getFnParent(); + assert(S && "Not in a function?"); + PushOnScopeChains(Res, S, true); + } + + return cast<LabelDecl>(Res); +} + +//===----------------------------------------------------------------------===// // Typo correction -//---------------------------------------------------------------------------- +//===----------------------------------------------------------------------===// namespace { class TypoCorrectionConsumer : public VisibleDeclConsumer { @@ -2682,46 +2799,44 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { /// \brief The results found that have the smallest edit distance /// found (so far) with the typo name. - llvm::SmallVector<NamedDecl *, 4> BestResults; + /// + /// The boolean value indicates whether there is a keyword with this name. + llvm::StringMap<bool, llvm::BumpPtrAllocator> BestResults; - /// \brief The keywords that have the smallest edit distance. - llvm::SmallVector<IdentifierInfo *, 4> BestKeywords; - /// \brief The best edit distance found so far. unsigned BestEditDistance; - + public: explicit TypoCorrectionConsumer(IdentifierInfo *Typo) - : Typo(Typo->getName()) { } + : Typo(Typo->getName()), + BestEditDistance((std::numeric_limits<unsigned>::max)()) { } virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); + void FoundName(llvm::StringRef Name); void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword); - typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator; - iterator begin() const { return BestResults.begin(); } - iterator end() const { return BestResults.end(); } - void clear_decls() { BestResults.clear(); } - - bool empty() const { return BestResults.empty() && BestKeywords.empty(); } - - typedef llvm::SmallVector<IdentifierInfo *, 4>::const_iterator - keyword_iterator; - keyword_iterator keyword_begin() const { return BestKeywords.begin(); } - keyword_iterator keyword_end() const { return BestKeywords.end(); } - bool keyword_empty() const { return BestKeywords.empty(); } - unsigned keyword_size() const { return BestKeywords.size(); } - - unsigned getBestEditDistance() const { return BestEditDistance; } + typedef llvm::StringMap<bool, llvm::BumpPtrAllocator>::iterator iterator; + iterator begin() { return BestResults.begin(); } + iterator end() { return BestResults.end(); } + void erase(iterator I) { BestResults.erase(I); } + unsigned size() const { return BestResults.size(); } + bool empty() const { return BestResults.empty(); } + + bool &operator[](llvm::StringRef Name) { + return BestResults[Name]; + } + + unsigned getBestEditDistance() const { return BestEditDistance; } }; } -void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, +void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) { // Don't consider hidden names for typo correction. if (Hiding) return; - + // Only consider entities with identifiers for names, ignoring // special names (constructors, overloaded operators, selectors, // etc.). @@ -2729,48 +2844,114 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, if (!Name) return; + FoundName(Name->getName()); +} + +void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) { + using namespace std; + + // Use a simple length-based heuristic to determine the minimum possible + // edit distance. If the minimum isn't good enough, bail out early. + unsigned MinED = abs((int)Name.size() - (int)Typo.size()); + if (MinED > BestEditDistance || (MinED && Typo.size() / MinED < 3)) + return; + + // Compute an upper bound on the allowable edit distance, so that the + // edit-distance algorithm can short-circuit. + unsigned UpperBound = min(unsigned((Typo.size() + 2) / 3), BestEditDistance); + // Compute the edit distance between the typo and the name of this // entity. If this edit distance is not worse than the best edit // distance we've seen so far, add it to the list of results. - unsigned ED = Typo.edit_distance(Name->getName()); - if (!BestResults.empty() || !BestKeywords.empty()) { - if (ED < BestEditDistance) { - // This result is better than any we've seen before; clear out - // the previous results. - BestResults.clear(); - BestKeywords.clear(); - BestEditDistance = ED; - } else if (ED > BestEditDistance) { - // This result is worse than the best results we've seen so far; - // ignore it. - return; - } - } else + unsigned ED = Typo.edit_distance(Name, true, UpperBound); + if (ED == 0) + return; + + if (ED < BestEditDistance) { + // This result is better than any we've seen before; clear out + // the previous results. + BestResults.clear(); BestEditDistance = ED; + } else if (ED > BestEditDistance) { + // This result is worse than the best results we've seen so far; + // ignore it. + return; + } - BestResults.push_back(ND); + // Add this name to the list of results. By not assigning a value, we + // keep the current value if we've seen this name before (either as a + // keyword or as a declaration), or get the default value (not a keyword) + // if we haven't seen it before. + (void)BestResults[Name]; } -void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, +void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, llvm::StringRef Keyword) { // Compute the edit distance between the typo and this keyword. // If this edit distance is not worse than the best edit // distance we've seen so far, add it to the list of results. unsigned ED = Typo.edit_distance(Keyword); - if (!BestResults.empty() || !BestKeywords.empty()) { - if (ED < BestEditDistance) { - BestResults.clear(); - BestKeywords.clear(); - BestEditDistance = ED; - } else if (ED > BestEditDistance) { - // This result is worse than the best results we've seen so far; - // ignore it. - return; - } - } else + if (ED < BestEditDistance) { + BestResults.clear(); BestEditDistance = ED; - - BestKeywords.push_back(&Context.Idents.get(Keyword)); + } else if (ED > BestEditDistance) { + // This result is worse than the best results we've seen so far; + // ignore it. + return; + } + + BestResults[Keyword] = true; +} + +/// \brief Perform name lookup for a possible result for typo correction. +static void LookupPotentialTypoResult(Sema &SemaRef, + LookupResult &Res, + IdentifierInfo *Name, + Scope *S, CXXScopeSpec *SS, + DeclContext *MemberContext, + bool EnteringContext, + Sema::CorrectTypoContext CTC) { + Res.suppressDiagnostics(); + Res.clear(); + Res.setLookupName(Name); + if (MemberContext) { + if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(MemberContext)) { + if (CTC == Sema::CTC_ObjCIvarLookup) { + if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(Name)) { + Res.addDecl(Ivar); + Res.resolveKind(); + return; + } + } + + if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration(Name)) { + Res.addDecl(Prop); + Res.resolveKind(); + return; + } + } + + SemaRef.LookupQualifiedName(Res, MemberContext); + return; + } + + SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, + EnteringContext); + + // Fake ivar lookup; this should really be part of + // LookupParsedName. + if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) { + if (Method->isInstanceMethod() && Method->getClassInterface() && + (Res.empty() || + (Res.isSingleResult() && + Res.getFoundDecl()->isDefinedOutsideFunctionOrMethod()))) { + if (ObjCIvarDecl *IV + = Method->getClassInterface()->lookupInstanceVariable(Name)) { + Res.addDecl(IV); + Res.resolveKind(); + } + } + } } /// \brief Try to "correct" a typo in the source code by finding @@ -2790,7 +2971,7 @@ void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, /// \param MemberContext if non-NULL, the context in which to look for /// a member access expression. /// -/// \param EnteringContext whether we're entering the context described by +/// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// /// \param CTC The context in which typo correction occurs, which impacts the @@ -2804,21 +2985,13 @@ void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, /// may contain the results of name lookup for the correct name or it may be /// empty. DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, - DeclContext *MemberContext, + DeclContext *MemberContext, bool EnteringContext, CorrectTypoContext CTC, const ObjCObjectPointerType *OPT) { if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking) return DeclarationName(); - // Provide a stop gap for files that are just seriously broken. Trying - // to correct all typos can turn into a HUGE performance penalty, causing - // some files to take minutes to get rejected by the parser. - // FIXME: Is this the right solution? - if (TyposCorrected == 20) - return DeclarationName(); - ++TyposCorrected; - // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); if (!Typo) @@ -2833,17 +3006,18 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, // instantiation. if (!ActiveTemplateInstantiations.empty()) return DeclarationName(); - + TypoCorrectionConsumer Consumer(Typo); - + // Perform name lookup to find visible, similarly-named entities. + bool IsUnqualifiedLookup = false; if (MemberContext) { LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer); // Look in qualified interfaces. if (OPT) { - for (ObjCObjectPointerType::qual_iterator - I = OPT->qual_begin(), E = OPT->qual_end(); + for (ObjCObjectPointerType::qual_iterator + I = OPT->qual_begin(), E = OPT->qual_end(); I != E; ++I) LookupVisibleDecls(*I, Res.getLookupKind(), Consumer); } @@ -2851,10 +3025,54 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, DeclContext *DC = computeDeclContext(*SS, EnteringContext); if (!DC) return DeclarationName(); - + + // Provide a stop gap for files that are just seriously broken. Trying + // to correct all typos can turn into a HUGE performance penalty, causing + // some files to take minutes to get rejected by the parser. + if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) + return DeclarationName(); + ++TyposCorrected; + LookupVisibleDecls(DC, Res.getLookupKind(), Consumer); } else { - LookupVisibleDecls(S, Res.getLookupKind(), Consumer); + IsUnqualifiedLookup = true; + UnqualifiedTyposCorrectedMap::iterator Cached + = UnqualifiedTyposCorrected.find(Typo); + if (Cached == UnqualifiedTyposCorrected.end()) { + // Provide a stop gap for files that are just seriously broken. Trying + // to correct all typos can turn into a HUGE performance penalty, causing + // some files to take minutes to get rejected by the parser. + if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) + return DeclarationName(); + + // For unqualified lookup, look through all of the names that we have + // seen in this translation unit. + for (IdentifierTable::iterator I = Context.Idents.begin(), + IEnd = Context.Idents.end(); + I != IEnd; ++I) + Consumer.FoundName(I->getKey()); + + // Walk through identifiers in external identifier sources. + if (IdentifierInfoLookup *External + = Context.Idents.getExternalIdentifierLookup()) { + llvm::OwningPtr<IdentifierIterator> Iter(External->getIdentifiers()); + do { + llvm::StringRef Name = Iter->Next(); + if (Name.empty()) + break; + + Consumer.FoundName(Name); + } while (true); + } + } else { + // Use the cached value, unless it's a keyword. In the keyword case, we'll + // end up adding the keyword below. + if (Cached->second.first.empty()) + return DeclarationName(); + + if (!Cached->second.second) + Consumer.FoundName(Cached->second.first); + } } // Add context-dependent keywords. @@ -2868,39 +3086,46 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, WantExpressionKeywords = true; WantCXXNamedCasts = true; WantRemainingKeywords = true; - + if (ObjCMethodDecl *Method = getCurMethodDecl()) if (Method->getClassInterface() && Method->getClassInterface()->getSuperClass()) Consumer.addKeywordResult(Context, "super"); - + break; - + case CTC_NoKeywords: break; - + case CTC_Type: WantTypeSpecifiers = true; break; - + case CTC_ObjCMessageReceiver: Consumer.addKeywordResult(Context, "super"); // Fall through to handle message receivers like expressions. - + case CTC_Expression: if (getLangOptions().CPlusPlus) WantTypeSpecifiers = true; WantExpressionKeywords = true; // Fall through to get C++ named casts. - + case CTC_CXXCasts: WantCXXNamedCasts = true; break; - + + case CTC_ObjCPropertyLookup: + // FIXME: Add "isa"? + break; + case CTC_MemberLookup: if (getLangOptions().CPlusPlus) Consumer.addKeywordResult(Context, "template"); break; + + case CTC_ObjCIvarLookup: + break; } if (WantTypeSpecifiers) { @@ -2912,67 +3137,67 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, // storage-specifiers as well "extern", "inline", "static", "typedef" }; - + const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]); for (unsigned I = 0; I != NumCTypeSpecs; ++I) Consumer.addKeywordResult(Context, CTypeSpecs[I]); - + if (getLangOptions().C99) Consumer.addKeywordResult(Context, "restrict"); if (getLangOptions().Bool || getLangOptions().CPlusPlus) Consumer.addKeywordResult(Context, "bool"); - + if (getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "class"); Consumer.addKeywordResult(Context, "typename"); Consumer.addKeywordResult(Context, "wchar_t"); - + if (getLangOptions().CPlusPlus0x) { Consumer.addKeywordResult(Context, "char16_t"); Consumer.addKeywordResult(Context, "char32_t"); Consumer.addKeywordResult(Context, "constexpr"); Consumer.addKeywordResult(Context, "decltype"); Consumer.addKeywordResult(Context, "thread_local"); - } + } } - + if (getLangOptions().GNUMode) Consumer.addKeywordResult(Context, "typeof"); } - + if (WantCXXNamedCasts && getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "const_cast"); Consumer.addKeywordResult(Context, "dynamic_cast"); Consumer.addKeywordResult(Context, "reinterpret_cast"); Consumer.addKeywordResult(Context, "static_cast"); } - + if (WantExpressionKeywords) { Consumer.addKeywordResult(Context, "sizeof"); if (getLangOptions().Bool || getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "false"); Consumer.addKeywordResult(Context, "true"); } - + if (getLangOptions().CPlusPlus) { - const char *CXXExprs[] = { - "delete", "new", "operator", "throw", "typeid" + const char *CXXExprs[] = { + "delete", "new", "operator", "throw", "typeid" }; const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]); for (unsigned I = 0; I != NumCXXExprs; ++I) Consumer.addKeywordResult(Context, CXXExprs[I]); - + if (isa<CXXMethodDecl>(CurContext) && cast<CXXMethodDecl>(CurContext)->isInstance()) Consumer.addKeywordResult(Context, "this"); - + if (getLangOptions().CPlusPlus0x) { Consumer.addKeywordResult(Context, "alignof"); Consumer.addKeywordResult(Context, "nullptr"); } } } - + if (WantRemainingKeywords) { if (getCurFunctionOrMethodDecl() || getCurBlock()) { // Statements. @@ -2981,18 +3206,18 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]); for (unsigned I = 0; I != NumCStmts; ++I) Consumer.addKeywordResult(Context, CStmts[I]); - + if (getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "catch"); Consumer.addKeywordResult(Context, "try"); } - + if (S && S->getBreakParent()) Consumer.addKeywordResult(Context, "break"); - + if (S && S->getContinueParent()) Consumer.addKeywordResult(Context, "continue"); - + if (!getCurFunction()->SwitchStack.empty()) { Consumer.addKeywordResult(Context, "case"); Consumer.addKeywordResult(Context, "default"); @@ -3013,7 +3238,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, Consumer.addKeywordResult(Context, "virtual"); } } - + if (getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "using"); @@ -3021,122 +3246,134 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, Consumer.addKeywordResult(Context, "static_assert"); } } - + // If we haven't found anything, we're done. - if (Consumer.empty()) + if (Consumer.empty()) { + // If this was an unqualified lookup, note that no correction was found. + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; + return DeclarationName(); + } - // Only allow a single, closest name in the result set (it's okay to - // have overloads of that name, though). - DeclarationName BestName; - NamedDecl *BestIvarOrPropertyDecl = 0; - bool FoundIvarOrPropertyDecl = false; - - // Check all of the declaration results to find the best name so far. - for (TypoCorrectionConsumer::iterator I = Consumer.begin(), + // Make sure that the user typed at least 3 characters for each correction + // made. Otherwise, we don't even both looking at the results. + + // We also suppress exact matches; those should be handled by a + // different mechanism (e.g., one that introduces qualification in + // C++). + unsigned ED = Consumer.getBestEditDistance(); + if (ED > 0 && Typo->getName().size() / ED < 3) { + // If this was an unqualified lookup, note that no correction was found. + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; + + return DeclarationName(); + } + + // Weed out any names that could not be found by name lookup. + bool LastLookupWasAccepted = false; + for (TypoCorrectionConsumer::iterator I = Consumer.begin(), IEnd = Consumer.end(); - I != IEnd; ++I) { - if (!BestName) - BestName = (*I)->getDeclName(); - else if (BestName != (*I)->getDeclName()) - return DeclarationName(); + I != IEnd; /* Increment in loop. */) { + // Keywords are always found. + if (I->second) { + ++I; + continue; + } + + // Perform name lookup on this name. + IdentifierInfo *Name = &Context.Idents.get(I->getKey()); + LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext, + EnteringContext, CTC); - // \brief Keep track of either an Objective-C ivar or a property, but not - // both. - if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I)) { - if (FoundIvarOrPropertyDecl) - BestIvarOrPropertyDecl = 0; - else { - BestIvarOrPropertyDecl = *I; - FoundIvarOrPropertyDecl = true; + switch (Res.getResultKind()) { + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::Ambiguous: + // We didn't find this name in our scope, or didn't like what we found; + // ignore it. + Res.suppressDiagnostics(); + { + TypoCorrectionConsumer::iterator Next = I; + ++Next; + Consumer.erase(I); + I = Next; } + LastLookupWasAccepted = false; + break; + + case LookupResult::Found: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + ++I; + LastLookupWasAccepted = true; + break; + } + + if (Res.isAmbiguous()) { + // We don't deal with ambiguities. + Res.suppressDiagnostics(); + Res.clear(); + return DeclarationName(); } } - // Now check all of the keyword results to find the best name. - switch (Consumer.keyword_size()) { - case 0: - // No keywords matched. - break; - - case 1: - // If we already have a name - if (!BestName) { - // We did not have anything previously, - BestName = *Consumer.keyword_begin(); - } else if (BestName.getAsIdentifierInfo() == *Consumer.keyword_begin()) { - // We have a declaration with the same name as a context-sensitive - // keyword. The keyword takes precedence. - BestIvarOrPropertyDecl = 0; - FoundIvarOrPropertyDecl = false; - Consumer.clear_decls(); - } else if (CTC == CTC_ObjCMessageReceiver && - (*Consumer.keyword_begin())->isStr("super")) { - // In an Objective-C message send, give the "super" keyword a slight - // edge over entities not in function or method scope. - for (TypoCorrectionConsumer::iterator I = Consumer.begin(), - IEnd = Consumer.end(); - I != IEnd; ++I) { - if ((*I)->getDeclName() == BestName) { - if ((*I)->getDeclContext()->isFunctionOrMethod()) - return DeclarationName(); - } - } - - // Everything found was outside a function or method; the 'super' - // keyword takes precedence. - BestIvarOrPropertyDecl = 0; - FoundIvarOrPropertyDecl = false; - Consumer.clear_decls(); - BestName = *Consumer.keyword_begin(); - } else { - // Name collision; we will not correct typos. + // If only a single name remains, return that result. + if (Consumer.size() == 1) { + IdentifierInfo *Name = &Context.Idents.get(Consumer.begin()->getKey()); + if (Consumer.begin()->second) { + Res.suppressDiagnostics(); + Res.clear(); + + // Don't correct to a keyword that's the same as the typo; the keyword + // wasn't actually in scope. + if (ED == 0) { + Res.setLookupName(Typo); return DeclarationName(); } - break; - - default: - // Name collision; we will not correct typos. - return DeclarationName(); - } - - // BestName is the closest viable name to what the user - // typed. However, to make sure that we don't pick something that's - // way off, make sure that the user typed at least 3 characters for - // each correction. - unsigned ED = Consumer.getBestEditDistance(); - if (ED == 0 || !BestName.getAsIdentifierInfo() || - (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3) - return DeclarationName(); - // Perform name lookup again with the name we chose, and declare - // success if we found something that was not ambiguous. - Res.clear(); - Res.setLookupName(BestName); - - // If we found an ivar or property, add that result; no further - // lookup is required. - if (BestIvarOrPropertyDecl) - Res.addDecl(BestIvarOrPropertyDecl); - // If we're looking into the context of a member, perform qualified - // name lookup on the best name. - else if (!Consumer.keyword_empty()) { - // The best match was a keyword. Return it. - return BestName; - } else if (MemberContext) - LookupQualifiedName(Res, MemberContext); - // Perform lookup as if we had just parsed the best name. - else - LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, - EnteringContext); + } else if (!LastLookupWasAccepted) { + // Perform name lookup on this name. + LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext, + EnteringContext, CTC); + } - if (Res.isAmbiguous()) { + // Record the correction for unqualified lookup. + if (IsUnqualifiedLookup) + UnqualifiedTyposCorrected[Typo] + = std::make_pair(Name->getName(), Consumer.begin()->second); + + return &Context.Idents.get(Consumer.begin()->getKey()); + } + else if (Consumer.size() > 1 && CTC == CTC_ObjCMessageReceiver + && Consumer["super"]) { + // Prefix 'super' when we're completing in a message-receiver + // context. Res.suppressDiagnostics(); - return DeclarationName(); + Res.clear(); + + // Don't correct to a keyword that's the same as the typo; the keyword + // wasn't actually in scope. + if (ED == 0) { + Res.setLookupName(Typo); + return DeclarationName(); + } + + // Record the correction for unqualified lookup. + if (IsUnqualifiedLookup) + UnqualifiedTyposCorrected[Typo] + = std::make_pair("super", Consumer.begin()->second); + + return &Context.Idents.get("super"); } - if (Res.getResultKind() != LookupResult::NotFound) - return BestName; - + Res.suppressDiagnostics(); + Res.setLookupName(Typo); + Res.clear(); + // Record the correction for unqualified lookup. + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; + return DeclarationName(); } diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 7181d58..b086ca7 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -31,7 +31,8 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, Selector SetterSel, Decl *ClassCategory, bool *isOverridingProperty, - tok::ObjCKeywordKind MethodImplKind) { + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC) { unsigned Attributes = ODS.getPropertyAttributes(); bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || // default is readwrite! @@ -70,6 +71,9 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, TSI, MethodImplKind); + if (lexicalDC) + Res->setLexicalDeclContext(lexicalDC); + // Validate the attributes on the @property. CheckObjCPropertyAttributes(Res, AtLoc, Attributes); return Res; @@ -89,16 +93,25 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, // Diagnose if this property is already in continuation class. DeclContext *DC = cast<DeclContext>(CDecl); IdentifierInfo *PropertyId = FD.D.getIdentifier(); - - if (ObjCPropertyDecl *prevDecl = - ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { - Diag(AtLoc, diag::err_duplicate_property); - Diag(prevDecl->getLocation(), diag::note_property_declare); - return 0; - } - + ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); + + if (CCPrimary) + // Check for duplicate declaration of this property in current and + // other class extensions. + for (const ObjCCategoryDecl *ClsExtDecl = + CCPrimary->getFirstClassExtension(); + ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) { + if (ObjCPropertyDecl *prevDecl = + ObjCPropertyDecl::findPropertyDecl(ClsExtDecl, PropertyId)) { + Diag(AtLoc, diag::err_duplicate_property); + Diag(prevDecl->getLocation(), diag::note_property_declare); + return 0; + } + } + // Create a new ObjCPropertyDecl with the DeclContext being // the class extension. + // FIXME. We should really be using CreatePropertyDecl for this. ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), PropertyId, AtLoc, T); @@ -106,12 +119,13 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); if (Attributes & ObjCDeclSpec::DQ_PR_readwrite) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); - + // Set setter/getter selector name. Needed later. + PDecl->setGetterName(GetterSel); + PDecl->setSetterName(SetterSel); DC->addDecl(PDecl); // We need to look in the @interface to see if the @property was // already declared. - ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); if (!CCPrimary) { Diag(CDecl->getLocation(), diag::err_continuation_class); *isOverridingProperty = true; @@ -137,9 +151,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, // A case of continuation class adding a new property in the class. This // is not what it was meant for. However, gcc supports it and so should we. // Make sure setter/getters are declared here. - ProcessPropertyDecl(PDecl, CCPrimary); + ProcessPropertyDecl(PDecl, CCPrimary, /* redeclaredProperty = */ 0, + /* lexicalDC = */ CDecl); return PDecl; - } // The property 'PIDecl's readonly attribute will be over-ridden @@ -172,7 +186,8 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, PIDecl->getGetterName(), PIDecl->getSetterName(), CCPrimary, isOverridingProperty, - MethodImplKind); + MethodImplKind, + /* lexicalDC = */ CDecl); PIDecl = cast<ObjCPropertyDecl>(ProtocolPtrTy); } PIDecl->makeitReadWriteAttribute(); @@ -182,13 +197,22 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); PIDecl->setSetterName(SetterSel); } else { - Diag(AtLoc, diag::err_use_continuation_class) + // Tailor the diagnostics for the common case where a readwrite + // property is declared both in the @interface and the continuation. + // This is a common error where the user often intended the original + // declaration to be readonly. + unsigned diag = + (Attributes & ObjCDeclSpec::DQ_PR_readwrite) && + (PIkind & ObjCPropertyDecl::OBJC_PR_readwrite) + ? diag::err_use_continuation_class_redeclaration_readwrite + : diag::err_use_continuation_class; + Diag(AtLoc, diag) << CCPrimary->getDeclName(); Diag(PIDecl->getLocation(), diag::note_property_declare); } *isOverridingProperty = true; // Make sure setter decl is synthesized, and added to primary class's list. - ProcessPropertyDecl(PIDecl, CCPrimary); + ProcessPropertyDecl(PIDecl, CCPrimary, PDecl, CDecl); return 0; } @@ -275,6 +299,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); + else if (Attributes & ObjCDeclSpec::DQ_PR_atomic) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic); PDecl->setPropertyAttributesAsWritten(PDecl->getPropertyAttributes()); @@ -297,7 +323,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, bool Synthesize, Decl *ClassCatImpDecl, IdentifierInfo *PropertyId, - IdentifierInfo *PropertyIvar) { + IdentifierInfo *PropertyIvar, + SourceLocation PropertyIvarLoc) { ObjCContainerDecl *ClassImpDecl = cast_or_null<ObjCContainerDecl>(ClassCatImpDecl); // Make sure we have a context for the property implementation declaration. @@ -324,6 +351,16 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); return 0; } + unsigned PIkind = property->getPropertyAttributesAsWritten(); + if ((PIkind & (ObjCPropertyDecl::OBJC_PR_atomic | + ObjCPropertyDecl::OBJC_PR_nonatomic) ) == 0) { + if (AtLoc.isValid()) + Diag(AtLoc, diag::warn_implicit_atomic_property); + else + Diag(IC->getLocation(), diag::warn_auto_implicit_atomic_property); + Diag(property->getLocation(), diag::note_property_declare); + } + if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) { if (!CD->IsClassExtension()) { @@ -373,7 +410,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (!Ivar) { Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc, PropertyIvar, PropType, /*Dinfo=*/0, - ObjCIvarDecl::Protected, + ObjCIvarDecl::Private, (Expr *)0, true); ClassImpDecl->addDecl(Ivar); IDecl->makeDeclVisibleInContext(Ivar, false); @@ -403,8 +440,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, Context.canAssignObjCInterfaces( PropType->getAs<ObjCObjectPointerType>(), IvarType->getAs<ObjCObjectPointerType>()); - else - compat = (CheckAssignmentConstraints(PropType, IvarType) == Compatible); + else { + SourceLocation Loc = PropertyIvarLoc; + if (Loc.isInvalid()) + Loc = PropertyLoc; + compat = (CheckAssignmentConstraints(Loc, PropType, IvarType) + == Compatible); + } if (!compat) { Diag(PropertyLoc, diag::error_property_ivar_type) << property->getDeclName() << PropType @@ -452,17 +494,18 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, (Synthesize ? ObjCPropertyImplDecl::Synthesize : ObjCPropertyImplDecl::Dynamic), - Ivar); + Ivar, PropertyIvarLoc); if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) { getterMethod->createImplicitParams(Context, IDecl); - if (getLangOptions().CPlusPlus && Synthesize) { + if (getLangOptions().CPlusPlus && Synthesize && + Ivar->getType()->isRecordType()) { // For Objective-C++, need to synthesize the AST for the IVAR object to be // returned by the getter as it must conform to C++'s copy-return rules. // FIXME. Eventually we want to do this for Objective-C as well. ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl(); DeclRefExpr *SelfExpr = - new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(), - SourceLocation()); + new (Context) DeclRefExpr(SelfDecl, SelfDecl->getType(), + VK_RValue, SourceLocation()); Expr *IvarRefExpr = new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, SelfExpr, true, true); @@ -476,27 +519,28 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (!Res.isInvalid()) { Expr *ResExpr = Res.takeAs<Expr>(); if (ResExpr) - ResExpr = MaybeCreateCXXExprWithTemporaries(ResExpr); + ResExpr = MaybeCreateExprWithCleanups(ResExpr); PIDecl->setGetterCXXConstructor(ResExpr); } } } if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { setterMethod->createImplicitParams(Context, IDecl); - if (getLangOptions().CPlusPlus && Synthesize) { + if (getLangOptions().CPlusPlus && Synthesize + && Ivar->getType()->isRecordType()) { // FIXME. Eventually we want to do this for Objective-C as well. ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl(); DeclRefExpr *SelfExpr = - new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(), - SourceLocation()); + new (Context) DeclRefExpr(SelfDecl, SelfDecl->getType(), + VK_RValue, SourceLocation()); Expr *lhs = new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, SelfExpr, true, true); ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); ParmVarDecl *Param = (*P); - Expr *rhs = new (Context) DeclRefExpr(Param,Param->getType(), - SourceLocation()); - ExprResult Res = BuildBinOp(S, SourceLocation(), + Expr *rhs = new (Context) DeclRefExpr(Param, Param->getType(), + VK_LValue, SourceLocation()); + ExprResult Res = BuildBinOp(S, lhs->getLocEnd(), BO_Assign, lhs, rhs); PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>()); } @@ -519,11 +563,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, return 0; } IC->addPropertyImplementation(PIDecl); - if (getLangOptions().ObjCNonFragileABI2) { + if (getLangOptions().ObjCDefaultSynthProperties && + getLangOptions().ObjCNonFragileABI2) { // Diagnose if an ivar was lazily synthesdized due to a previous // use and if 1) property is @dynamic or 2) property is synthesized // but it requires an ivar of different name. - ObjCInterfaceDecl *ClassDeclared; + ObjCInterfaceDecl *ClassDeclared=0; ObjCIvarDecl *Ivar = 0; if (!Synthesize) Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared); @@ -622,7 +667,7 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, GetterMethod->getResultType() != property->getType()) { AssignConvertType result = Incompatible; if (property->getType()->isObjCObjectPointerType()) - result = CheckAssignmentConstraints(GetterMethod->getResultType(), + result = CheckAssignmentConstraints(Loc, GetterMethod->getResultType(), property->getType()); if (result != Compatible) { Diag(Loc, diag::warn_accessor_property_type_mismatch) @@ -966,10 +1011,16 @@ void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, continue; } - ActOnPropertyImplDecl(S, IMPDecl->getLocation(), IMPDecl->getLocation(), - true, IMPDecl, - Prop->getIdentifier(), Prop->getIdentifier()); - } + + // We use invalid SourceLocations for the synthesized ivars since they + // aren't really synthesized at a particular location; they just exist. + // Saying that they are located at the @implementation isn't really going + // to help users. + ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(), + true,IMPDecl, + Prop->getIdentifier(), Prop->getIdentifier(), + SourceLocation()); + } } void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, @@ -1030,7 +1081,32 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, E = IDecl->prop_end(); I != E; ++I) { ObjCPropertyDecl *Property = (*I); + ObjCMethodDecl *GetterMethod = 0; + ObjCMethodDecl *SetterMethod = 0; + bool LookedUpGetterSetter = false; + unsigned Attributes = Property->getPropertyAttributes(); + unsigned AttributesAsWrittern = Property->getPropertyAttributesAsWritten(); + + if (!(AttributesAsWrittern & ObjCPropertyDecl::OBJC_PR_atomic) && + !(AttributesAsWrittern & ObjCPropertyDecl::OBJC_PR_nonatomic)) { + GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName()); + SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName()); + LookedUpGetterSetter = true; + if (GetterMethod) { + Diag(GetterMethod->getLocation(), + diag::warn_default_atomic_custom_getter_setter) + << Property->getIdentifier() << 0; + Diag(Property->getLocation(), diag::note_property_declare); + } + if (SetterMethod) { + Diag(SetterMethod->getLocation(), + diag::warn_default_atomic_custom_getter_setter) + << Property->getIdentifier() << 1; + Diag(Property->getLocation(), diag::note_property_declare); + } + } + // We only care about readwrite atomic property. if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) || !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite)) @@ -1039,10 +1115,11 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) { if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) continue; - ObjCMethodDecl *GetterMethod = - IMPDecl->getInstanceMethod(Property->getGetterName()); - ObjCMethodDecl *SetterMethod = - IMPDecl->getInstanceMethod(Property->getSetterName()); + if (!LookedUpGetterSetter) { + GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName()); + SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName()); + LookedUpGetterSetter = true; + } if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { SourceLocation MethodLoc = (GetterMethod ? GetterMethod->getLocation() @@ -1055,13 +1132,27 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, } } +/// AddPropertyAttrs - Propagates attributes from a property to the +/// implicitly-declared getter or setter for that property. +static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod, + ObjCPropertyDecl *Property) { + // Should we just clone all attributes over? + if (DeprecatedAttr *A = Property->getAttr<DeprecatedAttr>()) + PropertyMethod->addAttr(A->clone(S.Context)); + if (UnavailableAttr *A = Property->getAttr<UnavailableAttr>()) + PropertyMethod->addAttr(A->clone(S.Context)); +} + /// 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, - ObjCContainerDecl *CD) { + ObjCContainerDecl *CD, + ObjCPropertyDecl *redeclaredProperty, + ObjCContainerDecl *lexicalDC) { + ObjCMethodDecl *GetterMethod, *SetterMethod; GetterMethod = CD->getInstanceMethod(property->getGetterName()); @@ -1096,8 +1187,12 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // No instance method of same name as property getter name was found. // 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(), + SourceLocation Loc = redeclaredProperty ? + redeclaredProperty->getLocation() : + property->getLocation(); + + GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, + property->getGetterName(), property->getType(), 0, CD, true, false, true, false, (property->getPropertyImplementation() == @@ -1105,11 +1200,13 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCMethodDecl::Optional : ObjCMethodDecl::Required); CD->addDecl(GetterMethod); + + AddPropertyAttrs(*this, GetterMethod, property); + // FIXME: Eventually this shouldn't be needed, as the lexical context // and the real context should be the same. - if (DeclContext *lexicalDC = property->getLexicalDeclContext()) + if (lexicalDC) GetterMethod->setLexicalDeclContext(lexicalDC); - } else // A user declared getter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation @@ -1123,19 +1220,22 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // No instance method of same name as property setter name was found. // 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(), - Context.VoidTy, 0, CD, true, false, true, - false, + SourceLocation Loc = redeclaredProperty ? + redeclaredProperty->getLocation() : + property->getLocation(); + + SetterMethod = + ObjCMethodDecl::Create(Context, Loc, Loc, + property->getSetterName(), Context.VoidTy, 0, + CD, true, false, true, false, (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) ? - ObjCMethodDecl::Optional : - ObjCMethodDecl::Required); + 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(), + ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, Loc, property->getIdentifier(), property->getType(), /*TInfo=*/0, @@ -1143,10 +1243,13 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, SC_None, 0); SetterMethod->setMethodParams(Context, &Argument, 1, 1); + + AddPropertyAttrs(*this, SetterMethod, property); + CD->addDecl(SetterMethod); // FIXME: Eventually this shouldn't be needed, as the lexical context // and the real context should be the same. - if (DeclContext *lexicalDC = property->getLexicalDeclContext()) + if (lexicalDC) SetterMethod->setLexicalDeclContext(lexicalDC); } else // A user declared setter will be synthesize when @synthesize of @@ -1253,6 +1356,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, } if (!(Attributes & ObjCDeclSpec::DQ_PR_copy) + &&!(Attributes & ObjCDeclSpec::DQ_PR_readonly) && getLangOptions().getGCMode() == LangOptions::GCOnly && PropertyTy->isBlockPointerType()) Diag(Loc, diag::warn_objc_property_copy_missing_on_block); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 11b4bb3..6fb789c 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -23,8 +23,10 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/PartialDiagnostic.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include <algorithm> @@ -32,9 +34,20 @@ namespace clang { using namespace sema; +/// A convenience routine for creating a decayed reference to a +/// function. +static Expr * +CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, + SourceLocation Loc = SourceLocation()) { + Expr *E = new (S.Context) DeclRefExpr(Fn, Fn->getType(), VK_LValue, Loc); + S.DefaultFunctionArrayConversion(E); + return E; +} + static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, bool InOverloadResolution, - StandardConversionSequence &SCS); + StandardConversionSequence &SCS, + bool CStyle); static OverloadingResult IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, UserDefinedConversionSequence& User, @@ -158,7 +171,10 @@ void StandardConversionSequence::setAsIdentityConversion() { DeprecatedStringLiteralToCharPtr = false; ReferenceBinding = false; DirectBinding = false; - RRefBinding = false; + IsLvalueReference = true; + BindsToFunctionLvalue = false; + BindsToRvalue = false; + BindsImplicitObjectArgumentWithoutRefQualifier = false; CopyConstructor = 0; } @@ -189,6 +205,7 @@ bool StandardConversionSequence::isPointerConversionToBool() const { (getFromType()->isPointerType() || getFromType()->isObjCObjectPointerType() || getFromType()->isBlockPointerType() || + getFromType()->isNullPtrType() || First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer)) return true; @@ -323,7 +340,7 @@ namespace { TemplateArgument SecondArg; }; } - + /// \brief Convert from Sema's representation of template deduction information /// to the form used in overload-candidate information. OverloadCandidate::DeductionFailureInfo @@ -339,12 +356,12 @@ static MakeDeductionFailureInfo(ASTContext &Context, case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: break; - + case Sema::TDK_Incomplete: case Sema::TDK_InvalidExplicitArguments: Result.Data = Info.Param.getOpaqueValue(); break; - + case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: { // FIXME: Should allocate from normal heap so that we can free this later. @@ -355,16 +372,16 @@ static MakeDeductionFailureInfo(ASTContext &Context, Result.Data = Saved; break; } - + case Sema::TDK_SubstitutionFailure: Result.Data = Info.take(); break; - + case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: - break; + break; } - + return Result; } @@ -377,7 +394,7 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() { case Sema::TDK_TooFewArguments: case Sema::TDK_InvalidExplicitArguments: break; - + case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: // FIXME: Destroy the data? @@ -388,15 +405,15 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() { // FIXME: Destroy the template arugment list? Data = 0; break; - + // Unhandled case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; } } - -TemplateParameter + +TemplateParameter OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { switch (static_cast<Sema::TemplateDeductionResult>(Result)) { case Sema::TDK_Success: @@ -405,24 +422,24 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { case Sema::TDK_TooFewArguments: case Sema::TDK_SubstitutionFailure: return TemplateParameter(); - + case Sema::TDK_Incomplete: case Sema::TDK_InvalidExplicitArguments: - return TemplateParameter::getFromOpaqueValue(Data); + return TemplateParameter::getFromOpaqueValue(Data); case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: return static_cast<DFIParamWithArguments*>(Data)->Param; - + // Unhandled case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; } - + return TemplateParameter(); } - + TemplateArgumentList * OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() { switch (static_cast<Sema::TemplateDeductionResult>(Result)) { @@ -438,7 +455,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() { case Sema::TDK_SubstitutionFailure: return static_cast<TemplateArgumentList*>(Data); - + // Unhandled case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: @@ -461,16 +478,16 @@ const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() { case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: - return &static_cast<DFIParamWithArguments*>(Data)->FirstArg; + return &static_cast<DFIParamWithArguments*>(Data)->FirstArg; // Unhandled case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; } - + return 0; -} +} const TemplateArgument * OverloadCandidate::DeductionFailureInfo::getSecondArg() { @@ -493,7 +510,7 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() { case Sema::TDK_FailedOverloadResolution: break; } - + return 0; } @@ -501,7 +518,7 @@ void OverloadCandidateSet::clear() { inherited::clear(); Functions.clear(); } - + // IsOverload - Determine whether the given New declaration is an // overload of the declarations in Old. This routine returns false if // New and Old cannot be overloaded, e.g., if New has the same @@ -582,10 +599,12 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, Match = *I; return Ovl_Match; } - } else if (isa<UsingDecl>(OldD) || isa<TagDecl>(OldD)) { + } else if (isa<UsingDecl>(OldD)) { // We can overload with these, which can show up when doing // redeclaration checks for UsingDecls. assert(Old.getLookupKind() == LookupUsingDeclName); + } else if (isa<TagDecl>(OldD)) { + // We can always overload with tags by hiding them. } else if (isa<UnresolvedUsingValueDecl>(OldD)) { // Optimistically assume that an unresolved using decl will // overload; if it doesn't, we'll have to diagnose during @@ -632,8 +651,8 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, isa<FunctionNoProtoType>(NewQType.getTypePtr())) return false; - FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType); - FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType); + const FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType); + const FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType); // The signature of a function includes the types of its // parameters (C++ 1.3.10), which includes the presence or absence @@ -664,7 +683,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, return true; // If the function is a class member, its signature includes the - // cv-qualifiers (if any) on the function itself. + // cv-qualifiers (if any) and ref-qualifier (if any) on the function itself. // // As part of this, also check whether one of the member functions // is static, in which case they are not overloads (C++ @@ -675,9 +694,26 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); if (OldMethod && NewMethod && !OldMethod->isStatic() && !NewMethod->isStatic() && - OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers()) + (OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers() || + OldMethod->getRefQualifier() != NewMethod->getRefQualifier())) { + if (!UseUsingDeclRules && + OldMethod->getRefQualifier() != NewMethod->getRefQualifier() && + (OldMethod->getRefQualifier() == RQ_None || + NewMethod->getRefQualifier() == RQ_None)) { + // C++0x [over.load]p2: + // - Member function declarations with the same name and the same + // parameter-type-list as well as member function template + // declarations with the same name, the same parameter-type-list, and + // the same template parameter lists cannot be overloaded if any of + // them, but not all, have a ref-qualifier (8.3.5). + Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload) + << NewMethod->getRefQualifier() << OldMethod->getRefQualifier(); + Diag(OldMethod->getLocation(), diag::note_previous_declaration); + } + return true; - + } + // The signatures match; this is not an overload. return false; } @@ -708,11 +744,12 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, static ImplicitConversionSequence TryImplicitConversion(Sema &S, Expr *From, QualType ToType, bool SuppressUserConversions, - bool AllowExplicit, - bool InOverloadResolution) { + bool AllowExplicit, + bool InOverloadResolution, + bool CStyle) { ImplicitConversionSequence ICS; if (IsStandardConversion(S, From, ToType, InOverloadResolution, - ICS.Standard)) { + ICS.Standard, CStyle)) { ICS.setStandard(); return ICS; } @@ -737,20 +774,20 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType, ICS.Standard.setAsIdentityConversion(); ICS.Standard.setFromType(FromType); ICS.Standard.setAllToTypes(ToType); - + // We don't actually check at this point whether there is a valid // copy/move constructor, since overloading just assumes that it // exists. When we actually perform initialization, we'll find the // appropriate constructor to copy the returned object, if needed. ICS.Standard.CopyConstructor = 0; - + // Determine whether this is considered a derived-to-base conversion. if (!S.Context.hasSameUnqualifiedType(FromType, ToType)) ICS.Standard.Second = ICK_Derived_To_Base; - + return ICS; } - + if (SuppressUserConversions) { // We're not in the case above, so there is no conversion that // we can perform. @@ -823,12 +860,14 @@ bool Sema::TryImplicitConversion(InitializationSequence &Sequence, Expr *Initializer, bool SuppressUserConversions, bool AllowExplicitConversions, - bool InOverloadResolution) { + bool InOverloadResolution, + bool CStyle) { ImplicitConversionSequence ICS = clang::TryImplicitConversion(*this, Initializer, Entity.getType(), SuppressUserConversions, - AllowExplicitConversions, - InOverloadResolution); + AllowExplicitConversions, + InOverloadResolution, + CStyle); if (ICS.isBad()) return true; // Perform the actual conversion. @@ -856,34 +895,66 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ICS = clang::TryImplicitConversion(*this, From, ToType, /*SuppressUserConversions=*/false, AllowExplicit, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*CStyle=*/false); return PerformImplicitConversion(From, ToType, ICS, Action); } - -/// \brief Determine whether the conversion from FromType to ToType is a valid + +/// \brief Determine whether the conversion from FromType to ToType is a valid /// conversion that strips "noreturn" off the nested function type. -static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, +static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, QualType ToType, QualType &ResultTy) { if (Context.hasSameUnqualifiedType(FromType, ToType)) return false; - - // Strip the noreturn off the type we're converting from; noreturn can - // safely be removed. - FromType = Context.getNoReturnType(FromType, false); - if (!Context.hasSameUnqualifiedType(FromType, ToType)) - return false; - ResultTy = FromType; + // Permit the conversion F(t __attribute__((noreturn))) -> F(t) + // where F adds one of the following at most once: + // - a pointer + // - a member pointer + // - a block pointer + CanQualType CanTo = Context.getCanonicalType(ToType); + CanQualType CanFrom = Context.getCanonicalType(FromType); + Type::TypeClass TyClass = CanTo->getTypeClass(); + if (TyClass != CanFrom->getTypeClass()) return false; + if (TyClass != Type::FunctionProto && TyClass != Type::FunctionNoProto) { + if (TyClass == Type::Pointer) { + CanTo = CanTo.getAs<PointerType>()->getPointeeType(); + CanFrom = CanFrom.getAs<PointerType>()->getPointeeType(); + } else if (TyClass == Type::BlockPointer) { + CanTo = CanTo.getAs<BlockPointerType>()->getPointeeType(); + CanFrom = CanFrom.getAs<BlockPointerType>()->getPointeeType(); + } else if (TyClass == Type::MemberPointer) { + CanTo = CanTo.getAs<MemberPointerType>()->getPointeeType(); + CanFrom = CanFrom.getAs<MemberPointerType>()->getPointeeType(); + } else { + return false; + } + + TyClass = CanTo->getTypeClass(); + if (TyClass != CanFrom->getTypeClass()) return false; + if (TyClass != Type::FunctionProto && TyClass != Type::FunctionNoProto) + return false; + } + + const FunctionType *FromFn = cast<FunctionType>(CanFrom); + FunctionType::ExtInfo EInfo = FromFn->getExtInfo(); + if (!EInfo.getNoReturn()) return false; + + FromFn = Context.adjustFunctionType(FromFn, EInfo.withNoReturn(false)); + assert(QualType(FromFn, 0).isCanonical()); + if (QualType(FromFn, 0) != CanTo) return false; + + ResultTy = ToType; return true; } - + /// \brief Determine whether the conversion from FromType to ToType is a valid /// vector conversion. /// /// \param ICK Will be set to the vector conversion kind, if this is a vector /// conversion. -static bool IsVectorConversion(ASTContext &Context, QualType FromType, - QualType ToType, ImplicitConversionKind &ICK) { +static bool IsVectorConversion(ASTContext &Context, QualType FromType, + QualType ToType, ImplicitConversionKind &ICK) { // We need at least one of these types to be a vector type to have a vector // conversion. if (!ToType->isVectorType() && !FromType->isVectorType()) @@ -899,7 +970,7 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType, // identity conversion. if (FromType->isExtVectorType()) return false; - + // Vector splat from any arithmetic type to a vector. if (FromType->isArithmeticType()) { ICK = ICK_Vector_Splat; @@ -922,7 +993,7 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType, return false; } - + /// IsStandardConversion - Determines whether there is a standard /// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the /// expression From to the type ToType. Standard conversion sequences @@ -933,9 +1004,10 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType, /// routine will return false and the value of SCS is unspecified. static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, bool InOverloadResolution, - StandardConversionSequence &SCS) { + StandardConversionSequence &SCS, + bool CStyle) { QualType FromType = From->getType(); - + // Standard conversions (C++ [conv]) SCS.setAsIdentityConversion(); SCS.DeprecatedStringLiteralToCharPtr = false; @@ -959,38 +1031,53 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, if (FromType == S.Context.OverloadTy) { DeclAccessPair AccessPair; if (FunctionDecl *Fn - = S.ResolveAddressOfOverloadedFunction(From, ToType, false, + = S.ResolveAddressOfOverloadedFunction(From, ToType, false, AccessPair)) { // We were able to resolve the address of the overloaded function, // so we can convert to the type of that function. FromType = Fn->getType(); + + // we can sometimes resolve &foo<int> regardless of ToType, so check + // if the type matches (identity) or we are converting to bool + if (!S.Context.hasSameUnqualifiedType( + S.ExtractUnqualifiedFunctionType(ToType), FromType)) { + QualType resultTy; + // if the function type matches except for [[noreturn]], it's ok + if (!IsNoReturnConversion(S.Context, FromType, + S.ExtractUnqualifiedFunctionType(ToType), resultTy)) + // otherwise, only a boolean conversion is standard + if (!ToType->isBooleanType()) + return false; + + } + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) { if (!Method->isStatic()) { - Type *ClassType + const Type *ClassType = S.Context.getTypeDeclType(Method->getParent()).getTypePtr(); FromType = S.Context.getMemberPointerType(FromType, ClassType); } } - + // If the "from" expression takes the address of the overloaded // function, update the type of the resulting expression accordingly. if (FromType->getAs<FunctionType>()) if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(From->IgnoreParens())) if (UnOp->getOpcode() == UO_AddrOf) FromType = S.Context.getPointerType(FromType); - + // Check that we've computed the proper type after overload resolution. assert(S.Context.hasSameType(FromType, S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); } else { return false; } - } + } // 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(S.Context); - if (argIsLvalue == Expr::LV_Valid && + bool argIsLValue = From->isLValue(); + if (argIsLValue && !FromType->isFunctionType() && !FromType->isArrayType() && S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) { SCS.First = ICK_Lvalue_To_Rvalue; @@ -1022,7 +1109,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, SCS.setAllToTypes(FromType); return true; } - } else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) { + } else if (FromType->isFunctionType() && argIsLValue) { // Function-to-pointer conversion (C++ 4.3). SCS.First = ICK_Function_To_Pointer; @@ -1060,17 +1147,26 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // Complex promotion (Clang extension) SCS.Second = ICK_Complex_Promotion; FromType = ToType.getUnqualifiedType(); - } else if (FromType->isIntegralOrEnumerationType() && + } else if (ToType->isBooleanType() && + (FromType->isArithmeticType() || + FromType->isAnyPointerType() || + FromType->isBlockPointerType() || + FromType->isMemberPointerType() || + FromType->isNullPtrType())) { + // Boolean conversions (C++ 4.12). + SCS.Second = ICK_Boolean_Conversion; + FromType = S.Context.BoolTy; + } else if (FromType->isIntegralOrUnscopedEnumerationType() && ToType->isIntegralType(S.Context)) { // Integral conversions (C++ 4.7). SCS.Second = ICK_Integral_Conversion; FromType = ToType.getUnqualifiedType(); - } else if (FromType->isComplexType() && ToType->isComplexType()) { + } else if (FromType->isAnyComplexType() && ToType->isComplexType()) { // Complex conversions (C99 6.3.1.6) SCS.Second = ICK_Complex_Conversion; FromType = ToType.getUnqualifiedType(); - } else if ((FromType->isComplexType() && ToType->isArithmeticType()) || - (ToType->isComplexType() && FromType->isArithmeticType())) { + } else if ((FromType->isAnyComplexType() && ToType->isArithmeticType()) || + (ToType->isAnyComplexType() && FromType->isArithmeticType())) { // Complex-real conversions (C99 6.3.1.7) SCS.Second = ICK_Complex_Real; FromType = ToType.getUnqualifiedType(); @@ -1078,32 +1174,24 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // Floating point conversions (C++ 4.8). SCS.Second = ICK_Floating_Conversion; FromType = ToType.getUnqualifiedType(); - } else if ((FromType->isRealFloatingType() && - ToType->isIntegralType(S.Context) && !ToType->isBooleanType()) || - (FromType->isIntegralOrEnumerationType() && + } else if ((FromType->isRealFloatingType() && + ToType->isIntegralType(S.Context)) || + (FromType->isIntegralOrUnscopedEnumerationType() && ToType->isRealFloatingType())) { // Floating-integral conversions (C++ 4.9). SCS.Second = ICK_Floating_Integral; FromType = ToType.getUnqualifiedType(); + } else if (S.IsBlockPointerConversion(FromType, ToType, FromType)) { + SCS.Second = ICK_Block_Pointer_Conversion; } else if (S.IsPointerConversion(From, FromType, ToType, InOverloadResolution, FromType, IncompatibleObjC)) { // Pointer conversions (C++ 4.10). SCS.Second = ICK_Pointer_Conversion; SCS.IncompatibleObjC = IncompatibleObjC; - } else if (S.IsMemberPointerConversion(From, FromType, ToType, + } else if (S.IsMemberPointerConversion(From, FromType, ToType, InOverloadResolution, FromType)) { // Pointer to member conversions (4.11). SCS.Second = ICK_Pointer_Member; - } else if (ToType->isBooleanType() && - (FromType->isArithmeticType() || - FromType->isEnumeralType() || - FromType->isAnyPointerType() || - FromType->isBlockPointerType() || - FromType->isMemberPointerType() || - FromType->isNullPtrType())) { - // Boolean conversions (C++ 4.12). - SCS.Second = ICK_Boolean_Conversion; - FromType = S.Context.BoolTy; } else if (IsVectorConversion(S.Context, FromType, ToType, SecondICK)) { SCS.Second = SecondICK; FromType = ToType.getUnqualifiedType(); @@ -1124,7 +1212,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, QualType CanonFrom; QualType CanonTo; // The third conversion can be a qualification conversion (C++ 4p1). - if (S.IsQualificationConversion(FromType, ToType)) { + if (S.IsQualificationConversion(FromType, ToType, CStyle)) { SCS.Third = ICK_Qualification; FromType = ToType; CanonFrom = S.Context.getCanonicalType(FromType); @@ -1139,7 +1227,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // a conversion. [...] CanonFrom = S.Context.getCanonicalType(FromType); CanonTo = S.Context.getCanonicalType(ToType); - if (CanonFrom.getLocalUnqualifiedType() + if (CanonFrom.getLocalUnqualifiedType() == CanonTo.getLocalUnqualifiedType() && (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers() || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr())) { @@ -1187,23 +1275,47 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { return To->getKind() == BuiltinType::UInt; } - // An rvalue of type wchar_t (3.9.1) or an enumeration type (7.2) - // can be converted to an rvalue of the first of the following types - // that can represent all the values of its underlying type: int, - // unsigned int, long, or unsigned long (C++ 4.5p2). + // C++0x [conv.prom]p3: + // A prvalue of an unscoped enumeration type whose underlying type is not + // fixed (7.2) can be converted to an rvalue a prvalue of the first of the + // following types that can represent all the values of the enumeration + // (i.e., the values in the range bmin to bmax as described in 7.2): int, + // unsigned int, long int, unsigned long int, long long int, or unsigned + // long long int. If none of the types in that list can represent all the + // values of the enumeration, an rvalue a prvalue of an unscoped enumeration + // type can be converted to an rvalue a prvalue of the extended integer type + // with lowest integer conversion rank (4.13) greater than the rank of long + // long in which all the values of the enumeration can be represented. If + // there are two such extended types, the signed one is chosen. + if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) { + // C++0x 7.2p9: Note that this implicit enum to int conversion is not + // provided for a scoped enumeration. + if (FromEnumType->getDecl()->isScoped()) + return false; - // We pre-calculate the promotion type for enum types. - if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) - if (ToType->isIntegerType()) + // We have already pre-calculated the promotion type, so this is trivial. + if (ToType->isIntegerType() && + !RequireCompleteType(From->getLocStart(), FromType, PDiag())) return Context.hasSameUnqualifiedType(ToType, FromEnumType->getDecl()->getPromotionType()); + } - if (FromType->isWideCharType() && ToType->isIntegerType()) { + // C++0x [conv.prom]p2: + // A prvalue of type char16_t, char32_t, or wchar_t (3.9.1) can be converted + // to an rvalue a prvalue of the first of the following types that can + // represent all the values of its underlying type: int, unsigned int, + // long int, unsigned long int, long long int, or unsigned long long int. + // If none of the types in that list can represent all the values of its + // underlying type, an rvalue a prvalue of type char16_t, char32_t, + // or wchar_t can be converted to an rvalue a prvalue of its underlying + // type. + if (FromType->isAnyCharacterType() && !FromType->isCharType() && + ToType->isIntegerType()) { // Determine whether the type we're converting from is signed or // unsigned. bool FromIsSigned; uint64_t FromSize = Context.getTypeSize(FromType); - + // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. FromIsSigned = true; @@ -1321,10 +1433,19 @@ bool Sema::IsComplexPromotion(QualType FromType, QualType 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, +BuildSimilarlyQualifiedPointerType(const Type *FromPtr, QualType ToPointee, QualType ToType, ASTContext &Context) { - QualType CanonFromPointee = Context.getCanonicalType(FromPtr->getPointeeType()); + assert((FromPtr->getTypeClass() == Type::Pointer || + FromPtr->getTypeClass() == Type::ObjCObjectPointer) && + "Invalid similarly-qualified pointer type"); + + /// \brief Conversions to 'id' subsume cv-qualifier conversions. + if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType()) + return ToType.getUnqualifiedType(); + + QualType CanonFromPointee + = Context.getCanonicalType(FromPtr->getPointeeType()); QualType CanonToPointee = Context.getCanonicalType(ToPointee); Qualifiers Quals = CanonFromPointee.getQualifiers(); @@ -1336,34 +1457,20 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, // Build a pointer to ToPointee. It has the right qualifiers // already. + if (isa<ObjCObjectPointerType>(ToType)) + return Context.getObjCObjectPointerType(ToPointee); return Context.getPointerType(ToPointee); } // Just build a canonical type that has the right qualifiers. - return Context.getPointerType( - Context.getQualifiedType(CanonToPointee.getLocalUnqualifiedType(), - Quals)); -} + QualType QualifiedCanonToPointee + = Context.getQualifiedType(CanonToPointee.getLocalUnqualifiedType(), Quals); -/// BuildSimilarlyQualifiedObjCObjectPointerType - In a pointer conversion from -/// the FromType, which is an objective-c pointer, to ToType, which may or may -/// not have the right set of qualifiers. -static QualType -BuildSimilarlyQualifiedObjCObjectPointerType(QualType FromType, - QualType ToType, - ASTContext &Context) { - QualType CanonFromType = Context.getCanonicalType(FromType); - QualType CanonToType = Context.getCanonicalType(ToType); - Qualifiers Quals = CanonFromType.getQualifiers(); - - // Exact qualifier match -> return the pointer type we're converting to. - if (CanonToType.getLocalQualifiers() == Quals) - return ToType; - - // Just build a canonical type that has the right qualifiers. - return Context.getQualifiedType(CanonToType.getLocalUnqualifiedType(), Quals); + if (isa<ObjCObjectPointerType>(ToType)) + return Context.getObjCObjectPointerType(QualifiedCanonToPointee); + return Context.getPointerType(QualifiedCanonToPointee); } - + static bool isNullPointerConstantForConversion(Expr *Expr, bool InOverloadResolution, ASTContext &Context) { @@ -1399,7 +1506,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC) { IncompatibleObjC = false; - if (isObjCPointerConversion(FromType, ToType, ConvertedType, IncompatibleObjC)) + if (isObjCPointerConversion(FromType, ToType, ConvertedType, + IncompatibleObjC)) return true; // Conversion from a null pointer constant to any Objective-C pointer type. @@ -1441,14 +1549,15 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, return true; } - // Beyond this point, both types need to be pointers + // Beyond this point, both types need to be pointers // , including objective-c pointers. QualType ToPointeeType = ToTypePtr->getPointeeType(); if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType()) { - ConvertedType = BuildSimilarlyQualifiedObjCObjectPointerType(FromType, + ConvertedType = BuildSimilarlyQualifiedPointerType( + FromType->getAs<ObjCObjectPointerType>(), + ToPointeeType, ToType, Context); return true; - } const PointerType *FromTypePtr = FromType->getAs<PointerType>(); if (!FromTypePtr) @@ -1456,7 +1565,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, QualType FromPointeeType = FromTypePtr->getPointeeType(); - // If the unqualified pointee types are the same, this can't be a + // If the unqualified pointee types are the same, this can't be a // pointer conversion, so don't do all of the work below. if (Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType)) return false; @@ -1517,13 +1626,20 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, bool &IncompatibleObjC) { if (!getLangOptions().ObjC1) return false; - + // First, we handle all conversions on ObjC object pointer types. - const ObjCObjectPointerType* ToObjCPtr = ToType->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType* ToObjCPtr = + ToType->getAs<ObjCObjectPointerType>(); const ObjCObjectPointerType *FromObjCPtr = FromType->getAs<ObjCObjectPointerType>(); if (ToObjCPtr && FromObjCPtr) { + // If the pointee types are the same (ignoring qualifications), + // then this is not a pointer conversion. + if (Context.hasSameUnqualifiedType(ToObjCPtr->getPointeeType(), + FromObjCPtr->getPointeeType())) + return false; + // 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()) { @@ -1547,7 +1663,9 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, !ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs( FromObjCPtr->getPointeeType())) return false; - ConvertedType = ToType; + ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, + ToObjCPtr->getPointeeType(), + ToType, Context); return true; } @@ -1556,7 +1674,9 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, // interfaces, which is permitted. However, we're going to // complain about it. IncompatibleObjC = true; - ConvertedType = FromType; + ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, + ToObjCPtr->getPointeeType(), + ToType, Context); return true; } } @@ -1564,7 +1684,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, QualType ToPointeeType; if (const PointerType *ToCPtr = ToType->getAs<PointerType>()) ToPointeeType = ToCPtr->getPointeeType(); - else if (const BlockPointerType *ToBlockPtr = + else if (const BlockPointerType *ToBlockPtr = ToType->getAs<BlockPointerType>()) { // Objective C++: We're able to convert from a pointer to any object // to a block pointer type. @@ -1574,9 +1694,9 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, } ToPointeeType = ToBlockPtr->getPointeeType(); } - else if (FromType->getAs<BlockPointerType>() && + else if (FromType->getAs<BlockPointerType>() && ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) { - // Objective C++: We're able to convert from a block pointer type to a + // Objective C++: We're able to convert from a block pointer type to a // pointer to any object. ConvertedType = ToType; return true; @@ -1587,7 +1707,8 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, QualType FromPointeeType; if (const PointerType *FromCPtr = FromType->getAs<PointerType>()) FromPointeeType = FromCPtr->getPointeeType(); - else if (const BlockPointerType *FromBlockPtr = FromType->getAs<BlockPointerType>()) + else if (const BlockPointerType *FromBlockPtr = + FromType->getAs<BlockPointerType>()) FromPointeeType = FromBlockPtr->getPointeeType(); else return false; @@ -1599,7 +1720,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, IncompatibleObjC)) { // We always complain about this conversion. IncompatibleObjC = true; - ConvertedType = ToType; + ConvertedType = Context.getPointerType(ConvertedType); return true; } // Allow conversion of pointee being objective-c pointer to another one; @@ -1608,10 +1729,10 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ToPointeeType->getAs<ObjCObjectPointerType>() && isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType, IncompatibleObjC)) { - ConvertedType = ToType; + ConvertedType = Context.getPointerType(ConvertedType); 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 @@ -1677,17 +1798,102 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, return false; } - + +bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType, + QualType& ConvertedType) { + QualType ToPointeeType; + if (const BlockPointerType *ToBlockPtr = + ToType->getAs<BlockPointerType>()) + ToPointeeType = ToBlockPtr->getPointeeType(); + else + return false; + + QualType FromPointeeType; + if (const BlockPointerType *FromBlockPtr = + FromType->getAs<BlockPointerType>()) + FromPointeeType = FromBlockPtr->getPointeeType(); + else + return false; + // We have pointer to blocks, check whether the only + // differences in the argument and result types are in Objective-C + // pointer conversions. If so, we permit the conversion. + + const FunctionProtoType *FromFunctionType + = FromPointeeType->getAs<FunctionProtoType>(); + const FunctionProtoType *ToFunctionType + = ToPointeeType->getAs<FunctionProtoType>(); + + if (!FromFunctionType || !ToFunctionType) + return false; + + if (Context.hasSameType(FromPointeeType, ToPointeeType)) + return true; + + // Perform the quick checks that will tell us whether these + // function types are obviously different. + if (FromFunctionType->getNumArgs() != ToFunctionType->getNumArgs() || + FromFunctionType->isVariadic() != ToFunctionType->isVariadic()) + return false; + + FunctionType::ExtInfo FromEInfo = FromFunctionType->getExtInfo(); + FunctionType::ExtInfo ToEInfo = ToFunctionType->getExtInfo(); + if (FromEInfo != ToEInfo) + return false; + + bool IncompatibleObjC = false; + if (Context.hasSameType(FromFunctionType->getResultType(), + ToFunctionType->getResultType())) { + // Okay, the types match exactly. Nothing to do. + } else { + QualType RHS = FromFunctionType->getResultType(); + QualType LHS = ToFunctionType->getResultType(); + if ((!getLangOptions().CPlusPlus || !RHS->isRecordType()) && + !RHS.hasQualifiers() && LHS.hasQualifiers()) + LHS = LHS.getUnqualifiedType(); + + if (Context.hasSameType(RHS,LHS)) { + // OK exact match. + } else if (isObjCPointerConversion(RHS, LHS, + ConvertedType, IncompatibleObjC)) { + if (IncompatibleObjC) + return false; + // Okay, we have an Objective-C pointer conversion. + } + else + return false; + } + + // Check argument types. + for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs(); + ArgIdx != NumArgs; ++ArgIdx) { + IncompatibleObjC = false; + QualType FromArgType = FromFunctionType->getArgType(ArgIdx); + QualType ToArgType = ToFunctionType->getArgType(ArgIdx); + if (Context.hasSameType(FromArgType, ToArgType)) { + // Okay, the types match exactly. Nothing to do. + } else if (isObjCPointerConversion(ToArgType, FromArgType, + ConvertedType, IncompatibleObjC)) { + if (IncompatibleObjC) + return false; + // Okay, we have an Objective-C pointer conversion. + } else + // Argument types are too different. Abort. + return false; + } + ConvertedType = ToType; + return true; +} + /// FunctionArgTypesAreEqual - This routine checks two function proto types /// for equlity of their argument types. Caller has already checked that /// they have same number of arguments. This routine assumes that Objective-C /// pointer types which only differ in their protocol qualifiers are equal. -bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType, - FunctionProtoType* NewType){ +bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType, + const FunctionProtoType *NewType) { if (!getLangOptions().ObjC1) return std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), NewType->arg_type_begin()); - + for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(), N = NewType->arg_type_begin(), E = OldType->arg_type_end(); O && (O != E); ++O, ++N) { @@ -1704,12 +1910,12 @@ bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType, } else if (const ObjCObjectPointerType *PTTo = ToType->getAs<ObjCObjectPointerType>()) { - if (const ObjCObjectPointerType *PTFr = + if (const ObjCObjectPointerType *PTFr = FromType->getAs<ObjCObjectPointerType>()) if (PTTo->getInterfaceDecl() == PTFr->getInterfaceDecl()) continue; } - return false; + return false; } } return true; @@ -1726,10 +1932,13 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, CXXCastPath& BasePath, bool IgnoreBaseAccess) { QualType FromType = From->getType(); + bool IsCStyleOrFunctionalCast = IgnoreBaseAccess; + + Kind = CK_BitCast; if (CXXBoolLiteralExpr* LitBool = dyn_cast<CXXBoolLiteralExpr>(From->IgnoreParens())) - if (LitBool->getValue() == false) + if (!IsCStyleOrFunctionalCast && LitBool->getValue() == false) Diag(LitBool->getExprLoc(), diag::warn_init_pointer_from_false) << ToType; @@ -1747,13 +1956,13 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, From->getSourceRange(), &BasePath, IgnoreBaseAccess)) return true; - + // The conversion was successful. Kind = CK_DerivedToBase; } } if (const ObjCObjectPointerType *FromPtrType = - FromType->getAs<ObjCObjectPointerType>()) + FromType->getAs<ObjCObjectPointerType>()) { if (const ObjCObjectPointerType *ToPtrType = ToType->getAs<ObjCObjectPointerType>()) { // Objective-C++ conversions are always okay. @@ -1761,8 +1970,14 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, // Objective-C++ implicit conversions. if (FromPtrType->isObjCBuiltinType() || ToPtrType->isObjCBuiltinType()) return false; - + } } + + // We shouldn't fall into this case unless it's valid for other + // reasons. + if (From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) + Kind = CK_NullToPointer; + return false; } @@ -1772,7 +1987,7 @@ 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 ToType, bool InOverloadResolution, QualType &ConvertedType) { const MemberPointerType *ToTypePtr = ToType->getAs<MemberPointerType>(); @@ -1796,9 +2011,10 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, // where D is derived from B (C++ 4.11p2). QualType FromClass(FromTypePtr->getClass(), 0); QualType ToClass(ToTypePtr->getClass(), 0); - // FIXME: What happens when these are dependent? Is this function even called? - if (IsDerivedFrom(ToClass, FromClass)) { + if (!Context.hasSameUnqualifiedType(FromClass, ToClass) && + !RequireCompleteType(From->getLocStart(), ToClass, PDiag()) && + IsDerivedFrom(ToClass, FromClass)) { ConvertedType = Context.getMemberPointerType(FromTypePtr->getPointeeType(), ToClass.getTypePtr()); return true; @@ -1806,7 +2022,7 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, return false; } - + /// CheckMemberPointerConversion - Check the member pointer conversion from the /// expression From to the type ToType. This routine checks for ambiguous or /// virtual or inaccessible base-to-derived member pointer conversions @@ -1821,7 +2037,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>(); if (!FromPtrType) { // This must be a null pointer to member pointer conversion - assert(From->isNullPointerConstant(Context, + assert(From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull) && "Expr must be null pointer constant!"); Kind = CK_NullToMemberPointer; @@ -1876,7 +2092,8 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, /// an rvalue of type FromType to ToType is a qualification conversion /// (C++ 4.4). bool -Sema::IsQualificationConversion(QualType FromType, QualType ToType) { +Sema::IsQualificationConversion(QualType FromType, QualType ToType, + bool CStyle) { FromType = Context.getCanonicalType(FromType); ToType = Context.getCanonicalType(ToType); @@ -1901,12 +2118,12 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { // -- for every j > 0, if const is in cv 1,j then const is in cv // 2,j, and similarly for volatile. - if (!ToType.isAtLeastAsQualifiedAs(FromType)) + if (!CStyle && !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() + if (!CStyle && FromType.getCVRQualifiers() != ToType.getCVRQualifiers() && !PreviousToQualsIncludeConst) return false; @@ -1977,13 +2194,13 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); else Constructor = cast<CXXConstructorDecl>(D); - + if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, - &From, 1, CandidateSet, + &From, 1, CandidateSet, /*SuppressUserConversions=*/ !ConstructorsOnly); else @@ -2039,7 +2256,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, } OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(S, From->getLocStart(), Best)) { + switch (CandidateSet.BestViableFunction(S, From->getLocStart(), Best, true)) { case OR_Success: // Record the standard conversion we used and the conversion function. if (CXXConstructorDecl *Constructor @@ -2058,6 +2275,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, User.EllipsisConversion = false; } User.ConversionFunction = Constructor; + User.FoundConversionFunction = Best->FoundDecl.getDecl(); User.After.setAsIdentityConversion(); User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType()); User.After.setAllToTypes(ToType); @@ -2072,6 +2290,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // implicit object parameter of the conversion function. User.Before = Best->Conversions[0].Standard; User.ConversionFunction = Conversion; + User.FoundConversionFunction = Best->FoundDecl.getDecl(); User.EllipsisConversion = false; // C++ [over.ics.user]p2: @@ -2095,19 +2314,19 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, case OR_Deleted: // No conversion here! We're done. return OR_Deleted; - + case OR_Ambiguous: return OR_Ambiguous; } return OR_No_Viable_Function; } - + bool Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { ImplicitConversionSequence ICS; OverloadCandidateSet CandidateSet(From->getExprLoc()); - OverloadingResult OvResult = + OverloadingResult OvResult = IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined, CandidateSet, false); if (OvResult == OR_Ambiguous) @@ -2121,7 +2340,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { else return false; CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &From, 1); - return true; + return true; } /// CompareImplicitConversionSequences - Compare two implicit @@ -2182,12 +2401,12 @@ static bool hasSimilarType(ASTContext &Context, QualType T1, QualType T2) { while (Context.UnwrapSimilarPointerTypes(T1, T2)) { Qualifiers Quals; T1 = Context.getUnqualifiedArrayType(T1, Quals); - T2 = Context.getUnqualifiedArrayType(T2, Quals); + T2 = Context.getUnqualifiedArrayType(T2, Quals); } - + return Context.hasSameUnqualifiedType(T1, T2); } - + // Per 13.3.3.2p3, compare the given standard conversion sequences to // determine if one is a proper subset of the other. static ImplicitConversionSequence::CompareKind @@ -2197,7 +2416,7 @@ compareStandardConversionSubsets(ASTContext &Context, ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; - // the identity conversion sequence is considered to be a subsequence of + // the identity conversion sequence is considered to be a subsequence of // any non-identity conversion sequence if (SCS1.ReferenceBinding == SCS2.ReferenceBinding) { if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion()) @@ -2205,7 +2424,7 @@ compareStandardConversionSubsets(ASTContext &Context, else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion()) return ImplicitConversionSequence::Worse; } - + if (SCS1.Second != SCS2.Second) { if (SCS1.Second == ICK_Identity) Result = ImplicitConversionSequence::Better; @@ -2230,10 +2449,37 @@ compareStandardConversionSubsets(ASTContext &Context, return Result == ImplicitConversionSequence::Better ? ImplicitConversionSequence::Indistinguishable : ImplicitConversionSequence::Worse; - + return ImplicitConversionSequence::Indistinguishable; } +/// \brief Determine whether one of the given reference bindings is better +/// than the other based on what kind of bindings they are. +static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1, + const StandardConversionSequence &SCS2) { + // C++0x [over.ics.rank]p3b4: + // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an + // implicit object parameter of a non-static member function declared + // without a ref-qualifier, and *either* S1 binds an rvalue reference + // to an rvalue and S2 binds an lvalue reference *or S1 binds an + // lvalue reference to a function lvalue and S2 binds an rvalue + // reference*. + // + // FIXME: Rvalue references. We're going rogue with the above edits, + // because the semantics in the current C++0x working paper (N3225 at the + // time of this writing) break the standard definition of std::forward + // and std::reference_wrapper when dealing with references to functions. + // Proposed wording changes submitted to CWG for consideration. + if (SCS1.BindsImplicitObjectArgumentWithoutRefQualifier || + SCS2.BindsImplicitObjectArgumentWithoutRefQualifier) + return false; + + return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue && + SCS2.IsLvalueReference) || + (SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue && + !SCS2.IsLvalueReference); +} + /// 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). @@ -2339,17 +2585,11 @@ CompareStandardConversionSequences(Sema &S, return QualCK; if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { - // C++0x [over.ics.rank]p3b4: - // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an - // implicit object parameter of a non-static member function declared - // without a ref-qualifier, and S1 binds an rvalue reference to an - // rvalue and S2 binds an lvalue reference. - // FIXME: We don't know if we're dealing with the implicit object parameter, - // or if the member function in this case has a ref qualifier. - // (Of course, we don't have ref qualifiers yet.) - if (SCS1.RRefBinding != SCS2.RRefBinding) - return SCS1.RRefBinding ? ImplicitConversionSequence::Better - : ImplicitConversionSequence::Worse; + // Check for a better reference binding based on the kind of bindings. + if (isBetterReferenceBindingKind(SCS1, SCS2)) + return ImplicitConversionSequence::Better; + else if (isBetterReferenceBindingKind(SCS2, SCS1)) + return ImplicitConversionSequence::Worse; // C++ [over.ics.rank]p3b4: // -- S1 and S2 are reference bindings (8.5.3), and the types to @@ -2365,8 +2605,8 @@ CompareStandardConversionSequences(Sema &S, QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals); QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals); if (UnqualT1 == UnqualT2) { - // If the type is an array type, promote the element qualifiers to the type - // for comparison. + // If the type is an array type, promote the element qualifiers to the + // type for comparison. if (isa<ArrayType>(T1) && T1Quals) T1 = S.Context.getQualifiedType(UnqualT1, T1Quals); if (isa<ArrayType>(T2) && T2Quals) @@ -2513,9 +2753,6 @@ CompareDerivedToBaseConversions(Sema &S, // If class B is derived directly or indirectly from class A and // class C is derived directly or indirectly from B, // - // For Objective-C, we let A, B, and C also be Objective-C - // interfaces. - // Compare based on pointer conversions. if (SCS1.Second == ICK_Pointer_Conversion && SCS2.Second == ICK_Pointer_Conversion && @@ -2531,24 +2768,12 @@ CompareDerivedToBaseConversions(Sema &S, QualType ToPointee2 = ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); - const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>(); - const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>(); - const ObjCObjectType* ToIface1 = ToPointee1->getAs<ObjCObjectType>(); - const ObjCObjectType* ToIface2 = ToPointee2->getAs<ObjCObjectType>(); - // -- conversion of C* to B* is better than conversion of C* to A*, if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) { if (S.IsDerivedFrom(ToPointee1, ToPointee2)) return ImplicitConversionSequence::Better; else if (S.IsDerivedFrom(ToPointee2, ToPointee1)) return ImplicitConversionSequence::Worse; - - if (ToIface1 && ToIface2) { - if (S.Context.canAssignObjCInterfaces(ToIface2, ToIface1)) - return ImplicitConversionSequence::Better; - else if (S.Context.canAssignObjCInterfaces(ToIface1, ToIface2)) - return ImplicitConversionSequence::Worse; - } } // -- conversion of B* to A* is better than conversion of C* to A*, @@ -2557,27 +2782,90 @@ CompareDerivedToBaseConversions(Sema &S, return ImplicitConversionSequence::Better; else if (S.IsDerivedFrom(FromPointee1, FromPointee2)) return ImplicitConversionSequence::Worse; + } + } else if (SCS1.Second == ICK_Pointer_Conversion && + SCS2.Second == ICK_Pointer_Conversion) { + const ObjCObjectPointerType *FromPtr1 + = FromType1->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *FromPtr2 + = FromType2->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *ToPtr1 + = ToType1->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *ToPtr2 + = ToType2->getAs<ObjCObjectPointerType>(); + + if (FromPtr1 && FromPtr2 && ToPtr1 && ToPtr2) { + // Apply the same conversion ranking rules for Objective-C pointer types + // that we do for C++ pointers to class types. However, we employ the + // Objective-C pseudo-subtyping relationship used for assignment of + // Objective-C pointer types. + bool FromAssignLeft + = S.Context.canAssignObjCInterfaces(FromPtr1, FromPtr2); + bool FromAssignRight + = S.Context.canAssignObjCInterfaces(FromPtr2, FromPtr1); + bool ToAssignLeft + = S.Context.canAssignObjCInterfaces(ToPtr1, ToPtr2); + bool ToAssignRight + = S.Context.canAssignObjCInterfaces(ToPtr2, ToPtr1); + + // A conversion to an a non-id object pointer type or qualified 'id' + // type is better than a conversion to 'id'. + if (ToPtr1->isObjCIdType() && + (ToPtr2->isObjCQualifiedIdType() || ToPtr2->getInterfaceDecl())) + return ImplicitConversionSequence::Worse; + if (ToPtr2->isObjCIdType() && + (ToPtr1->isObjCQualifiedIdType() || ToPtr1->getInterfaceDecl())) + return ImplicitConversionSequence::Better; + + // A conversion to a non-id object pointer type is better than a + // conversion to a qualified 'id' type + if (ToPtr1->isObjCQualifiedIdType() && ToPtr2->getInterfaceDecl()) + return ImplicitConversionSequence::Worse; + if (ToPtr2->isObjCQualifiedIdType() && ToPtr1->getInterfaceDecl()) + return ImplicitConversionSequence::Better; + + // A conversion to an a non-Class object pointer type or qualified 'Class' + // type is better than a conversion to 'Class'. + if (ToPtr1->isObjCClassType() && + (ToPtr2->isObjCQualifiedClassType() || ToPtr2->getInterfaceDecl())) + return ImplicitConversionSequence::Worse; + if (ToPtr2->isObjCClassType() && + (ToPtr1->isObjCQualifiedClassType() || ToPtr1->getInterfaceDecl())) + return ImplicitConversionSequence::Better; + + // A conversion to a non-Class object pointer type is better than a + // conversion to a qualified 'Class' type. + if (ToPtr1->isObjCQualifiedClassType() && ToPtr2->getInterfaceDecl()) + return ImplicitConversionSequence::Worse; + if (ToPtr2->isObjCQualifiedClassType() && ToPtr1->getInterfaceDecl()) + return ImplicitConversionSequence::Better; - if (FromIface1 && FromIface2) { - if (S.Context.canAssignObjCInterfaces(FromIface1, FromIface2)) - return ImplicitConversionSequence::Better; - else if (S.Context.canAssignObjCInterfaces(FromIface2, FromIface1)) - return ImplicitConversionSequence::Worse; - } + // -- "conversion of C* to B* is better than conversion of C* to A*," + if (S.Context.hasSameType(FromType1, FromType2) && + !FromPtr1->isObjCIdType() && !FromPtr1->isObjCClassType() && + (ToAssignLeft != ToAssignRight)) + return ToAssignLeft? ImplicitConversionSequence::Worse + : ImplicitConversionSequence::Better; + + // -- "conversion of B* to A* is better than conversion of C* to A*," + if (S.Context.hasSameUnqualifiedType(ToType1, ToType2) && + (FromAssignLeft != FromAssignRight)) + return FromAssignLeft? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; } } - + // Ranking of member-pointer types. if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member && FromType1->isMemberPointerType() && FromType2->isMemberPointerType() && ToType1->isMemberPointerType() && ToType2->isMemberPointerType()) { - const MemberPointerType * FromMemPointer1 = + const MemberPointerType * FromMemPointer1 = FromType1->getAs<MemberPointerType>(); - const MemberPointerType * ToMemPointer1 = + const MemberPointerType * ToMemPointer1 = ToType1->getAs<MemberPointerType>(); - const MemberPointerType * FromMemPointer2 = + const MemberPointerType * FromMemPointer2 = FromType2->getAs<MemberPointerType>(); - const MemberPointerType * ToMemPointer2 = + const MemberPointerType * ToMemPointer2 = ToType2->getAs<MemberPointerType>(); const Type *FromPointeeType1 = FromMemPointer1->getClass(); const Type *ToPointeeType1 = ToMemPointer1->getClass(); @@ -2602,7 +2890,7 @@ CompareDerivedToBaseConversions(Sema &S, return ImplicitConversionSequence::Worse; } } - + if (SCS1.Second == ICK_Derived_To_Base) { // -- conversion of C to B is better than conversion of C to A, // -- binding of an expression of type C to a reference of type @@ -2708,10 +2996,6 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, CXXRecordDecl *T2RecordDecl = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); - QualType ToType - = AllowRvalues? DeclType->getAs<ReferenceType>()->getPointeeType() - : DeclType; - OverloadCandidateSet CandidateSet(DeclLoc); const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); @@ -2730,20 +3014,22 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, else Conv = cast<CXXConversionDecl>(D); - // If this is an explicit conversion, and we're not allowed to consider + // If this is an explicit conversion, and we're not allowed to consider // explicit conversions, skip it. if (!AllowExplicit && Conv->isExplicit()) continue; - + if (AllowRvalues) { bool DerivedToBase = false; bool ObjCConversion = false; if (!ConvTemplate && - S.CompareReferenceRelationship(DeclLoc, - Conv->getConversionType().getNonReferenceType().getUnqualifiedType(), - DeclType.getNonReferenceType().getUnqualifiedType(), - DerivedToBase, ObjCConversion) - == Sema::Ref_Incompatible) + S.CompareReferenceRelationship( + DeclLoc, + Conv->getConversionType().getNonReferenceType() + .getUnqualifiedType(), + DeclType.getNonReferenceType().getUnqualifiedType(), + DerivedToBase, ObjCConversion) == + Sema::Ref_Incompatible) continue; } else { // If the conversion function doesn't return a reference type, @@ -2757,17 +3043,17 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, !RefType->getPointeeType()->isFunctionType())) continue; } - + if (ConvTemplate) S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, - Init, ToType, CandidateSet); + Init, DeclType, CandidateSet); else S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, - ToType, CandidateSet); + DeclType, CandidateSet); } OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) { + switch (CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) { case OR_Success: // C++ [over.ics.ref]p1: // @@ -2786,6 +3072,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, ICS.UserDefined.Before = Best->Conversions[0].Standard; ICS.UserDefined.After = Best->FinalConversion; ICS.UserDefined.ConversionFunction = Best->Function; + ICS.UserDefined.FoundConversionFunction = Best->FoundDecl.getDecl(); ICS.UserDefined.EllipsisConversion = false; assert(ICS.UserDefined.After.ReferenceBinding && ICS.UserDefined.After.DirectBinding && @@ -2806,7 +3093,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, // conversion; continue with other checks. return false; } - + return false; } @@ -2851,9 +3138,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // of type "cv2 T2" as follows: // -- If reference is an lvalue reference and the initializer expression - // The next bullet point (T1 is a function) is pretty much equivalent to this - // one, so it's handled here. - if (!isRValRef || T1->isFunctionType()) { + if (!isRValRef) { // -- is an lvalue (but is not a bit-field), and "cv1 T1" is // reference-compatible with "cv2 T2," or // @@ -2879,7 +3164,10 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, ICS.Standard.setToType(2, T1); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = false; + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; ICS.Standard.CopyConstructor = 0; // Nothing more to do: the inaccessibility/ambiguity check for @@ -2897,7 +3185,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // conversion functions (13.3.1.6) and choosing the best // one through overload resolution (13.3)), if (!SuppressUserConversions && T2->isRecordType() && - !S.RequireCompleteType(DeclLoc, T2, 0) && + !S.RequireCompleteType(DeclLoc, T2, 0) && RefRelationship == Sema::Ref_Incompatible) { if (FindConversionForRefInit(S, ICS, DeclType, DeclLoc, Init, T2, /*AllowRvalues=*/false, @@ -2908,9 +3196,8 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // -- Otherwise, the reference shall be an lvalue reference 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 or have a function type. - // + // shall be an rvalue reference. + // // We actually handle one oddity of C++ [over.ics.ref] at this // point, which is that, due to p2 (which short-circuits reference // binding by only attempting a simple conversion for non-direct @@ -2920,70 +3207,70 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // qualifier. // This is also the point where rvalue references and lvalue inits no longer // go together. - if ((!isRValRef && !T1.isConstQualified()) || - (isRValRef && InitCategory.isLValue())) + if (!isRValRef && !T1.isConstQualified()) return ICS; - // -- If T1 is a function type, then - // -- if T2 is the same type as T1, the reference is bound to the - // initializer expression lvalue; - // -- if T2 is a class type and the initializer expression can be - // implicitly converted to an lvalue of type T1 [...], the - // reference is bound to the function lvalue that is the result - // of the conversion; - // This is the same as for the lvalue case above, so it was handled there. - // -- otherwise, the program is ill-formed. - // This is the one difference to the lvalue case. - if (T1->isFunctionType()) + // -- If the initializer expression + // + // -- is an xvalue, class prvalue, array prvalue or function + // lvalue and "cv1T1" is reference-compatible with "cv2 T2", or + if (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification && + (InitCategory.isXValue() || + (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) || + (InitCategory.isLValue() && T2->isFunctionType()))) { + ICS.setStandard(); + ICS.Standard.First = ICK_Identity; + ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base + : ObjCConversion? ICK_Compatible_Conversion + : ICK_Identity; + ICS.Standard.Third = ICK_Identity; + ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS.Standard.setToType(0, T2); + ICS.Standard.setToType(1, T1); + ICS.Standard.setToType(2, T1); + ICS.Standard.ReferenceBinding = true; + // In C++0x, this is always a direct binding. In C++98/03, it's a direct + // binding unless we're binding to a class prvalue. + // Note: Although xvalues wouldn't normally show up in C++98/03 code, we + // allow the use of rvalue references in C++98/03 for the benefit of + // standard library implementors; therefore, we need the xvalue check here. + ICS.Standard.DirectBinding = + S.getLangOptions().CPlusPlus0x || + (InitCategory.isPRValue() && !T2->isRecordType()); + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = InitCategory.isRValue(); + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; + ICS.Standard.CopyConstructor = 0; return ICS; + } - // -- Otherwise, if T2 is a class type and - // -- the initializer expression is an rvalue and "cv1 T1" - // is reference-compatible with "cv2 T2," or - // - // -- T1 is not reference-related to T2 and the initializer - // expression can be implicitly converted to an rvalue - // of type "cv3 T3" (this conversion is selected by - // enumerating the applicable conversion functions - // (13.3.1.6) and choosing the best one through overload - // resolution (13.3)), + // -- has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to + // an xvalue, class prvalue, or function lvalue of type + // "cv3 T3", where "cv1 T1" is reference-compatible with + // "cv3 T3", // - // then the reference is bound to the initializer - // expression rvalue in the first case and to the object - // that is the result of the conversion in the second case - // (or, in either case, to the appropriate base class - // subobject of the object). - if (T2->isRecordType()) { - // First case: "cv1 T1" is reference-compatible with "cv2 T2". This is a - // direct binding in C++0x but not in C++03. - if (InitCategory.isRValue() && - RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { - ICS.setStandard(); - ICS.Standard.First = ICK_Identity; - ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base - : ObjCConversion? ICK_Compatible_Conversion - : ICK_Identity; - ICS.Standard.Third = ICK_Identity; - ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS.Standard.setToType(0, T2); - ICS.Standard.setToType(1, T1); - ICS.Standard.setToType(2, T1); - ICS.Standard.ReferenceBinding = true; - ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x; - ICS.Standard.RRefBinding = isRValRef; - ICS.Standard.CopyConstructor = 0; - return ICS; - } - - // Second case: not reference-related. - if (RefRelationship == Sema::Ref_Incompatible && - !S.RequireCompleteType(DeclLoc, T2, 0) && - FindConversionForRefInit(S, ICS, DeclType, DeclLoc, - Init, T2, /*AllowRvalues=*/true, - AllowExplicit)) - return ICS; + // then the reference is bound to the value of the initializer + // expression in the first case and to the result of the conversion + // in the second case (or, in either case, to an appropriate base + // class subobject). + if (!SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible && + T2->isRecordType() && !S.RequireCompleteType(DeclLoc, T2, 0) && + FindConversionForRefInit(S, ICS, DeclType, DeclLoc, + Init, T2, /*AllowRvalues=*/true, + AllowExplicit)) { + // In the second case, if the reference is an rvalue reference + // and the second standard conversion sequence of the + // user-defined conversion sequence includes an lvalue-to-rvalue + // conversion, the program is ill-formed. + if (ICS.isUserDefined() && isRValRef && + ICS.UserDefined.After.First == ICK_Lvalue_To_Rvalue) + ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType); + + return ICS; } - + // -- 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 @@ -3008,6 +3295,12 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, (T1->isRecordType() || T2->isRecordType())) return ICS; + // If T1 is reference-related to T2 and the reference is an rvalue + // reference, the initializer expression shall not be an lvalue. + if (RefRelationship >= Sema::Ref_Related && + isRValRef && Init->Classify(S.Context).isLValue()) + return 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 @@ -3020,16 +3313,24 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // and does not constitute a conversion. ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions, /*AllowExplicit=*/false, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*CStyle=*/false); // Of course, that's still a reference binding. if (ICS.isStandard()) { ICS.Standard.ReferenceBinding = true; - ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = true; + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; } else if (ICS.isUserDefined()) { ICS.UserDefined.After.ReferenceBinding = true; - ICS.UserDefined.After.RRefBinding = isRValRef; + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = true; + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; } + return ICS; } @@ -3041,7 +3342,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, /// do not permit any user-defined conversion sequences. static ImplicitConversionSequence TryCopyInitialization(Sema &S, Expr *From, QualType ToType, - bool SuppressUserConversions, + bool SuppressUserConversions, bool InOverloadResolution) { if (ToType->isReferenceType()) return TryReferenceInit(S, From, ToType, @@ -3052,7 +3353,8 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType, return TryImplicitConversion(S, From, ToType, SuppressUserConversions, /*AllowExplicit=*/false, - InOverloadResolution); + InOverloadResolution, + /*CStyle=*/false); } /// TryObjectArgumentInitialization - Try to initialize the object @@ -3060,6 +3362,7 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType, /// expression @p From. static ImplicitConversionSequence TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, + Expr::Classification FromClassification, CXXMethodDecl *Method, CXXRecordDecl *ActingContext) { QualType ClassType = S.Context.getTypeDeclType(ActingContext); @@ -3075,24 +3378,37 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, // We need to have an object of class type. QualType FromType = OrigFromType; - if (const PointerType *PT = FromType->getAs<PointerType>()) + if (const PointerType *PT = FromType->getAs<PointerType>()) { FromType = PT->getPointeeType(); + // When we had a pointer, it's implicitly dereferenced, so we + // better have an lvalue. + assert(FromClassification.isLValue()); + } + assert(FromType->isRecordType()); - // The implicit object parameter is has the type "reference to cv X", - // 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 + // C++0x [over.match.funcs]p4: + // For non-static member functions, the type of the implicit object + // parameter is + // + // - "lvalue reference to cv X" for functions declared without a + // ref-qualifier or with the & ref-qualifier + // - "rvalue reference to cv X" for functions declared with the && + // ref-qualifier + // + // where X is the class of which the function is a member and cv is the + // cv-qualification on the member function declaration. + // + // However, when finding an implicit conversion sequence for the argument, we + // are not allowed to 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. - // First check the qualifiers. We don't care about lvalue-vs-rvalue - // with the implicit object parameter (C++ [over.match.funcs]p5). + // First check the qualifiers. QualType FromTypeCanon = S.Context.getCanonicalType(FromType); - if (ImplicitParamType.getCVRQualifiers() + if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) { ICS.setBad(BadConversionSequence::bad_qualifiers, @@ -3114,6 +3430,31 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, return ICS; } + // Check the ref-qualifier. + switch (Method->getRefQualifier()) { + case RQ_None: + // Do nothing; we don't care about lvalueness or rvalueness. + break; + + case RQ_LValue: + if (!FromClassification.isLValue() && Quals != Qualifiers::Const) { + // non-const lvalue reference cannot bind to an rvalue + ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, FromType, + ImplicitParamType); + return ICS; + } + break; + + case RQ_RValue: + if (!FromClassification.isRValue()) { + // rvalue reference cannot bind to an lvalue + ICS.setBad(BadConversionSequence::rvalue_ref_to_lvalue, FromType, + ImplicitParamType); + return ICS; + } + break; + } + // Success. Mark this as a reference binding. ICS.setStandard(); ICS.Standard.setAsIdentityConversion(); @@ -3122,7 +3463,11 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; - ICS.Standard.RRefBinding = false; + ICS.Standard.IsLvalueReference = Method->getRefQualifier() != RQ_RValue; + ICS.Standard.BindsToFunctionLvalue = false; + ICS.Standard.BindsToRvalue = FromClassification.isRValue(); + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier + = (Method->getRefQualifier() == RQ_None); return ICS; } @@ -3130,31 +3475,50 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, /// the implicit object parameter for the given Method with the given /// expression. bool -Sema::PerformObjectArgumentInitialization(Expr *&From, - NestedNameSpecifier *Qualifier, +Sema::PerformObjectArgumentInitialization(Expr *&From, + NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method) { QualType FromRecordType, DestType; QualType ImplicitParamRecordType = Method->getThisType(Context)->getAs<PointerType>()->getPointeeType(); + Expr::Classification FromClassification; if (const PointerType *PT = From->getType()->getAs<PointerType>()) { FromRecordType = PT->getPointeeType(); DestType = Method->getThisType(Context); + FromClassification = Expr::Classification::makeSimpleLValue(); } else { FromRecordType = From->getType(); DestType = ImplicitParamRecordType; + FromClassification = From->Classify(Context); } // Note that we always use the true parent context when performing // the actual argument initialization. ImplicitConversionSequence ICS - = TryObjectArgumentInitialization(*this, From->getType(), Method, - Method->getParent()); - if (ICS.isBad()) + = TryObjectArgumentInitialization(*this, From->getType(), FromClassification, + Method, Method->getParent()); + if (ICS.isBad()) { + if (ICS.Bad.Kind == BadConversionSequence::bad_qualifiers) { + Qualifiers FromQs = FromRecordType.getQualifiers(); + Qualifiers ToQs = DestType.getQualifiers(); + unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers(); + if (CVR) { + Diag(From->getSourceRange().getBegin(), + diag::err_member_function_call_bad_cvr) + << Method->getDeclName() << FromRecordType << (CVR - 1) + << From->getSourceRange(); + Diag(Method->getLocation(), diag::note_previous_decl) + << Method->getDeclName(); + return true; + } + } + return Diag(From->getSourceRange().getBegin(), diag::err_implicit_object_parameter_init) << ImplicitParamRecordType << FromRecordType << From->getSourceRange(); + } if (ICS.Standard.Second == ICK_Derived_To_Base) return PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method); @@ -3174,7 +3538,8 @@ TryContextuallyConvertToBool(Sema &S, Expr *From) { // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*CStyle=*/false); } /// PerformContextuallyConvertToBool - Perform a contextual conversion @@ -3183,14 +3548,14 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From); if (!ICS.isBad()) return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting); - + if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy)) return Diag(From->getSourceRange().getBegin(), diag::err_typecheck_bool_condition) << From->getType() << From->getSourceRange(); return true; } - + /// TryContextuallyConvertToObjCId - Attempt to contextually convert the /// expression From to 'id'. static ImplicitConversionSequence @@ -3200,7 +3565,8 @@ TryContextuallyConvertToObjCId(Sema &S, Expr *From) { // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*CStyle=*/false); } /// PerformContextuallyConvertToObjCId - Perform a contextual conversion @@ -3213,7 +3579,7 @@ bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) { return true; } -/// \brief Attempt to convert the given expression to an integral or +/// \brief Attempt to convert the given expression to an integral or /// enumeration type. /// /// This routine will attempt to convert an expression of class type to an @@ -3241,7 +3607,7 @@ bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) { /// \param AmbigDiag The diagnostic to be emitted if there is more than one /// conversion function that could convert to integral or enumeration type. /// -/// \param AmbigNote The note to be emitted with \p AmbigDiag for each +/// \param AmbigNote The note to be emitted with \p AmbigDiag for each /// usable conversion function. /// /// \param ConvDiag The diagnostic to be emitted if we are calling a conversion @@ -3249,7 +3615,7 @@ bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) { /// /// \returns The expression, converted to an integral or enumeration type if /// successful. -ExprResult +ExprResult Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, const PartialDiagnostic &NotIntDiag, const PartialDiagnostic &IncompleteDiag, @@ -3261,7 +3627,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, // We can't perform any more checking for type-dependent expressions. if (From->isTypeDependent()) return Owned(From); - + // If the expression already has integral or enumeration type, we're golden. QualType T = From->getType(); if (T->isIntegralOrEnumerationType()) @@ -3269,7 +3635,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, // FIXME: Check for missing '()' if T is a function type? - // If we don't have a class type in C++, there's no way we can get an + // If we don't have a class type in C++, there's no way we can get an // expression of integral or enumeration type. const RecordType *RecordTy = T->getAs<RecordType>(); if (!RecordTy || !getLangOptions().CPlusPlus) { @@ -3277,20 +3643,20 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, << T << From->getSourceRange(); return Owned(From); } - + // We must have a complete class type. if (RequireCompleteType(Loc, T, IncompleteDiag)) return Owned(From); - + // Look for a conversion to an integral or enumeration type. UnresolvedSet<4> ViableConversions; UnresolvedSet<4> ExplicitConversions; const UnresolvedSetImpl *Conversions = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions(); - + for (UnresolvedSetImpl::iterator I = Conversions->begin(), - E = Conversions->end(); - I != E; + E = Conversions->end(); + I != E; ++I) { if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) @@ -3302,21 +3668,21 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, ViableConversions.addDecl(I.getDecl(), I.getAccess()); } } - + switch (ViableConversions.size()) { case 0: if (ExplicitConversions.size() == 1) { DeclAccessPair Found = ExplicitConversions[0]; CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Found->getUnderlyingDecl()); - + // The user probably meant to invoke the given explicit // conversion; use it. QualType ConvTy = Conversion->getConversionType().getNonReferenceType(); std::string TypeStr; ConvTy.getAsStringInternal(TypeStr, Context.PrintingPolicy); - + Diag(Loc, ExplicitConvDiag) << T << ConvTy << FixItHint::CreateInsertion(From->getLocStart(), @@ -3325,41 +3691,49 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, ")"); Diag(Conversion->getLocation(), ExplicitConvNote) << ConvTy->isEnumeralType() << ConvTy; - - // If we aren't in a SFINAE context, build a call to the + + // If we aren't in a SFINAE context, build a call to the // explicit conversion function. if (isSFINAEContext()) return ExprError(); - + CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); - From = BuildCXXMemberCallExpr(From, Found, Conversion); + ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion); + if (Result.isInvalid()) + return ExprError(); + + From = Result.get(); } - + // We'll complain below about a non-integral condition type. break; - + case 1: { // Apply this conversion. DeclAccessPair Found = ViableConversions[0]; CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); - + CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Found->getUnderlyingDecl()); QualType ConvTy - = Conversion->getConversionType().getNonReferenceType(); + = Conversion->getConversionType().getNonReferenceType(); if (ConvDiag.getDiagID()) { if (isSFINAEContext()) return ExprError(); - + Diag(Loc, ConvDiag) << T << ConvTy->isEnumeralType() << ConvTy << From->getSourceRange(); } - - From = BuildCXXMemberCallExpr(From, Found, + + ExprResult Result = BuildCXXMemberCallExpr(From, Found, cast<CXXConversionDecl>(Found->getUnderlyingDecl())); + if (Result.isInvalid()) + return ExprError(); + + From = Result.get(); break; } - + default: Diag(Loc, AmbigDiag) << T << From->getSourceRange(); @@ -3372,7 +3746,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, } return Owned(From); } - + if (!From->getType()->isIntegralOrEnumerationType()) Diag(Loc, NotIntDiag) << From->getType() << From->getSourceRange(); @@ -3411,7 +3785,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // object argument (C++ [over.call.func]p3), and the acting context // is irrelevant. AddMethodCandidate(Method, FoundDecl, Method->getParent(), - QualType(), Args, NumArgs, CandidateSet, + QualType(), Expr::Classification::makeSimpleLValue(), + Args, NumArgs, CandidateSet, SuppressUserConversions); return; } @@ -3430,13 +3805,13 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // A member function template is never instantiated to perform the copy // of a class object to an object of its class type. QualType ClassType = Context.getTypeDeclType(Constructor->getParent()); - if (NumArgs == 1 && - Constructor->isCopyConstructorLikeSpecialization() && + if (NumArgs == 1 && + Constructor->isSpecializationCopyingObject() && (Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) || IsDerivedFrom(Args[0]->getType(), ClassType))) return; } - + // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); @@ -3445,13 +3820,14 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, Candidate.Viable = true; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + Candidate.ExplicitCallArguments = NumArgs; unsigned NumArgsInProto = Proto->getNumArgs(); // (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 + (PartialOverloading && NumArgs)) > NumArgsInProto && + if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_too_many_arguments; @@ -3483,7 +3859,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, QualType ParamType = Proto->getArgType(ArgIdx); Candidate.Conversions[ArgIdx] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, - SuppressUserConversions, + SuppressUserConversions, /*InOverloadResolution=*/true); if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; @@ -3511,7 +3887,8 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(), cast<CXXMethodDecl>(FD)->getParent(), - Args[0]->getType(), Args + 1, NumArgs - 1, + Args[0]->getType(), Args[0]->Classify(Context), + Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else AddOverloadCandidate(FD, F.getPair(), Args, NumArgs, CandidateSet, @@ -3523,7 +3900,9 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, AddMethodTemplateCandidate(FunTmpl, F.getPair(), cast<CXXRecordDecl>(FunTmpl->getDeclContext()), /*FIXME: explicit args */ 0, - Args[0]->getType(), Args + 1, NumArgs - 1, + Args[0]->getType(), + Args[0]->Classify(Context), + Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else @@ -3539,6 +3918,7 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, /// method) as a method candidate to the given overload set. void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { @@ -3547,18 +3927,18 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, if (isa<UsingShadowDecl>(Decl)) Decl = cast<UsingShadowDecl>(Decl)->getTargetDecl(); - + if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) { assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) && "Expected a member function template"); AddMethodTemplateCandidate(TD, FoundDecl, ActingContext, /*ExplicitArgs*/ 0, - ObjectType, Args, NumArgs, + ObjectType, ObjectClassification, Args, NumArgs, CandidateSet, SuppressUserConversions); } else { AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext, - ObjectType, Args, NumArgs, + ObjectType, ObjectClassification, Args, NumArgs, CandidateSet, SuppressUserConversions); } } @@ -3573,6 +3953,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, void Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { @@ -3595,6 +3976,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, Candidate.Function = Method; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + Candidate.ExplicitCallArguments = NumArgs; unsigned NumArgsInProto = Proto->getNumArgs(); @@ -3630,8 +4012,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // Determine the implicit conversion sequence for the object // parameter. Candidate.Conversions[0] - = TryObjectArgumentInitialization(*this, ObjectType, Method, - ActingContext); + = TryObjectArgumentInitialization(*this, ObjectType, ObjectClassification, + Method, ActingContext); if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -3650,7 +4032,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, QualType ParamType = Proto->getArgType(ArgIdx); Candidate.Conversions[ArgIdx + 1] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, - SuppressUserConversions, + SuppressUserConversions, /*InOverloadResolution=*/true); if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; @@ -3665,7 +4047,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, } } } - + /// \brief Add a C++ member function template as a candidate to the candidate /// set, using template argument deduction to produce an appropriate member /// function template specialization. @@ -3675,6 +4057,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { @@ -3703,7 +4086,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; - Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Candidate.ExplicitCallArguments = NumArgs; + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, Info); return; } @@ -3714,8 +4098,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, assert(isa<CXXMethodDecl>(Specialization) && "Specialization is not a member function?"); AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl, - ActingContext, ObjectType, Args, NumArgs, - CandidateSet, SuppressUserConversions); + ActingContext, ObjectType, ObjectClassification, + Args, NumArgs, CandidateSet, SuppressUserConversions); } /// \brief Add a C++ function template specialization as a candidate @@ -3753,7 +4137,8 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; - Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Candidate.ExplicitCallArguments = NumArgs; + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, Info); return; } @@ -3798,10 +4183,11 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.FinalConversion.setAllToTypes(ToType); Candidate.Viable = true; Candidate.Conversions.resize(1); + Candidate.ExplicitCallArguments = 1; // C++ [over.match.funcs]p4: - // For conversion functions, the function is considered to be a member of - // the class of the implicit implied object argument for the purpose of + // For conversion functions, the function is considered to be a member of + // the class of the implicit implied object argument for the purpose of // defining the type of the implicit object parameter. // // Determine the implicit conversion sequence for the implicit @@ -3811,18 +4197,19 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, ImplicitParamType = FromPtrType->getPointeeType(); CXXRecordDecl *ConversionContext = cast<CXXRecordDecl>(ImplicitParamType->getAs<RecordType>()->getDecl()); - + Candidate.Conversions[0] - = TryObjectArgumentInitialization(*this, From->getType(), Conversion, - ConversionContext); - + = TryObjectArgumentInitialization(*this, From->getType(), + From->Classify(Context), + Conversion, ConversionContext); + if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; return; } - // We won't go through a user-define type conversion function to convert a + // We won't go through a user-define type conversion function to convert a // derived to base as such conversions are given Conversion Rank. They only // go through a copy constructor. 13.3.3.1.2-p4 [over.ics.user] QualType FromCanon @@ -3833,7 +4220,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.FailureKind = ovl_fail_trivial_conversion; return; } - + // To determine what the conversion from the result of calling the // conversion function to the type we're eventually trying to // convert to (ToType), we need to synthesize a call to the @@ -3843,17 +4230,26 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // call on the stack and we don't need its arguments to be // well-formed. DeclRefExpr ConversionRef(Conversion, Conversion->getType(), - From->getLocStart()); + VK_LValue, From->getLocStart()); ImplicitCastExpr ConversionFn(ImplicitCastExpr::OnStack, Context.getPointerType(Conversion->getType()), CK_FunctionToPointerDecay, &ConversionRef, VK_RValue); + QualType CallResultType + = Conversion->getConversionType().getNonLValueExprType(Context); + if (RequireCompleteType(From->getLocStart(), CallResultType, 0)) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_final_conversion; + return; + } + + ExprValueKind VK = Expr::getValueKindForType(Conversion->getConversionType()); + // 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, - Conversion->getConversionType().getNonLValueExprType(Context), + CallExpr Call(Context, &ConversionFn, 0, 0, CallResultType, VK, From->getLocStart()); ImplicitConversionSequence ICS = TryCopyInitialization(*this, &Call, ToType, @@ -3863,17 +4259,27 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: Candidate.FinalConversion = ICS.Standard; - + // C++ [over.ics.user]p3: // If the user-defined conversion is specified by a specialization of a - // conversion function template, the second standard conversion sequence + // conversion function template, the second standard conversion sequence // shall have exact match rank. if (Conversion->getPrimaryTemplate() && GetConversionRank(ICS.Standard.Second) != ICR_Exact_Match) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_final_conversion_not_exact; } - + + // C++0x [dcl.init.ref]p5: + // In the second case, if the reference is an rvalue reference and + // the second standard conversion sequence of the user-defined + // conversion sequence includes an lvalue-to-rvalue conversion, the + // program is ill-formed. + if (ToType->isRValueReferenceType() && + ICS.Standard.First == ICK_Lvalue_To_Rvalue) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_final_conversion; + } break; case ImplicitConversionSequence::BadConversion: @@ -3917,7 +4323,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; - Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, + Candidate.ExplicitCallArguments = 1; + Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, Info); return; } @@ -3938,7 +4345,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, - QualType ObjectType, + Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet) { if (!CandidateSet.isNewCandidate(Conversion)) @@ -3956,12 +4363,14 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, Candidate.IsSurrogate = true; Candidate.IgnoreObjectArgument = false; Candidate.Conversions.resize(NumArgs + 1); + Candidate.ExplicitCallArguments = NumArgs; // Determine the implicit conversion sequence for the implicit // object parameter. ImplicitConversionSequence ObjectInit - = TryObjectArgumentInitialization(*this, ObjectType, Conversion, - ActingContext); + = TryObjectArgumentInitialization(*this, Object->getType(), + Object->Classify(Context), + Conversion, ActingContext); if (ObjectInit.isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -3976,6 +4385,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard; Candidate.Conversions[0].UserDefined.EllipsisConversion = false; Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion; + Candidate.Conversions[0].UserDefined.FoundConversionFunction + = FoundDecl.getDecl(); Candidate.Conversions[0].UserDefined.After = Candidate.Conversions[0].UserDefined.Before; Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion(); @@ -4071,7 +4482,8 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, Oper != OperEnd; ++Oper) AddMethodCandidate(Oper.getPair(), Args[0]->getType(), - Args + 1, NumArgs - 1, CandidateSet, + Args[0]->Classify(Context), Args + 1, NumArgs - 1, + CandidateSet, /* SuppressUserConversions = */ false); } } @@ -4107,6 +4519,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, // arguments. Candidate.Viable = true; Candidate.Conversions.resize(NumArgs); + Candidate.ExplicitCallArguments = NumArgs; for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { // C++ [over.match.oper]p4: // For the built-in assignment operators, conversions of the @@ -4159,10 +4572,17 @@ class BuiltinCandidateTypeSet { /// used in the built-in candidates. TypeSet EnumerationTypes; - /// \brief The set of vector types that will be used in the built-in + /// \brief The set of vector types that will be used in the built-in /// candidates. TypeSet VectorTypes; - + + /// \brief A flag indicating non-record types are viable candidates + bool HasNonRecordTypes; + + /// \brief A flag indicating whether either arithmetic or enumeration types + /// were present in the candidate set. + bool HasArithmeticOrEnumeralTypes; + /// Sema - The semantic analysis instance where we are building the /// candidate type set. Sema &SemaRef; @@ -4179,9 +4599,12 @@ public: typedef TypeSet::iterator iterator; BuiltinCandidateTypeSet(Sema &SemaRef) - : SemaRef(SemaRef), Context(SemaRef.Context) { } + : HasNonRecordTypes(false), + HasArithmeticOrEnumeralTypes(false), + SemaRef(SemaRef), + Context(SemaRef.Context) { } - void AddTypesConvertedFrom(QualType Ty, + void AddTypesConvertedFrom(QualType Ty, SourceLocation Loc, bool AllowUserConversions, bool AllowExplicitConversions, @@ -4204,9 +4627,12 @@ public: /// enumeration_end - Past the last enumeration type found; iterator enumeration_end() { return EnumerationTypes.end(); } - + iterator vector_begin() { return VectorTypes.begin(); } iterator vector_end() { return VectorTypes.end(); } + + bool hasNonRecordTypes() { return HasNonRecordTypes; } + bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; } }; /// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to @@ -4225,7 +4651,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, // Insert this type. if (!PointerTypes.insert(Ty)) return false; - + QualType PointeeTy; const PointerType *PointerTy = Ty->getAs<PointerType>(); bool buildObjCPtr = false; @@ -4239,7 +4665,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, } else PointeeTy = PointerTy->getPointeeType(); - + // Don't add qualified variants of arrays. For one, they're not allowed // (the qualifier would sink to the element type), and for another, the // only overload situation where it matters is subscript or pointer +- int, @@ -4251,7 +4677,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, BaseCVR = Array->getElementType().getCVRQualifiers(); bool hasVolatile = VisibleQuals.hasVolatile(); bool hasRestrict = VisibleQuals.hasRestrict(); - + // Iterate through all strict supersets of BaseCVR. for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) { if ((CVR | BaseCVR) != CVR) continue; @@ -4302,9 +4728,10 @@ BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( 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)); + MemberPointerTypes.insert( + Context.getMemberPointerType(QPointeeTy, ClassTy)); } return true; @@ -4332,12 +4759,21 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, if (const ReferenceType *RefTy = Ty->getAs<ReferenceType>()) Ty = RefTy->getPointeeType(); - // We don't care about qualifiers on the type. - Ty = Ty.getLocalUnqualifiedType(); - // If we're dealing with an array type, decay to the pointer. if (Ty->isArrayType()) Ty = SemaRef.Context.getArrayDecayedType(Ty); + + // Otherwise, we don't care about qualifiers on the type. + Ty = Ty.getLocalUnqualifiedType(); + + // Flag if we ever add a non-record type. + const RecordType *TyRec = Ty->getAs<RecordType>(); + HasNonRecordTypes = HasNonRecordTypes || !TyRec; + + // Flag if we encounter an arithmetic type. + HasArithmeticOrEnumeralTypes = + HasArithmeticOrEnumeralTypes || Ty->isArithmeticType(); + if (Ty->isObjCIdType() || Ty->isObjCClassType()) PointerTypes.insert(Ty); else if (Ty->getAs<PointerType>() || Ty->getAs<ObjCObjectPointerType>()) { @@ -4350,35 +4786,36 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, if (!AddMemberPointerWithMoreQualifiedTypeVariants(Ty)) return; } else if (Ty->isEnumeralType()) { + HasArithmeticOrEnumeralTypes = true; EnumerationTypes.insert(Ty); } else if (Ty->isVectorType()) { + // We treat vector types as arithmetic types in many contexts as an + // extension. + HasArithmeticOrEnumeralTypes = true; VectorTypes.insert(Ty); - } else if (AllowUserConversions) { - if (const RecordType *TyRec = Ty->getAs<RecordType>()) { - if (SemaRef.RequireCompleteType(Loc, Ty, 0)) { - // No conversion functions in incomplete types. - return; - } + } else if (AllowUserConversions && TyRec) { + // No conversion functions in incomplete types. + if (SemaRef.RequireCompleteType(Loc, Ty, 0)) + return; - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); - const UnresolvedSetImpl *Conversions - = ClassDecl->getVisibleConversionFunctions(); - for (UnresolvedSetImpl::iterator I = Conversions->begin(), - E = Conversions->end(); I != E; ++I) { - NamedDecl *D = I.getDecl(); - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); + const UnresolvedSetImpl *Conversions + = ClassDecl->getVisibleConversionFunctions(); + for (UnresolvedSetImpl::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { + NamedDecl *D = I.getDecl(); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); - // Skip conversion function templates; they don't tell us anything - // about which builtin types we can convert to. - if (isa<FunctionTemplateDecl>(D)) - continue; + // Skip conversion function templates; they don't tell us anything + // about which builtin types we can convert to. + if (isa<FunctionTemplateDecl>(D)) + continue; - CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); - if (AllowExplicitConversions || !Conv->isExplicit()) { - AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, - VisibleQuals); - } + CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); + if (AllowExplicitConversions || !Conv->isExplicit()) { + AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, + VisibleQuals); } } } @@ -4426,14 +4863,14 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { VRQuals.addRestrict(); return VRQuals; } - + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); if (!ClassDecl->hasDefinition()) return VRQuals; const UnresolvedSetImpl *Conversions = ClassDecl->getVisibleConversionFunctions(); - + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = I.getDecl(); @@ -4449,7 +4886,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { while (!done) { if (const PointerType *ResTypePtr = CanTy->getAs<PointerType>()) CanTy = ResTypePtr->getPointeeType(); - else if (const MemberPointerType *ResTypeMPtr = + else if (const MemberPointerType *ResTypeMPtr = CanTy->getAs<MemberPointerType>()) CanTy = ResTypeMPtr->getPointeeType(); else @@ -4465,765 +4902,1174 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { } return VRQuals; } - -/// 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, - SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet) { - // The set of "promoted arithmetic types", which are the arithmetic - // types are that preserved by promotion (C++ [over.built]p2). Note - // that the first few of these types are the promoted integral - // types; these types need to be first. - // FIXME: What about complex? - const unsigned FirstIntegralType = 0; - const unsigned LastIntegralType = 13; - 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, - Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy, - Context.FloatTy, Context.DoubleTy, Context.LongDoubleTy - }; - assert(ArithmeticTypes[FirstPromotedIntegralType] == Context.IntTy && - "Invalid first promoted integral type"); - assert(ArithmeticTypes[LastPromotedIntegralType - 1] - == Context.UnsignedLongLongTy && - "Invalid last promoted integral type"); - assert(ArithmeticTypes[FirstPromotedArithmeticType] == Context.IntTy && - "Invalid first promoted arithmetic type"); - assert(ArithmeticTypes[LastPromotedArithmeticType - 1] - == Context.LongDoubleTy && - "Invalid last promoted arithmetic type"); - - // 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. - Qualifiers VisibleTypeConversionsQuals; - VisibleTypeConversionsQuals.addConst(); - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) - VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]); - - BuiltinCandidateTypeSet CandidateTypes(*this); - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) - CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(), - OpLoc, - true, - (Op == OO_Exclaim || - Op == OO_AmpAmp || - Op == OO_PipePipe), - VisibleTypeConversionsQuals); - - bool isComparison = false; - switch (Op) { - case OO_None: - case NUM_OVERLOADED_OPERATORS: - assert(false && "Expected an overloaded operator"); - break; - case OO_Star: // '*' is either unary or binary - if (NumArgs == 1) - goto UnaryStar; - else - goto BinaryStar; - break; +namespace { - case OO_Plus: // '+' is either unary or binary - if (NumArgs == 1) - goto UnaryPlus; - else - goto BinaryPlus; - break; +/// \brief Helper class to manage the addition of builtin operator overload +/// candidates. It provides shared state and utility methods used throughout +/// the process, as well as a helper method to add each group of builtin +/// operator overloads from the standard to a candidate set. +class BuiltinOperatorOverloadBuilder { + // Common instance state available to all overload candidate addition methods. + Sema &S; + Expr **Args; + unsigned NumArgs; + Qualifiers VisibleTypeConversionsQuals; + bool HasArithmeticOrEnumeralCandidateType; + llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes; + OverloadCandidateSet &CandidateSet; + + // Define some constants used to index and iterate over the arithemetic types + // provided via the getArithmeticType() method below. + // The "promoted arithmetic types" are the arithmetic + // types are that preserved by promotion (C++ [over.built]p2). + static const unsigned FirstIntegralType = 3; + static const unsigned LastIntegralType = 18; + static const unsigned FirstPromotedIntegralType = 3, + LastPromotedIntegralType = 9; + static const unsigned FirstPromotedArithmeticType = 0, + LastPromotedArithmeticType = 9; + static const unsigned NumArithmeticTypes = 18; + + /// \brief Get the canonical type for a given arithmetic type index. + CanQualType getArithmeticType(unsigned index) { + assert(index < NumArithmeticTypes); + static CanQualType ASTContext::* const + ArithmeticTypes[NumArithmeticTypes] = { + // Start of promoted types. + &ASTContext::FloatTy, + &ASTContext::DoubleTy, + &ASTContext::LongDoubleTy, + + // Start of integral types. + &ASTContext::IntTy, + &ASTContext::LongTy, + &ASTContext::LongLongTy, + &ASTContext::UnsignedIntTy, + &ASTContext::UnsignedLongTy, + &ASTContext::UnsignedLongLongTy, + // End of promoted types. + + &ASTContext::BoolTy, + &ASTContext::CharTy, + &ASTContext::WCharTy, + &ASTContext::Char16Ty, + &ASTContext::Char32Ty, + &ASTContext::SignedCharTy, + &ASTContext::ShortTy, + &ASTContext::UnsignedCharTy, + &ASTContext::UnsignedShortTy, + // End of integral types. + // FIXME: What about complex? + }; + return S.Context.*ArithmeticTypes[index]; + } + + /// \brief Gets the canonical type resulting from the usual arithemetic + /// converions for the given arithmetic types. + CanQualType getUsualArithmeticConversions(unsigned L, unsigned R) { + // Accelerator table for performing the usual arithmetic conversions. + // The rules are basically: + // - if either is floating-point, use the wider floating-point + // - if same signedness, use the higher rank + // - if same size, use unsigned of the higher rank + // - use the larger type + // These rules, together with the axiom that higher ranks are + // never smaller, are sufficient to precompute all of these results + // *except* when dealing with signed types of higher rank. + // (we could precompute SLL x UI for all known platforms, but it's + // better not to make any assumptions). + enum PromotedType { + Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL, Dep=-1 + }; + static PromotedType ConversionsTable[LastPromotedArithmeticType] + [LastPromotedArithmeticType] = { + /* Flt*/ { Flt, Dbl, LDbl, Flt, Flt, Flt, Flt, Flt, Flt }, + /* Dbl*/ { Dbl, Dbl, LDbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl }, + /*LDbl*/ { LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl }, + /* SI*/ { Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL }, + /* SL*/ { Flt, Dbl, LDbl, SL, SL, SLL, Dep, UL, ULL }, + /* SLL*/ { Flt, Dbl, LDbl, SLL, SLL, SLL, Dep, Dep, ULL }, + /* UI*/ { Flt, Dbl, LDbl, UI, Dep, Dep, UI, UL, ULL }, + /* UL*/ { Flt, Dbl, LDbl, UL, UL, Dep, UL, UL, ULL }, + /* ULL*/ { Flt, Dbl, LDbl, ULL, ULL, ULL, ULL, ULL, ULL }, + }; - case OO_Minus: // '-' is either unary or binary - if (NumArgs == 1) - goto UnaryMinus; - else - goto BinaryMinus; - break; + assert(L < LastPromotedArithmeticType); + assert(R < LastPromotedArithmeticType); + int Idx = ConversionsTable[L][R]; + + // Fast path: the table gives us a concrete answer. + if (Idx != Dep) return getArithmeticType(Idx); + + // Slow path: we need to compare widths. + // An invariant is that the signed type has higher rank. + CanQualType LT = getArithmeticType(L), + RT = getArithmeticType(R); + unsigned LW = S.Context.getIntWidth(LT), + RW = S.Context.getIntWidth(RT); + + // If they're different widths, use the signed type. + if (LW > RW) return LT; + else if (LW < RW) return RT; + + // Otherwise, use the unsigned type of the signed type's rank. + if (L == SL || R == SL) return S.Context.UnsignedLongTy; + assert(L == SLL || R == SLL); + return S.Context.UnsignedLongLongTy; + } + + /// \brief Helper method to factor out the common pattern of adding overloads + /// for '++' and '--' builtin operators. + void addPlusPlusMinusMinusStyleOverloads(QualType CandidateTy, + bool HasVolatile) { + QualType ParamTypes[2] = { + S.Context.getLValueReferenceType(CandidateTy), + S.Context.IntTy + }; - case OO_Amp: // '&' is either unary or binary + // Non-volatile version. if (NumArgs == 1) - goto UnaryAmp; + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); else - goto BinaryAmp; + S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet); + + // Use a heuristic to reduce number of builtin candidates in the set: + // add volatile version only if there are conversions to a volatile type. + if (HasVolatile) { + ParamTypes[0] = + S.Context.getLValueReferenceType( + S.Context.getVolatileType(CandidateTy)); + if (NumArgs == 1) + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet); + } + } + +public: + BuiltinOperatorOverloadBuilder( + Sema &S, Expr **Args, unsigned NumArgs, + Qualifiers VisibleTypeConversionsQuals, + bool HasArithmeticOrEnumeralCandidateType, + llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes, + OverloadCandidateSet &CandidateSet) + : S(S), Args(Args), NumArgs(NumArgs), + VisibleTypeConversionsQuals(VisibleTypeConversionsQuals), + HasArithmeticOrEnumeralCandidateType( + HasArithmeticOrEnumeralCandidateType), + CandidateTypes(CandidateTypes), + CandidateSet(CandidateSet) { + // Validate some of our static helper constants in debug builds. + assert(getArithmeticType(FirstPromotedIntegralType) == S.Context.IntTy && + "Invalid first promoted integral type"); + assert(getArithmeticType(LastPromotedIntegralType - 1) + == S.Context.UnsignedLongLongTy && + "Invalid last promoted integral type"); + assert(getArithmeticType(FirstPromotedArithmeticType) + == S.Context.FloatTy && + "Invalid first promoted arithmetic type"); + assert(getArithmeticType(LastPromotedArithmeticType - 1) + == S.Context.UnsignedLongLongTy && + "Invalid last promoted arithmetic type"); + } + + // C++ [over.built]p3: + // + // For every pair (T, VQ), where T is an arithmetic type, and VQ + // is either volatile or empty, there exist candidate operator + // functions of the form + // + // VQ T& operator++(VQ T&); + // T operator++(VQ T&, int); + // + // C++ [over.built]p4: + // + // For every pair (T, VQ), where T is an arithmetic type other + // than bool, and VQ is either volatile or empty, there exist + // candidate operator functions of the form + // + // VQ T& operator--(VQ T&); + // T operator--(VQ T&, int); + void addPlusPlusMinusMinusArithmeticOverloads(OverloadedOperatorKind Op) { + if (!HasArithmeticOrEnumeralCandidateType) + return; - case OO_PlusPlus: - case OO_MinusMinus: - // C++ [over.built]p3: - // - // For every pair (T, VQ), where T is an arithmetic type, and VQ - // is either volatile or empty, there exist candidate operator - // functions of the form - // - // VQ T& operator++(VQ T&); - // T operator++(VQ T&, int); - // - // C++ [over.built]p4: - // - // For every pair (T, VQ), where T is an arithmetic type other - // than bool, and VQ is either volatile or empty, there exist - // candidate operator functions of the form - // - // VQ T& operator--(VQ T&); - // T operator--(VQ T&, int); for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1); Arith < NumArithmeticTypes; ++Arith) { - QualType ArithTy = ArithmeticTypes[Arith]; - QualType ParamTypes[2] - = { Context.getLValueReferenceType(ArithTy), Context.IntTy }; - - // Non-volatile version. - if (NumArgs == 1) - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); - else - AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); - // heuristic to reduce number of builtin candidates in the set. - // Add volatile version only if there are conversions to a volatile type. - if (VisibleTypeConversionsQuals.hasVolatile()) { - // Volatile version - ParamTypes[0] - = Context.getLValueReferenceType(Context.getVolatileType(ArithTy)); - if (NumArgs == 1) - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); - else - AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); - } + addPlusPlusMinusMinusStyleOverloads( + getArithmeticType(Arith), + VisibleTypeConversionsQuals.hasVolatile()); } + } - // C++ [over.built]p5: - // - // For every pair (T, VQ), where T is a cv-qualified or - // cv-unqualified object type, and VQ is either volatile or - // empty, there exist candidate operator functions of the form - // - // T*VQ& operator++(T*VQ&); - // T*VQ& operator--(T*VQ&); - // T* operator++(T*VQ&, int); - // T* operator--(T*VQ&, int); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { + // C++ [over.built]p5: + // + // For every pair (T, VQ), where T is a cv-qualified or + // cv-unqualified object type, and VQ is either volatile or + // empty, there exist candidate operator functions of the form + // + // T*VQ& operator++(T*VQ&); + // T*VQ& operator--(T*VQ&); + // T* operator++(T*VQ&, int); + // T* operator--(T*VQ&, int); + void addPlusPlusMinusMinusPointerOverloads() { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[0].pointer_begin(), + PtrEnd = CandidateTypes[0].pointer_end(); + Ptr != PtrEnd; ++Ptr) { // Skip pointer types that aren't pointers to object types. - if (!(*Ptr)->getPointeeType()->isIncompleteOrObjectType()) + if (!(*Ptr)->getPointeeType()->isObjectType()) continue; - QualType ParamTypes[2] = { - Context.getLValueReferenceType(*Ptr), Context.IntTy - }; - - // Without volatile - if (NumArgs == 1) - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); - else - AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); - - if (!Context.getCanonicalType(*Ptr).isVolatileQualified() && - VisibleTypeConversionsQuals.hasVolatile()) { - // With volatile - ParamTypes[0] - = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); - if (NumArgs == 1) - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); - else - AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); - } + addPlusPlusMinusMinusStyleOverloads(*Ptr, + (!S.Context.getCanonicalType(*Ptr).isVolatileQualified() && + VisibleTypeConversionsQuals.hasVolatile())); } - break; + } - UnaryStar: - // C++ [over.built]p6: - // For every cv-qualified or cv-unqualified object type T, there - // exist candidate operator functions of the form - // - // T& operator*(T*); - // - // C++ [over.built]p7: - // For every function type T, there exist candidate operator - // functions of the form - // T& operator*(T*); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { + // C++ [over.built]p6: + // For every cv-qualified or cv-unqualified object type T, there + // exist candidate operator functions of the form + // + // T& operator*(T*); + // + // C++ [over.built]p7: + // For every function type T that does not have cv-qualifiers or a + // ref-qualifier, there exist candidate operator functions of the form + // T& operator*(T*); + void addUnaryStarPointerOverloads() { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[0].pointer_begin(), + PtrEnd = CandidateTypes[0].pointer_end(); + Ptr != PtrEnd; ++Ptr) { QualType ParamTy = *Ptr; QualType PointeeTy = ParamTy->getPointeeType(); - AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy), - &ParamTy, Args, 1, CandidateSet); - } - break; + if (!PointeeTy->isObjectType() && !PointeeTy->isFunctionType()) + continue; - UnaryPlus: - // C++ [over.built]p8: - // For every type T, there exist candidate operator functions of - // the form - // - // T* operator+(T*); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { - QualType ParamTy = *Ptr; - AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet); + if (const FunctionProtoType *Proto =PointeeTy->getAs<FunctionProtoType>()) + if (Proto->getTypeQuals() || Proto->getRefQualifier()) + continue; + + S.AddBuiltinCandidate(S.Context.getLValueReferenceType(PointeeTy), + &ParamTy, Args, 1, CandidateSet); } + } - // Fall through + // C++ [over.built]p9: + // For every promoted arithmetic type T, there exist candidate + // operator functions of the form + // + // T operator+(T); + // T operator-(T); + void addUnaryPlusOrMinusArithmeticOverloads() { + if (!HasArithmeticOrEnumeralCandidateType) + return; - UnaryMinus: - // C++ [over.built]p9: - // For every promoted arithmetic type T, there exist candidate - // operator functions of the form - // - // T operator+(T); - // T operator-(T); for (unsigned Arith = FirstPromotedArithmeticType; Arith < LastPromotedArithmeticType; ++Arith) { - QualType ArithTy = ArithmeticTypes[Arith]; - AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet); + QualType ArithTy = getArithmeticType(Arith); + S.AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet); } - + // Extension: We also add these operators for vector types. - for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(), - VecEnd = CandidateTypes.vector_end(); + for (BuiltinCandidateTypeSet::iterator + Vec = CandidateTypes[0].vector_begin(), + VecEnd = CandidateTypes[0].vector_end(); Vec != VecEnd; ++Vec) { QualType VecTy = *Vec; - AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); } - break; + } + + // C++ [over.built]p8: + // For every type T, there exist candidate operator functions of + // the form + // + // T* operator+(T*); + void addUnaryPlusPointerOverloads() { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[0].pointer_begin(), + PtrEnd = CandidateTypes[0].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + QualType ParamTy = *Ptr; + S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet); + } + } + + // C++ [over.built]p10: + // For every promoted integral type T, there exist candidate + // operator functions of the form + // + // T operator~(T); + void addUnaryTildePromotedIntegralOverloads() { + if (!HasArithmeticOrEnumeralCandidateType) + return; - case OO_Tilde: - // C++ [over.built]p10: - // For every promoted integral type T, there exist candidate - // operator functions of the form - // - // T operator~(T); for (unsigned Int = FirstPromotedIntegralType; Int < LastPromotedIntegralType; ++Int) { - QualType IntTy = ArithmeticTypes[Int]; - AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet); + QualType IntTy = getArithmeticType(Int); + S.AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet); } - + // Extension: We also add this operator for vector types. - for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(), - VecEnd = CandidateTypes.vector_end(); + for (BuiltinCandidateTypeSet::iterator + Vec = CandidateTypes[0].vector_begin(), + VecEnd = CandidateTypes[0].vector_end(); Vec != VecEnd; ++Vec) { QualType VecTy = *Vec; - AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); - } - break; + S.AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); + } + } - case OO_New: - case OO_Delete: - case OO_Array_New: - case OO_Array_Delete: - case OO_Call: - assert(false && "Special operators don't use AddBuiltinOperatorCandidates"); - break; + // 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); + void addEqualEqualOrNotEqualMemberPointerOverloads() { + /// Set of (canonical) types that we've already handled. + llvm::SmallPtrSet<QualType, 8> AddedTypes; + + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (BuiltinCandidateTypeSet::iterator + MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(), + MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end(); + MemPtr != MemPtrEnd; + ++MemPtr) { + // Don't add the same builtin candidate twice. + if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr))) + continue; - case OO_Comma: - UnaryAmp: - case OO_Arrow: - // C++ [over.match.oper]p3: - // -- For the operator ',', the unary operator '&', or the - // operator '->', the built-in candidates set is empty. - break; + QualType ParamTypes[2] = { *MemPtr, *MemPtr }; + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, + CandidateSet); + } + } + } - 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 + // 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); + // bool operator>=(T, T); + // bool operator==(T, T); + // bool operator!=(T, T); + void addRelationalPointerOrEnumeralOverloads() { + // C++ [over.built]p1: + // If there is a user-written candidate with the same name and parameter + // types as a built-in candidate operator function, the built-in operator + // function is hidden and is not included in the set of candidate + // functions. // - // 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); - } + // The text is actually in a note, but if we don't implement it then we end + // up with ambiguities when the user provides an overloaded operator for + // an enumeration type. Note that only enumeration types have this problem, + // so we track which enumeration types we've seen operators for. Also, the + // only other overloaded operator with enumeration argumenst, operator=, + // cannot be overloaded for enumeration types, so this is the only place + // where we must suppress candidates like this. + llvm::DenseSet<std::pair<CanQualType, CanQualType> > + UserDefinedBinaryOperators; + + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + if (CandidateTypes[ArgIdx].enumeration_begin() != + CandidateTypes[ArgIdx].enumeration_end()) { + for (OverloadCandidateSet::iterator C = CandidateSet.begin(), + CEnd = CandidateSet.end(); + C != CEnd; ++C) { + if (!C->Viable || !C->Function || C->Function->getNumParams() != 2) + continue; - // Fall through + QualType FirstParamType = + C->Function->getParamDecl(0)->getType().getUnqualifiedType(); + QualType SecondParamType = + C->Function->getParamDecl(1)->getType().getUnqualifiedType(); - case OO_Less: - case OO_Greater: - case OO_LessEqual: - case OO_GreaterEqual: - // 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); - // bool operator>=(T, T); - // bool operator==(T, T); - // bool operator!=(T, T); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { - QualType ParamTypes[2] = { *Ptr, *Ptr }; - AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); - } - for (BuiltinCandidateTypeSet::iterator Enum - = CandidateTypes.enumeration_begin(); - Enum != CandidateTypes.enumeration_end(); ++Enum) { - QualType ParamTypes[2] = { *Enum, *Enum }; - AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); + // Skip if either parameter isn't of enumeral type. + if (!FirstParamType->isEnumeralType() || + !SecondParamType->isEnumeralType()) + continue; + + // Add this operator to the set of known user-defined operators. + UserDefinedBinaryOperators.insert( + std::make_pair(S.Context.getCanonicalType(FirstParamType), + S.Context.getCanonicalType(SecondParamType))); + } + } } - // Fall through. - isComparison = true; + /// Set of (canonical) types that we've already handled. + llvm::SmallPtrSet<QualType, 8> AddedTypes; - BinaryPlus: - BinaryMinus: - if (!isComparison) { - // We didn't fall through, so we must have OO_Plus or OO_Minus. + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[ArgIdx].pointer_begin(), + PtrEnd = CandidateTypes[ArgIdx].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + // Don't add the same builtin candidate twice. + if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr))) + continue; - // C++ [over.built]p13: - // - // 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); - // T* operator+(ptrdiff_t, T*); - // T& operator[](ptrdiff_t, T*); [BELOW] - // - // C++ [over.built]p14: - // - // For every T, where T is a pointer to object type, there - // exist candidate operator functions of the form - // - // ptrdiff_t operator-(T, T); - for (BuiltinCandidateTypeSet::iterator Ptr - = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { - QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() }; + QualType ParamTypes[2] = { *Ptr, *Ptr }; + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, + CandidateSet); + } + for (BuiltinCandidateTypeSet::iterator + Enum = CandidateTypes[ArgIdx].enumeration_begin(), + EnumEnd = CandidateTypes[ArgIdx].enumeration_end(); + Enum != EnumEnd; ++Enum) { + CanQualType CanonType = S.Context.getCanonicalType(*Enum); + + // Don't add the same builtin candidate twice, or if a user defined + // candidate exists. + if (!AddedTypes.insert(CanonType) || + UserDefinedBinaryOperators.count(std::make_pair(CanonType, + CanonType))) + continue; - // operator+(T*, ptrdiff_t) or operator-(T*, ptrdiff_t) - AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + QualType ParamTypes[2] = { *Enum, *Enum }; + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, + CandidateSet); + } + } + } - if (Op == OO_Plus) { + // C++ [over.built]p13: + // + // 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); + // T* operator+(ptrdiff_t, T*); + // T& operator[](ptrdiff_t, T*); [BELOW] + // + // C++ [over.built]p14: + // + // For every T, where T is a pointer to object type, there + // exist candidate operator functions of the form + // + // ptrdiff_t operator-(T, T); + void addBinaryPlusOrMinusPointerOverloads(OverloadedOperatorKind Op) { + /// Set of (canonical) types that we've already handled. + llvm::SmallPtrSet<QualType, 8> AddedTypes; + + for (int Arg = 0; Arg < 2; ++Arg) { + QualType AsymetricParamTypes[2] = { + S.Context.getPointerDiffType(), + S.Context.getPointerDiffType(), + }; + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[Arg].pointer_begin(), + PtrEnd = CandidateTypes[Arg].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + QualType PointeeTy = (*Ptr)->getPointeeType(); + if (!PointeeTy->isObjectType()) + continue; + + AsymetricParamTypes[Arg] = *Ptr; + if (Arg == 0 || Op == OO_Plus) { + // operator+(T*, ptrdiff_t) or operator-(T*, ptrdiff_t) // T* operator+(ptrdiff_t, T*); - ParamTypes[0] = ParamTypes[1]; - ParamTypes[1] = *Ptr; - AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); - } else { + S.AddBuiltinCandidate(*Ptr, AsymetricParamTypes, Args, 2, + CandidateSet); + } + if (Op == OO_Minus) { // ptrdiff_t operator-(T, T); - ParamTypes[1] = *Ptr; - AddBuiltinCandidate(Context.getPointerDiffType(), ParamTypes, - Args, 2, CandidateSet); + if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr))) + continue; + + QualType ParamTypes[2] = { *Ptr, *Ptr }; + S.AddBuiltinCandidate(S.Context.getPointerDiffType(), ParamTypes, + Args, 2, CandidateSet); } } } - // Fall through + } + + // C++ [over.built]p12: + // + // For every pair of promoted arithmetic types L and R, there + // exist candidate operator functions of the form + // + // LR operator*(L, R); + // LR operator/(L, R); + // LR operator+(L, R); + // LR operator-(L, R); + // bool operator<(L, R); + // bool operator>(L, R); + // bool operator<=(L, R); + // bool operator>=(L, R); + // bool operator==(L, R); + // bool operator!=(L, R); + // + // where LR is the result of the usual arithmetic conversions + // between types L and R. + // + // C++ [over.built]p24: + // + // For every pair of promoted arithmetic types L and R, there exist + // candidate operator functions of the form + // + // LR operator?(bool, L, R); + // + // where LR is the result of the usual arithmetic conversions + // between types L and R. + // Our candidates ignore the first parameter. + void addGenericBinaryArithmeticOverloads(bool isComparison) { + if (!HasArithmeticOrEnumeralCandidateType) + return; - case OO_Slash: - BinaryStar: - Conditional: - // C++ [over.built]p12: - // - // For every pair of promoted arithmetic types L and R, there - // exist candidate operator functions of the form - // - // LR operator*(L, R); - // LR operator/(L, R); - // LR operator+(L, R); - // LR operator-(L, R); - // bool operator<(L, R); - // bool operator>(L, R); - // bool operator<=(L, R); - // bool operator>=(L, R); - // bool operator==(L, R); - // bool operator!=(L, R); - // - // where LR is the result of the usual arithmetic conversions - // between types L and R. - // - // C++ [over.built]p24: - // - // For every pair of promoted arithmetic types L and R, there exist - // candidate operator functions of the form - // - // LR operator?(bool, L, R); - // - // 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; Left < LastPromotedArithmeticType; ++Left) { for (unsigned Right = FirstPromotedArithmeticType; Right < LastPromotedArithmeticType; ++Right) { - QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] }; - QualType Result - = isComparison - ? Context.BoolTy - : Context.UsualArithmeticConversionsType(LandR[0], LandR[1]); - AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + QualType LandR[2] = { getArithmeticType(Left), + getArithmeticType(Right) }; + QualType Result = + isComparison ? S.Context.BoolTy + : getUsualArithmeticConversions(Left, Right); + S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); } } // Extension: Add the binary operators ==, !=, <, <=, >=, >, *, /, and the // conditional operator for vector types. - for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(), - Vec1End = CandidateTypes.vector_end(); - Vec1 != Vec1End; ++Vec1) - for (BuiltinCandidateTypeSet::iterator - Vec2 = CandidateTypes.vector_begin(), - Vec2End = CandidateTypes.vector_end(); + for (BuiltinCandidateTypeSet::iterator + Vec1 = CandidateTypes[0].vector_begin(), + Vec1End = CandidateTypes[0].vector_end(); + Vec1 != Vec1End; ++Vec1) { + for (BuiltinCandidateTypeSet::iterator + Vec2 = CandidateTypes[1].vector_begin(), + Vec2End = CandidateTypes[1].vector_end(); Vec2 != Vec2End; ++Vec2) { QualType LandR[2] = { *Vec1, *Vec2 }; - QualType Result; - if (isComparison) - Result = Context.BoolTy; - else { + QualType Result = S.Context.BoolTy; + if (!isComparison) { if ((*Vec1)->isExtVectorType() || !(*Vec2)->isExtVectorType()) Result = *Vec1; else Result = *Vec2; } - - AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + + S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); } - - break; + } + } + + // C++ [over.built]p17: + // + // For every pair of promoted integral types L and R, there + // exist candidate operator functions of the form + // + // LR operator%(L, R); + // LR operator&(L, R); + // LR operator^(L, R); + // LR operator|(L, R); + // L operator<<(L, R); + // L operator>>(L, R); + // + // where LR is the result of the usual arithmetic conversions + // between types L and R. + void addBinaryBitwiseArithmeticOverloads(OverloadedOperatorKind Op) { + if (!HasArithmeticOrEnumeralCandidateType) + return; - case OO_Percent: - BinaryAmp: - case OO_Caret: - case OO_Pipe: - case OO_LessLess: - case OO_GreaterGreater: - // C++ [over.built]p17: - // - // For every pair of promoted integral types L and R, there - // exist candidate operator functions of the form - // - // LR operator%(L, R); - // LR operator&(L, R); - // LR operator^(L, R); - // LR operator|(L, R); - // L operator<<(L, R); - // L operator>>(L, R); - // - // where LR is the result of the usual arithmetic conversions - // between types L and R. for (unsigned Left = FirstPromotedIntegralType; Left < LastPromotedIntegralType; ++Left) { for (unsigned Right = FirstPromotedIntegralType; Right < LastPromotedIntegralType; ++Right) { - QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] }; + QualType LandR[2] = { getArithmeticType(Left), + getArithmeticType(Right) }; QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater) ? LandR[0] - : Context.UsualArithmeticConversionsType(LandR[0], LandR[1]); - AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + : getUsualArithmeticConversions(Left, Right); + S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); } } - break; + } - case OO_Equal: - // C++ [over.built]p20: - // - // For every pair (T, VQ), where T is an enumeration 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(), - 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. + // C++ [over.built]p20: + // + // For every pair (T, VQ), where T is an enumeration 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); + void addAssignmentMemberPointerOrEnumeralOverloads() { + /// Set of (canonical) types that we've already handled. + llvm::SmallPtrSet<QualType, 8> AddedTypes; + + for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) { + for (BuiltinCandidateTypeSet::iterator + Enum = CandidateTypes[ArgIdx].enumeration_begin(), + EnumEnd = CandidateTypes[ArgIdx].enumeration_end(); + Enum != EnumEnd; ++Enum) { + if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum))) + continue; - case OO_PlusEqual: - case OO_MinusEqual: - // C++ [over.built]p19: - // - // For every pair (T, VQ), where T is any type and VQ is either - // volatile or empty, there exist candidate operator functions - // of the form - // - // T*VQ& operator=(T*VQ&, T*); - // - // C++ [over.built]p21: - // - // For every pair (T, VQ), where T is a cv-qualified or - // cv-unqualified object type and VQ is either volatile or - // empty, there exist candidate operator functions of the form - // - // T*VQ& operator+=(T*VQ&, ptrdiff_t); - // T*VQ& operator-=(T*VQ&, ptrdiff_t); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { - QualType ParamTypes[2]; - ParamTypes[1] = (Op == OO_Equal)? *Ptr : Context.getPointerDiffType(); + AddBuiltinAssignmentOperatorCandidates(S, *Enum, Args, 2, + CandidateSet); + } + + for (BuiltinCandidateTypeSet::iterator + MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(), + MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end(); + MemPtr != MemPtrEnd; ++MemPtr) { + if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr))) + continue; + + AddBuiltinAssignmentOperatorCandidates(S, *MemPtr, Args, 2, + CandidateSet); + } + } + } + + // C++ [over.built]p19: + // + // For every pair (T, VQ), where T is any type and VQ is either + // volatile or empty, there exist candidate operator functions + // of the form + // + // T*VQ& operator=(T*VQ&, T*); + // + // C++ [over.built]p21: + // + // For every pair (T, VQ), where T is a cv-qualified or + // cv-unqualified object type and VQ is either volatile or + // empty, there exist candidate operator functions of the form + // + // T*VQ& operator+=(T*VQ&, ptrdiff_t); + // T*VQ& operator-=(T*VQ&, ptrdiff_t); + void addAssignmentPointerOverloads(bool isEqualOp) { + /// Set of (canonical) types that we've already handled. + llvm::SmallPtrSet<QualType, 8> AddedTypes; + + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[0].pointer_begin(), + PtrEnd = CandidateTypes[0].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + // If this is operator=, keep track of the builtin candidates we added. + if (isEqualOp) + AddedTypes.insert(S.Context.getCanonicalType(*Ptr)); + else if (!(*Ptr)->getPointeeType()->isObjectType()) + continue; // non-volatile version - ParamTypes[0] = Context.getLValueReferenceType(*Ptr); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, - /*IsAssigmentOperator=*/Op == OO_Equal); + QualType ParamTypes[2] = { + S.Context.getLValueReferenceType(*Ptr), + isEqualOp ? *Ptr : S.Context.getPointerDiffType(), + }; + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/ isEqualOp); - if (!Context.getCanonicalType(*Ptr).isVolatileQualified() && + if (!S.Context.getCanonicalType(*Ptr).isVolatileQualified() && VisibleTypeConversionsQuals.hasVolatile()) { // volatile version - ParamTypes[0] - = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, - /*IsAssigmentOperator=*/Op == OO_Equal); + ParamTypes[0] = + S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr)); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/isEqualOp); } } - // Fall through. - case OO_StarEqual: - case OO_SlashEqual: - // C++ [over.built]p18: - // - // For every triple (L, VQ, R), where L is an arithmetic type, - // VQ is either volatile or empty, and R is a promoted - // arithmetic type, there exist candidate operator functions of - // the form - // - // VQ L& operator=(VQ L&, R); - // VQ L& operator*=(VQ L&, R); - // VQ L& operator/=(VQ L&, R); - // VQ L& operator+=(VQ L&, R); - // VQ L& operator-=(VQ L&, R); + if (isEqualOp) { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[1].pointer_begin(), + PtrEnd = CandidateTypes[1].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + // Make sure we don't add the same candidate twice. + if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr))) + continue; + + QualType ParamTypes[2] = { + S.Context.getLValueReferenceType(*Ptr), + *Ptr, + }; + + // non-volatile version + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/true); + + if (!S.Context.getCanonicalType(*Ptr).isVolatileQualified() && + VisibleTypeConversionsQuals.hasVolatile()) { + // volatile version + ParamTypes[0] = + S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr)); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, + CandidateSet, /*IsAssigmentOperator=*/true); + } + } + } + } + + // C++ [over.built]p18: + // + // For every triple (L, VQ, R), where L is an arithmetic type, + // VQ is either volatile or empty, and R is a promoted + // arithmetic type, there exist candidate operator functions of + // the form + // + // VQ L& operator=(VQ L&, R); + // VQ L& operator*=(VQ L&, R); + // VQ L& operator/=(VQ L&, R); + // VQ L& operator+=(VQ L&, R); + // VQ L& operator-=(VQ L&, R); + void addAssignmentArithmeticOverloads(bool isEqualOp) { + if (!HasArithmeticOrEnumeralCandidateType) + return; + for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) { for (unsigned Right = FirstPromotedArithmeticType; Right < LastPromotedArithmeticType; ++Right) { QualType ParamTypes[2]; - ParamTypes[1] = ArithmeticTypes[Right]; + ParamTypes[1] = getArithmeticType(Right); // Add this built-in operator as a candidate (VQ is empty). - ParamTypes[0] = Context.getLValueReferenceType(ArithmeticTypes[Left]); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, - /*IsAssigmentOperator=*/Op == OO_Equal); + ParamTypes[0] = + S.Context.getLValueReferenceType(getArithmeticType(Left)); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/isEqualOp); // Add this built-in operator as a candidate (VQ is 'volatile'). if (VisibleTypeConversionsQuals.hasVolatile()) { - ParamTypes[0] = Context.getVolatileType(ArithmeticTypes[Left]); - ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, - /*IsAssigmentOperator=*/Op == OO_Equal); + ParamTypes[0] = + S.Context.getVolatileType(getArithmeticType(Left)); + ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, + CandidateSet, + /*IsAssigmentOperator=*/isEqualOp); } } } - + // Extension: Add the binary operators =, +=, -=, *=, /= for vector types. - for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(), - Vec1End = CandidateTypes.vector_end(); - Vec1 != Vec1End; ++Vec1) - for (BuiltinCandidateTypeSet::iterator - Vec2 = CandidateTypes.vector_begin(), - Vec2End = CandidateTypes.vector_end(); + for (BuiltinCandidateTypeSet::iterator + Vec1 = CandidateTypes[0].vector_begin(), + Vec1End = CandidateTypes[0].vector_end(); + Vec1 != Vec1End; ++Vec1) { + for (BuiltinCandidateTypeSet::iterator + Vec2 = CandidateTypes[1].vector_begin(), + Vec2End = CandidateTypes[1].vector_end(); Vec2 != Vec2End; ++Vec2) { QualType ParamTypes[2]; ParamTypes[1] = *Vec2; // Add this built-in operator as a candidate (VQ is empty). - ParamTypes[0] = Context.getLValueReferenceType(*Vec1); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, - /*IsAssigmentOperator=*/Op == OO_Equal); - + ParamTypes[0] = S.Context.getLValueReferenceType(*Vec1); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/isEqualOp); + // Add this built-in operator as a candidate (VQ is 'volatile'). if (VisibleTypeConversionsQuals.hasVolatile()) { - ParamTypes[0] = Context.getVolatileType(*Vec1); - ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, - /*IsAssigmentOperator=*/Op == OO_Equal); + ParamTypes[0] = S.Context.getVolatileType(*Vec1); + ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, + CandidateSet, + /*IsAssigmentOperator=*/isEqualOp); } } - break; + } + } + + // C++ [over.built]p22: + // + // For every triple (L, VQ, R), where L is an integral type, VQ + // is either volatile or empty, and R is a promoted integral + // type, there exist candidate operator functions of the form + // + // VQ L& operator%=(VQ L&, R); + // VQ L& operator<<=(VQ L&, R); + // VQ L& operator>>=(VQ L&, R); + // VQ L& operator&=(VQ L&, R); + // VQ L& operator^=(VQ L&, R); + // VQ L& operator|=(VQ L&, R); + void addAssignmentIntegralOverloads() { + if (!HasArithmeticOrEnumeralCandidateType) + return; - case OO_PercentEqual: - case OO_LessLessEqual: - case OO_GreaterGreaterEqual: - case OO_AmpEqual: - case OO_CaretEqual: - case OO_PipeEqual: - // C++ [over.built]p22: - // - // For every triple (L, VQ, R), where L is an integral type, VQ - // is either volatile or empty, and R is a promoted integral - // type, there exist candidate operator functions of the form - // - // VQ L& operator%=(VQ L&, R); - // VQ L& operator<<=(VQ L&, R); - // VQ L& operator>>=(VQ L&, R); - // VQ L& operator&=(VQ L&, R); - // VQ L& operator^=(VQ L&, R); - // VQ L& operator|=(VQ L&, R); for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) { for (unsigned Right = FirstPromotedIntegralType; Right < LastPromotedIntegralType; ++Right) { QualType ParamTypes[2]; - ParamTypes[1] = ArithmeticTypes[Right]; + ParamTypes[1] = getArithmeticType(Right); // Add this built-in operator as a candidate (VQ is empty). - ParamTypes[0] = Context.getLValueReferenceType(ArithmeticTypes[Left]); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + ParamTypes[0] = + S.Context.getLValueReferenceType(getArithmeticType(Left)); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); if (VisibleTypeConversionsQuals.hasVolatile()) { // Add this built-in operator as a candidate (VQ is 'volatile'). - ParamTypes[0] = ArithmeticTypes[Left]; - ParamTypes[0] = Context.getVolatileType(ParamTypes[0]); - ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + ParamTypes[0] = getArithmeticType(Left); + ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]); + ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, + CandidateSet); } } } - break; - - case OO_Exclaim: { - // C++ [over.operator]p23: - // - // There also exist candidate operator functions of the form - // - // bool operator!(bool); - // bool operator&&(bool, bool); [BELOW] - // bool operator||(bool, bool); [BELOW] - QualType ParamTy = Context.BoolTy; - AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet, - /*IsAssignmentOperator=*/false, - /*NumContextualBoolArguments=*/1); - break; - } - - case OO_AmpAmp: - case OO_PipePipe: { - // C++ [over.operator]p23: - // - // There also exist candidate operator functions of the form - // - // bool operator!(bool); [ABOVE] - // bool operator&&(bool, bool); - // bool operator||(bool, bool); - QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy }; - AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet, - /*IsAssignmentOperator=*/false, - /*NumContextualBoolArguments=*/2); - break; } - case OO_Subscript: - // C++ [over.built]p13: - // - // 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] - // T* operator+(ptrdiff_t, T*); [ABOVE] - // T& operator[](ptrdiff_t, T*); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { - QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() }; + // C++ [over.operator]p23: + // + // There also exist candidate operator functions of the form + // + // bool operator!(bool); + // bool operator&&(bool, bool); + // bool operator||(bool, bool); + void addExclaimOverload() { + QualType ParamTy = S.Context.BoolTy; + S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet, + /*IsAssignmentOperator=*/false, + /*NumContextualBoolArguments=*/1); + } + void addAmpAmpOrPipePipeOverload() { + QualType ParamTypes[2] = { S.Context.BoolTy, S.Context.BoolTy }; + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, CandidateSet, + /*IsAssignmentOperator=*/false, + /*NumContextualBoolArguments=*/2); + } + + // C++ [over.built]p13: + // + // 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] + // T* operator+(ptrdiff_t, T*); [ABOVE] + // T& operator[](ptrdiff_t, T*); + void addSubscriptOverloads() { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[0].pointer_begin(), + PtrEnd = CandidateTypes[0].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + QualType ParamTypes[2] = { *Ptr, S.Context.getPointerDiffType() }; QualType PointeeType = (*Ptr)->getPointeeType(); - QualType ResultTy = Context.getLValueReferenceType(PointeeType); + if (!PointeeType->isObjectType()) + continue; + + QualType ResultTy = S.Context.getLValueReferenceType(PointeeType); // T& operator[](T*, ptrdiff_t) - AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + } - // T& operator[](ptrdiff_t, T*); - ParamTypes[0] = ParamTypes[1]; - ParamTypes[1] = *Ptr; - AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); - } - break; + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[1].pointer_begin(), + PtrEnd = CandidateTypes[1].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + QualType ParamTypes[2] = { S.Context.getPointerDiffType(), *Ptr }; + QualType PointeeType = (*Ptr)->getPointeeType(); + if (!PointeeType->isObjectType()) + continue; - case OO_ArrowStar: - // 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; - C1 = QualType(Q1.strip(C1Ty->getPointeeType()), 0); - if (!isa<RecordType>(C1)) + QualType ResultTy = S.Context.getLValueReferenceType(PointeeType); + + // T& operator[](ptrdiff_t, T*) + S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + } + } + + // 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. + void addArrowStarOverloads() { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[0].pointer_begin(), + PtrEnd = CandidateTypes[0].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + QualType C1Ty = (*Ptr); + QualType C1; + QualifierCollector Q1; + C1 = QualType(Q1.strip(C1Ty->getPointeeType()), 0); + if (!isa<RecordType>(C1)) + continue; + // heuristic to reduce number of builtin candidates in the set. + // Add volatile/restrict version only if there are conversions to a + // volatile/restrict type. + if (!VisibleTypeConversionsQuals.hasVolatile() && Q1.hasVolatile()) + continue; + if (!VisibleTypeConversionsQuals.hasRestrict() && Q1.hasRestrict()) + continue; + for (BuiltinCandidateTypeSet::iterator + MemPtr = CandidateTypes[1].member_pointer_begin(), + MemPtrEnd = CandidateTypes[1].member_pointer_end(); + MemPtr != MemPtrEnd; ++MemPtr) { + const MemberPointerType *mptr = cast<MemberPointerType>(*MemPtr); + QualType C2 = QualType(mptr->getClass(), 0); + C2 = C2.getUnqualifiedType(); + if (C1 != C2 && !S.IsDerivedFrom(C1, C2)) + break; + QualType ParamTypes[2] = { *Ptr, *MemPtr }; + // build CV12 T& + QualType T = mptr->getPointeeType(); + if (!VisibleTypeConversionsQuals.hasVolatile() && + T.isVolatileQualified()) + continue; + if (!VisibleTypeConversionsQuals.hasRestrict() && + T.isRestrictQualified()) continue; - // heuristic to reduce number of builtin candidates in the set. - // Add volatile/restrict version only if there are conversions to a - // volatile/restrict type. - if (!VisibleTypeConversionsQuals.hasVolatile() && Q1.hasVolatile()) + T = Q1.apply(S.Context, T); + QualType ResultTy = S.Context.getLValueReferenceType(T); + S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + } + } + } + + // Note that we don't consider the first argument, since it has been + // contextually converted to bool long ago. The candidates below are + // therefore added as binary. + // + // C++ [over.built]p25: + // For every type T, where T is a pointer, pointer-to-member, or scoped + // enumeration type, there exist candidate operator functions of the form + // + // T operator?(bool, T, T); + // + void addConditionalOperatorOverloads() { + /// Set of (canonical) types that we've already handled. + llvm::SmallPtrSet<QualType, 8> AddedTypes; + + for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[ArgIdx].pointer_begin(), + PtrEnd = CandidateTypes[ArgIdx].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr))) continue; - if (!VisibleTypeConversionsQuals.hasRestrict() && Q1.hasRestrict()) + + QualType ParamTypes[2] = { *Ptr, *Ptr }; + S.AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + } + + for (BuiltinCandidateTypeSet::iterator + MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(), + MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end(); + MemPtr != MemPtrEnd; ++MemPtr) { + if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr))) continue; + + QualType ParamTypes[2] = { *MemPtr, *MemPtr }; + S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, 2, CandidateSet); + } + + if (S.getLangOptions().CPlusPlus0x) { 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(); - if (!VisibleTypeConversionsQuals.hasVolatile() && - T.isVolatileQualified()) + Enum = CandidateTypes[ArgIdx].enumeration_begin(), + EnumEnd = CandidateTypes[ArgIdx].enumeration_end(); + Enum != EnumEnd; ++Enum) { + if (!(*Enum)->getAs<EnumType>()->getDecl()->isScoped()) continue; - if (!VisibleTypeConversionsQuals.hasRestrict() && - T.isRestrictQualified()) + + if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum))) continue; - T = Q1.apply(T); - QualType ResultTy = Context.getLValueReferenceType(T); - AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + + QualType ParamTypes[2] = { *Enum, *Enum }; + S.AddBuiltinCandidate(*Enum, ParamTypes, Args, 2, CandidateSet); } } } + } +}; + +} // end anonymous namespace + +/// 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, + SourceLocation OpLoc, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet) { + // 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. Also record whether we encounter non-record + // candidate types or either arithmetic or enumeral candidate types. + Qualifiers VisibleTypeConversionsQuals; + VisibleTypeConversionsQuals.addConst(); + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]); + + bool HasNonRecordCandidateType = false; + bool HasArithmeticOrEnumeralCandidateType = false; + llvm::SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes; + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + CandidateTypes.push_back(BuiltinCandidateTypeSet(*this)); + CandidateTypes[ArgIdx].AddTypesConvertedFrom(Args[ArgIdx]->getType(), + OpLoc, + true, + (Op == OO_Exclaim || + Op == OO_AmpAmp || + Op == OO_PipePipe), + VisibleTypeConversionsQuals); + HasNonRecordCandidateType = HasNonRecordCandidateType || + CandidateTypes[ArgIdx].hasNonRecordTypes(); + HasArithmeticOrEnumeralCandidateType = + HasArithmeticOrEnumeralCandidateType || + CandidateTypes[ArgIdx].hasArithmeticOrEnumeralTypes(); + } + + // Exit early when no non-record types have been added to the candidate set + // for any of the arguments to the operator. + if (!HasNonRecordCandidateType) + return; + + // Setup an object to manage the common state for building overloads. + BuiltinOperatorOverloadBuilder OpBuilder(*this, Args, NumArgs, + VisibleTypeConversionsQuals, + HasArithmeticOrEnumeralCandidateType, + CandidateTypes, CandidateSet); + + // Dispatch over the operation to add in only those overloads which apply. + switch (Op) { + case OO_None: + case NUM_OVERLOADED_OPERATORS: + assert(false && "Expected an overloaded operator"); break; - case OO_Conditional: - // Note that we don't consider the first argument, since it has been - // contextually converted to bool long ago. The candidates below are - // therefore added as binary. - // - // C++ [over.built]p24: - // For every type T, where T is a pointer or pointer-to-member type, - // there exist candidate operator functions of the form - // - // T operator?(bool, T, T); - // - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(), - E = CandidateTypes.pointer_end(); Ptr != E; ++Ptr) { - QualType ParamTypes[2] = { *Ptr, *Ptr }; - AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); - } - for (BuiltinCandidateTypeSet::iterator Ptr = - CandidateTypes.member_pointer_begin(), - E = CandidateTypes.member_pointer_end(); Ptr != E; ++Ptr) { - QualType ParamTypes[2] = { *Ptr, *Ptr }; - AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + case OO_Call: + assert(false && "Special operators don't use AddBuiltinOperatorCandidates"); + break; + + case OO_Comma: + case OO_Arrow: + // C++ [over.match.oper]p3: + // -- For the operator ',', the unary operator '&', or the + // operator '->', the built-in candidates set is empty. + break; + + case OO_Plus: // '+' is either unary or binary + if (NumArgs == 1) + OpBuilder.addUnaryPlusPointerOverloads(); + // Fall through. + + case OO_Minus: // '-' is either unary or binary + if (NumArgs == 1) { + OpBuilder.addUnaryPlusOrMinusArithmeticOverloads(); + } else { + OpBuilder.addBinaryPlusOrMinusPointerOverloads(Op); + OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false); } - goto Conditional; + break; + + case OO_Star: // '*' is either unary or binary + if (NumArgs == 1) + OpBuilder.addUnaryStarPointerOverloads(); + else + OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false); + break; + + case OO_Slash: + OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false); + break; + + case OO_PlusPlus: + case OO_MinusMinus: + OpBuilder.addPlusPlusMinusMinusArithmeticOverloads(Op); + OpBuilder.addPlusPlusMinusMinusPointerOverloads(); + break; + + case OO_EqualEqual: + case OO_ExclaimEqual: + OpBuilder.addEqualEqualOrNotEqualMemberPointerOverloads(); + // Fall through. + + case OO_Less: + case OO_Greater: + case OO_LessEqual: + case OO_GreaterEqual: + OpBuilder.addRelationalPointerOrEnumeralOverloads(); + OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/true); + break; + + case OO_Percent: + case OO_Caret: + case OO_Pipe: + case OO_LessLess: + case OO_GreaterGreater: + OpBuilder.addBinaryBitwiseArithmeticOverloads(Op); + break; + + case OO_Amp: // '&' is either unary or binary + if (NumArgs == 1) + // C++ [over.match.oper]p3: + // -- For the operator ',', the unary operator '&', or the + // operator '->', the built-in candidates set is empty. + break; + + OpBuilder.addBinaryBitwiseArithmeticOverloads(Op); + break; + + case OO_Tilde: + OpBuilder.addUnaryTildePromotedIntegralOverloads(); + break; + + case OO_Equal: + OpBuilder.addAssignmentMemberPointerOrEnumeralOverloads(); + // Fall through. + + case OO_PlusEqual: + case OO_MinusEqual: + OpBuilder.addAssignmentPointerOverloads(Op == OO_Equal); + // Fall through. + + case OO_StarEqual: + case OO_SlashEqual: + OpBuilder.addAssignmentArithmeticOverloads(Op == OO_Equal); + break; + + case OO_PercentEqual: + case OO_LessLessEqual: + case OO_GreaterGreaterEqual: + case OO_AmpEqual: + case OO_CaretEqual: + case OO_PipeEqual: + OpBuilder.addAssignmentIntegralOverloads(); + break; + + case OO_Exclaim: + OpBuilder.addExclaimOverload(); + break; + + case OO_AmpAmp: + case OO_PipePipe: + OpBuilder.addAmpAmpOrPipePipeOverload(); + break; + + case OO_Subscript: + OpBuilder.addSubscriptOverloads(); + break; + + case OO_ArrowStar: + OpBuilder.addArrowStarOverloads(); + break; + + case OO_Conditional: + OpBuilder.addConditionalOperatorOverloads(); + OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false); + break; } } @@ -5270,7 +6116,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { if (ExplicitTemplateArgs) continue; - + AddOverloadCandidate(FD, FoundDecl, Args, NumArgs, CandidateSet, false, PartialOverloading); } else @@ -5284,9 +6130,10 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, /// candidate is a better candidate than the second (C++ 13.3.3p1). bool isBetterOverloadCandidate(Sema &S, - const OverloadCandidate& Cand1, - const OverloadCandidate& Cand2, - SourceLocation Loc) { + const OverloadCandidate &Cand1, + const OverloadCandidate &Cand2, + SourceLocation Loc, + bool UserDefinedConversion) { // Define viable functions to be better candidates than non-viable // functions. if (!Cand2.Viable) @@ -5346,14 +6193,16 @@ isBetterOverloadCandidate(Sema &S, // 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()) + Cand2.Function && Cand2.Function->getPrimaryTemplate()) { if (FunctionTemplateDecl *BetterTemplate = S.getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(), Cand2.Function->getPrimaryTemplate(), Loc, - isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion - : TPOC_Call)) + isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion + : TPOC_Call, + Cand1.ExplicitCallArguments)) return BetterTemplate == Cand1.Function->getPrimaryTemplate(); + } // -- the context is an initialization by user-defined conversion // (see 8.5, 13.3.1.5) and the standard conversion sequence @@ -5361,7 +6210,7 @@ isBetterOverloadCandidate(Sema &S, // 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 && + if (UserDefinedConversion && Cand1.Function && Cand2.Function && isa<CXXConversionDecl>(Cand1.Function) && isa<CXXConversionDecl>(Cand2.Function)) { switch (CompareStandardConversionSequences(S, @@ -5398,12 +6247,14 @@ isBetterOverloadCandidate(Sema &S, /// \returns The result of overload resolution. OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, - iterator& Best) { + iterator &Best, + bool UserDefinedConversion) { // Find the best viable function. Best = end(); for (iterator Cand = begin(); Cand != end(); ++Cand) { if (Cand->Viable) - if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc)) + if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc, + UserDefinedConversion)) Best = Cand; } @@ -5416,7 +6267,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, for (iterator Cand = begin(); Cand != end(); ++Cand) { if (Cand->Viable && Cand != Best && - !isBetterOverloadCandidate(S, *Best, *Cand, Loc)) { + !isBetterOverloadCandidate(S, *Best, *Cand, Loc, + UserDefinedConversion)) { Best = end(); return OR_Ambiguous; } @@ -5436,6 +6288,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, // placement new (5.3.4), as well as non-default initialization (8.5). if (Best->Function) S.MarkDeclarationReferenced(Loc, Best->Function); + return OR_Success; } @@ -5450,7 +6303,8 @@ enum OverloadCandidateKind { oc_constructor_template, oc_implicit_default_constructor, oc_implicit_copy_constructor, - oc_implicit_copy_assignment + oc_implicit_copy_assignment, + oc_implicit_inherited_constructor }; OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, @@ -5468,6 +6322,9 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, if (!Ctor->isImplicit()) return isTemplate ? oc_constructor_template : oc_constructor; + if (Ctor->getInheritedConstructor()) + return oc_implicit_inherited_constructor; + return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor : oc_implicit_default_constructor; } @@ -5478,7 +6335,7 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, if (!Meth->isImplicit()) return isTemplate ? oc_method_template : oc_method; - assert(Meth->isCopyAssignment() + assert(Meth->isCopyAssignmentOperator() && "implicit method is not copy assignment operator?"); return oc_implicit_copy_assignment; } @@ -5486,6 +6343,16 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, return isTemplate ? oc_function_template : oc_function; } +void MaybeEmitInheritedConstructorNote(Sema &S, FunctionDecl *Fn) { + const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn); + if (!Ctor) return; + + Ctor = Ctor->getInheritedConstructor(); + if (!Ctor) return; + + S.Diag(Ctor->getLocation(), diag::note_ovl_candidate_inherited_constructor); +} + } // end anonymous namespace // Notes the location of an overload candidate. @@ -5494,6 +6361,28 @@ void Sema::NoteOverloadCandidate(FunctionDecl *Fn) { OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc); Diag(Fn->getLocation(), diag::note_ovl_candidate) << (unsigned) K << FnDesc; + MaybeEmitInheritedConstructorNote(*this, Fn); +} + +//Notes the location of all overload candidates designated through +// OverloadedExpr +void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr) { + assert(OverloadedExpr->getType() == Context.OverloadTy); + + OverloadExpr::FindResult Ovl = OverloadExpr::find(OverloadedExpr); + OverloadExpr *OvlExpr = Ovl.Expression; + + for (UnresolvedSetIterator I = OvlExpr->decls_begin(), + IEnd = OvlExpr->decls_end(); + I != IEnd; ++I) { + if (FunctionTemplateDecl *FunTmpl = + dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) { + NoteOverloadCandidate(FunTmpl->getTemplatedDecl()); + } else if (FunctionDecl *Fun + = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) { + NoteOverloadCandidate(Fun); + } + } } /// Diagnoses an ambiguous conversion. The partial diagnostic is the @@ -5548,6 +6437,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << ToTy << Name << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); return; } @@ -5582,6 +6472,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { << FromTy << FromQs.getAddressSpace() << ToQs.getAddressSpace() << (unsigned) isObjectArgument << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); return; } @@ -5599,6 +6490,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy << (CVR - 1) << I+1; } + MaybeEmitInheritedConstructorNote(S, Fn); return; } @@ -5613,6 +6505,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); return; } @@ -5624,7 +6517,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { FromPtrTy->getPointeeType()) && !FromPtrTy->getPointeeType()->isIncompleteType() && !ToPtrTy->getPointeeType()->isIncompleteType() && - S.IsDerivedFrom(ToPtrTy->getPointeeType(), + S.IsDerivedFrom(ToPtrTy->getPointeeType(), FromPtrTy->getPointeeType())) BaseToDerivedConversion = 1; } @@ -5645,22 +6538,24 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { S.IsDerivedFrom(ToRefTy->getPointeeType(), FromTy)) BaseToDerivedConversion = 3; } - + if (BaseToDerivedConversion) { - S.Diag(Fn->getLocation(), + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_base_to_derived_conv) << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << (BaseToDerivedConversion - 1) - << FromTy << ToTy << I+1; + << FromTy << ToTy << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); return; } - + // TODO: specialize more based on the kind of mismatch S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv) << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); } void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, @@ -5671,15 +6566,15 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>(); unsigned MinParams = Fn->getMinRequiredArguments(); - + // at least / at most / exactly - // FIXME: variadic templates "at most" should account for parameter packs unsigned mode, modeCount; if (NumFormalArgs < MinParams) { assert((Cand->FailureKind == ovl_fail_too_few_arguments) || (Cand->FailureKind == ovl_fail_bad_deduction && Cand->DeductionFailure.Result == Sema::TDK_TooFewArguments)); - if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic()) + if (MinParams != FnTy->getNumArgs() || + FnTy->isVariadic() || FnTy->isTemplateVariadic()) mode = 0; // "at least" else mode = 2; // "exactly" @@ -5699,8 +6594,9 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) - << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode + << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode << modeCount << NumFormalArgs; + MaybeEmitInheritedConstructorNote(S, Fn); } /// Diagnose a failed template-argument deduction. @@ -5721,6 +6617,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, assert(ParamD && "no parameter found for incomplete deduction result"); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction) << ParamD->getDeclName(); + MaybeEmitInheritedConstructorNote(S, Fn); return; } @@ -5732,9 +6629,9 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, // Param will have been canonicalized, but it should just be a // qualified version of ParamD, so move the qualifiers to that. - QualifierCollector Qs(S.Context); + QualifierCollector Qs; Qs.strip(Param); - QualType NonCanonParam = Qs.apply(TParam->getTypeForDecl()); + QualType NonCanonParam = Qs.apply(S.Context, TParam->getTypeForDecl()); assert(S.Context.hasSameType(Param, NonCanonParam)); // Arg has also been canonicalized, but there's nothing we can do @@ -5745,11 +6642,12 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, S.Diag(Fn->getLocation(), diag::note_ovl_candidate_underqualified) << ParamD->getDeclName() << Arg << NonCanonParam; + MaybeEmitInheritedConstructorNote(S, Fn); return; } case Sema::TDK_Inconsistent: { - assert(ParamD && "no parameter found for inconsistent deduction result"); + assert(ParamD && "no parameter found for inconsistent deduction result"); int which = 0; if (isa<TemplateTypeParmDecl>(ParamD)) which = 0; @@ -5758,18 +6656,19 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, else { which = 2; } - + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_inconsistent_deduction) - << which << ParamD->getDeclName() + << which << ParamD->getDeclName() << *Cand->DeductionFailure.getFirstArg() << *Cand->DeductionFailure.getSecondArg(); + MaybeEmitInheritedConstructorNote(S, Fn); return; } case Sema::TDK_InvalidExplicitArguments: - assert(ParamD && "no parameter found for invalid explicit arguments"); + assert(ParamD && "no parameter found for invalid explicit arguments"); if (ParamD->getDeclName()) - S.Diag(Fn->getLocation(), + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_explicit_arg_mismatch_named) << ParamD->getDeclName(); else { @@ -5781,12 +6680,13 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, index = NTTP->getIndex(); else index = cast<TemplateTemplateParmDecl>(ParamD)->getIndex(); - S.Diag(Fn->getLocation(), + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_explicit_arg_mismatch_unnamed) << (index + 1); } + MaybeEmitInheritedConstructorNote(S, Fn); return; - + case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: DiagnoseArityMismatch(S, Cand, NumArgs); @@ -5794,6 +6694,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, case Sema::TDK_InstantiationDepth: S.Diag(Fn->getLocation(), diag::note_ovl_candidate_instantiation_depth); + MaybeEmitInheritedConstructorNote(S, Fn); return; case Sema::TDK_SubstitutionFailure: { @@ -5805,14 +6706,16 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, *Args); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure) << ArgString; + MaybeEmitInheritedConstructorNote(S, Fn); return; } - + // TODO: diagnose these individually, then kill off // note_ovl_candidate_bad_deduction, which is uselessly vague. case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction); + MaybeEmitInheritedConstructorNote(S, Fn); return; } } @@ -5841,6 +6744,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted) << FnKind << FnDesc << Fn->isDeleted(); + MaybeEmitInheritedConstructorNote(S, Fn); return; } @@ -5868,7 +6772,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, for (unsigned N = Cand->Conversions.size(); I != N; ++I) if (Cand->Conversions[I].isBad()) return DiagnoseBadConversion(S, Cand, I); - + // FIXME: this currently happens when we're called from SemaInit // when user-conversion overload fails. Figure out how to handle // those conditions and diagnose them well. @@ -5907,6 +6811,7 @@ void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand) << FnType; + MaybeEmitInheritedConstructorNote(S, Cand->Surrogate); } void NoteBuiltinOperatorCandidate(Sema &S, @@ -6083,7 +6988,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, Cand->Conversions[ConvIdx] = TryCopyInitialization(S, Args[ConvIdx], Cand->BuiltinTypes.ParamTypes[ConvIdx], - SuppressUserConversions, + SuppressUserConversions, /*InOverloadResolution*/ true); return; } @@ -6094,7 +6999,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, if (ArgIdx < NumArgsInProto) Cand->Conversions[ConvIdx] = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx), - SuppressUserConversions, + SuppressUserConversions, /*InOverloadResolution=*/true); else Cand->Conversions[ConvIdx].setEllipsis(); @@ -6129,7 +7034,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, std::sort(Cands.begin(), Cands.end(), CompareOverloadCandidatesForDisplay(S)); - + bool ReportedAmbiguousConversions = false; llvm::SmallVectorImpl<OverloadCandidate*>::iterator I, E; @@ -6180,186 +7085,207 @@ static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) { return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D); } -/// ResolveAddressOfOverloadedFunction - Try to resolve the address of -/// an overloaded function (C++ [over.over]), where @p From is an -/// expression with overloaded function type and @p ToType is the type -/// we're trying to resolve to. For example: -/// -/// @code -/// int f(double); -/// int f(int); -/// -/// int (*pfd)(double) = f; // selects f(double) -/// @endcode -/// -/// This routine returns the resulting FunctionDecl if it could be -/// resolved, and NULL otherwise. When @p Complain is true, this -/// routine will emit diagnostics if there is an error. -FunctionDecl * -Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, - bool Complain, - DeclAccessPair &FoundResult) { - QualType FunctionType = ToType; - bool IsMember = false; - if (const PointerType *ToTypePtr = ToType->getAs<PointerType>()) - FunctionType = ToTypePtr->getPointeeType(); - else if (const ReferenceType *ToTypeRef = ToType->getAs<ReferenceType>()) - FunctionType = ToTypeRef->getPointeeType(); - else if (const MemberPointerType *MemTypePtr = - ToType->getAs<MemberPointerType>()) { - FunctionType = MemTypePtr->getPointeeType(); - IsMember = true; - } - // C++ [over.over]p1: - // [...] [Note: any redundant set of parentheses surrounding the - // overloaded function name is ignored (5.1). ] - // C++ [over.over]p1: - // [...] The overloaded function name can be preceded by the & - // operator. - // However, remember whether the expression has member-pointer form: - // C++ [expr.unary.op]p4: - // A pointer to member is only formed when an explicit & is used - // and its operand is a qualified-id not enclosed in - // parentheses. - OverloadExpr::FindResult Ovl = OverloadExpr::find(From); - OverloadExpr *OvlExpr = Ovl.Expression; - - // We expect a pointer or reference to function, or a function pointer. - FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); - if (!FunctionType->isFunctionType()) { - if (Complain) - Diag(From->getLocStart(), diag::err_addr_ovl_not_func_ptrref) - << OvlExpr->getName() << ToType; - - return 0; - } - // If the overload expression doesn't have the form of a pointer to - // member, don't try to convert it to a pointer-to-member type. - if (IsMember && !Ovl.HasFormOfMemberPointer) { - if (!Complain) return 0; - // TODO: Should we condition this on whether any functions might - // have matched, or is it more appropriate to do that in callers? - // TODO: a fixit wouldn't hurt. - Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier) - << ToType << OvlExpr->getSourceRange(); - return 0; - } +// [PossiblyAFunctionType] --> [Return] +// NonFunctionType --> NonFunctionType +// R (A) --> R(A) +// R (*)(A) --> R (A) +// R (&)(A) --> R (A) +// R (S::*)(A) --> R (A) +QualType Sema::ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType) { + QualType Ret = PossiblyAFunctionType; + if (const PointerType *ToTypePtr = + PossiblyAFunctionType->getAs<PointerType>()) + Ret = ToTypePtr->getPointeeType(); + else if (const ReferenceType *ToTypeRef = + PossiblyAFunctionType->getAs<ReferenceType>()) + Ret = ToTypeRef->getPointeeType(); + else if (const MemberPointerType *MemTypePtr = + PossiblyAFunctionType->getAs<MemberPointerType>()) + Ret = MemTypePtr->getPointeeType(); + Ret = + Context.getCanonicalType(Ret).getUnqualifiedType(); + return Ret; +} - TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0; - if (OvlExpr->hasExplicitTemplateArgs()) { - OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer); - ExplicitTemplateArgs = &ETABuffer; - } +// A helper class to help with address of function resolution +// - allows us to avoid passing around all those ugly parameters +class AddressOfFunctionResolver +{ + Sema& S; + Expr* SourceExpr; + const QualType& TargetType; + QualType TargetFunctionType; // Extracted function type from target type + + bool Complain; + //DeclAccessPair& ResultFunctionAccessPair; + ASTContext& Context; - assert(From->getType() == Context.OverloadTy); + bool TargetTypeIsNonStaticMemberFunction; + bool FoundNonTemplateFunction; - // Look through all of the overloaded functions, searching for one - // whose type matches exactly. + OverloadExpr::FindResult OvlExprInfo; + OverloadExpr *OvlExpr; + TemplateArgumentListInfo OvlExplicitTemplateArgs; llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches; - llvm::SmallVector<FunctionDecl *, 4> NonMatches; - - bool FoundNonTemplateFunction = false; - for (UnresolvedSetIterator I = OvlExpr->decls_begin(), - E = OvlExpr->decls_end(); I != E; ++I) { - // Look through any using declarations to find the underlying function. - NamedDecl *Fn = (*I)->getUnderlyingDecl(); - - // 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>(Fn)) { - 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, OvlExpr->getNameLoc()); - if (TemplateDeductionResult Result - = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, - 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.push_back(std::make_pair(I.getPair(), - cast<FunctionDecl>(Specialization->getCanonicalDecl()))); +public: + AddressOfFunctionResolver(Sema &S, Expr* SourceExpr, + const QualType& TargetType, bool Complain) + : S(S), SourceExpr(SourceExpr), TargetType(TargetType), + Complain(Complain), Context(S.getASTContext()), + TargetTypeIsNonStaticMemberFunction( + !!TargetType->getAs<MemberPointerType>()), + FoundNonTemplateFunction(false), + OvlExprInfo(OverloadExpr::find(SourceExpr)), + OvlExpr(OvlExprInfo.Expression) + { + ExtractUnqualifiedFunctionTypeFromTargetType(); + + if (!TargetFunctionType->isFunctionType()) { + if (OvlExpr->hasExplicitTemplateArgs()) { + DeclAccessPair dap; + if( FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization( + OvlExpr, false, &dap) ) { + Matches.push_back(std::make_pair(dap,Fn)); + } + } + return; + } + + if (OvlExpr->hasExplicitTemplateArgs()) + OvlExpr->getExplicitTemplateArgs().copyInto(OvlExplicitTemplateArgs); + + if (FindAllFunctionsThatMatchTargetTypeExactly()) { + // C++ [over.over]p4: + // If more than one function is selected, [...] + if (Matches.size() > 1) { + if (FoundNonTemplateFunction) + EliminateAllTemplateMatches(); + else + EliminateAllExceptMostSpecializedTemplate(); } - - continue; } + } + +private: + bool isTargetTypeAFunction() const { + return TargetFunctionType->isFunctionType(); + } + + // [ToType] [Return] + // R (*)(A) --> R (A), IsNonStaticMemberFunction = false + // R (&)(A) --> R (A), IsNonStaticMemberFunction = false + // R (S::*)(A) --> R (A), IsNonStaticMemberFunction = true + void inline ExtractUnqualifiedFunctionTypeFromTargetType() { + TargetFunctionType = S.ExtractUnqualifiedFunctionType(TargetType); + } + + // return true if any matching specializations were found + bool AddMatchingTemplateFunction(FunctionTemplateDecl* FunctionTemplate, + const DeclAccessPair& CurAccessFunPair) { + 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() == TargetTypeIsNonStaticMemberFunction) + return false; + } + else if (TargetTypeIsNonStaticMemberFunction) + return false; + + // 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. + FunctionDecl *Specialization = 0; + TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc()); + if (Sema::TemplateDeductionResult Result + = S.DeduceTemplateArguments(FunctionTemplate, + &OvlExplicitTemplateArgs, + TargetFunctionType, Specialization, + Info)) { + // FIXME: make a note of the failed deduction for diagnostics. + (void)Result; + return false; + } + + // Template argument deduction ensures that we have an exact match. + // This function template specicalization works. + Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl()); + assert(TargetFunctionType + == Context.getCanonicalType(Specialization->getType())); + Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); + return true; + } + + bool AddMatchingNonTemplateFunction(NamedDecl* Fn, + const DeclAccessPair& CurAccessFunPair) { if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) { // Skip non-static functions when converting to pointer, and static // when converting to member pointer. - if (Method->isStatic() == IsMember) - continue; - - // If we have explicit template arguments, skip non-templates. - if (OvlExpr->hasExplicitTemplateArgs()) - continue; - } else if (IsMember) - continue; + if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction) + return false; + } + else if (TargetTypeIsNonStaticMemberFunction) + return false; if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) { QualType ResultTy; - if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || - IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, + if (Context.hasSameUnqualifiedType(TargetFunctionType, + FunDecl->getType()) || + IsNoReturnConversion(Context, FunDecl->getType(), TargetFunctionType, ResultTy)) { - Matches.push_back(std::make_pair(I.getPair(), - cast<FunctionDecl>(FunDecl->getCanonicalDecl()))); + Matches.push_back(std::make_pair(CurAccessFunPair, + cast<FunctionDecl>(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; + return true; } } + + return false; } + + bool FindAllFunctionsThatMatchTargetTypeExactly() { + bool Ret = false; + + // If the overload expression doesn't have the form of a pointer to + // member, don't try to convert it to a pointer-to-member type. + if (IsInvalidFormOfPointerToMemberFunction()) + return false; - // If there were 0 or 1 matches, we're done. - if (Matches.empty()) { - if (Complain) { - Diag(From->getLocStart(), diag::err_addr_ovl_no_viable) - << OvlExpr->getName() << FunctionType; - for (UnresolvedSetIterator I = OvlExpr->decls_begin(), - E = OvlExpr->decls_end(); - I != E; ++I) - if (FunctionDecl *F = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl())) - NoteOverloadCandidate(F); + for (UnresolvedSetIterator I = OvlExpr->decls_begin(), + E = OvlExpr->decls_end(); + I != E; ++I) { + // Look through any using declarations to find the underlying function. + NamedDecl *Fn = (*I)->getUnderlyingDecl(); + + // 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>(Fn)) { + if (AddMatchingTemplateFunction(FunctionTemplate, I.getPair())) + Ret = true; + } + // If we have explicit template arguments supplied, skip non-templates. + else if (!OvlExpr->hasExplicitTemplateArgs() && + AddMatchingNonTemplateFunction(Fn, I.getPair())) + Ret = true; } - - return 0; - } else if (Matches.size() == 1) { - FunctionDecl *Result = Matches[0].second; - FoundResult = Matches[0].first; - MarkDeclarationReferenced(From->getLocStart(), Result); - if (Complain) - CheckAddressOfMemberAccess(OvlExpr, Matches[0].first); - return Result; + assert(Ret || Matches.empty()); + return Ret; } - // C++ [over.over]p4: - // If more than one function is selected, [...] - if (!FoundNonTemplateFunction) { + void EliminateAllExceptMostSpecializedTemplate() { // [...] and any given function template specialization F1 is // eliminated if the set contains a second function template // specialization whose function template is more specialized @@ -6374,84 +7300,159 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, UnresolvedSet<4> MatchesCopy; // TODO: avoid! for (unsigned I = 0, E = Matches.size(); I != E; ++I) MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess()); - + UnresolvedSetIterator Result = - getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(), - TPOC_Other, From->getLocStart(), - PDiag(), - PDiag(diag::err_addr_ovl_ambiguous) - << Matches[0].second->getDeclName(), - PDiag(diag::note_ovl_candidate) - << (unsigned) oc_function_template); - assert(Result != MatchesCopy.end() && "no most-specialized template"); - MarkDeclarationReferenced(From->getLocStart(), *Result); - FoundResult = Matches[Result - MatchesCopy.begin()].first; - if (Complain) { - CheckUnresolvedAccess(*this, OvlExpr, FoundResult); - DiagnoseUseOfDecl(FoundResult, OvlExpr->getNameLoc()); - } - return cast<FunctionDecl>(*Result); - } - - // [...] any function template specializations in the set are - // eliminated if the set also contains a non-template function, [...] - for (unsigned I = 0, N = Matches.size(); I != N; ) { - if (Matches[I].second->getPrimaryTemplate() == 0) - ++I; - else { - Matches[I] = Matches[--N]; - Matches.set_size(N); + S.getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(), + TPOC_Other, 0, SourceExpr->getLocStart(), + S.PDiag(), + S.PDiag(diag::err_addr_ovl_ambiguous) + << Matches[0].second->getDeclName(), + S.PDiag(diag::note_ovl_candidate) + << (unsigned) oc_function_template, + Complain); + + if (Result != MatchesCopy.end()) { + // Make it the first and only element + Matches[0].first = Matches[Result - MatchesCopy.begin()].first; + Matches[0].second = cast<FunctionDecl>(*Result); + Matches.resize(1); + } + } + + void EliminateAllTemplateMatches() { + // [...] any function template specializations in the set are + // eliminated if the set also contains a non-template function, [...] + for (unsigned I = 0, N = Matches.size(); I != N; ) { + if (Matches[I].second->getPrimaryTemplate() == 0) + ++I; + else { + Matches[I] = Matches[--N]; + Matches.set_size(N); + } } } + +public: + void ComplainNoMatchesFound() const { + assert(Matches.empty()); + S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_no_viable) + << OvlExpr->getName() << TargetFunctionType + << OvlExpr->getSourceRange(); + S.NoteAllOverloadCandidates(OvlExpr); + } - // [...] After such eliminations, if any, there shall remain exactly one - // selected function. - if (Matches.size() == 1) { - MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); - FoundResult = Matches[0].first; - if (Complain) { - CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); - DiagnoseUseOfDecl(Matches[0].first, OvlExpr->getNameLoc()); - } - return cast<FunctionDecl>(Matches[0].second); - } - - // 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) - << Matches[0].second->getDeclName(); - for (unsigned I = 0, E = Matches.size(); I != E; ++I) - NoteOverloadCandidate(Matches[I].second); - return 0; + bool IsInvalidFormOfPointerToMemberFunction() const { + return TargetTypeIsNonStaticMemberFunction && + !OvlExprInfo.HasFormOfMemberPointer; + } + + void ComplainIsInvalidFormOfPointerToMemberFunction() const { + // TODO: Should we condition this on whether any functions might + // have matched, or is it more appropriate to do that in callers? + // TODO: a fixit wouldn't hurt. + S.Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier) + << TargetType << OvlExpr->getSourceRange(); + } + + void ComplainOfInvalidConversion() const { + S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_not_func_ptrref) + << OvlExpr->getName() << TargetType; + } + + void ComplainMultipleMatchesFound() const { + assert(Matches.size() > 1); + S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_ambiguous) + << OvlExpr->getName() + << OvlExpr->getSourceRange(); + S.NoteAllOverloadCandidates(OvlExpr); + } + + int getNumMatches() const { return Matches.size(); } + + FunctionDecl* getMatchingFunctionDecl() const { + if (Matches.size() != 1) return 0; + return Matches[0].second; + } + + const DeclAccessPair* getMatchingFunctionAccessPair() const { + if (Matches.size() != 1) return 0; + return &Matches[0].first; + } +}; + +/// ResolveAddressOfOverloadedFunction - Try to resolve the address of +/// an overloaded function (C++ [over.over]), where @p From is an +/// expression with overloaded function type and @p ToType is the type +/// we're trying to resolve to. For example: +/// +/// @code +/// int f(double); +/// int f(int); +/// +/// int (*pfd)(double) = f; // selects f(double) +/// @endcode +/// +/// This routine returns the resulting FunctionDecl if it could be +/// resolved, and NULL otherwise. When @p Complain is true, this +/// routine will emit diagnostics if there is an error. +FunctionDecl * +Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType, + bool Complain, + DeclAccessPair &FoundResult) { + + assert(AddressOfExpr->getType() == Context.OverloadTy); + + AddressOfFunctionResolver Resolver(*this, AddressOfExpr, TargetType, Complain); + int NumMatches = Resolver.getNumMatches(); + FunctionDecl* Fn = 0; + if ( NumMatches == 0 && Complain) { + if (Resolver.IsInvalidFormOfPointerToMemberFunction()) + Resolver.ComplainIsInvalidFormOfPointerToMemberFunction(); + else + Resolver.ComplainNoMatchesFound(); + } + else if (NumMatches > 1 && Complain) + Resolver.ComplainMultipleMatchesFound(); + else if (NumMatches == 1) { + Fn = Resolver.getMatchingFunctionDecl(); + assert(Fn); + FoundResult = *Resolver.getMatchingFunctionAccessPair(); + MarkDeclarationReferenced(AddressOfExpr->getLocStart(), Fn); + if (Complain) + CheckAddressOfMemberAccess(AddressOfExpr, FoundResult); + } + + return Fn; } -/// \brief Given an expression that refers to an overloaded function, try to +/// \brief Given an expression that refers to an overloaded function, try to /// resolve that overloaded function expression down to a single function. /// /// This routine can only resolve template-ids that refer to a single function /// template, where that template-id refers to a single template whose template -/// arguments are either provided by the template-id or have defaults, +/// arguments are either provided by the template-id or have defaults, /// as described in C++0x [temp.arg.explicit]p3. -FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { +FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From, + bool Complain, + DeclAccessPair* FoundResult) { // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] // C++ [over.over]p1: // [...] The overloaded function name can be preceded by the & // operator. - if (From->getType() != Context.OverloadTy) return 0; OverloadExpr *OvlExpr = OverloadExpr::find(From).Expression; - + // If we didn't actually find any template-ids, we're done. if (!OvlExpr->hasExplicitTemplateArgs()) return 0; TemplateArgumentListInfo ExplicitTemplateArgs; OvlExpr->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs); - + // Look through all of the overloaded functions, searching for one // whose type matches exactly. FunctionDecl *Matched = 0; @@ -6459,13 +7460,13 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { E = OvlExpr->decls_end(); I != E; ++I) { // C++0x [temp.arg.explicit]p3: // [...] In contexts where deduction is done and fails, or in contexts - // where deduction is not done, if a template argument list is - // specified and it, along with any default template arguments, - // identifies a single function template specialization, then the + // where deduction is not done, if a template argument list is + // specified and it, along with any default template arguments, + // identifies a single function template specialization, then the // template-id is an lvalue for the function template specialization. FunctionTemplateDecl *FunctionTemplate = cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()); - + // 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 @@ -6480,18 +7481,28 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { // FIXME: make a note of the failed deduction for diagnostics. (void)Result; continue; - } - + } + // Multiple matches; we can't resolve to a single declaration. - if (Matched) + if (Matched) { + if (FoundResult) + *FoundResult = DeclAccessPair(); + + if (Complain) { + Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous) + << OvlExpr->getName(); + NoteAllOverloadCandidates(OvlExpr); + } return 0; - - Matched = Specialization; + } + + if ((Matched = Specialization) && FoundResult) + *FoundResult = I.getPair(); } return Matched; } - + /// \brief Add a single candidate to the overload set. static void AddOverloadedCallCandidate(Sema &S, DeclAccessPair FoundDecl, @@ -6522,7 +7533,7 @@ static void AddOverloadedCallCandidate(Sema &S, // do nothing? } - + /// \brief Add the overload candidates named by callee and/or found by argument /// dependent lookup to the given overload set. void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, @@ -6570,7 +7581,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(), E = ULE->decls_end(); I != E; ++I) AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs, - Args, NumArgs, CandidateSet, + Args, NumArgs, CandidateSet, PartialOverloading); if (ULE->requiresADL()) @@ -6578,7 +7589,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, Args, NumArgs, ExplicitTemplateArgs, CandidateSet, - PartialOverloading); + PartialOverloading); } /// Attempts to recover from a call where no functions were found. @@ -6589,7 +7600,6 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, SourceLocation RParenLoc) { CXXScopeSpec SS; @@ -6616,7 +7626,8 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, // casts and such from the call, we don't really care. ExprResult NewFn = ExprError(); if ((*R.begin())->isCXXClassMember()) - NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, R, ExplicitTemplateArgs); + NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, R, + ExplicitTemplateArgs); else if (ExplicitTemplateArgs) NewFn = SemaRef.BuildTemplateIdExpr(SS, R, false, *ExplicitTemplateArgs); else @@ -6629,8 +7640,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, // an expression with non-empty lookup results, which should never // end up here. return SemaRef.ActOnCallExpr(/*Scope*/ 0, NewFn.take(), LParenLoc, - MultiExprArg(Args, NumArgs), - CommaLocs, RParenLoc); + MultiExprArg(Args, NumArgs), RParenLoc); } /// ResolveOverloadedCallFn - Given the call expression that calls Fn @@ -6644,8 +7654,8 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + Expr *ExecConfig) { #ifndef NDEBUG if (ULE->requiresADL()) { // To do ADL, we must have found an unqualified name. @@ -6658,7 +7668,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, (F = dyn_cast<FunctionDecl>(*ULE->decls_begin())) && F->getBuiltinID() && F->isImplicit()) assert(0 && "performing ADL for builtin"); - + // We don't perform ADL in C. assert(getLangOptions().CPlusPlus && "ADL enabled in C"); } @@ -6675,16 +7685,18 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, // bailout out if it fails. if (CandidateSet.empty()) return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc); + RParenLoc); OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) { case OR_Success: { FunctionDecl *FDecl = Best->Function; CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); - DiagnoseUseOfDecl(Best->FoundDecl, ULE->getNameLoc()); + DiagnoseUseOfDecl(FDecl? FDecl : Best->FoundDecl.getDecl(), + ULE->getNameLoc()); Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); - return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); + return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc, + ExecConfig); } case OR_No_Viable_Function: @@ -6746,6 +7758,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // TODO: provide better source location info. DeclarationNameInfo OpNameInfo(OpName, OpLoc); + if (Input->getObjectKind() == OK_ObjCProperty) + ConvertPropertyForRValue(Input); + Expr *Args[2] = { Input, 0 }; unsigned NumArgs = 1; @@ -6762,19 +7777,21 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, if (Input->isTypeDependent()) { if (Fns.empty()) return Owned(new (Context) UnaryOperator(Input, - Opc, + Opc, Context.DependentTy, + VK_RValue, OK_Ordinary, OpLoc)); - + CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, + = UnresolvedLookupExpr::Create(Context, NamingClass, 0, SourceRange(), OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, &Args[0], NumArgs, Context.DependentTy, + VK_RValue, OpLoc)); } @@ -6818,8 +7835,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // Convert the arguments. ExprResult InputInit = PerformCopyInitialization(InitializedEntity::InitializeParameter( + Context, FnDecl->getParamDecl(0)), - SourceLocation(), + SourceLocation(), Input); if (InputInit.isInvalid()) return ExprError(); @@ -6828,20 +7846,20 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, DiagnoseUseOfDecl(Best->FoundDecl, OpLoc); - // Determine the result type - QualType ResultTy = FnDecl->getCallResultType(); + // Determine the result type. + QualType ResultTy = FnDecl->getResultType(); + ExprValueKind VK = Expr::getValueKindForType(ResultTy); + ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), - SourceLocation()); - UsualUnaryConversions(FnExpr); + Expr *FnExpr = CreateFunctionRefExpr(*this, FnDecl); Args[0] = Input; CallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, - Args, NumArgs, ResultTy, OpLoc); + Args, NumArgs, ResultTy, VK, OpLoc); - if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, FnDecl)) return ExprError(); @@ -6864,8 +7882,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, break; case OR_Ambiguous: - Diag(OpLoc, diag::err_ovl_ambiguous_oper) + Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary) << UnaryOperator::getOpcodeStr(Opc) + << Input->getType() << Input->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs, @@ -6920,14 +7939,18 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // expression. if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { if (Fns.empty()) { - // If there are no functions to store, just build a dependent + // If there are no functions to store, just build a dependent // BinaryOperator or CompoundAssignment. if (Opc <= BO_Assign || Opc > BO_OrAssign) return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc, - Context.DependentTy, OpLoc)); - + Context.DependentTy, + VK_RValue, OK_Ordinary, + OpLoc)); + return Owned(new (Context) CompoundAssignOperator(Args[0], Args[1], Opc, Context.DependentTy, + VK_LValue, + OK_Ordinary, Context.DependentTy, Context.DependentTy, OpLoc)); @@ -6938,20 +7961,48 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // TODO: provide better source location info in DNLoc component. DeclarationNameInfo OpNameInfo(OpName, OpLoc); UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, - 0, SourceRange(), OpNameInfo, - /*ADL*/ true, IsOverloaded(Fns), + = UnresolvedLookupExpr::Create(Context, NamingClass, 0, SourceRange(), + OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args, 2, Context.DependentTy, + VK_RValue, OpLoc)); } - // If this is the .* operator, which is not overloadable, just - // create a built-in binary operator. - if (Opc == BO_PtrMemD) - return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); + // Always do property rvalue conversions on the RHS. + if (Args[1]->getObjectKind() == OK_ObjCProperty) + ConvertPropertyForRValue(Args[1]); + + // The LHS is more complicated. + if (Args[0]->getObjectKind() == OK_ObjCProperty) { + + // There's a tension for assignment operators between primitive + // property assignment and the overloaded operators. + if (BinaryOperator::isAssignmentOp(Opc)) { + const ObjCPropertyRefExpr *PRE = LHS->getObjCProperty(); + + // Is the property "logically" settable? + bool Settable = (PRE->isExplicitProperty() || + PRE->getImplicitPropertySetter()); + + // To avoid gratuitously inventing semantics, use the primitive + // unless it isn't. Thoughts in case we ever really care: + // - If the property isn't logically settable, we have to + // load and hope. + // - If the property is settable and this is simple assignment, + // we really should use the primitive. + // - If the property is settable, then we could try overloading + // on a generic lvalue of the appropriate type; if it works + // out to a builtin candidate, we would do that same operation + // on the property, and otherwise just error. + if (Settable) + return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); + } + + ConvertPropertyForRValue(Args[0]); + } // If this is the assignment operator, we only perform overload resolution // if the left-hand side is a class or enumeration type. This is actually @@ -6962,6 +8013,11 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Opc == BO_Assign && !Args[0]->getType()->isOverloadableType()) return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); + // If this is the .* operator, which is not overloadable, just + // create a built-in binary operator. + if (Opc == BO_PtrMemD) + return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); + // Build an empty overload set. OverloadCandidateSet CandidateSet(OpLoc); @@ -6996,37 +8052,33 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Best->Access is only meaningful for class members. CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Best->FoundDecl); - ExprResult Arg1 - = PerformCopyInitialization( - InitializedEntity::InitializeParameter( - FnDecl->getParamDecl(0)), - SourceLocation(), - Owned(Args[1])); + ExprResult Arg1 = + PerformCopyInitialization( + InitializedEntity::InitializeParameter(Context, + FnDecl->getParamDecl(0)), + SourceLocation(), Owned(Args[1])); if (Arg1.isInvalid()) return ExprError(); - if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, + if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, Best->FoundDecl, Method)) return ExprError(); Args[1] = RHS = Arg1.takeAs<Expr>(); } else { // Convert the arguments. - ExprResult Arg0 - = PerformCopyInitialization( - InitializedEntity::InitializeParameter( - FnDecl->getParamDecl(0)), - SourceLocation(), - Owned(Args[0])); + ExprResult Arg0 = PerformCopyInitialization( + InitializedEntity::InitializeParameter(Context, + FnDecl->getParamDecl(0)), + SourceLocation(), Owned(Args[0])); if (Arg0.isInvalid()) return ExprError(); - ExprResult Arg1 - = PerformCopyInitialization( - InitializedEntity::InitializeParameter( - FnDecl->getParamDecl(1)), - SourceLocation(), - Owned(Args[1])); + ExprResult Arg1 = + PerformCopyInitialization( + InitializedEntity::InitializeParameter(Context, + FnDecl->getParamDecl(1)), + SourceLocation(), Owned(Args[1])); if (Arg1.isInvalid()) return ExprError(); Args[0] = LHS = Arg0.takeAs<Expr>(); @@ -7035,21 +8087,19 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, DiagnoseUseOfDecl(Best->FoundDecl, OpLoc); - // Determine the result type - QualType ResultTy - = FnDecl->getType()->getAs<FunctionType>() - ->getCallResultType(Context); + // Determine the result type. + QualType ResultTy = FnDecl->getResultType(); + ExprValueKind VK = Expr::getValueKindForType(ResultTy); + ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), - OpLoc); - UsualUnaryConversions(FnExpr); + Expr *FnExpr = CreateFunctionRefExpr(*this, FnDecl, OpLoc); CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, - Args, 2, ResultTy, OpLoc); - - if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, + Args, 2, ResultTy, VK, OpLoc); + + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, FnDecl)) return ExprError(); @@ -7076,11 +8126,11 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Opc == BO_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 + // 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 ExprResult Result = ExprError(); - if (Args[0]->getType()->isRecordType() && + if (Args[0]->getType()->isRecordType() && Opc >= BO_Assign && Opc <= BO_OrAssign) { Diag(OpLoc, diag::err_ovl_no_viable_oper) << BinaryOperator::getOpcodeStr(Opc) @@ -7090,7 +8140,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // produce an error. Then, show the non-viable candidates. Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } - assert(Result.isInvalid() && + assert(Result.isInvalid() && "C++ binary operator overloading is missing candidates!"); if (Result.isInvalid()) CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2, @@ -7099,8 +8149,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, } case OR_Ambiguous: - Diag(OpLoc, diag::err_ovl_ambiguous_oper) + Diag(OpLoc, diag::err_ovl_ambiguous_oper_binary) << BinaryOperator::getOpcodeStr(Opc) + << Args[0]->getType() << Args[1]->getType() << Args[0]->getSourceRange() << Args[1]->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, 2, BinaryOperator::getOpcodeStr(Opc), OpLoc); @@ -7136,7 +8187,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, DeclarationNameInfo OpNameInfo(OpName, LLoc); OpNameInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc)); UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, + = UnresolvedLookupExpr::Create(Context, NamingClass, 0, SourceRange(), OpNameInfo, /*ADL*/ true, /*Overloaded*/ false, UnresolvedSetIterator(), @@ -7146,9 +8197,15 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript, Fn, Args, 2, Context.DependentTy, + VK_RValue, RLoc)); } + if (Args[0]->getObjectKind() == OK_ObjCProperty) + ConvertPropertyForRValue(Args[0]); + if (Args[1]->getObjectKind() == OK_ObjCProperty) + ConvertPropertyForRValue(Args[1]); + // Build an empty overload set. OverloadCandidateSet CandidateSet(LLoc); @@ -7176,15 +8233,16 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); - if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, + if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, Best->FoundDecl, Method)) return ExprError(); // Convert the arguments. ExprResult InputInit = PerformCopyInitialization(InitializedEntity::InitializeParameter( + Context, FnDecl->getParamDecl(0)), - SourceLocation(), + SourceLocation(), Owned(Args[1])); if (InputInit.isInvalid()) return ExprError(); @@ -7192,19 +8250,17 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, Args[1] = InputInit.takeAs<Expr>(); // Determine the result type - QualType ResultTy - = FnDecl->getType()->getAs<FunctionType>() - ->getCallResultType(Context); + QualType ResultTy = FnDecl->getResultType(); + ExprValueKind VK = Expr::getValueKindForType(ResultTy); + ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), - LLoc); - UsualUnaryConversions(FnExpr); + Expr *FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc); CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, OO_Subscript, FnExpr, Args, 2, - ResultTy, RLoc); + ResultTy, VK, RLoc); if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall, FnDecl)) @@ -7240,8 +8296,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, } case OR_Ambiguous: - Diag(LLoc, diag::err_ovl_ambiguous_oper) - << "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + Diag(LLoc, diag::err_ovl_ambiguous_oper_binary) + << "[]" + << Args[0]->getType() << Args[1]->getType() + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, 2, "[]", LLoc); return ExprError(); @@ -7269,12 +8327,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, SourceLocation LParenLoc, Expr **Args, - unsigned NumArgs, SourceLocation *CommaLocs, - SourceLocation RParenLoc) { + unsigned NumArgs, SourceLocation RParenLoc) { // Dig out the member expression. This holds both the object // argument and the member function we're referring to. Expr *NakedMemExpr = MemExprE->IgnoreParens(); - + MemberExpr *MemExpr; CXXMethodDecl *Method = 0; DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public); @@ -7287,8 +8344,11 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, } else { UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr); Qualifier = UnresExpr->getQualifier(); - + QualType ObjectType = UnresExpr->getBaseType(); + Expr::Classification ObjectClassification + = UnresExpr->isArrow()? Expr::Classification::makeSimpleLValue() + : UnresExpr->getBase()->Classify(Context); // Add overload candidates OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc()); @@ -7308,20 +8368,26 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, if (isa<UsingShadowDecl>(Func)) Func = cast<UsingShadowDecl>(Func)->getTargetDecl(); - if ((Method = dyn_cast<CXXMethodDecl>(Func))) { + + // Microsoft supports direct constructor calls. + if (getLangOptions().Microsoft && isa<CXXConstructorDecl>(Func)) { + AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args, NumArgs, + CandidateSet); + } else if ((Method = dyn_cast<CXXMethodDecl>(Func))) { // If explicit template arguments were provided, we can't call a // non-template member function. if (TemplateArgs) continue; - + AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType, - Args, NumArgs, - CandidateSet, /*SuppressUserConversions=*/false); + ObjectClassification, + Args, NumArgs, CandidateSet, + /*SuppressUserConversions=*/false); } else { AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func), I.getPair(), ActingDC, TemplateArgs, - ObjectType, Args, NumArgs, - CandidateSet, + ObjectType, ObjectClassification, + Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); } } @@ -7330,7 +8396,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, UnresExpr->getLocStart(), - Best)) { + Best)) { case OR_Success: Method = cast<CXXMethodDecl>(Best->Function); FoundDecl = Best->FoundDecl; @@ -7374,17 +8440,20 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens()); } + QualType ResultType = Method->getResultType(); + ExprValueKind VK = Expr::getValueKindForType(ResultType); + ResultType = ResultType.getNonLValueExprType(Context); + assert(Method && "Member call to something that isn't a method?"); - CXXMemberCallExpr *TheCall = + CXXMemberCallExpr *TheCall = new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs, - Method->getCallResultType(), - RParenLoc); + ResultType, VK, RParenLoc); // Check for a valid return type. - if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(), + if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(), TheCall, Method)) return ExprError(); - + // Convert the object argument (for a non-static member function call). // We only need to do this if there was actually an overload; otherwise // it was done at lookup. @@ -7396,7 +8465,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, MemExpr->setBase(ObjectArg); // Convert the rest of the arguments - const FunctionProtoType *Proto = Method->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *Proto = + Method->getType()->getAs<FunctionProtoType>(); if (ConvertArgumentsForCall(TheCall, MemExpr, Method, Proto, Args, NumArgs, RParenLoc)) return ExprError(); @@ -7415,8 +8485,10 @@ ExprResult Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, SourceLocation RParenLoc) { + if (Object->getObjectKind() == OK_ObjCProperty) + ConvertPropertyForRValue(Object); + assert(Object->getType()->isRecordType() && "Requires object type argument"); const RecordType *Record = Object->getType()->getAs<RecordType>(); @@ -7430,11 +8502,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, OverloadCandidateSet CandidateSet(LParenLoc); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); - if (RequireCompleteType(LParenLoc, Object->getType(), + if (RequireCompleteType(LParenLoc, Object->getType(), PDiag(diag::err_incomplete_object_call) << Object->getSourceRange())) return true; - + LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName); LookupQualifiedName(R, Record->getDecl()); R.suppressDiagnostics(); @@ -7442,10 +8514,10 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Object->getType(), - Args, NumArgs, CandidateSet, + Object->Classify(Context), Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ false); } - + // C++ [over.call.object]p2: // In addition, for each conversion function declared in T of the // form @@ -7471,7 +8543,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); - + // Skip over templated conversion functions; they aren't // surrogates. if (isa<FunctionTemplateDecl>(D)) @@ -7487,8 +8559,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto, - Object->getType(), Args, NumArgs, - CandidateSet); + Object, Args, NumArgs, CandidateSet); } // Perform overload resolution. @@ -7544,14 +8615,15 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // 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. - + // Create an implicit member expr to refer to the conversion operator. // and then call it. - CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Best->FoundDecl, - Conv); - - return ActOnCallExpr(S, CE, LParenLoc, MultiExprArg(Args, NumArgs), - CommaLocs, RParenLoc); + ExprResult Call = BuildCXXMemberCallExpr(Object, Best->FoundDecl, Conv); + if (Call.isInvalid()) + return ExprError(); + + return ActOnCallExpr(S, Call.get(), LParenLoc, MultiExprArg(Args, NumArgs), + RParenLoc); } CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); @@ -7561,7 +8633,8 @@ 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()->getAs<FunctionProtoType>(); + const FunctionProtoType *Proto = + Method->getType()->getAs<FunctionProtoType>(); unsigned NumArgsInProto = Proto->getNumArgs(); unsigned NumArgsToCheck = NumArgs; @@ -7580,23 +8653,24 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) MethodArgs[ArgIdx + 1] = Args[ArgIdx]; - Expr *NewFn = new (Context) DeclRefExpr(Method, Method->getType(), - SourceLocation()); - UsualUnaryConversions(NewFn); + Expr *NewFn = CreateFunctionRefExpr(*this, Method); // Once we've built TheCall, all of the expressions are properly // owned. - QualType ResultTy = Method->getCallResultType(); + QualType ResultTy = Method->getResultType(); + ExprValueKind VK = Expr::getValueKindForType(ResultTy); + ResultTy = ResultTy.getNonLValueExprType(Context); + CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn, MethodArgs, NumArgs + 1, - ResultTy, RParenLoc); + ResultTy, VK, RParenLoc); delete [] MethodArgs; - if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall, + if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall, Method)) return true; - + // We may have default arguments. If so, we need to allocate more // slots in the call for them. if (NumArgs < NumArgsInProto) @@ -7607,7 +8681,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, bool IsError = false; // Initialize the implicit object parameter. - IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0, + IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0, Best->FoundDecl, Method); TheCall->setArg(0, Object); @@ -7622,9 +8696,10 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, ExprResult InputInit = PerformCopyInitialization(InitializedEntity::InitializeParameter( + Context, Method->getParamDecl(i)), SourceLocation(), Arg); - + IsError |= InputInit.isInvalid(); Arg = InputInit.takeAs<Expr>(); } else { @@ -7634,7 +8709,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, IsError = true; break; } - + Arg = DefArg.takeAs<Expr>(); } @@ -7664,7 +8739,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, /// @c Member is the name of the member we're trying to find. ExprResult Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { - assert(Base->getType()->isRecordType() && "left-hand side must have class type"); + assert(Base->getType()->isRecordType() && + "left-hand side must have class type"); + + if (Base->getObjectKind() == OK_ObjCProperty) + ConvertPropertyForRValue(Base); SourceLocation Loc = Base->getExprLoc(); @@ -7674,7 +8753,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { // 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). - DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow); + DeclarationName OpName = + Context.DeclarationNames.getCXXOperatorName(OO_Arrow); OverloadCandidateSet CandidateSet(Loc); const RecordType *BaseRecord = Base->getType()->getAs<RecordType>(); @@ -7689,8 +8769,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - AddMethodCandidate(Oper.getPair(), Base->getType(), 0, 0, CandidateSet, - /*SuppressUserConversions=*/false); + AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context), + 0, 0, CandidateSet, /*SuppressUserConversions=*/false); } // Perform overload resolution. @@ -7711,8 +8791,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { return ExprError(); case OR_Ambiguous: - Diag(OpLoc, diag::err_ovl_ambiguous_oper) - << "->" << Base->getSourceRange(); + Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary) + << "->" << Base->getType() << Base->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, &Base, 1); return ExprError(); @@ -7734,16 +8814,16 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { return ExprError(); // Build the operator call. - Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(), - SourceLocation()); - UsualUnaryConversions(FnExpr); - - QualType ResultTy = Method->getCallResultType(); + Expr *FnExpr = CreateFunctionRefExpr(*this, Method); + + QualType ResultTy = Method->getResultType(); + ExprValueKind VK = Expr::getValueKindForType(ResultTy); + ResultTy = ResultTy.getNonLValueExprType(Context); CXXOperatorCallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, - &Base, 1, ResultTy, OpLoc); + new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, + &Base, 1, ResultTy, VK, OpLoc); - if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall, + if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall, Method)) return ExprError(); return Owned(TheCall); @@ -7760,27 +8840,27 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Found, Fn); if (SubExpr == PE->getSubExpr()) - return PE->Retain(); - + return PE; + return new (Context) ParenExpr(PE->getLParen(), PE->getRParen(), SubExpr); - } - + } + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Found, Fn); - assert(Context.hasSameType(ICE->getSubExpr()->getType(), + assert(Context.hasSameType(ICE->getSubExpr()->getType(), SubExpr->getType()) && "Implicit cast type cannot be determined from overload"); assert(ICE->path_empty() && "fixing up hierarchy conversion?"); if (SubExpr == ICE->getSubExpr()) - return ICE->Retain(); - - return ImplicitCastExpr::Create(Context, ICE->getType(), + return ICE; + + return ImplicitCastExpr::Create(Context, ICE->getType(), ICE->getCastKind(), SubExpr, 0, ICE->getValueKind()); - } - + } + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) { assert(UnOp->getOpcode() == UO_AddrOf && "Can only take the address of an overloaded function"); @@ -7795,7 +8875,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Found, Fn); if (SubExpr == UnOp->getSubExpr()) - return UnOp->Retain(); + return UnOp; assert(isa<DeclRefExpr>(SubExpr) && "fixed to something other than a decl ref"); @@ -7810,19 +8890,21 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, QualType MemPtrType = Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr()); - return new (Context) UnaryOperator(SubExpr, UO_AddrOf, - MemPtrType, UnOp->getOperatorLoc()); + return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType, + VK_RValue, OK_Ordinary, + UnOp->getOperatorLoc()); } } Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Found, Fn); if (SubExpr == UnOp->getSubExpr()) - return UnOp->Retain(); - + return UnOp; + return new (Context) UnaryOperator(SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()), + VK_RValue, OK_Ordinary, UnOp->getOperatorLoc()); - } + } if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { // FIXME: avoid copy. @@ -7838,6 +8920,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, Fn, ULE->getNameLoc(), Fn->getType(), + VK_LValue, TemplateArgs); } @@ -7851,7 +8934,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, Expr *Base; - // If we're filling in + // If we're filling in a static method where we used to have an + // implicit member access, rewrite to a simple decl ref. if (MemExpr->isImplicitAccess()) { if (cast<CXXMethodDecl>(Fn)->isStatic()) { return DeclRefExpr::Create(Context, @@ -7860,6 +8944,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, Fn, MemExpr->getMemberLoc(), Fn->getType(), + VK_LValue, TemplateArgs); } else { SourceLocation Loc = MemExpr->getMemberLoc(); @@ -7870,24 +8955,27 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, /*isImplicit=*/true); } } else - Base = MemExpr->getBase()->Retain(); + Base = MemExpr->getBase(); return MemberExpr::Create(Context, Base, - MemExpr->isArrow(), - MemExpr->getQualifier(), + MemExpr->isArrow(), + MemExpr->getQualifier(), MemExpr->getQualifierRange(), - Fn, + Fn, Found, MemExpr->getMemberNameInfo(), TemplateArgs, - Fn->getType()); + Fn->getType(), + cast<CXXMethodDecl>(Fn)->isStatic() + ? VK_LValue : VK_RValue, + OK_Ordinary); } - - assert(false && "Invalid reference to overloaded function"); - return E->Retain(); + + llvm_unreachable("Invalid reference to overloaded function"); + return E; } -ExprResult Sema::FixOverloadedFunctionReference(ExprResult E, +ExprResult Sema::FixOverloadedFunctionReference(ExprResult E, DeclAccessPair Found, FunctionDecl *Fn) { return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn)); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 083e4db..e995e8f 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -32,7 +32,9 @@ using namespace sema; StmtResult Sema::ActOnExprStmt(FullExprArg expr) { Expr *E = expr.get(); - assert(E && "ActOnExprStmt(): missing expression"); + if (!E) // FIXME: FullExprArg has no error state? + 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 +44,12 @@ StmtResult Sema::ActOnExprStmt(FullExprArg expr) { } -StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) { - return Owned(new (Context) NullStmt(SemiLoc)); +StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc, bool LeadingEmptyMacro) { + return Owned(new (Context) NullStmt(SemiLoc, LeadingEmptyMacro)); } -StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, - SourceLocation StartLoc, - SourceLocation EndLoc) { +StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc, + SourceLocation EndLoc) { DeclGroupRef DG = dg.getAsVal<DeclGroupRef>(); // If we have an invalid decl, just return an error. @@ -59,7 +60,7 @@ StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { DeclGroupRef DG = dg.getAsVal<DeclGroupRef>(); - + // If we have an invalid decl, just return. if (DG.isNull() || !DG.isSingleDecl()) return; // suppress any potential 'unused variable' warning. @@ -67,10 +68,19 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { } void Sema::DiagnoseUnusedExprResult(const Stmt *S) { + if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) + return DiagnoseUnusedExprResult(Label->getSubStmt()); + const Expr *E = dyn_cast_or_null<Expr>(S); if (!E) return; + if (E->isBoundMemberFunction(Context)) { + Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func) + << E->getSourceRange(); + return; + } + SourceLocation Loc; SourceRange R1, R2; if (!E->isUnusedResultAWarning(Loc, R1, R2, Context)) @@ -80,13 +90,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { // 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 CXXExprWithTemporaries *Temps = dyn_cast<CXXExprWithTemporaries>(E)) + if (const ExprWithCleanups *Temps = dyn_cast<ExprWithCleanups>(E)) E = Temps->getSubExpr(); - + + E = E->IgnoreParenImpCasts(); if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { if (E->getType()->isVoidType()) return; @@ -106,14 +113,15 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const"; return; } - } - } - else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) { + } + } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) { const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD && MD->getAttr<WarnUnusedResultAttr>()) { Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; return; } + } else if (isa<ObjCPropertyRefExpr>(E)) { + DiagID = diag::warn_unused_property_expr; } else if (const CXXFunctionalCastExpr *FC = dyn_cast<CXXFunctionalCastExpr>(E)) { if (isa<CXXConstructExpr>(FC->getSubExpr()) || @@ -223,30 +231,23 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, } StmtResult -Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, +Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt) { - // Look up the record for this label identifier. - LabelStmt *&LabelDecl = getCurFunction()->LabelMap[II]; - - // If not forward referenced or defined already, just create a new LabelStmt. - if (LabelDecl == 0) - return Owned(LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt)); - - assert(LabelDecl->getID() == II && "Label mismatch!"); - - // Otherwise, this label was either forward reference or multiply defined. If - // multiply defined, reject it now. - if (LabelDecl->getSubStmt()) { - Diag(IdentLoc, diag::err_redefinition_of_label) << LabelDecl->getID(); - Diag(LabelDecl->getIdentLoc(), diag::note_previous_definition); + + // If the label was multiply defined, reject it now. + if (TheDecl->getStmt()) { + Diag(IdentLoc, diag::err_redefinition_of_label) << TheDecl->getDeclName(); + Diag(TheDecl->getLocation(), diag::note_previous_definition); return Owned(SubStmt); } - // Otherwise, this label was forward declared, and we just found its real - // definition. Fill in the forward definition and return it. - LabelDecl->setIdentLoc(IdentLoc); - LabelDecl->setSubStmt(SubStmt); - return Owned(LabelDecl); + // Otherwise, things are good. Fill in the declaration and return it. + TheDecl->setLocation(IdentLoc); + + LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt); + TheDecl->setStmt(LS); + TheDecl->setLocation(IdentLoc); + return Owned(LS); } StmtResult @@ -265,21 +266,29 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, Expr *ConditionExpr = CondResult.takeAs<Expr>(); if (!ConditionExpr) return StmtError(); - + 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 (!elseStmt) { if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt)) - Diag(stmt->getSemiLoc(), diag::warn_empty_if_body); + // But do not warn if the body is a macro that expands to nothing, e.g: + // + // #define CALL(x) + // if (condition) + // CALL(0); + // + if (!stmt->hasLeadingEmptyMacro()) + Diag(stmt->getSemiLoc(), diag::warn_empty_if_body); } DiagnoseUnusedExprResult(elseStmt); - return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, + return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, thenStmt, ElseLoc, elseStmt)); } @@ -293,7 +302,7 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, // Perform a conversion to the promoted condition type if needed. if (NewWidth > Val.getBitWidth()) { // If this is an extension, just do it. - Val.extend(NewWidth); + Val = Val.extend(NewWidth); Val.setIsSigned(NewSign); // If the input was signed and negative and the output is @@ -303,21 +312,21 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, } else if (NewWidth < Val.getBitWidth()) { // If this is a truncation, check for overflow. llvm::APSInt ConvVal(Val); - ConvVal.trunc(NewWidth); + ConvVal = ConvVal.trunc(NewWidth); ConvVal.setIsSigned(NewSign); - ConvVal.extend(Val.getBitWidth()); + ConvVal = ConvVal.extend(Val.getBitWidth()); 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); + Val = Val.trunc(NewWidth); Val.setIsSigned(NewSign); } else if (NewSign != Val.isSigned()) { // Convert the sign to match the sign of the condition. This can cause // overflow as well: unsigned(INTMIN) - // We don't diagnose this overflow, because it is implementation-defined + // We don't diagnose this overflow, because it is implementation-defined // behavior. // FIXME: Introduce a second, default-ignored warning for this case? llvm::APSInt OldVal(Val); @@ -386,7 +395,7 @@ static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) { } StmtResult -Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, +Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, Decl *CondVar) { ExprResult CondResult; @@ -396,15 +405,15 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, CondResult = CheckConditionVariable(ConditionVar, SourceLocation(), false); if (CondResult.isInvalid()) return StmtError(); - + Cond = CondResult.release(); } - + if (!Cond) return StmtError(); - + CondResult - = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, + = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, PDiag(diag::err_typecheck_statement_requires_integer), PDiag(diag::err_switch_incomplete_class_type) << Cond->getSourceRange(), @@ -415,21 +424,30 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, PDiag(0)); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); - + if (!CondVar) { - CondResult = MaybeCreateCXXExprWithTemporaries(Cond); + CheckImplicitConversions(Cond, SwitchLoc); + CondResult = MaybeCreateExprWithCleanups(Cond); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); } getCurFunction()->setHasBranchIntoScope(); - + SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, Cond); getCurFunction()->SwitchStack.push_back(SS); return Owned(SS); } +static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) { + if (Val.getBitWidth() < BitWidth) + Val = Val.extend(BitWidth); + else if (Val.getBitWidth() > BitWidth) + Val = Val.trunc(BitWidth); + Val.setIsSigned(IsSigned); +} + StmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *BodyStmt) { @@ -442,7 +460,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, if (SS->getCond() == 0) return StmtError(); - + Expr *CondExpr = SS->getCond(); Expr *CondExprBeforePromotion = CondExpr; QualType CondTypeBeforePromotion = @@ -462,7 +480,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // the pre-promotion type of the switch condition. if (!CondExpr->isTypeDependent()) { // We have already converted the expression to an integral or enumeration - // type, when we started the switch statement. If we don't have an + // type, when we started the switch statement. If we don't have an // appropriate type now, just return an error. if (!CondType->isIntegralOrEnumerationType()) return StmtError(); @@ -531,7 +549,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // Convert the value to the same width/sign as the condition. ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned, - CS->getLHS()->getLocStart(), + Lo->getLocStart(), diag::warn_case_value_overflow); // If the LHS is not the same type as the condition, insert an implicit @@ -610,7 +628,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // Convert the value to the same width/sign as the condition. ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, - CR->getRHS()->getLocStart(), + Hi->getLocStart(), diag::warn_case_value_overflow); // If the LHS is not the same type as the condition, insert an implicit @@ -622,7 +640,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, if (LoVal > HiVal) { Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range) << SourceRange(CR->getLHS()->getLocStart(), - CR->getRHS()->getLocEnd()); + Hi->getLocEnd()); CaseRanges.erase(CaseRanges.begin()+i); --i, --e; continue; @@ -696,14 +714,14 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, } // Check to see if switch is over an Enum and handles all of its - // values. We don't need to do this if there's a default - // statement or if we have a constant condition. + // values. We only issue a warning if there is not 'default:', but + // we still do the analysis to preserve this information in the AST + // (which can be used by flow-based analyes). // - // TODO: we might want to check whether case values are out of the - // enum even if we don't want to check whether all cases are handled. - const EnumType* ET = CondTypeBeforePromotion->getAs<EnumType>(); + const EnumType *ET = CondTypeBeforePromotion->getAs<EnumType>(); + // If switch has default case, then ignore it. - if (!CaseListIsErroneous && !TheDefaultStmt && !HasConstantCond && ET) { + if (!CaseListIsErroneous && !HasConstantCond && ET) { const EnumDecl *ED = ET->getDecl(); typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; EnumValsTy EnumVals; @@ -711,71 +729,105 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // Gather all enum values, set their type and sort them, // allowing easier comparison with CaseVals. for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); - EDI != ED->enumerator_end(); EDI++) { - llvm::APSInt Val = (*EDI)->getInitVal(); - if(Val.getBitWidth() < CondWidth) - Val.extend(CondWidth); - else if (Val.getBitWidth() > CondWidth) - Val.trunc(CondWidth); - Val.setIsSigned(CondIsSigned); - EnumVals.push_back(std::make_pair(Val, (*EDI))); + EDI != ED->enumerator_end(); ++EDI) { + llvm::APSInt Val = EDI->getInitVal(); + AdjustAPSInt(Val, CondWidth, CondIsSigned); + EnumVals.push_back(std::make_pair(Val, *EDI)); } std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); - // See which case values aren't in enum - EnumValsTy::const_iterator EI = EnumVals.begin(); - for (CaseValsTy::const_iterator CI = CaseVals.begin(); + + // See which case values aren't in enum. + // TODO: we might want to check whether case values are out of the + // enum even if we don't want to check whether all cases are handled. + if (!TheDefaultStmt) { + EnumValsTy::const_iterator EI = EnumVals.begin(); + for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) { - while (EI != EIend && EI->first < CI->first) - EI++; - if (EI == EIend || EI->first > CI->first) + while (EI != EIend && EI->first < CI->first) + EI++; + if (EI == EIend || EI->first > CI->first) Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) << ED->getDeclName(); - } - // See which of case ranges aren't in enum - EI = EnumVals.begin(); - for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); - RI != CaseRanges.end() && EI != EIend; RI++) { - while (EI != EIend && EI->first < RI->first) - EI++; - - if (EI == EIend || EI->first != RI->first) { - Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) - << ED->getDeclName(); } + // See which of case ranges aren't in enum + EI = EnumVals.begin(); + for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); + RI != CaseRanges.end() && EI != EIend; RI++) { + while (EI != EIend && EI->first < RI->first) + EI++; + + if (EI == EIend || EI->first != RI->first) { + Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) + << ED->getDeclName(); + } - llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); - while (EI != EIend && EI->first < Hi) - EI++; - if (EI == EIend || EI->first != Hi) - Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum) - << ED->getDeclName(); + llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); + AdjustAPSInt(Hi, CondWidth, CondIsSigned); + while (EI != EIend && EI->first < Hi) + EI++; + if (EI == EIend || EI->first != Hi) + Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum) + << ED->getDeclName(); + } } - //Check which enum vals aren't in switch + + // Check which enum vals aren't in switch CaseValsTy::const_iterator CI = CaseVals.begin(); CaseRangesTy::const_iterator RI = CaseRanges.begin(); - EI = EnumVals.begin(); - for (; EI != EIend; EI++) { - //Drop unneeded case values + bool hasCasesNotInSwitch = false; + + llvm::SmallVector<DeclarationName,8> UnhandledNames; + + for (EnumValsTy::const_iterator EI = EnumVals.begin(); EI != EIend; EI++){ + // Drop unneeded case values llvm::APSInt CIVal; while (CI != CaseVals.end() && CI->first < EI->first) CI++; - + if (CI != CaseVals.end() && CI->first == EI->first) continue; - //Drop unneeded case ranges + // Drop unneeded case ranges for (; RI != CaseRanges.end(); RI++) { llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); + AdjustAPSInt(Hi, CondWidth, CondIsSigned); if (EI->first <= Hi) break; } - if (RI == CaseRanges.end() || EI->first < RI->first) - Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) - << EI->second->getDeclName(); + if (RI == CaseRanges.end() || EI->first < RI->first) { + hasCasesNotInSwitch = true; + if (!TheDefaultStmt) + UnhandledNames.push_back(EI->second->getDeclName()); + } + } + + // Produce a nice diagnostic if multiple values aren't handled. + switch (UnhandledNames.size()) { + case 0: break; + case 1: + Diag(CondExpr->getExprLoc(), diag::warn_missing_case1) + << UnhandledNames[0]; + break; + case 2: + Diag(CondExpr->getExprLoc(), diag::warn_missing_case2) + << UnhandledNames[0] << UnhandledNames[1]; + break; + case 3: + Diag(CondExpr->getExprLoc(), diag::warn_missing_case3) + << UnhandledNames[0] << UnhandledNames[1] << UnhandledNames[2]; + break; + default: + Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) + << (unsigned)UnhandledNames.size() + << UnhandledNames[0] << UnhandledNames[1] << UnhandledNames[2]; + break; } + + if (!hasCasesNotInSwitch) + SS->setAllEnumCasesCovered(); } } @@ -788,10 +840,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, } StmtResult -Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, +Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, Decl *CondVar, Stmt *Body) { ExprResult CondResult(Cond.release()); - + VarDecl *ConditionVar = 0; if (CondVar) { ConditionVar = cast<VarDecl>(CondVar); @@ -802,7 +854,7 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, Expr *ConditionExpr = CondResult.take(); if (!ConditionExpr) return StmtError(); - + DiagnoseUnusedExprResult(Body); return Owned(new (Context) WhileStmt(Context, ConditionVar, ConditionExpr, @@ -818,11 +870,12 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, if (CheckBooleanCondition(Cond, DoLoc)) return StmtError(); - ExprResult CondResult = MaybeCreateCXXExprWithTemporaries(Cond); + CheckImplicitConversions(Cond, DoLoc); + ExprResult CondResult = MaybeCreateExprWithCleanups(Cond); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); - + DiagnoseUnusedExprResult(Body); return Owned(new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen)); @@ -841,7 +894,7 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end(); DI!=DE; ++DI) { VarDecl *VD = dyn_cast<VarDecl>(*DI); - if (VD && VD->isBlockVarDecl() && !VD->hasLocalStorage()) + if (VD && VD->isLocalVarDecl() && !VD->hasLocalStorage()) VD = 0; if (VD == 0) Diag((*DI)->getLocation(), diag::err_non_variable_decl_in_for); @@ -858,19 +911,30 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, if (SecondResult.isInvalid()) return StmtError(); } - + Expr *Third = third.release().takeAs<Expr>(); - + DiagnoseUnusedExprResult(First); DiagnoseUnusedExprResult(Third); DiagnoseUnusedExprResult(Body); - return Owned(new (Context) ForStmt(Context, First, - SecondResult.take(), ConditionVar, - Third, Body, ForLoc, LParenLoc, + return Owned(new (Context) ForStmt(Context, First, + SecondResult.take(), ConditionVar, + Third, Body, ForLoc, LParenLoc, RParenLoc)); } +/// In an Objective C collection iteration statement: +/// for (x in y) +/// x can be an arbitrary l-value expression. Bind it up as a +/// full-expression. +StmtResult Sema::ActOnForEachLValueExpr(Expr *E) { + CheckImplicitConversions(E); + ExprResult Result = MaybeCreateExprWithCleanups(E); + if (Result.isInvalid()) return StmtError(); + return Owned(static_cast<Stmt*>(Result.get())); +} + StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, SourceLocation LParenLoc, @@ -889,13 +953,12 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, // declare identifiers for objects having storage class 'auto' or // 'register'. VarDecl *VD = cast<VarDecl>(D); - if (VD->isBlockVarDecl() && !VD->hasLocalStorage()) + if (VD->isLocalVarDecl() && !VD->hasLocalStorage()) return StmtError(Diag(VD->getLocation(), diag::err_non_variable_decl_in_for)); } else { Expr *FirstE = cast<Expr>(First); - if (!FirstE->isTypeDependent() && - FirstE->isLvalue(Context) != Expr::LV_Valid) + if (!FirstE->isTypeDependent() && !FirstE->isLValue()) return StmtError(Diag(First->getLocStart(), diag::err_selector_element_not_lvalue) << First->getSourceRange()); @@ -917,7 +980,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, else if (const ObjCObjectPointerType *OPT = SecondType->getAsObjCInterfacePointerType()) { llvm::SmallVector<IdentifierInfo *, 4> KeyIdents; - IdentifierInfo* selIdent = + IdentifierInfo* selIdent = &Context.Idents.get("countByEnumeratingWithState"); KeyIdents.push_back(selIdent); selIdent = &Context.Idents.get("objects"); @@ -926,7 +989,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, KeyIdents.push_back(selIdent); Selector CSelector = Context.Selectors.getSelector(3, &KeyIdents[0]); if (ObjCInterfaceDecl *IDecl = OPT->getInterfaceDecl()) { - if (!IDecl->isForwardDecl() && + if (!IDecl->isForwardDecl() && !IDecl->lookupInstanceMethod(CSelector)) { // Must further look into private implementation methods. if (!LookupPrivateInstanceMethod(CSelector, IDecl)) @@ -940,19 +1003,12 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, ForLoc, RParenLoc)); } -StmtResult -Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, - IdentifierInfo *LabelII) { - // Look up the record for this label identifier. - LabelStmt *&LabelDecl = getCurFunction()->LabelMap[LabelII]; - +StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, + SourceLocation LabelLoc, + LabelDecl *TheDecl) { getCurFunction()->setHasBranchIntoScope(); - - // If we haven't seen this label yet, create a forward reference. - if (LabelDecl == 0) - LabelDecl = new (Context) LabelStmt(LabelLoc, LabelII, 0); - - return Owned(new (Context) GotoStmt(LabelDecl, GotoLoc, LabelLoc)); + TheDecl->setUsed(); + return Owned(new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc)); } StmtResult @@ -995,45 +1051,130 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { return Owned(new (Context) BreakStmt(BreakLoc)); } -/// \brief Determine whether a return statement is a candidate for the named -/// return value optimization (C++0x 12.8p34, bullet 1). +/// \brief Determine whether the given expression is a candidate for +/// copy elision in either a return statement or a throw expression. /// -/// \param Ctx The context in which the return expression and type occur. +/// \param ReturnType If we're determining the copy elision candidate for +/// a return statement, this is the return type of the function. If we're +/// determining the copy elision candidate for a throw expression, this will +/// be a NULL type. /// -/// \param RetType The return type of the function or block. +/// \param E The expression being returned from the function or block, or +/// being thrown. /// -/// \param RetExpr The expression being returned from the function or block. +/// \param AllowFunctionParameter /// /// \returns The NRVO candidate variable, if the return statement may use the /// NRVO, or NULL if there is no such candidate. -static const VarDecl *getNRVOCandidate(ASTContext &Ctx, QualType RetType, - Expr *RetExpr) { - QualType ExprType = RetExpr->getType(); +const VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, + Expr *E, + bool AllowFunctionParameter) { + QualType ExprType = E->getType(); // - in a return statement in a function with ... // ... a class return type ... - if (!RetType->isRecordType()) - return 0; - // ... the same cv-unqualified type as the function return type ... - if (!Ctx.hasSameUnqualifiedType(RetType, ExprType)) - return 0; - // ... the expression is the name of a non-volatile automatic object ... - // We ignore parentheses here. - // FIXME: Is this compliant? (Everyone else does it) - const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens()); + if (!ReturnType.isNull()) { + if (!ReturnType->isRecordType()) + return 0; + // ... the same cv-unqualified type as the function return type ... + if (!Context.hasSameUnqualifiedType(ReturnType, ExprType)) + return 0; + } + + // ... the expression is the name of a non-volatile automatic object + // (other than a function or catch-clause parameter)) ... + const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens()); if (!DR) return 0; const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) return 0; - - if (VD->getKind() == Decl::Var && VD->hasLocalStorage() && + + if (VD->hasLocalStorage() && !VD->isExceptionVariable() && !VD->getType()->isReferenceType() && !VD->hasAttr<BlocksAttr>() && - !VD->getType().isVolatileQualified()) + !VD->getType().isVolatileQualified() && + ((VD->getKind() == Decl::Var) || + (AllowFunctionParameter && VD->getKind() == Decl::ParmVar))) return VD; - + return 0; } +/// \brief Perform the initialization of a potentially-movable value, which +/// is the result of return value. +/// +/// This routine implements C++0x [class.copy]p33, which attempts to treat +/// returned lvalues as rvalues in certain cases (to prefer move construction), +/// then falls back to treating them as lvalues if that failed. +ExprResult +Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, + const VarDecl *NRVOCandidate, + QualType ResultType, + Expr *Value) { + // C++0x [class.copy]p33: + // When the criteria for elision of a copy operation are met or would + // be met save for the fact that the source object is a function + // parameter, and the object to be copied is designated by an lvalue, + // overload resolution to select the constructor for the copy is first + // performed as if the object were designated by an rvalue. + ExprResult Res = ExprError(); + if (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true)) { + ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, + Value->getType(), CK_LValueToRValue, + Value, VK_XValue); + + Expr *InitExpr = &AsRvalue; + InitializationKind Kind + = InitializationKind::CreateCopy(Value->getLocStart(), + Value->getLocStart()); + InitializationSequence Seq(*this, Entity, Kind, &InitExpr, 1); + + // [...] If overload resolution fails, or if the type of the first + // parameter of the selected constructor is not an rvalue reference + // to the object's type (possibly cv-qualified), overload resolution + // is performed again, considering the object as an lvalue. + if (Seq.getKind() != InitializationSequence::FailedSequence) { + for (InitializationSequence::step_iterator Step = Seq.step_begin(), + StepEnd = Seq.step_end(); + Step != StepEnd; ++Step) { + if (Step->Kind + != InitializationSequence::SK_ConstructorInitialization) + continue; + + CXXConstructorDecl *Constructor + = cast<CXXConstructorDecl>(Step->Function.Function); + + const RValueReferenceType *RRefType + = Constructor->getParamDecl(0)->getType() + ->getAs<RValueReferenceType>(); + + // If we don't meet the criteria, break out now. + if (!RRefType || + !Context.hasSameUnqualifiedType(RRefType->getPointeeType(), + Context.getTypeDeclType(Constructor->getParent()))) + break; + + // Promote "AsRvalue" to the heap, since we now need this + // expression node to persist. + Value = ImplicitCastExpr::Create(Context, Value->getType(), + CK_LValueToRValue, Value, 0, + VK_XValue); + + // Complete type-checking the initialization of the return type + // using the constructor we found. + Res = Seq.Perform(*this, Entity, Kind, MultiExprArg(&Value, 1)); + } + } + } + + // Either we didn't meet the criteria for treating an lvalue as an rvalue, + // above, or overload resolution failed. Either way, we need to try + // (again) now with the return value expression as written. + if (Res.isInvalid()) + Res = PerformCopyInitialization(Entity, SourceLocation(), Value); + + return Res; +} + /// ActOnBlockReturnStmt - Utility routine to figure out block's return type. /// StmtResult @@ -1052,14 +1193,14 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // part of the implementation spec. and not the actual qualifier for // the variable. if (CDRE->isConstQualAdded()) - CurBlock->ReturnType.removeConst(); + CurBlock->ReturnType.removeLocalConst(); // FIXME: local??? } } else CurBlock->ReturnType = Context.VoidTy; } QualType FnRetType = CurBlock->ReturnType; - if (CurBlock->TheDecl->hasAttr<NoReturnAttr>()) { + if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) { Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr) << getCurFunctionOrMethodDecl()->getDeclName(); return StmtError(); @@ -1079,7 +1220,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); } else { const VarDecl *NRVOCandidate = 0; - + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { // we have a non-void block with an expression, continue checking @@ -1089,35 +1230,36 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp); - ExprResult Res = PerformCopyInitialization( - InitializedEntity::InitializeResult(ReturnLoc, - FnRetType, - NRVOCandidate != 0), - SourceLocation(), - Owned(RetValExp)); + NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); + InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, + FnRetType, + NRVOCandidate != 0); + ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, + FnRetType, RetValExp); if (Res.isInvalid()) { // FIXME: Cleanup temporaries here, anyway? return StmtError(); } - - if (RetValExp) - RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); + + if (RetValExp) { + CheckImplicitConversions(RetValExp, ReturnLoc); + RetValExp = MaybeCreateExprWithCleanups(RetValExp); + } RetValExp = Res.takeAs<Expr>(); - if (RetValExp) + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } - + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); } - // If we need to check for the named return value optimization, save the + // If we need to check for the named return value optimization, save the // return statement in our scope for later processing. if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && !CurContext->isDependentContext()) FunctionScopes.back()->Returns.push_back(Result); - + return Owned(Result); } @@ -1145,6 +1287,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { unsigned D = diag::ext_return_has_expr; if (RetValExp->getType()->isVoidType()) D = diag::ext_return_has_void_expr; + else { + IgnoredValueConversions(RetValExp); + ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid); + } // return (some void expression); is legal in C++. if (D != diag::ext_return_has_void_expr || @@ -1155,9 +1301,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { << RetValExp->getSourceRange(); } - RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); + CheckImplicitConversions(RetValExp, ReturnLoc); + RetValExp = MaybeCreateExprWithCleanups(RetValExp); } - + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); } else if (!RetValExp && !FnRetType->isDependentType()) { unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4 @@ -1180,34 +1327,35 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp); - ExprResult Res = PerformCopyInitialization( - InitializedEntity::InitializeResult(ReturnLoc, - FnRetType, - NRVOCandidate != 0), - SourceLocation(), - Owned(RetValExp)); + NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); + InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, + FnRetType, + NRVOCandidate != 0); + ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, + FnRetType, RetValExp); if (Res.isInvalid()) { // FIXME: Cleanup temporaries here, anyway? return StmtError(); } RetValExp = Res.takeAs<Expr>(); - if (RetValExp) + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } - - if (RetValExp) - RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); + + if (RetValExp) { + CheckImplicitConversions(RetValExp, ReturnLoc); + RetValExp = MaybeCreateExprWithCleanups(RetValExp); + } Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); } - - // If we need to check for the named return value optimization, save the + + // If we need to check for the named return value optimization, save the // return statement in our scope for later processing. if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && !CurContext->isDependentContext()) FunctionScopes.back()->Returns.push_back(Result); - + return Owned(Result); } @@ -1222,14 +1370,14 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) { // Type dependent expressions will be checked during instantiation. if (E->isTypeDependent()) return false; - - if (E->isLvalue(S.Context) == Expr::LV_Valid) + + if (E->isLValue()) return false; // Cool, this is an lvalue. // Okay, this is not an lvalue, but perhaps it is the result of a cast that we // are supposed to allow. const Expr *E2 = E->IgnoreParenNoopCasts(S.Context); - if (E != E2 && E2->isLvalue(S.Context) == Expr::LV_Valid) { + if (E != E2 && E2->isLValue()) { if (!S.getLangOptions().HeinousExtensions) S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue) << E->getSourceRange(); @@ -1358,8 +1506,8 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, } AsmStmt *NS = - new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm, - NumOutputs, NumInputs, Names, Constraints, Exprs, + new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm, + NumOutputs, NumInputs, Names, Constraints, Exprs, AsmString, NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. @@ -1393,7 +1541,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, enum AsmDomain { AD_Int, AD_FP, AD_Other } InputDomain, OutputDomain; - + if (InTy->isIntegerType() || InTy->isPointerType()) InputDomain = AD_Int; else if (InTy->isRealFloatingType()) @@ -1407,19 +1555,19 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, OutputDomain = AD_FP; else OutputDomain = AD_Other; - + // They are ok if they are the same size and in the same domain. This // allows tying things like: // void* to int* // void* to int if they are the same size. // double to long double if they are the same size. - // + // uint64_t OutSize = Context.getTypeSize(OutTy); uint64_t InSize = Context.getTypeSize(InTy); if (OutSize == InSize && InputDomain == OutputDomain && InputDomain != AD_Other) 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. @@ -1471,7 +1619,7 @@ Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc, VarDecl *Var = cast_or_null<VarDecl>(Parm); if (Var && Var->isInvalidDecl()) return StmtError(); - + return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var, Body)); } @@ -1481,8 +1629,11 @@ Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body) { } StmtResult -Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, +Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, MultiStmtArg CatchStmts, Stmt *Finally) { + if (!getLangOptions().ObjCExceptions) + Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@try"; + getCurFunction()->setHasBranchProtectedScope(); unsigned NumCatchStmts = CatchStmts.size(); return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try, @@ -1494,6 +1645,8 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) { if (Throw) { + DefaultLvalueConversion(Throw); + QualType ThrowType = Throw->getType(); // Make sure the expression type is an ObjC pointer or "void *". if (!ThrowType->isDependentType() && @@ -1504,13 +1657,16 @@ StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, << Throw->getType() << Throw->getSourceRange()); } } - + return Owned(new (Context) ObjCAtThrowStmt(AtLoc, Throw)); } StmtResult -Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, +Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, Scope *CurScope) { + if (!getLangOptions().ObjCExceptions) + Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@throw"; + if (!Throw) { // @throw without an expression designates a rethrow (which much occur // in the context of an @catch clause). @@ -1519,8 +1675,8 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, AtCatchParent = AtCatchParent->getParent(); if (!AtCatchParent) return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); - } - + } + return BuildObjCAtThrowStmt(AtLoc, Throw); } @@ -1529,6 +1685,8 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr, Stmt *SyncBody) { getCurFunction()->setHasBranchProtectedScope(); + DefaultLvalueConversion(SyncExpr); + // Make sure the expression type is an ObjC pointer or "void *". if (!SyncExpr->getType()->isDependentType() && !SyncExpr->getType()->isObjCObjectPointerType()) { @@ -1589,6 +1747,9 @@ public: StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, MultiStmtArg RawHandlers) { + if (!getLangOptions().Exceptions) + Diag(TryLoc, diag::err_exceptions_disabled) << "try"; + unsigned NumHandlers = RawHandlers.size(); assert(NumHandlers > 0 && "The parser shouldn't call this if there are no handlers."); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 0fc8392..f0a0103 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -20,6 +20,8 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/TypeVisitor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Basic/LangOptions.h" @@ -28,6 +30,14 @@ using namespace clang; using namespace sema; +// Exported for use by Parser. +SourceRange +clang::getTemplateParamsRange(TemplateParameterList const * const *Ps, + unsigned N) { + if (!N) return SourceRange(); + return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); +} + /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns NULL. @@ -78,12 +88,12 @@ static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) { else if (Repl != Orig) { // C++ [temp.local]p3: - // A lookup that finds an injected-class-name (10.2) can result in an + // A lookup that finds an injected-class-name (10.2) can result in an // ambiguity in certain cases (for example, if it is found in more than - // one base class). If all of the injected-class-names that are found - // refer to specializations of the same class template, and if the name - // is followed by a template-argument-list, the reference refers to the - // class template itself and not a specialization thereof, and is not + // one base class). If all of the injected-class-names that are found + // refer to specializations of the same class template, and if the name + // is followed by a template-argument-list, the reference refers to the + // class template itself and not a specialization thereof, and is not // ambiguous. // // FIXME: Will we eventually have to do the same for alias templates? @@ -116,12 +126,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S, DeclarationName TName; MemberOfUnknownSpecialization = false; - + switch (Name.getKind()) { case UnqualifiedId::IK_Identifier: TName = DeclarationName(Name.Identifier); break; - + case UnqualifiedId::IK_OperatorFunctionId: TName = Context.DeclarationNames.getCXXOperatorName( Name.OperatorFunctionId.Operator); @@ -137,7 +147,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, QualType ObjectType = ObjectTypePtr.get(); - LookupResult R(*this, TName, Name.getSourceRange().getBegin(), + LookupResult R(*this, TName, Name.getSourceRange().getBegin(), LookupOrdinaryName); LookupTemplateName(R, S, SS, ObjectType, EnteringContext, MemberOfUnknownSpecialization); @@ -190,7 +200,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, return TemplateKind; } -bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, +bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, @@ -202,14 +212,14 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) || computeDeclContext(*SS)) return false; - + // The code is missing a 'template' keyword prior to the dependent template // name. NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep(); Diag(IILoc, diag::err_template_kw_missing) << Qualifier << II.getName() << FixItHint::CreateInsertion(IILoc, "template "); - SuggestedTemplate + SuggestedTemplate = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II)); SuggestedKind = TNK_Dependent_template_name; return true; @@ -230,14 +240,14 @@ void Sema::LookupTemplateName(LookupResult &Found, assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); - assert((isDependent || !ObjectType->isIncompleteType()) && + assert((isDependent || !ObjectType->isIncompleteType()) && "Caller should have completed object type"); } 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); - + // The declaration context must be complete. if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) return; @@ -277,7 +287,7 @@ void Sema::LookupTemplateName(LookupResult &Found, if (Found.empty() && !isDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); - if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx, + if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx, false, CTC_CXXCasts)) { FilterAcceptableTemplateNames(Context, Found); if (!Found.empty()) { @@ -318,7 +328,7 @@ void Sema::LookupTemplateName(LookupResult &Found, LookupOrdinaryName); LookupName(FoundOuter, S); FilterAcceptableTemplateNames(Context, FoundOuter); - + if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise @@ -333,7 +343,7 @@ void Sema::LookupTemplateName(LookupResult &Found, if (!Found.isSingleResult() || Found.getFoundDecl()->getCanonicalDecl() != FoundOuter.getFoundDecl()->getCanonicalDecl()) { - Diag(Found.getNameLoc(), + Diag(Found.getNameLoc(), diag::ext_nested_name_member_ref_lookup_ambiguous) << Found.getLookupName() << ObjectType; @@ -362,12 +372,12 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); DeclContext *DC = getFunctionLevelDeclContext(); - + if (!isAddressOfOperand && isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->isInstance()) { QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); - + // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. NamedDecl *FirstQualifierInScope = 0; @@ -427,35 +437,52 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(Decl *&D) { return 0; } +ParsedTemplateArgument ParsedTemplateArgument::getTemplatePackExpansion( + SourceLocation EllipsisLoc) const { + assert(Kind == Template && + "Only template template arguments can be pack expansions here"); + assert(getAsTemplate().get().containsUnexpandedParameterPack() && + "Template template argument pack expansion without packs"); + ParsedTemplateArgument Result(*this); + Result.EllipsisLoc = EllipsisLoc; + return Result; +} + static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, const ParsedTemplateArgument &Arg) { - + switch (Arg.getKind()) { case ParsedTemplateArgument::Type: { TypeSourceInfo *DI; QualType T = SemaRef.GetTypeFromParser(Arg.getAsType(), &DI); - if (!DI) + if (!DI) DI = SemaRef.Context.getTrivialTypeSourceInfo(T, Arg.getLocation()); return TemplateArgumentLoc(TemplateArgument(T), DI); } - + case ParsedTemplateArgument::NonType: { Expr *E = static_cast<Expr *>(Arg.getAsExpr()); return TemplateArgumentLoc(TemplateArgument(E), E); } - + case ParsedTemplateArgument::Template: { TemplateName Template = Arg.getAsTemplate().get(); - return TemplateArgumentLoc(TemplateArgument(Template), + TemplateArgument TArg; + if (Arg.getEllipsisLoc().isValid()) + TArg = TemplateArgument(Template, llvm::Optional<unsigned int>()); + else + TArg = Template; + return TemplateArgumentLoc(TArg, Arg.getScopeSpec().getRange(), - Arg.getLocation()); + Arg.getLocation(), + Arg.getEllipsisLoc()); } } - + llvm_unreachable("Unhandled parsed template argument"); return TemplateArgumentLoc(); } - + /// \brief Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, @@ -464,7 +491,7 @@ void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, TemplateArgs.addArgument(translateTemplateArgument(*this, TemplateArgsIn[I])); } - + /// ActOnTypeParameter - Called when a C++ template type parameter /// (e.g., "typename T") has been parsed. Typename specifies whether /// the keyword "typename" was used to declare the type parameter @@ -512,30 +539,35 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, IdResolver.AddDecl(Param); } + // 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. + if (DefaultArg && Ellipsis) { + Diag(EqualLoc, diag::err_template_param_pack_default_arg); + DefaultArg = ParsedType(); + } + // Handle the default argument, if provided. if (DefaultArg) { TypeSourceInfo *DefaultTInfo; GetTypeFromParser(DefaultArg, &DefaultTInfo); - + assert(DefaultTInfo && "expected source information for type"); - - // 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. - if (Ellipsis) { - Diag(EqualLoc, diag::err_template_param_pack_default_arg); + + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo, + UPPC_DefaultArgument)) return Param; - } - + // Check the template argument itself. if (CheckTemplateArgument(Param, DefaultTInfo)) { Param->setInvalidDecl(); return Param; } - + Param->setDefaultArgument(DefaultTInfo, false); } - + return Param; } @@ -582,7 +614,7 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { else if (T->isFunctionType()) // FIXME: Keep the type prior to promotion? return Context.getPointerType(T); - + Diag(Loc, diag::err_template_nontype_parm_bad_type) << T; @@ -617,10 +649,12 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Invalid = true; } + bool IsParameterPack = D.hasEllipsis(); NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), D.getIdentifierLoc(), - Depth, Position, ParamName, T, TInfo); + Depth, Position, ParamName, T, + IsParameterPack, TInfo); if (Invalid) Param->setInvalidDecl(); @@ -629,18 +663,30 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, S->AddDecl(Param); IdResolver.AddDecl(Param); } - + + // 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. + if (Default && IsParameterPack) { + Diag(EqualLoc, diag::err_template_param_pack_default_arg); + Default = 0; + } + // Check the well-formedness of the default template argument, if provided. - if (Default) { + if (Default) { + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument)) + return Param; + TemplateArgument Converted; if (CheckTemplateArgument(Param, Param->getType(), Default, Converted)) { Param->setInvalidDecl(); return Param; } - + Param->setDefaultArgument(Default, false); } - + return Param; } @@ -650,29 +696,46 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, SourceLocation TmpLoc, TemplateParamsTy *Params, + SourceLocation EllipsisLoc, IdentifierInfo *Name, SourceLocation NameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, - const ParsedTemplateArgument &Default) { + ParsedTemplateArgument Default) { assert(S->isTemplateParamScope() && "Template template parameter not in template parameter scope!"); // Construct the parameter object. + bool IsParameterPack = EllipsisLoc.isValid(); + // FIXME: Pack-ness is dropped TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), - NameLoc.isInvalid()? TmpLoc : NameLoc, - Depth, Position, Name, - (TemplateParameterList*)Params); + NameLoc.isInvalid()? TmpLoc : NameLoc, + Depth, Position, IsParameterPack, + Name, Params); - // If the template template parameter has a name, then link the identifier + // If the template template parameter has a name, then link the identifier // into the scope and lookup mechanisms. if (Name) { S->AddDecl(Param); IdResolver.AddDecl(Param); } + if (Params->size() == 0) { + Diag(Param->getLocation(), diag::err_template_template_parm_no_parms) + << SourceRange(Params->getLAngleLoc(), Params->getRAngleLoc()); + Param->setInvalidDecl(); + } + + // 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. + if (IsParameterPack && !Default.isInvalid()) { + Diag(EqualLoc, diag::err_template_param_pack_default_arg); + Default = ParsedTemplateArgument(); + } + if (!Default.isInvalid()) { // Check only that we have a template template argument. We don't want to // try to check well-formedness now, because our template template parameter @@ -688,10 +751,16 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, << DefaultArg.getSourceRange(); return Param; } - + + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(DefaultArg.getLocation(), + DefaultArg.getArgument().getAsTemplate(), + UPPC_DefaultArgument)) + return Param; + Param->setDefaultArgument(DefaultArg, false); } - + return Param; } @@ -708,7 +777,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth, Diag(ExportLoc, diag::warn_template_export_unsupported); return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, - (NamedDecl**)Params, NumParams, + (NamedDecl**)Params, NumParams, RAngleLoc); } @@ -765,7 +834,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Previous.isAmbiguous()) return true; - + NamedDecl *PrevDecl = 0; if (Previous.begin() != Previous.end()) PrevDecl = (*Previous.begin())->getUnderlyingDecl(); @@ -776,12 +845,12 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, = 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. + // 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) && + if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) && cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) { PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext()); - PrevClassTemplate + PrevClassTemplate = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate(); if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) { PrevClassTemplate @@ -792,8 +861,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (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 + // [...] 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. if (!SS.isSet()) { @@ -807,7 +876,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, SemanticContext = PrevDecl->getDeclContext(); } else { // Declarations in outer scopes don't matter. However, the outermost - // context we computed is the semantic context for our new + // context we computed is the semantic context for our new // declaration. PrevDecl = PrevClassTemplate = 0; SemanticContext = OutermostContext; @@ -823,7 +892,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) PrevDecl = PrevClassTemplate = 0; - + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. if (!TemplateParameterListsAreEqual(TemplateParams, @@ -877,18 +946,22 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // template declaration. if (CheckTemplateParameterList(TemplateParams, PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0, - TPC_ClassTemplate)) + (SS.isSet() && SemanticContext && + SemanticContext->isRecord() && + SemanticContext->isDependentContext()) + ? TPC_ClassTemplateMember + : TPC_ClassTemplate)) Invalid = true; if (SS.isSet()) { - // If the name of the template was qualified, we must be defining the + // If the name of the template was qualified, we must be defining the // template out-of-line. if (!SS.isInvalid() && !Invalid && !PrevClassTemplate && !(TUK == TUK_Friend && CurContext->isDependentContext())) Diag(NameLoc, diag::err_member_def_does_not_match) << Name << SemanticContext << SS.getRange(); - } - + } + CXXRecordDecl *NewClass = CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc, PrevClassTemplate? @@ -908,12 +981,12 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, assert(T->isDependentType() && "Class template type is not dependent?"); (void)T; - // If we are providing an explicit specialization of a member that is a + // If we are providing an explicit specialization of a member that is a // class template, make a note of that. - if (PrevClassTemplate && + if (PrevClassTemplate && PrevClassTemplate->getInstantiatedFromMemberTemplate()) PrevClassTemplate->setMemberSpecialization(); - + // Set the access specifier. if (!Invalid && TUK != TUK_Friend) SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS); @@ -938,16 +1011,16 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */ PrevClassTemplate != NULL); - + // Friend templates are visible in fairly strange ways. if (!CurContext->isDependentContext()) { DeclContext *DC = SemanticContext->getRedeclContext(); DC->makeDeclVisibleInContext(NewTemplate, /* Recoverable = */ false); if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(NewTemplate, EnclosingScope, - /* AddToContext = */ false); + /* AddToContext = */ false); } - + FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NewClass->getLocation(), NewTemplate, @@ -967,7 +1040,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, /// template parameter, which is ill-formed in certain contexts. /// /// \returns true if the default template argument should be dropped. -static bool DiagnoseDefaultTemplateArgument(Sema &S, +static bool DiagnoseDefaultTemplateArgument(Sema &S, Sema::TemplateParamListContext TPC, SourceLocation ParamLoc, SourceRange DefArgRange) { @@ -976,14 +1049,18 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, return false; case Sema::TPC_FunctionTemplate: - // C++ [temp.param]p9: + case Sema::TPC_FriendFunctionTemplateDefinition: + // C++ [temp.param]p9: // A default template-argument shall not be specified in a // function template declaration or a function template // definition [...] - // (This sentence is not in C++0x, per DR226). + // If a friend function template declaration specifies a default + // template-argument, that declaration shall be a definition and shall be + // the only declaration of the function template in the translation unit. + // (C++98/03 doesn't have this wording; see DR226). if (!S.getLangOptions().CPlusPlus0x) - S.Diag(ParamLoc, - diag::err_template_parameter_default_in_function_template) + S.Diag(ParamLoc, + diag::ext_template_parameter_default_in_function_template) << DefArgRange; return false; @@ -1012,6 +1089,30 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, return false; } +/// \brief Check for unexpanded parameter packs within the template parameters +/// of a template template parameter, recursively. +bool DiagnoseUnexpandedParameterPacks(Sema &S, TemplateTemplateParmDecl *TTP){ + TemplateParameterList *Params = TTP->getTemplateParameters(); + for (unsigned I = 0, N = Params->size(); I != N; ++I) { + NamedDecl *P = Params->getParam(I); + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) { + if (S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(), + NTTP->getTypeSourceInfo(), + Sema::UPPC_NonTypeTemplateParameterType)) + return true; + + continue; + } + + if (TemplateTemplateParmDecl *InnerTTP + = dyn_cast<TemplateTemplateParmDecl>(P)) + if (DiagnoseUnexpandedParameterPacks(S, InnerTTP)) + return true; + } + + return false; +} + /// \brief Checks the validity of a template parameter list, possibly /// considering the template parameter list from a previous /// declaration. @@ -1056,6 +1157,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, if (OldParams) OldParam = OldParams->begin(); + bool RemoveDefaultArguments = false; for (TemplateParameterList::iterator NewParam = NewParams->begin(), NewParamEnd = NewParams->end(); NewParam != NewParamEnd; ++NewParam) { @@ -1068,9 +1170,9 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, bool MissingDefaultArg = false; // C++0x [temp.param]p11: - // If a template parameter of a class template is a template parameter pack, - // it must be the last template parameter. - if (SawParameterPack) { + // If a template parameter of a primary class template is a template + // parameter pack, it shall be the last template parameter. + if (SawParameterPack && TPC == TPC_ClassTemplate) { Diag(ParameterPackLoc, diag::err_template_param_pack_must_be_last_template_parameter); Invalid = true; @@ -1079,9 +1181,9 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, if (TemplateTypeParmDecl *NewTypeParm = dyn_cast<TemplateTypeParmDecl>(*NewParam)) { // Check the presence of a default argument here. - if (NewTypeParm->hasDefaultArgument() && - DiagnoseDefaultTemplateArgument(*this, TPC, - NewTypeParm->getLocation(), + if (NewTypeParm->hasDefaultArgument() && + DiagnoseDefaultTemplateArgument(*this, TPC, + NewTypeParm->getLocation(), NewTypeParm->getDefaultArgumentInfo()->getTypeLoc() .getSourceRange())) NewTypeParm->removeDefaultArgument(); @@ -1116,10 +1218,18 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, MissingDefaultArg = true; } else if (NonTypeTemplateParmDecl *NewNonTypeParm = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) { + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(), + NewNonTypeParm->getTypeSourceInfo(), + UPPC_NonTypeTemplateParameterType)) { + Invalid = true; + continue; + } + // Check the presence of a default argument here. - if (NewNonTypeParm->hasDefaultArgument() && - DiagnoseDefaultTemplateArgument(*this, TPC, - NewNonTypeParm->getLocation(), + if (NewNonTypeParm->hasDefaultArgument() && + DiagnoseDefaultTemplateArgument(*this, TPC, + NewNonTypeParm->getLocation(), NewNonTypeParm->getDefaultArgument()->getSourceRange())) { NewNonTypeParm->removeDefaultArgument(); } @@ -1127,7 +1237,12 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Merge default arguments for non-type template parameters NonTypeTemplateParmDecl *OldNonTypeParm = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0; - if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() && + if (NewNonTypeParm->isParameterPack()) { + assert(!NewNonTypeParm->hasDefaultArgument() && + "Parameter packs can't have a default argument!"); + SawParameterPack = true; + ParameterPackLoc = NewNonTypeParm->getLocation(); + } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() && NewNonTypeParm->hasDefaultArgument()) { OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc(); @@ -1139,7 +1254,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // new declaration. SawDefaultArgument = true; // FIXME: We need to create a new kind of "default argument" - // expression that points to a previous template template + // expression that points to a previous non-type template // parameter. NewNonTypeParm->setDefaultArgument( OldNonTypeParm->getDefaultArgument(), @@ -1154,16 +1269,28 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Check the presence of a default argument here. TemplateTemplateParmDecl *NewTemplateParm = cast<TemplateTemplateParmDecl>(*NewParam); - if (NewTemplateParm->hasDefaultArgument() && - DiagnoseDefaultTemplateArgument(*this, TPC, - NewTemplateParm->getLocation(), + + // Check for unexpanded parameter packs, recursively. + if (DiagnoseUnexpandedParameterPacks(*this, NewTemplateParm)) { + Invalid = true; + continue; + } + + if (NewTemplateParm->hasDefaultArgument() && + DiagnoseDefaultTemplateArgument(*this, TPC, + NewTemplateParm->getLocation(), NewTemplateParm->getDefaultArgument().getSourceRange())) NewTemplateParm->removeDefaultArgument(); // Merge default arguments for template template parameters TemplateTemplateParmDecl *OldTemplateParm = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0; - if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && + if (NewTemplateParm->isParameterPack()) { + assert(!NewTemplateParm->hasDefaultArgument() && + "Parameter packs can't have a default argument!"); + SawParameterPack = true; + ParameterPackLoc = NewTemplateParm->getLocation(); + } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && NewTemplateParm->hasDefaultArgument()) { OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation(); NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation(); @@ -1196,15 +1323,17 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, Diag(NewDefaultLoc, diag::err_template_param_default_arg_redefinition); Diag(OldDefaultLoc, diag::note_template_param_prev_default_arg); Invalid = true; - } else if (MissingDefaultArg) { + } else if (MissingDefaultArg && TPC != TPC_FunctionTemplate) { // C++ [temp.param]p11: - // If a template-parameter has a default template-argument, - // all subsequent template-parameters shall have a default - // template-argument supplied. + // If a template-parameter of a class template has a default + // template-argument, each subsequent template-parameter shall either + // have a default template-argument supplied or be a template parameter + // pack. Diag((*NewParam)->getLocation(), diag::err_template_param_default_arg_missing); Diag(PreviousDefaultArgLoc, diag::note_template_param_prev_default_arg); Invalid = true; + RemoveDefaultArguments = true; } // If we have an old template parameter list that we're merging @@ -1213,9 +1342,89 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, ++OldParam; } + // We were missing some default arguments at the end of the list, so remove + // all of the default arguments. + if (RemoveDefaultArguments) { + for (TemplateParameterList::iterator NewParam = NewParams->begin(), + NewParamEnd = NewParams->end(); + NewParam != NewParamEnd; ++NewParam) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*NewParam)) + TTP->removeDefaultArgument(); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) + NTTP->removeDefaultArgument(); + else + cast<TemplateTemplateParmDecl>(*NewParam)->removeDefaultArgument(); + } + } + return Invalid; } +namespace { + +/// A class which looks for a use of a certain level of template +/// parameter. +struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { + typedef RecursiveASTVisitor<DependencyChecker> super; + + unsigned Depth; + bool Match; + + DependencyChecker(TemplateParameterList *Params) : Match(false) { + NamedDecl *ND = Params->getParam(0); + if (TemplateTypeParmDecl *PD = dyn_cast<TemplateTypeParmDecl>(ND)) { + Depth = PD->getDepth(); + } else if (NonTypeTemplateParmDecl *PD = + dyn_cast<NonTypeTemplateParmDecl>(ND)) { + Depth = PD->getDepth(); + } else { + Depth = cast<TemplateTemplateParmDecl>(ND)->getDepth(); + } + } + + bool Matches(unsigned ParmDepth) { + if (ParmDepth >= Depth) { + Match = true; + return true; + } + return false; + } + + bool VisitTemplateTypeParmType(const TemplateTypeParmType *T) { + return !Matches(T->getDepth()); + } + + bool TraverseTemplateName(TemplateName N) { + if (TemplateTemplateParmDecl *PD = + dyn_cast_or_null<TemplateTemplateParmDecl>(N.getAsTemplateDecl())) + if (Matches(PD->getDepth())) return false; + return super::TraverseTemplateName(N); + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (NonTypeTemplateParmDecl *PD = + dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) { + if (PD->getDepth() == Depth) { + Match = true; + return false; + } + } + return super::VisitDeclRefExpr(E); + } +}; +} + +/// Determines whether a template-id depends on the given parameter +/// list. +static bool +DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId, + TemplateParameterList *Params) { + DependencyChecker Checker(Params); + Checker.TraverseType(QualType(TemplateId, 0)); + return Checker.Match; +} + /// \brief Match the given template parameter lists to the given scope /// specifier, returning the template parameter list that applies to the /// name. @@ -1254,7 +1463,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, bool &IsExplicitSpecialization, bool &Invalid) { 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> @@ -1275,8 +1484,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // // Following the existing practice of GNU and EDG, we allow a typedef of a // template specialization type. - if (const TypedefType *TT = dyn_cast<TypedefType>(T)) - T = TT->LookThroughTypedefs().getTypePtr(); + while (const TypedefType *TT = dyn_cast<TypedefType>(T)) + T = TT->getDecl()->getUnderlyingType().getTypePtr(); if (const TemplateSpecializationType *SpecType = dyn_cast<TemplateSpecializationType>(T)) { @@ -1309,12 +1518,24 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // Match the template-ids found in the specifier to the template parameter // lists. - unsigned Idx = 0; + unsigned ParamIdx = 0, TemplateIdx = 0; for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size(); - Idx != NumTemplateIds; ++Idx) { - QualType TemplateId = QualType(TemplateIdsInSpecifier[Idx], 0); + TemplateIdx != NumTemplateIds; ++TemplateIdx) { + const TemplateSpecializationType *TemplateId + = TemplateIdsInSpecifier[TemplateIdx]; bool DependentTemplateId = TemplateId->isDependentType(); - if (Idx >= NumParamLists) { + + // In friend declarations we can have template-ids which don't + // depend on the corresponding template parameter lists. But + // assume that empty parameter lists are supposed to match this + // template-id. + if (IsFriend && ParamIdx < NumParamLists && ParamLists[ParamIdx]->size()) { + if (!DependentTemplateId || + !DependsOnTemplateParameters(TemplateId, ParamLists[ParamIdx])) + continue; + } + + if (ParamIdx >= NumParamLists) { // We have a template-id without a corresponding template parameter // list. @@ -1328,7 +1549,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // FIXME: the location information here isn't great. Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_template_parameters) - << TemplateId + << QualType(TemplateId, 0) << SS.getRange(); Invalid = true; } else { @@ -1357,35 +1578,38 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, } if (ExpectedTemplateParams) - TemplateParameterListsAreEqual(ParamLists[Idx], + TemplateParameterListsAreEqual(ParamLists[ParamIdx], ExpectedTemplateParams, true, TPL_TemplateMatch); - CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember); - } else if (ParamLists[Idx]->size() > 0) - Diag(ParamLists[Idx]->getTemplateLoc(), + CheckTemplateParameterList(ParamLists[ParamIdx], 0, + TPC_ClassTemplateMember); + } else if (ParamLists[ParamIdx]->size() > 0) + Diag(ParamLists[ParamIdx]->getTemplateLoc(), diag::err_template_param_list_matches_nontemplate) << TemplateId - << ParamLists[Idx]->getSourceRange(); + << ParamLists[ParamIdx]->getSourceRange(); else IsExplicitSpecialization = true; + + ++ParamIdx; } // 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) + if (ParamIdx >= NumParamLists) return 0; // If there were too many template parameter lists, complain about that now. - if (Idx != NumParamLists - 1) { - while (Idx < NumParamLists - 1) { - bool isExplicitSpecHeader = ParamLists[Idx]->size() == 0; - Diag(ParamLists[Idx]->getTemplateLoc(), + if (ParamIdx != NumParamLists - 1) { + while (ParamIdx < NumParamLists - 1) { + bool isExplicitSpecHeader = ParamLists[ParamIdx]->size() == 0; + Diag(ParamLists[ParamIdx]->getTemplateLoc(), isExplicitSpecHeader? diag::warn_template_spec_extra_headers : diag::err_template_spec_extra_headers) - << SourceRange(ParamLists[Idx]->getTemplateLoc(), - ParamLists[Idx]->getRAngleLoc()); + << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), + ParamLists[ParamIdx]->getRAngleLoc()); if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) { Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(), @@ -1394,13 +1618,13 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, ExplicitSpecializationsInSpecifier.pop_back(); } - // We have a template parameter list with no corresponding scope, which + // We have a template parameter list with no corresponding scope, which // means that the resulting template declaration can't be instantiated // properly (we'll end up with dependent nodes when we shouldn't). if (!isExplicitSpecHeader) Invalid = true; - - ++Idx; + + ++ParamIdx; } } @@ -1421,14 +1645,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Check that the template argument list is well-formed for this // template. - TemplateArgumentListBuilder Converted(Template->getTemplateParameters(), - TemplateArgs.size()); + llvm::SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false, Converted)) return QualType(); - assert((Converted.structuredSize() == - Template->getTemplateParameters()->size()) && + assert((Converted.size() == Template->getTemplateParameters()->size()) && "Converted template argument list is too short!"); QualType CanonType; @@ -1445,8 +1667,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // template<typename T, typename U = T> struct A; TemplateName CanonName = Context.getCanonicalTemplateName(Name); CanonType = Context.getTemplateSpecializationType(CanonName, - Converted.getFlatArguments(), - Converted.flatSize()); + Converted.data(), + Converted.size()); // FIXME: CanonType is not actually the canonical type, and unfortunately // it is a TemplateSpecializationType that we will never use again. @@ -1474,7 +1696,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, if (!isa<ClassTemplatePartialSpecializationDecl>(Record) && !Record->getDescribedClassTemplate()) continue; - + // Fetch the injected class name type and check whether its // injected type is equal to the type we just built. QualType ICNT = Context.getTypeDeclType(Record); @@ -1497,8 +1719,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // corresponds to these arguments. void *InsertPos = 0; ClassTemplateSpecializationDecl *Decl - = ClassTemplate->findSpecialization(Converted.getFlatArguments(), - Converted.flatSize(), InsertPos); + = ClassTemplate->findSpecialization(Converted.data(), Converted.size(), + InsertPos); if (!Decl) { // This is the first time we have referenced this class template // specialization. Create the canonical declaration and add it to @@ -1507,8 +1729,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, ClassTemplate->getTemplatedDecl()->getTagKind(), ClassTemplate->getDeclContext(), ClassTemplate->getLocation(), - ClassTemplate, - Converted, 0); + ClassTemplate, + Converted.data(), + Converted.size(), 0); ClassTemplate->AddSpecialization(Decl, InsertPos); Decl->setLexicalDeclContext(CurContext); } @@ -1553,14 +1776,14 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, return CreateParsedType(Result, DI); } -TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, +TypeResult Sema::ActOnTagTemplateIdType(CXXScopeSpec &SS, + TypeResult TypeResult, TagUseKind TUK, TypeSpecifierType TagSpec, SourceLocation TagLoc) { if (TypeResult.isInvalid()) return ::TypeResult(); - // FIXME: preserve source info, ideally without copying the DI. TypeSourceInfo *DI; QualType Type = GetTypeFromParser(TypeResult.get(), &DI); @@ -1585,7 +1808,12 @@ TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, = TypeWithKeyword::getKeywordForTagTypeKind(TagKind); QualType ElabType = Context.getElaboratedType(Keyword, /*NNS=*/0, Type); - return ParsedType::make(ElabType); + TypeSourceInfo *ElabDI = Context.CreateTypeSourceInfo(ElabType); + ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(ElabDI->getTypeLoc()); + TL.setKeywordLoc(TagLoc); + TL.setQualifierRange(SS.getRange()); + TL.getNamedTypeLoc().initializeFullCopy(DI->getTypeLoc()); + return CreateParsedType(ElabType, ElabDI); } ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, @@ -1596,6 +1824,11 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, // 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, // though. + // foo<int> could identify a single function unambiguously + // This approach does NOT work, since f<int>(1); + // gets resolved prior to resorting to overload resolution + // i.e., template<class T> void f(double); + // vs template<class T, class U> void f(U); // These should be filtered out by our callers. assert(!R.empty() && "empty lookup results when building templateid"); @@ -1610,15 +1843,12 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, // We don't want lookup warnings at this point. R.suppressDiagnostics(); - - bool Dependent - = UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), - &TemplateArgs); + UnresolvedLookupExpr *ULE - = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(), + = UnresolvedLookupExpr::Create(Context, R.getNamingClass(), Qualifier, QualifierRange, R.getLookupNameInfo(), - RequiresADL, TemplateArgs, + RequiresADL, TemplateArgs, R.begin(), R.end()); return Owned(ULE); @@ -1642,7 +1872,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, if (R.isAmbiguous()) return ExprError(); - + if (R.empty()) { Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_non_template) << NameInfo.getName() << SS.getRange(); @@ -1667,7 +1897,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, /// 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. -TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, +TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, SourceLocation TemplateKWLoc, CXXScopeSpec &SS, UnqualifiedId &Name, @@ -1677,8 +1907,8 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent() && !getLangOptions().CPlusPlus0x) Diag(TemplateKWLoc, diag::ext_template_outside_of_template) - << FixItHint::CreateRemoval(TemplateKWLoc); - + << FixItHint::CreateRemoval(TemplateKWLoc); + DeclContext *LookupCtx = 0; if (SS.isSet()) LookupCtx = computeDeclContext(SS, EnteringContext); @@ -1710,7 +1940,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) { // This is a dependent template. Handle it below. } else if (TNK == TNK_Non_template) { - Diag(Name.getSourceRange().getBegin(), + Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name).getName() << Name.getSourceRange() @@ -1724,13 +1954,13 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, NestedNameSpecifier *Qualifier = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - + switch (Name.getKind()) { case UnqualifiedId::IK_Identifier: - Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, + Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, Name.Identifier)); return TNK_Dependent_template_name; - + case UnqualifiedId::IK_OperatorFunctionId: Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, Name.OperatorFunctionId.Operator)); @@ -1742,8 +1972,8 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, default: break; } - - Diag(Name.getSourceRange().getBegin(), + + Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name).getName() << Name.getSourceRange() @@ -1753,7 +1983,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const TemplateArgumentLoc &AL, - TemplateArgumentListBuilder &Converted) { + llvm::SmallVectorImpl<TemplateArgument> &Converted) { const TemplateArgument &Arg = AL.getArgument(); // Check template type parameter. @@ -1790,7 +2020,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return true; // Add the converted template type argument. - Converted.Append( + Converted.push_back( TemplateArgument(Context.getCanonicalType(Arg.getAsType()))); return false; } @@ -1801,7 +2031,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, /// \param SemaRef the semantic analysis object for which we are performing /// the substitution. /// -/// \param Template the template that we are synthesizing template arguments +/// \param Template the template that we are synthesizing template arguments /// for. /// /// \param TemplateLoc the location of the template name that started the @@ -1823,23 +2053,23 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation TemplateLoc, SourceLocation RAngleLoc, TemplateTypeParmDecl *Param, - TemplateArgumentListBuilder &Converted) { + llvm::SmallVectorImpl<TemplateArgument> &Converted) { TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo(); // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. if (ArgType->getType()->isDependentType()) { - TemplateArgumentList TemplateArgs(SemaRef.Context, Converted, - /*TakeArgs=*/false); - + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + MultiLevelTemplateArgumentList AllTemplateArgs = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, - Template, Converted.getFlatArguments(), - Converted.flatSize(), + Template, Converted.data(), + Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); - + ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs, Param->getDefaultArgumentLoc(), Param->getDeclName()); @@ -1854,7 +2084,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, /// \param SemaRef the semantic analysis object for which we are performing /// the substitution. /// -/// \param Template the template that we are synthesizing template arguments +/// \param Template the template that we are synthesizing template arguments /// for. /// /// \param TemplateLoc the location of the template name that started the @@ -1876,16 +2106,16 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation TemplateLoc, SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param, - TemplateArgumentListBuilder &Converted) { - TemplateArgumentList TemplateArgs(SemaRef.Context, Converted, - /*TakeArgs=*/false); - + llvm::SmallVectorImpl<TemplateArgument> &Converted) { + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + MultiLevelTemplateArgumentList AllTemplateArgs = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); - + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, - Template, Converted.getFlatArguments(), - Converted.flatSize(), + Template, Converted.data(), + Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs); @@ -1897,7 +2127,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, /// \param SemaRef the semantic analysis object for which we are performing /// the substitution. /// -/// \param Template the template that we are synthesizing template arguments +/// \param Template the template that we are synthesizing template arguments /// for. /// /// \param TemplateLoc the location of the template name that started the @@ -1919,34 +2149,34 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation TemplateLoc, SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param, - TemplateArgumentListBuilder &Converted) { - TemplateArgumentList TemplateArgs(SemaRef.Context, Converted, - /*TakeArgs=*/false); - + llvm::SmallVectorImpl<TemplateArgument> &Converted) { + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + MultiLevelTemplateArgumentList AllTemplateArgs = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); - + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, - Template, Converted.getFlatArguments(), - Converted.flatSize(), + Template, Converted.data(), + Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); - + return SemaRef.SubstTemplateName( Param->getDefaultArgument().getArgument().getAsTemplate(), - Param->getDefaultArgument().getTemplateNameLoc(), + Param->getDefaultArgument().getTemplateNameLoc(), AllTemplateArgs); } /// \brief If the given template parameter has a default template /// argument, substitute into that default template argument and /// return the corresponding template argument. -TemplateArgumentLoc +TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, Decl *Param, - TemplateArgumentListBuilder &Converted) { - if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) { + llvm::SmallVectorImpl<TemplateArgument> &Converted) { + if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) { if (!TypeParm->hasDefaultArgument()) return TemplateArgumentLoc(); @@ -1984,45 +2214,75 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, return TemplateArgumentLoc(); TemplateName TName = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, + TemplateLoc, RAngleLoc, TempTempParm, Converted); if (TName.isNull()) return TemplateArgumentLoc(); - return TemplateArgumentLoc(TemplateArgument(TName), + return TemplateArgumentLoc(TemplateArgument(TName), TempTempParm->getDefaultArgument().getTemplateQualifierRange(), TempTempParm->getDefaultArgument().getTemplateNameLoc()); } /// \brief Check that the given template argument corresponds to the given /// template parameter. +/// +/// \param Param The template parameter against which the argument will be +/// checked. +/// +/// \param Arg The template argument. +/// +/// \param Template The template in which the template argument resides. +/// +/// \param TemplateLoc The location of the template name for the template +/// whose argument list we're matching. +/// +/// \param RAngleLoc The location of the right angle bracket ('>') that closes +/// the template argument list. +/// +/// \param ArgumentPackIndex The index into the argument pack where this +/// argument will be placed. Only valid if the parameter is a parameter pack. +/// +/// \param Converted The checked, converted argument will be added to the +/// end of this small vector. +/// +/// \param CTAK Describes how we arrived at this particular template argument: +/// explicitly written, deduced, etc. +/// +/// \returns true on error, false otherwise. bool Sema::CheckTemplateArgument(NamedDecl *Param, const TemplateArgumentLoc &Arg, - TemplateDecl *Template, + NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, - TemplateArgumentListBuilder &Converted, + unsigned ArgumentPackIndex, + llvm::SmallVectorImpl<TemplateArgument> &Converted, CheckTemplateArgumentKind CTAK) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) return CheckTemplateTypeArgument(TTP, Arg, Converted); - + // Check non-type template parameters. - if (NonTypeTemplateParmDecl *NTTP =dyn_cast<NonTypeTemplateParmDecl>(Param)) { + if (NonTypeTemplateParmDecl *NTTP =dyn_cast<NonTypeTemplateParmDecl>(Param)) { // Do substitution on the type of the non-type template parameter - // with the template arguments we've seen thus far. + // with the template arguments we've seen thus far. But if the + // template has a dependent context then we cannot substitute yet. QualType NTTPType = NTTP->getType(); - if (NTTPType->isDependentType()) { + if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack()) + NTTPType = NTTP->getExpansionType(ArgumentPackIndex); + + if (NTTPType->isDependentType() && + !isa<TemplateTemplateParmDecl>(Template) && + !Template->getDeclContext()->isDependentContext()) { // Do substitution on the type of the non-type template parameter. InstantiatingTemplate Inst(*this, TemplateLoc, Template, - NTTP, Converted.getFlatArguments(), - Converted.flatSize(), + NTTP, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); - - TemplateArgumentList TemplateArgs(Context, Converted, - /*TakeArgs=*/false); + + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); NTTPType = SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs), NTTP->getLocation(), @@ -2035,34 +2295,36 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, if (NTTPType.isNull()) return true; } - + switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: assert(false && "Should never see a NULL template argument here"); return true; - + case TemplateArgument::Expression: { Expr *E = Arg.getArgument().getAsExpr(); TemplateArgument Result; if (CheckTemplateArgument(NTTP, NTTPType, E, Result, CTAK)) return true; - - Converted.Append(Result); + + Converted.push_back(Result); break; } - + case TemplateArgument::Declaration: case TemplateArgument::Integral: // We've already checked this template argument, so just copy // it to the list of converted arguments. - Converted.Append(Arg.getArgument()); + Converted.push_back(Arg.getArgument()); break; - + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: // We were given a template template argument. It may not be ill-formed; // see below. if (DependentTemplateName *DTN - = Arg.getArgument().getAsTemplate().getAsDependentTemplateName()) { + = Arg.getArgument().getAsTemplateOrTemplatePattern() + .getAsDependentTemplateName()) { // We have a template argument such as \c T::template X, which we // parsed as a template template argument. However, since we now // know that we need a non-type template argument, convert this @@ -2075,28 +2337,39 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, DTN->getQualifier(), Arg.getTemplateQualifierRange(), NameInfo); - + + // If we parsed the template argument as a pack expansion, create a + // pack expansion expression. + if (Arg.getArgument().getKind() == TemplateArgument::TemplateExpansion){ + ExprResult Expansion = ActOnPackExpansion(E, + Arg.getTemplateEllipsisLoc()); + if (Expansion.isInvalid()) + return true; + + E = Expansion.get(); + } + TemplateArgument Result; if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) return true; - - Converted.Append(Result); + + Converted.push_back(Result); break; } - + // We have a template argument that actually does refer to a class // template, template alias, or template template parameter, and // therefore cannot be a non-type template argument. Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr) << Arg.getSourceRange(); - + Diag(Param->getLocation(), diag::note_template_param_here); return true; - + 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 @@ -2113,19 +2386,19 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, Diag(Param->getLocation(), diag::note_template_param_here); return true; } - + case TemplateArgument::Pack: llvm_unreachable("Caller must expand template argument packs"); break; } - + return false; - } - - + } + + // Check template template parameters. TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(Param); - + // Substitute into the template parameter list of the template // template parameter, since previously-supplied template arguments // may appear within the template template parameter. @@ -2133,40 +2406,38 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, // Set up a template instantiation context. LocalInstantiationScope Scope(*this); InstantiatingTemplate Inst(*this, TemplateLoc, Template, - TempParm, Converted.getFlatArguments(), - Converted.flatSize(), + TempParm, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); - - TemplateArgumentList TemplateArgs(Context, Converted, - /*TakeArgs=*/false); + + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); TempParm = cast_or_null<TemplateTemplateParmDecl>( - SubstDecl(TempParm, CurContext, + SubstDecl(TempParm, CurContext, MultiLevelTemplateArgumentList(TemplateArgs))); if (!TempParm) return true; - - // FIXME: TempParam is leaked. } - + switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: assert(false && "Should never see a NULL template argument here"); return true; - + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: if (CheckTemplateArgument(TempParm, Arg)) return true; - - Converted.Append(Arg.getArgument()); + + Converted.push_back(Arg.getArgument()); break; - + case TemplateArgument::Expression: case TemplateArgument::Type: // We have a template template parameter but the template // argument does not refer to a template. Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); return true; - + case TemplateArgument::Declaration: llvm_unreachable( "Declaration argument with template template parameter"); @@ -2175,12 +2446,12 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, llvm_unreachable( "Integral argument with template template parameter"); break; - + case TemplateArgument::Pack: llvm_unreachable("Caller must expand template argument packs"); break; } - + return false; } @@ -2190,7 +2461,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, const TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, - TemplateArgumentListBuilder &Converted) { + llvm::SmallVectorImpl<TemplateArgument> &Converted) { TemplateParameterList *Params = Template->getTemplateParameters(); unsigned NumParams = Params->size(); unsigned NumArgs = TemplateArgs.size(); @@ -2226,44 +2497,67 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // a template-id shall match the type and form specified for the // corresponding parameter declared by the template in its // template-parameter-list. + llvm::SmallVector<TemplateArgument, 2> ArgumentPack; + TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); unsigned ArgIdx = 0; - for (TemplateParameterList::iterator Param = Params->begin(), - ParamEnd = Params->end(); - Param != ParamEnd; ++Param, ++ArgIdx) { + LocalInstantiationScope InstScope(*this, true); + while (Param != ParamEnd) { if (ArgIdx > NumArgs && PartialTemplateArgs) break; - // If we have a template parameter pack, check every remaining template - // argument against that template parameter pack. - if ((*Param)->isTemplateParameterPack()) { - Converted.BeginPack(); - for (; ArgIdx < NumArgs; ++ArgIdx) { - if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, - TemplateLoc, RAngleLoc, Converted)) { - Invalid = true; - break; + if (ArgIdx < NumArgs) { + // If we have an expanded parameter pack, make sure we don't have too + // many arguments. + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { + if (NTTP->isExpandedParameterPack() && + ArgumentPack.size() >= NTTP->getNumExpansionTypes()) { + Diag(TemplateLoc, diag::err_template_arg_list_different_arity) + << true + << (isa<ClassTemplateDecl>(Template)? 0 : + isa<FunctionTemplateDecl>(Template)? 1 : + isa<TemplateTemplateParmDecl>(Template)? 2 : 3) + << Template; + Diag(Template->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + return true; } } - Converted.EndPack(); - continue; - } - - if (ArgIdx < NumArgs) { + // Check the template argument we were given. - if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, - TemplateLoc, RAngleLoc, Converted)) + if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, + TemplateLoc, RAngleLoc, + ArgumentPack.size(), Converted)) return true; - + + if ((*Param)->isTemplateParameterPack()) { + // The template parameter was a template parameter pack, so take the + // deduced argument and place it on the argument pack. Note that we + // stay on the same template parameter so that we can deduce more + // arguments. + ArgumentPack.push_back(Converted.back()); + Converted.pop_back(); + } else { + // Move to the next template parameter. + ++Param; + } + ++ArgIdx; continue; } - + + // If we have a template parameter pack with no more corresponding + // arguments, just break out now and we'll fill in the argument pack below. + if ((*Param)->isTemplateParameterPack()) + break; + // We have a default template argument that we will use. TemplateArgumentLoc Arg; - + // Retrieve the default template argument from the template // parameter. For each kind of template parameter, we substitute the // template arguments provided thus far and any "outer" template arguments - // (when the template parameter was part of a nested template) into + // (when the template parameter was part of a nested template) into // the default argument. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { if (!TTP->hasDefaultArgument()) { @@ -2271,7 +2565,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; } - TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, + TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, @@ -2279,7 +2573,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, Converted); if (!ArgType) return true; - + Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), ArgType); } else if (NonTypeTemplateParmDecl *NTTP @@ -2290,9 +2584,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } ExprResult E = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, - NTTP, + TemplateLoc, + RAngleLoc, + NTTP, Converted); if (E.isInvalid()) return true; @@ -2309,34 +2603,282 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } TemplateName Name = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, + TemplateLoc, + RAngleLoc, TempParm, Converted); if (Name.isNull()) return true; - - Arg = TemplateArgumentLoc(TemplateArgument(Name), + + Arg = TemplateArgumentLoc(TemplateArgument(Name), TempParm->getDefaultArgument().getTemplateQualifierRange(), TempParm->getDefaultArgument().getTemplateNameLoc()); } - + // Introduce an instantiation record that describes where we are using // the default template argument. InstantiatingTemplate Instantiating(*this, RAngleLoc, Template, *Param, - Converted.getFlatArguments(), - Converted.flatSize(), - SourceRange(TemplateLoc, RAngleLoc)); - + Converted.data(), Converted.size(), + SourceRange(TemplateLoc, RAngleLoc)); + // Check the default template argument. if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, - RAngleLoc, Converted)) + RAngleLoc, 0, Converted)) return true; + + // Move to the next template parameter and argument. + ++Param; + ++ArgIdx; + } + + // Form argument packs for each of the parameter packs remaining. + while (Param != ParamEnd) { + // If we're checking a partial list of template arguments, don't fill + // in arguments for non-template parameter packs. + + if ((*Param)->isTemplateParameterPack()) { + if (PartialTemplateArgs && ArgumentPack.empty()) { + Converted.push_back(TemplateArgument()); + } else if (ArgumentPack.empty()) + Converted.push_back(TemplateArgument(0, 0)); + else { + Converted.push_back(TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), + ArgumentPack.size())); + ArgumentPack.clear(); + } + } + + ++Param; } return Invalid; } +namespace { + class UnnamedLocalNoLinkageFinder + : public TypeVisitor<UnnamedLocalNoLinkageFinder, bool> + { + Sema &S; + SourceRange SR; + + typedef TypeVisitor<UnnamedLocalNoLinkageFinder, bool> inherited; + + public: + UnnamedLocalNoLinkageFinder(Sema &S, SourceRange SR) : S(S), SR(SR) { } + + bool Visit(QualType T) { + return inherited::Visit(T.getTypePtr()); + } + +#define TYPE(Class, Parent) \ + bool Visit##Class##Type(const Class##Type *); +#define ABSTRACT_TYPE(Class, Parent) \ + bool Visit##Class##Type(const Class##Type *) { return false; } +#define NON_CANONICAL_TYPE(Class, Parent) \ + bool Visit##Class##Type(const Class##Type *) { return false; } +#include "clang/AST/TypeNodes.def" + + bool VisitTagDecl(const TagDecl *Tag); + bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS); + }; +} + +bool UnnamedLocalNoLinkageFinder::VisitBuiltinType(const BuiltinType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitComplexType(const ComplexType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitPointerType(const PointerType* T) { + return Visit(T->getPointeeType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitBlockPointerType( + const BlockPointerType* T) { + return Visit(T->getPointeeType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitLValueReferenceType( + const LValueReferenceType* T) { + return Visit(T->getPointeeType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitRValueReferenceType( + const RValueReferenceType* T) { + return Visit(T->getPointeeType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitMemberPointerType( + const MemberPointerType* T) { + return Visit(T->getPointeeType()) || Visit(QualType(T->getClass(), 0)); +} + +bool UnnamedLocalNoLinkageFinder::VisitConstantArrayType( + const ConstantArrayType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitIncompleteArrayType( + const IncompleteArrayType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitVariableArrayType( + const VariableArrayType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitDependentSizedArrayType( + const DependentSizedArrayType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitVectorType(const VectorType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitExtVectorType(const ExtVectorType* T) { + return Visit(T->getElementType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitFunctionProtoType( + const FunctionProtoType* T) { + for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(), + AEnd = T->arg_type_end(); + A != AEnd; ++A) { + if (Visit(*A)) + return true; + } + + return Visit(T->getResultType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitFunctionNoProtoType( + const FunctionNoProtoType* T) { + return Visit(T->getResultType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitUnresolvedUsingType( + const UnresolvedUsingType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitTypeOfExprType(const TypeOfExprType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitTypeOfType(const TypeOfType* T) { + return Visit(T->getUnderlyingType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitAutoType(const AutoType *T) { + return Visit(T->getDeducedType()); +} + +bool UnnamedLocalNoLinkageFinder::VisitRecordType(const RecordType* T) { + return VisitTagDecl(T->getDecl()); +} + +bool UnnamedLocalNoLinkageFinder::VisitEnumType(const EnumType* T) { + return VisitTagDecl(T->getDecl()); +} + +bool UnnamedLocalNoLinkageFinder::VisitTemplateTypeParmType( + const TemplateTypeParmType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitSubstTemplateTypeParmPackType( + const SubstTemplateTypeParmPackType *) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitTemplateSpecializationType( + const TemplateSpecializationType*) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitInjectedClassNameType( + const InjectedClassNameType* T) { + return VisitTagDecl(T->getDecl()); +} + +bool UnnamedLocalNoLinkageFinder::VisitDependentNameType( + const DependentNameType* T) { + return VisitNestedNameSpecifier(T->getQualifier()); +} + +bool UnnamedLocalNoLinkageFinder::VisitDependentTemplateSpecializationType( + const DependentTemplateSpecializationType* T) { + return VisitNestedNameSpecifier(T->getQualifier()); +} + +bool UnnamedLocalNoLinkageFinder::VisitPackExpansionType( + const PackExpansionType* T) { + return Visit(T->getPattern()); +} + +bool UnnamedLocalNoLinkageFinder::VisitObjCObjectType(const ObjCObjectType *) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitObjCInterfaceType( + const ObjCInterfaceType *) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitObjCObjectPointerType( + const ObjCObjectPointerType *) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { + if (Tag->getDeclContext()->isFunctionOrMethod()) { + S.Diag(SR.getBegin(), diag::ext_template_arg_local_type) + << S.Context.getTypeDeclType(Tag) << SR; + return true; + } + + if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl()) { + S.Diag(SR.getBegin(), diag::ext_template_arg_unnamed_type) << SR; + S.Diag(Tag->getLocation(), diag::note_template_unnamed_type_here); + return true; + } + + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( + NestedNameSpecifier *NNS) { + if (NNS->getPrefix() && VisitNestedNameSpecifier(NNS->getPrefix())) + return true; + + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::Global: + return false; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + return Visit(QualType(NNS->getAsType(), 0)); + } + return false; +} + + /// \brief Check a template argument against its corresponding /// template type parameter. /// @@ -2346,36 +2888,24 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *ArgInfo) { assert(ArgInfo && "invalid TypeSourceInfo"); QualType Arg = ArgInfo->getType(); + SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); + + if (Arg->isVariablyModifiedType()) { + return Diag(SR.getBegin(), diag::err_variably_modified_template_arg) << Arg; + } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) { + return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR; + } // C++03 [temp.arg.type]p2: // A local type, a type with no linkage, an unnamed type or a type // compounded from any of these types shall not be used as a // template-argument for a template type-parameter. + // // C++0x allows these, and even in C++03 we allow them as an extension with // a warning. - SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); - if (!LangOpts.CPlusPlus0x) { - const TagType *Tag = 0; - if (const EnumType *EnumT = Arg->getAs<EnumType>()) - Tag = EnumT; - else if (const RecordType *RecordT = Arg->getAs<RecordType>()) - Tag = RecordT; - if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) { - SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); - Diag(SR.getBegin(), diag::ext_template_arg_local_type) - << QualType(Tag, 0) << SR; - } else if (Tag && !Tag->getDecl()->getDeclName() && - !Tag->getDecl()->getTypedefForAnonDecl()) { - Diag(SR.getBegin(), diag::ext_template_arg_unnamed_type) << SR; - Diag(Tag->getDecl()->getLocation(), - diag::note_template_unnamed_type_here); - } - } - - if (Arg->isVariablyModifiedType()) { - return Diag(SR.getBegin(), diag::err_variably_modified_template_arg) << Arg; - } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) { - return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR; + if (!LangOpts.CPlusPlus0x && Arg->hasUnnamedOrLocalType()) { + UnnamedLocalNoLinkageFinder Finder(*this, SR); + (void)Finder.Visit(Context.getCanonicalType(Arg)); } return false; @@ -2383,7 +2913,7 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, /// \brief Checks whether the given template argument is the address /// of an object or function according to C++ [temp.arg.nontype]p1. -static bool +static bool CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, @@ -2410,13 +2940,15 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // corresponding template-parameter is a reference; or DeclRefExpr *DRE = 0; - // Ignore (and complain about) any excess parentheses. + // In C++98/03 mode, give an extension warning on any extra parentheses. + // See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773 + bool ExtraParens = false; while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) { - if (!Invalid) { + if (!Invalid && !ExtraParens && !S.getLangOptions().CPlusPlus0x) { S.Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_extra_parens) + diag::ext_template_arg_extra_parens) << Arg->getSourceRange(); - Invalid = true; + ExtraParens = true; } Arg = Parens->getSubExpr(); @@ -2443,7 +2975,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // Stop checking the precise nature of the argument if it is value dependent, // it should be checked when instantiated. if (Arg->isValueDependent()) { - Converted = TemplateArgument(ArgIn->Retain()); + Converted = TemplateArgument(ArgIn); return false; } @@ -2522,7 +3054,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // A value of reference type is not an object. if (Var->getType()->isReferenceType()) { - S.Diag(Arg->getSourceRange().getBegin(), + S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_reference_var) << Var->getType() << Arg->getSourceRange(); S.Diag(Param->getLocation(), diag::note_template_param_here); @@ -2586,9 +3118,9 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, return true; } - if (ParamType->isPointerType() && + if (ParamType->isPointerType() && !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() && - S.IsQualificationConversion(ArgType, ParamType)) { + S.IsQualificationConversion(ArgType, ParamType, false)) { // For pointer-to-object types, qualification conversions are // permitted. } else { @@ -2613,7 +3145,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, << Arg->getSourceRange(); S.Diag(Param->getLocation(), diag::note_template_param_here); return true; - } + } } } @@ -2642,7 +3174,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, /// \brief Checks whether the given template argument is a pointer to /// member constant according to C++ [temp.arg.nontype]p1. -bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, +bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, TemplateArgument &Converted) { bool Invalid = false; @@ -2658,13 +3190,15 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, // -- a pointer to member expressed as described in 5.3.1. DeclRefExpr *DRE = 0; - // Ignore (and complain about) any excess parentheses. + // In C++98/03 mode, give an extension warning on any extra parentheses. + // See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773 + bool ExtraParens = false; while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) { - if (!Invalid) { + if (!Invalid && !ExtraParens && !getLangOptions().CPlusPlus0x) { Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_extra_parens) + diag::ext_template_arg_extra_parens) << Arg->getSourceRange(); - Invalid = true; + ExtraParens = true; } Arg = Parens->getSubExpr(); @@ -2677,26 +3211,26 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, if (DRE && !DRE->getQualifier()) DRE = 0; } - } + } // A constant of pointer-to-member type. else if ((DRE = dyn_cast<DeclRefExpr>(Arg))) { if (ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) { if (VD->getType()->isMemberPointerType()) { if (isa<NonTypeTemplateParmDecl>(VD) || - (isa<VarDecl>(VD) && + (isa<VarDecl>(VD) && Context.getCanonicalType(VD->getType()).isConstQualified())) { if (Arg->isTypeDependent() || Arg->isValueDependent()) - Converted = TemplateArgument(Arg->Retain()); + Converted = TemplateArgument(Arg); else Converted = TemplateArgument(VD->getCanonicalDecl()); return Invalid; } } } - + DRE = 0; } - + if (!DRE) return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_pointer_to_member_form) @@ -2710,7 +3244,7 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, // Okay: this is the address of a non-static member, and therefore // a member pointer constant. if (Arg->isTypeDependent() || Arg->isValueDependent()) - Converted = TemplateArgument(Arg->Retain()); + Converted = TemplateArgument(Arg); else Converted = TemplateArgument(DRE->getDecl()->getCanonicalDecl()); return Invalid; @@ -2803,7 +3337,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch) << ArgType << ParamType; Diag(Param->getLocation(), diag::note_template_param_here); - return true; + return true; + } else if (ParamType->isBooleanType()) { + // This is an integral-to-boolean conversion. + ImpCastExprToType(Arg, ParamType, CK_IntegralToBoolean); } else if (IsIntegralPromotion(Arg, ArgType, ParamType) || !ParamType->isEnumeralType()) { // This is an integral promotion or conversion. @@ -2823,12 +3360,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (!Arg->isValueDependent()) { llvm::APSInt OldValue = Value; - - // Coerce the template argument's value to the value it will have + + // Coerce the template argument's value to the value it will have // based on the template parameter's type. unsigned AllowedBits = Context.getTypeSize(IntegerType); if (Value.getBitWidth() != AllowedBits) - Value.extOrTrunc(AllowedBits); + Value = Value.extOrTrunc(AllowedBits); Value.setIsSigned(IntegerType->isSignedIntegerType()); // Complain if an unsigned parameter received a negative value. @@ -2879,7 +3416,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // from a template argument of type std::nullptr_t to a non-type // template parameter of type pointer to object, pointer to // function, or pointer-to-member, respectively. - if (ArgType->isNullPtrType() && + if (ArgType->isNullPtrType() && (ParamType->isPointerType() || ParamType->isMemberPointerType())) { Converted = TemplateArgument((NamedDecl *)0); return false; @@ -2910,7 +3447,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ->isFunctionType())) { if (Arg->getType() == Context.OverloadTy) { - if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, true, FoundResult)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) @@ -2921,13 +3458,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } else return true; } - + if (!ParamType->isMemberPointerType()) return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, + ParamType, Arg, Converted); - if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType())) { + if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(), + false)) { ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)); } else if (!Context.hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) { @@ -2950,7 +3488,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamType->getPointeeType()->isIncompleteOrObjectType() && "Only object pointers allowed here"); - return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, ParamType, Arg, Converted); } @@ -2966,8 +3504,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, "Only object references allowed here"); if (Arg->getType() == Context.OverloadTy) { - if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, - ParamRefType->getPointeeType(), + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, + ParamRefType->getPointeeType(), true, FoundResult)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) @@ -2978,8 +3516,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } else return true; } - - return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, ParamType, Arg, Converted); } @@ -2990,7 +3528,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Context.hasSameUnqualifiedType(ParamType, ArgType)) { // Types match exactly: nothing more to do here. - } else if (IsQualificationConversion(ArgType, ParamType)) { + } else if (IsQualificationConversion(ArgType, ParamType, false)) { ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)); } else { // We can't perform this conversion. @@ -3041,7 +3579,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), Param->getTemplateParameters(), - true, + true, TPL_TemplateTemplateArgumentMatch, Arg.getLocation()); } @@ -3050,7 +3588,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, /// declaration and the type of its corresponding non-type template /// parameter, produce an expression that properly refers to that /// declaration. -ExprResult +ExprResult Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc) { @@ -3058,7 +3596,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, "Only declaration template arguments permitted here"); ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); - if (VD->getDeclContext()->isRecord() && + if (VD->getDeclContext()->isRecord() && (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) { // If the value is a class member, we might have a pointer-to-member. // Determine whether the non-type template template parameter is of @@ -3073,37 +3611,46 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, ClassType.getTypePtr()); CXXScopeSpec SS; SS.setScopeRep(Qualifier); - ExprResult RefExpr = BuildDeclRefExpr(VD, - VD->getType().getNonReferenceType(), - Loc, - &SS); + + // The actual value-ness of this is unimportant, but for + // internal consistency's sake, references to instance methods + // are r-values. + ExprValueKind VK = VK_LValue; + if (isa<CXXMethodDecl>(VD) && cast<CXXMethodDecl>(VD)->isInstance()) + VK = VK_RValue; + + ExprResult RefExpr = BuildDeclRefExpr(VD, + VD->getType().getNonReferenceType(), + VK, + Loc, + &SS); if (RefExpr.isInvalid()) return ExprError(); - + RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); - + // We might need to perform a trailing qualification conversion, since // the element type on the parameter could be more qualified than the // element type in the expression we constructed. if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(), - ParamType.getUnqualifiedType())) { + ParamType.getUnqualifiedType(), false)) { Expr *RefE = RefExpr.takeAs<Expr>(); ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), CK_NoOp); RefExpr = Owned(RefE); } - + assert(!RefExpr.isInvalid() && Context.hasSameType(((Expr*) RefExpr.get())->getType(), ParamType.getUnqualifiedType())); return move(RefExpr); } } - + QualType T = VD->getType().getNonReferenceType(); if (ParamType->isPointerType()) { // When the non-type template parameter is a pointer, take the // address of the declaration. - ExprResult RefExpr = BuildDeclRefExpr(VD, T, Loc); + ExprResult RefExpr = BuildDeclRefExpr(VD, T, VK_LValue, Loc); if (RefExpr.isInvalid()) return ExprError(); @@ -3118,18 +3665,23 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, return move(RefExpr); } - + // Take the address of everything else return CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); } + ExprValueKind VK = VK_RValue; + // If the non-type template parameter has reference type, qualify the // resulting declaration reference with the extra qualifiers on the // type that the reference refers to. - if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>()) - T = Context.getQualifiedType(T, TargetRef->getPointeeType().getQualifiers()); - - return BuildDeclRefExpr(VD, T, Loc); + if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>()) { + VK = VK_LValue; + T = Context.getQualifiedType(T, + TargetRef->getPointeeType().getQualifiers()); + } + + return BuildDeclRefExpr(VD, T, VK, Loc); } /// \brief Construct a new expression that refers to the given @@ -3139,11 +3691,11 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, /// This routine takes care of the mapping from an integral template /// argument (which may have any integral type) to the appropriate /// literal value. -ExprResult +ExprResult Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc) { assert(Arg.getKind() == TemplateArgument::Integral && - "Operation is only value for integral template arguments"); + "Operation is only valid for integral template arguments"); QualType T = Arg.getIntegralType(); if (T->isCharType() || T->isWideCharType()) return Owned(new (Context) CharacterLiteral( @@ -3157,9 +3709,149 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, T, Loc)); - return Owned(IntegerLiteral::Create(Context, *Arg.getAsIntegral(), T, Loc)); + QualType BT; + if (const EnumType *ET = T->getAs<EnumType>()) + BT = ET->getDecl()->getPromotionType(); + else + BT = T; + + Expr *E = IntegerLiteral::Create(Context, *Arg.getAsIntegral(), BT, Loc); + if (T->isEnumeralType()) { + // FIXME: This is a hack. We need a better way to handle substituted + // non-type template parameters. + E = CStyleCastExpr::Create(Context, T, VK_RValue, CK_IntegralCast, + E, 0, + Context.getTrivialTypeSourceInfo(T, Loc), + Loc, Loc); + } + + return Owned(E); } +/// \brief Match two template parameters within template parameter lists. +static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, + bool Complain, + Sema::TemplateParameterListEqualKind Kind, + SourceLocation TemplateArgLoc) { + // Check the actual kind (type, non-type, template). + if (Old->getKind() != New->getKind()) { + if (Complain) { + unsigned NextDiag = diag::err_template_param_different_kind; + if (TemplateArgLoc.isValid()) { + S.Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_param_different_kind; + } + S.Diag(New->getLocation(), NextDiag) + << (Kind != Sema::TPL_TemplateMatch); + S.Diag(Old->getLocation(), diag::note_template_prev_declaration) + << (Kind != Sema::TPL_TemplateMatch); + } + + return false; + } + + // Check that both are parameter packs are neither are parameter packs. + // However, if we are matching a template template argument to a + // template template parameter, the template template parameter can have + // a parameter pack where the template template argument does not. + if (Old->isTemplateParameterPack() != New->isTemplateParameterPack() && + !(Kind == Sema::TPL_TemplateTemplateArgumentMatch && + Old->isTemplateParameterPack())) { + if (Complain) { + unsigned NextDiag = diag::err_template_parameter_pack_non_pack; + if (TemplateArgLoc.isValid()) { + S.Diag(TemplateArgLoc, + diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_parameter_pack_non_pack; + } + + unsigned ParamKind = isa<TemplateTypeParmDecl>(New)? 0 + : isa<NonTypeTemplateParmDecl>(New)? 1 + : 2; + S.Diag(New->getLocation(), NextDiag) + << ParamKind << New->isParameterPack(); + S.Diag(Old->getLocation(), diag::note_template_parameter_pack_here) + << ParamKind << Old->isParameterPack(); + } + + return false; + } + + // For non-type template parameters, check the type of the parameter. + if (NonTypeTemplateParmDecl *OldNTTP + = dyn_cast<NonTypeTemplateParmDecl>(Old)) { + NonTypeTemplateParmDecl *NewNTTP = cast<NonTypeTemplateParmDecl>(New); + + // If we are matching a template template argument to a template + // template parameter and one of the non-type template parameter types + // is dependent, then we must wait until template instantiation time + // to actually compare the arguments. + if (Kind == Sema::TPL_TemplateTemplateArgumentMatch && + (OldNTTP->getType()->isDependentType() || + NewNTTP->getType()->isDependentType())) + return true; + + if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { + if (Complain) { + unsigned NextDiag = diag::err_template_nontype_parm_different_type; + if (TemplateArgLoc.isValid()) { + S.Diag(TemplateArgLoc, + diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_nontype_parm_different_type; + } + S.Diag(NewNTTP->getLocation(), NextDiag) + << NewNTTP->getType() + << (Kind != Sema::TPL_TemplateMatch); + S.Diag(OldNTTP->getLocation(), + diag::note_template_nontype_parm_prev_declaration) + << OldNTTP->getType(); + } + + return false; + } + + return true; + } + + // For template template parameters, check the template parameter types. + // The template parameter lists of template template + // parameters must agree. + if (TemplateTemplateParmDecl *OldTTP + = dyn_cast<TemplateTemplateParmDecl>(Old)) { + TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New); + return S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), + OldTTP->getTemplateParameters(), + Complain, + (Kind == Sema::TPL_TemplateMatch + ? Sema::TPL_TemplateTemplateParmMatch + : Kind), + TemplateArgLoc); + } + + return true; +} + +/// \brief Diagnose a known arity mismatch when comparing template argument +/// lists. +static +void DiagnoseTemplateParameterListArityMismatch(Sema &S, + TemplateParameterList *New, + TemplateParameterList *Old, + Sema::TemplateParameterListEqualKind Kind, + SourceLocation TemplateArgLoc) { + unsigned NextDiag = diag::err_template_param_list_different_arity; + if (TemplateArgLoc.isValid()) { + S.Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_param_list_different_arity; + } + S.Diag(New->getTemplateLoc(), NextDiag) + << (New->size() > Old->size()) + << (Kind != Sema::TPL_TemplateMatch) + << SourceRange(New->getTemplateLoc(), New->getRAngleLoc()); + S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration) + << (Kind != Sema::TPL_TemplateMatch) + << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); +} /// \brief Determine whether the given template parameter lists are /// equivalent. @@ -3190,120 +3882,66 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, bool Complain, TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) { - if (Old->size() != New->size()) { - if (Complain) { - unsigned NextDiag = diag::err_template_param_list_different_arity; - 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()) - << (Kind != TPL_TemplateMatch) - << SourceRange(New->getTemplateLoc(), New->getRAngleLoc()); - Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration) - << (Kind != TPL_TemplateMatch) - << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); - } + if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) { + if (Complain) + DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, + TemplateArgLoc); return false; } + // C++0x [temp.arg.template]p3: + // A template-argument matches a template template-parameter (call it P) + // when each of the template parameters in the template-parameter-list of + // the template-argument's corresponding class template or template alias + // (call it A) matches the corresponding template parameter in the + // template-parameter-list of P. [...] + TemplateParameterList::iterator NewParm = New->begin(); + TemplateParameterList::iterator NewParmEnd = New->end(); for (TemplateParameterList::iterator OldParm = Old->begin(), - OldParmEnd = Old->end(), NewParm = New->begin(); - OldParm != OldParmEnd; ++OldParm, ++NewParm) { - if ((*OldParm)->getKind() != (*NewParm)->getKind()) { - if (Complain) { - unsigned NextDiag = diag::err_template_param_different_kind; - if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_param_different_kind; - } - Diag((*NewParm)->getLocation(), NextDiag) - << (Kind != TPL_TemplateMatch); - Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration) - << (Kind != TPL_TemplateMatch); - } - return false; - } + OldParmEnd = Old->end(); + OldParm != OldParmEnd; ++OldParm) { + if (Kind != TPL_TemplateTemplateArgumentMatch || + !(*OldParm)->isTemplateParameterPack()) { + if (NewParm == NewParmEnd) { + if (Complain) + DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, + TemplateArgLoc); - if (TemplateTypeParmDecl *OldTTP - = dyn_cast<TemplateTypeParmDecl>(*OldParm)) { - // Template type parameters are equivalent if either both are template - // type parameter packs or neither are (since we know we're at the same - // index). - TemplateTypeParmDecl *NewTTP = cast<TemplateTypeParmDecl>(*NewParm); - if (OldTTP->isParameterPack() != NewTTP->isParameterPack()) { - // FIXME: Implement the rules in C++0x [temp.arg.template]p5 that - // allow one to match a template parameter pack in the template - // parameter list of a template template parameter to one or more - // template parameters in the template parameter list of the - // corresponding template template argument. - if (Complain) { - unsigned NextDiag = diag::err_template_parameter_pack_non_pack; - if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, - diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_parameter_pack_non_pack; - } - Diag(NewTTP->getLocation(), NextDiag) - << 0 << NewTTP->isParameterPack(); - Diag(OldTTP->getLocation(), diag::note_template_parameter_pack_here) - << 0 << OldTTP->isParameterPack(); - } return false; } - } else if (NonTypeTemplateParmDecl *OldNTTP - = dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) { - // The types of non-type template parameters must agree. - NonTypeTemplateParmDecl *NewNTTP - = cast<NonTypeTemplateParmDecl>(*NewParm); - - // If we are matching a template template argument to a template - // template parameter and one of the non-type template parameter types - // is dependent, then we must wait until template instantiation time - // to actually compare the arguments. - if (Kind == TPL_TemplateTemplateArgumentMatch && - (OldNTTP->getType()->isDependentType() || - NewNTTP->getType()->isDependentType())) - continue; - - if (Context.getCanonicalType(OldNTTP->getType()) != - Context.getCanonicalType(NewNTTP->getType())) { - if (Complain) { - unsigned NextDiag = diag::err_template_nontype_parm_different_type; - if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, - diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_nontype_parm_different_type; - } - Diag(NewNTTP->getLocation(), NextDiag) - << NewNTTP->getType() - << (Kind != TPL_TemplateMatch); - Diag(OldNTTP->getLocation(), - diag::note_template_nontype_parm_prev_declaration) - << OldNTTP->getType(); - } + + if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, + Kind, TemplateArgLoc)) return false; - } - } else { - // The template parameter lists of template template - // parameters must agree. - assert(isa<TemplateTemplateParmDecl>(*OldParm) && - "Only template template parameters handled here"); - TemplateTemplateParmDecl *OldTTP - = cast<TemplateTemplateParmDecl>(*OldParm); - TemplateTemplateParmDecl *NewTTP - = cast<TemplateTemplateParmDecl>(*NewParm); - if (!TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), - OldTTP->getTemplateParameters(), - Complain, - (Kind == TPL_TemplateMatch? TPL_TemplateTemplateParmMatch : Kind), - TemplateArgLoc)) + + ++NewParm; + continue; + } + + // C++0x [temp.arg.template]p3: + // [...] When P's template- parameter-list contains a template parameter + // pack (14.5.3), the template parameter pack will match zero or more + // template parameters or template parameter packs in the + // template-parameter-list of A with the same type and form as the + // template parameter pack in P (ignoring whether those template + // parameters are template parameter packs). + for (; NewParm != NewParmEnd; ++NewParm) { + if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, + Kind, TemplateArgLoc)) return false; } } + // Make sure we exhausted all of the arguments. + if (NewParm != NewParmEnd) { + if (Complain) + DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, + TemplateArgLoc); + + return false; + } + return true; } @@ -3343,18 +3981,18 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) { 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 specialization is well-formed in the current +/// \brief Check whether a specialization is well-formed in the current /// context. /// /// This routine determines whether a template specialization can be declared @@ -3365,7 +4003,7 @@ static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) { /// /// \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, +/// a member of a class template (member function, static data member, /// member class). /// /// \param PrevDecl the previous declaration of this entity, if any. @@ -3386,14 +4024,11 @@ static bool CheckTemplateSpecializationScope(Sema &S, // 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)) { + if (isa<ClassTemplateDecl>(Specialized)) EntityKind = IsPartialSpecialization? 1 : 0; - isTemplateSpecialization = true; - } else if (isa<FunctionTemplateDecl>(Specialized)) { + else if (isa<FunctionTemplateDecl>(Specialized)) EntityKind = 2; - isTemplateSpecialization = true; - } else if (isa<CXXMethodDecl>(Specialized)) + else if (isa<CXXMethodDecl>(Specialized)) EntityKind = 3; else if (isa<VarDecl>(Specialized)) EntityKind = 4; @@ -3429,38 +4064,53 @@ static bool CheckTemplateSpecializationScope(Sema &S, << Specialized; return 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). + // in any namespace scope in which its definition may be defined (14.5.1 + // and 14.5.2). bool ComplainedAboutScope = false; - DeclContext *SpecializedContext + DeclContext *SpecializedContext = Specialized->getDeclContext()->getEnclosingNamespaceContext(); DeclContext *DC = S.CurContext->getEnclosingNamespaceContext(); - if ((!PrevDecl || + 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, or in the enclosing namespace set. - if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) { + // C++ [temp.exp.spec]p2: + // An explicit specialization shall be declared in the namespace of which + // the template is a member, or, for member templates, in the namespace + // of which the enclosing class or enclosing class template is a member. + // An explicit specialization of a member function, member class or + // static data member of a class template shall be declared in the + // namespace of which the class template is a member. + // + // C++0x [temp.expl.spec]p2: + // An explicit specialization shall be declared in a namespace enclosing + // the specialized template. + if (!DC->InEnclosingNamespaceSetOf(SpecializedContext) && + !(S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext))) { + bool IsCPlusPlus0xExtension + = !S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext); if (isa<TranslationUnitDecl>(SpecializedContext)) - S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global) - << EntityKind << Specialized; + S.Diag(Loc, IsCPlusPlus0xExtension + ? diag::ext_template_spec_decl_out_of_scope_global + : 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(Loc, IsCPlusPlus0xExtension + ? diag::ext_template_spec_decl_out_of_scope + : diag::err_template_spec_decl_out_of_scope) + << EntityKind << Specialized + << cast<NamedDecl>(SpecializedContext); + S.Diag(Specialized->getLocation(), diag::note_specialized_entity); ComplainedAboutScope = true; } } - - // Make sure that this redeclaration (or definition) occurs in an enclosing + + // Make sure that this redeclaration (or definition) occurs in an enclosing // namespace. - // Note that HandleDeclarator() performs this check for explicit + // 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. @@ -3475,77 +4125,44 @@ static bool CheckTemplateSpecializationScope(Sema &S, S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope) << EntityKind << Specialized << cast<NamedDecl>(SpecializedContext); - + S.Diag(Specialized->getLocation(), diag::note_specialized_entity); } - + // 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. -/// -/// \param TemplateParams the template parameters of the primary class -/// template. -/// -/// \param TemplateArg the template arguments of the class template -/// partial specialization. -/// -/// \param MirrorsPrimaryTemplate will be set true if the class -/// template partial specialization arguments are identical to the -/// implicit template arguments of the primary template. This is not -/// necessarily an error (C++0x), and it is left to the caller to diagnose -/// this condition when it is an error. -/// -/// \returns true if there was an error, false otherwise. -bool Sema::CheckClassTemplatePartialSpecializationArgs( - TemplateParameterList *TemplateParams, - const TemplateArgumentListBuilder &TemplateArgs, - bool &MirrorsPrimaryTemplate) { - // 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 - = dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(I))) { - if (Context.getCanonicalType(Context.getTypeDeclType(TTP)) != - Context.getCanonicalType(ArgList[I].getAsType())) - MirrorsPrimaryTemplate = false; - } else if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>( - TemplateParams->getParam(I))) { - TemplateName Name = ArgList[I].getAsTemplate(); - TemplateTemplateParmDecl *ArgDecl - = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl()); - if (!ArgDecl || - ArgDecl->getIndex() != TTP->getIndex() || - ArgDecl->getDepth() != TTP->getDepth()) - MirrorsPrimaryTemplate = false; - } - } +/// \brief Subroutine of Sema::CheckClassTemplatePartialSpecializationArgs +/// that checks non-type template partial specialization arguments. +static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, + NonTypeTemplateParmDecl *Param, + const TemplateArgument *Args, + unsigned NumArgs) { + for (unsigned I = 0; I != NumArgs; ++I) { + if (Args[I].getKind() == TemplateArgument::Pack) { + if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, + Args[I].pack_begin(), + Args[I].pack_size())) + return true; - NonTypeTemplateParmDecl *Param - = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I)); - if (!Param) { continue; } - Expr *ArgExpr = ArgList[I].getAsExpr(); + Expr *ArgExpr = Args[I].getAsExpr(); if (!ArgExpr) { - MirrorsPrimaryTemplate = false; continue; } + // We can have a pack expansion of any of the bullets below. + if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(ArgExpr)) + ArgExpr = Expansion->getPattern(); + + // Strip off any implicit casts we added as part of type checking. + while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgExpr)) + ArgExpr = ICE->getSubExpr(); + // C++ [temp.class.spec]p8: // A non-type argument is non-specialized if it is the name of a // non-type parameter. All other non-type arguments are @@ -3555,15 +4172,8 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( // specialized non-type arguments, so skip any non-specialized // arguments. if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) - if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl())) { - if (MirrorsPrimaryTemplate && - (Param->getIndex() != NTTP->getIndex() || - Param->getDepth() != NTTP->getDepth())) - MirrorsPrimaryTemplate = false; - + if (isa<NonTypeTemplateParmDecl>(DRE->getDecl())) continue; - } // C++ [temp.class.spec]p9: // Within the argument list of a class template partial @@ -3573,7 +4183,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( // specialization except when the argument expression is a // simple identifier. if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) { - Diag(ArgExpr->getLocStart(), + S.Diag(ArgExpr->getLocStart(), diag::err_dependent_non_type_arg_in_partial_spec) << ArgExpr->getSourceRange(); return true; @@ -3583,15 +4193,42 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( // specialized non-type argument shall not be dependent on a // parameter of the specialization. if (Param->getType()->isDependentType()) { - Diag(ArgExpr->getLocStart(), + S.Diag(ArgExpr->getLocStart(), diag::err_dependent_typed_non_type_arg_in_partial_spec) << Param->getType() << ArgExpr->getSourceRange(); - Diag(Param->getLocation(), diag::note_template_param_here); + S.Diag(Param->getLocation(), diag::note_template_param_here); return true; } + } + + return false; +} - MirrorsPrimaryTemplate = false; +/// \brief Check the non-type template arguments of a class template +/// partial specialization according to C++ [temp.class.spec]p9. +/// +/// \param TemplateParams the template parameters of the primary class +/// template. +/// +/// \param TemplateArg the template arguments of the class template +/// partial specialization. +/// +/// \returns true if there was an error, false otherwise. +static bool CheckClassTemplatePartialSpecializationArgs(Sema &S, + TemplateParameterList *TemplateParams, + llvm::SmallVectorImpl<TemplateArgument> &TemplateArgs) { + const TemplateArgument *ArgList = TemplateArgs.data(); + + for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { + NonTypeTemplateParmDecl *Param + = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I)); + if (!Param) + continue; + + if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, + &ArgList[I], 1)) + return true; } return false; @@ -3635,7 +4272,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (!ClassTemplate) { Diag(TemplateNameLoc, diag::err_not_class_template_specialization) - << (Name.getAsTemplateDecl() && + << (Name.getAsTemplateDecl() && isa<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())); return true; } @@ -3657,7 +4294,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Invalid); if (Invalid) return true; - + unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size(); if (TemplateParams) --NumMatchedTemplateParamLists; @@ -3665,6 +4302,12 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (TemplateParams && TemplateParams->size() > 0) { isPartialSpecialization = true; + if (TUK == TUK_Friend) { + Diag(KWLoc, diag::err_partial_specialization_friend) + << SourceRange(LAngleLoc, RAngleLoc); + return true; + } + // C++ [temp.class.spec]p10: // The template parameter list of a specialization shall not // contain default template argument values. @@ -3731,48 +4374,33 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateArgs.setRAngleLoc(RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); + // Check for unexpanded parameter packs in any of the template arguments. + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + if (DiagnoseUnexpandedParameterPack(TemplateArgs[I], + UPPC_PartialSpecialization)) + return true; + // Check that the template argument list is well-formed for this // template. - TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), - TemplateArgs.size()); + llvm::SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, false, Converted)) return true; - assert((Converted.structuredSize() == - ClassTemplate->getTemplateParameters()->size()) && + assert((Converted.size() == ClassTemplate->getTemplateParameters()->size()) && "Converted template argument list is too short!"); // Find the class template (partial) specialization declaration that // corresponds to these arguments. if (isPartialSpecialization) { - bool MirrorsPrimaryTemplate; - if (CheckClassTemplatePartialSpecializationArgs( + if (CheckClassTemplatePartialSpecializationArgs(*this, ClassTemplate->getTemplateParameters(), - Converted, MirrorsPrimaryTemplate)) + Converted)) return true; - 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. - Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) - << (TUK == TUK_Definition) - << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); - return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, - ClassTemplate->getIdentifier(), - TemplateNameLoc, - Attr, - TemplateParams, - AS_none); - } - - // FIXME: Diagnose friend partial specializations - - if (!Name.isDependent() && + if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs.getArgumentArray(), + TemplateArgs.getArgumentArray(), TemplateArgs.size())) { Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) << ClassTemplate->getDeclName(); @@ -3786,27 +4414,27 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (isPartialSpecialization) // FIXME: Template parameter list matters, too PrevDecl - = ClassTemplate->findPartialSpecialization(Converted.getFlatArguments(), - Converted.flatSize(), + = ClassTemplate->findPartialSpecialization(Converted.data(), + Converted.size(), InsertPos); else PrevDecl - = ClassTemplate->findSpecialization(Converted.getFlatArguments(), - Converted.flatSize(), InsertPos); + = ClassTemplate->findSpecialization(Converted.data(), + Converted.size(), InsertPos); ClassTemplateSpecializationDecl *Specialization = 0; // Check whether we can declare a class template specialization in // the current scope. if (TUK != TUK_Friend && - CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl, - TemplateNameLoc, + CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl, + TemplateNameLoc, isPartialSpecialization)) return true; - + // The canonical type QualType CanonType; - if (PrevDecl && + if (PrevDecl && (PrevDecl->getSpecializationKind() == TSK_Undeclared || TUK == TUK_Friend)) { // Since the only prior class template specialization with these @@ -3823,8 +4451,25 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // arguments of the class template partial specialization. TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); CanonType = Context.getTemplateSpecializationType(CanonTemplate, - Converted.getFlatArguments(), - Converted.flatSize()); + Converted.data(), + Converted.size()); + + if (Context.hasSameType(CanonType, + ClassTemplate->getInjectedClassNameSpecialization())) { + // C++ [temp.class.spec]p9b3: + // + // -- 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) + << (TUK == TUK_Definition) + << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); + return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, + ClassTemplate->getIdentifier(), + TemplateNameLoc, + Attr, + TemplateParams, + AS_none); + } // Create a new class template partial specialization declaration node. ClassTemplatePartialSpecializationDecl *PrevPartial @@ -3837,7 +4482,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateNameLoc, TemplateParams, ClassTemplate, - Converted, + Converted.data(), + Converted.size(), TemplateArgs, CanonType, PrevPartial, @@ -3853,18 +4499,18 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, ClassTemplate->AddPartialSpecialization(Partial, InsertPos); Specialization = Partial; - // If we are providing an explicit specialization of a member class + // If we are providing an explicit specialization of a member class // template specialization, make a note of that. if (PrevPartial && PrevPartial->getInstantiatedFromMember()) PrevPartial->setMemberSpecialization(); - + // Check that all of the template parameters of the class template // partial specialization are deducible from the template // arguments. If not, this class template partial specialization // will never be used. llvm::SmallVector<bool, 8> DeducibleParams; DeducibleParams.resize(TemplateParams->size()); - MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, + MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, TemplateParams->getDepth(), DeducibleParams); unsigned NumNonDeducible = 0; @@ -3898,7 +4544,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, - Converted, + Converted.data(), + Converted.size(), PrevDecl); SetNestedNameSpecifier(Specialization, SS); if (NumMatchedTemplateParamLists > 0 && SS.isSet()) { @@ -3915,9 +4562,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // 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 + // 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 + // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) { bool Okay = false; @@ -3934,14 +4581,14 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) << Context.getTypeDeclType(Specialization) << Range; - Diag(PrevDecl->getPointOfInstantiation(), + Diag(PrevDecl->getPointOfInstantiation(), diag::note_instantiation_required_here) - << (PrevDecl->getTemplateSpecializationKind() + << (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); @@ -3958,6 +4605,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } } + if (Attr) + ProcessDeclAttributeList(S, Specialization, Attr); + // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization // itself. This means that we'll pretty-print the type retrieved @@ -4015,9 +4665,7 @@ Decl *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; + DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); if (FTI.hasPrototype) { // FIXME: Diagnose arguments without names in C. @@ -4047,12 +4695,12 @@ static void StripImplicitInstantiation(NamedDecl *D) { } } -/// \brief Diagnose cases where we have an explicit template specialization +/// \brief Diagnose cases where we have an explicit template specialization /// before/after an explicit template instantiation, producing diagnostics -/// for those cases where they are required and determining whether the +/// for those cases where they are required and determining whether the /// new specialization/instantiation will have any effect. /// -/// \param NewLoc the location of the new explicit specialization or +/// \param NewLoc the location of the new explicit specialization or /// instantiation. /// /// \param NewTSK the kind of the new explicit specialization or instantiation. @@ -4061,10 +4709,10 @@ static void StripImplicitInstantiation(NamedDecl *D) { /// /// \param PrevTSK the kind of the old explicit specialization or instantiatin. /// -/// \param PrevPointOfInstantiation if valid, indicates where the previus +/// \param PrevPointOfInstantiation if valid, indicates where the previus /// declaration was instantiated (either implicitly or explicitly). /// -/// \param HasNoEffect will be set to true to indicate that the new +/// \param HasNoEffect will be set to true to indicate that the new /// specialization or instantiation has no effect and should be ignored. /// /// \returns true if there was an error that should prevent the introduction of @@ -4077,18 +4725,18 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, SourceLocation PrevPointOfInstantiation, bool &HasNoEffect) { HasNoEffect = false; - + switch (NewTSK) { case TSK_Undeclared: case TSK_ImplicitInstantiation: assert(false && "Don't check implicit instantiations here"); return false; - + case TSK_ExplicitSpecialization: switch (PrevTSK) { case TSK_Undeclared: case TSK_ExplicitSpecialization: - // Okay, we're just specializing something that is either already + // Okay, we're just specializing something that is either already // explicitly specialized or has merely been mentioned without any // instantiation. return false; @@ -4101,17 +4749,17 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, return false; } // Fall through - + case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: - assert((PrevTSK == TSK_ImplicitInstantiation || - PrevPointOfInstantiation.isValid()) && + assert((PrevTSK == TSK_ImplicitInstantiation || + PrevPointOfInstantiation.isValid()) && "Explicit instantiation without point of instantiation?"); - + // C++ [temp.expl.spec]p6: - // If a template, a member template or the member of a class template + // 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 + // 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. for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) { @@ -4124,41 +4772,41 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, << PrevDecl; Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) << (PrevTSK != TSK_ImplicitInstantiation); - + return true; } break; - + case TSK_ExplicitInstantiationDeclaration: switch (PrevTSK) { case TSK_ExplicitInstantiationDeclaration: // This explicit instantiation declaration is redundant (that's okay). HasNoEffect = true; return false; - + case TSK_Undeclared: case TSK_ImplicitInstantiation: // We're explicitly instantiating something that may have already been // implicitly instantiated; that's fine. return false; - + case TSK_ExplicitSpecialization: // C++0x [temp.explicit]p4: // For a given set of template parameters, if an explicit instantiation - // of a template appears after a declaration of an explicit + // of a template appears after a declaration of an explicit // specialization for that template, the explicit instantiation has no // effect. HasNoEffect = true; return false; - + case TSK_ExplicitInstantiationDefinition: // C++0x [temp.explicit]p10: - // If an entity is the subject of both an explicit instantiation - // declaration and an explicit instantiation definition in the same + // If an entity is the subject of both an explicit instantiation + // declaration and an explicit instantiation definition in the same // translation unit, the definition shall follow the declaration. - Diag(NewLoc, + Diag(NewLoc, diag::err_explicit_instantiation_declaration_after_definition); - Diag(PrevPointOfInstantiation, + Diag(PrevPointOfInstantiation, diag::note_explicit_instantiation_definition_here); assert(PrevPointOfInstantiation.isValid() && "Explicit instantiation without point of instantiation?"); @@ -4166,7 +4814,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, return false; } break; - + case TSK_ExplicitInstantiationDefinition: switch (PrevTSK) { case TSK_Undeclared: @@ -4174,7 +4822,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // We're explicitly instantiating something that may have already been // implicitly instantiated; that's fine. return false; - + case TSK_ExplicitSpecialization: // C++ DR 259, C++0x [temp.explicit]p4: // For a given set of template parameters, if an explicit @@ -4182,7 +4830,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // an explicit specialization for that template, the explicit // instantiation has no effect. // - // In C++98/03 mode, we only give an extension warning here, because it + // In C++98/03 mode, we only give an extension warning here, because it // is not harmful to try to explicitly instantiate something that // has been explicitly specialized. if (!getLangOptions().CPlusPlus0x) { @@ -4193,12 +4841,12 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, } HasNoEffect = true; return false; - + case TSK_ExplicitInstantiationDeclaration: // We're explicity instantiating a definition for something for which we - // were previously asked to suppress instantiations. That's fine. + // were previously asked to suppress instantiations. That's fine. return false; - + case TSK_ExplicitInstantiationDefinition: // C++0x [temp.spec]p5: // For a given template and a given set of template-arguments, @@ -4206,16 +4854,16 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // in a program, Diag(NewLoc, diag::err_explicit_instantiation_duplicate) << PrevDecl; - Diag(PrevPointOfInstantiation, + Diag(PrevPointOfInstantiation, diag::note_previous_explicit_instantiation); HasNoEffect = true; - return false; + return false; } break; } - + assert(false && "Missing specialization/instantiation case?"); - + return false; } @@ -4281,21 +4929,21 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // The set of function template specializations that could match this // explicit function template specialization. UnresolvedSet<8> Candidates; - + DeclContext *FDLookupContext = FD->getDeclContext()->getRedeclContext(); for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); I != E; ++I) { NamedDecl *Ovl = (*I)->getUnderlyingDecl(); if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Ovl)) { - // Only consider templates found within the same semantic lookup scope as + // Only consider templates found within the same semantic lookup scope as // FD. if (!FDLookupContext->InEnclosingNamespaceSetOf( Ovl->getDeclContext()->getRedeclContext())) continue; - + // C++ [temp.expl.spec]p11: - // A trailing template-argument can be left unspecified in the - // template-id naming an explicit function template specialization + // 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. @@ -4312,17 +4960,17 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, (void)TDK; continue; } - + // Record this candidate. Candidates.addDecl(Specialization, I.getAccess()); } } - + // Find the most specialized function template. UnresolvedSetIterator Result = getMostSpecialized(Candidates.begin(), Candidates.end(), - TPOC_Other, FD->getLocation(), - PDiag(diag::err_function_template_spec_no_match) + TPOC_Other, 0, FD->getLocation(), + PDiag(diag::err_function_template_spec_no_match) << FD->getDeclName(), PDiag(diag::err_function_template_spec_ambiguous) << FD->getDeclName() << (ExplicitTemplateArgs != 0), @@ -4333,27 +4981,27 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Ignore access information; it doesn't figure into redeclaration checking. FunctionDecl *Specialization = cast<FunctionDecl>(*Result); Specialization->setLocation(FD->getLocation()); - + // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . // If this is a friend declaration, then we're not really declaring // an explicit specialization. bool isFriend = (FD->getFriendObjectKind() != Decl::FOK_None); - + // Check the scope of this explicit specialization. if (!isFriend && - CheckTemplateSpecializationScope(*this, + CheckTemplateSpecializationScope(*this, Specialization->getPrimaryTemplate(), - Specialization, FD->getLocation(), + Specialization, FD->getLocation(), false)) 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 specialization shall be declared + // 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 + // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. FunctionTemplateSpecializationInfo *SpecInfo = Specialization->getTemplateSpecializationInfo(); @@ -4368,14 +5016,14 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, SpecInfo->getPointOfInstantiation(), HasNoEffect)) return true; - + // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. if (!isFriend) { SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); MarkUnusedFileScopedDecl(Specialization); } - + // Turn the given function declaration into a function template // specialization, with the template arguments from the previous // specialization. @@ -4399,7 +5047,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, /// \brief Perform semantic analysis for the given non-template member /// specialization. /// -/// This routine performs all of the semantic analysis required for an +/// 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. @@ -4410,7 +5058,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, /// \param Previous the set of declarations, one of which may be specialized /// by this function specialization; the set will be modified to contain the /// redeclared member. -bool +bool Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { assert(!isa<TemplateDecl>(Member) && "Only for non-template members"); @@ -4452,7 +5100,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { 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 @@ -4478,7 +5126,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { Previous.addDecl(Instantiation); return false; } - + // Make sure that this is a specialization of a member. if (!InstantiatedFrom) { Diag(Member->getLocation(), diag::err_spec_member_not_instantiated) @@ -4486,12 +5134,12 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { 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 + // 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 + // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. assert(MSInfo && "Member specialization info missing?"); @@ -4503,11 +5151,11 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { MSInfo->getPointOfInstantiation(), HasNoEffect)) return true; - + // Check the scope of this explicit specialization. - if (CheckTemplateSpecializationScope(*this, + if (CheckTemplateSpecializationScope(*this, InstantiatedFrom, - Instantiation, Member->getLocation(), + Instantiation, Member->getLocation(), false)) return true; @@ -4523,7 +5171,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { TSK_ExplicitSpecialization); InstantiationFunction->setLocation(Member->getLocation()); } - + cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction( cast<CXXMethodDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); @@ -4536,7 +5184,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { TSK_ExplicitSpecialization); InstantiationVar->setLocation(Member->getLocation()); } - + Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member), cast<VarDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); @@ -4550,12 +5198,12 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { 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. Previous.clear(); @@ -4571,28 +5219,28 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, bool WasQualifiedName) { DeclContext *OrigContext= D->getDeclContext()->getEnclosingNamespaceContext(); DeclContext *CurContext = S.CurContext->getRedeclContext(); - + if (CurContext->isRecord()) { S.Diag(InstLoc, diag::err_explicit_instantiation_in_class) << D; return true; } - + // C++0x [temp.explicit]p2: - // An explicit instantiation shall appear in an enclosing namespace of its + // An explicit instantiation shall appear in an enclosing namespace of its // template. // // This is DR275, which we do not retroactively apply to C++98/03. - if (S.getLangOptions().CPlusPlus0x && + if (S.getLangOptions().CPlusPlus0x && !CurContext->Encloses(OrigContext)) { if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(OrigContext)) - S.Diag(InstLoc, - S.getLangOptions().CPlusPlus0x? + S.Diag(InstLoc, + S.getLangOptions().CPlusPlus0x? diag::err_explicit_instantiation_out_of_scope : diag::warn_explicit_instantiation_out_of_scope_0x) << D << NS; else - S.Diag(InstLoc, + S.Diag(InstLoc, S.getLangOptions().CPlusPlus0x? diag::err_explicit_instantiation_must_be_global : diag::warn_explicit_instantiation_out_of_scope_0x) @@ -4602,8 +5250,8 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, } // C++0x [temp.explicit]p2: - // If the name declared in the explicit instantiation is an unqualified - // name, the explicit instantiation shall appear in the namespace where + // If the name declared in the explicit instantiation is an unqualified + // name, the explicit instantiation shall appear in the namespace where // its template is declared or, if that namespace is inline (7.3.1), any // namespace from its enclosing namespace set. if (WasQualifiedName) @@ -4612,7 +5260,7 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, if (CurContext->InEnclosingNamespaceSetOf(OrigContext)) return false; - S.Diag(InstLoc, + S.Diag(InstLoc, S.getLangOptions().CPlusPlus0x? diag::err_explicit_instantiation_unqualified_wrong_namespace : diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x) @@ -4625,9 +5273,9 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { if (!SS.isSet()) return false; - + // C++0x [temp.explicit]p2: - // If the explicit instantiation is for a member function, a member class + // If the explicit instantiation is for a member function, a member class // or a static data member of a class template specialization, the name of // the class template specialization in the qualified-id for the member // name shall be a simple-template-id. @@ -4635,7 +5283,7 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { // C++98 has the same restriction, just worded differently. for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); NNS; NNS = NNS->getPrefix()) - if (Type *T = NNS->getAsType()) + if (const Type *T = NNS->getAsType()) if (isa<TemplateSpecializationType>(T)) return true; @@ -4680,34 +5328,32 @@ Sema::ActOnExplicitInstantiation(Scope *S, // C++0x [temp.explicit]p2: // There are two forms of explicit instantiation: an explicit instantiation - // definition and an explicit instantiation declaration. An explicit - // instantiation declaration begins with the extern keyword. [...] + // definition and an explicit instantiation declaration. An explicit + // instantiation declaration begins with the extern keyword. [...] TemplateSpecializationKind TSK = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - + // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); // Check that the template argument list is well-formed for this // template. - TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), - TemplateArgs.size()); + llvm::SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, false, Converted)) return true; - assert((Converted.structuredSize() == - ClassTemplate->getTemplateParameters()->size()) && + assert((Converted.size() == ClassTemplate->getTemplateParameters()->size()) && "Converted template argument list is too short!"); // Find the class template specialization declaration that // corresponds to these arguments. void *InsertPos = 0; ClassTemplateSpecializationDecl *PrevDecl - = ClassTemplate->findSpecialization(Converted.getFlatArguments(), - Converted.flatSize(), InsertPos); + = ClassTemplate->findSpecialization(Converted.data(), + Converted.size(), InsertPos); TemplateSpecializationKind PrevDecl_TSK = PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared; @@ -4720,10 +5366,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, if (CheckExplicitInstantiationScope(*this, ClassTemplate, TemplateNameLoc, SS.isSet())) return true; - + ClassTemplateSpecializationDecl *Specialization = 0; - bool ReusedDecl = false; bool HasNoEffect = false; if (PrevDecl) { if (CheckSpecializationInstantiationRedecl(TemplateNameLoc, TSK, @@ -4745,7 +5390,6 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization = PrevDecl; Specialization->setLocation(TemplateNameLoc); PrevDecl = 0; - ReusedDecl = true; } } @@ -4757,7 +5401,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, - Converted, PrevDecl); + Converted.data(), + Converted.size(), + PrevDecl); SetNestedNameSpecifier(Specialization, SS); if (!HasNoEffect && !PrevDecl) { @@ -4851,7 +5497,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr, AS_none, MultiTemplateParamsArg(*this, 0, 0), - Owned, IsDependent); + Owned, IsDependent, false, false, + TypeResult()); assert(!IsDependent && "explicit instantiation of dependent name not yet handled"); if (!TagD) @@ -4866,7 +5513,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, if (Tag->isInvalidDecl()) return true; - + CXXRecordDecl *Record = cast<CXXRecordDecl>(Tag); CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); if (!Pattern) { @@ -4877,32 +5524,32 @@ Sema::ActOnExplicitInstantiation(Scope *S, } // C++0x [temp.explicit]p2: - // If the explicit instantiation is for a class or member class, the - // elaborated-type-specifier in the declaration shall include a + // If the explicit instantiation is for a class or member class, the + // elaborated-type-specifier in the declaration shall include a // simple-template-id. // // C++98 has the same restriction, just worded differently. if (!ScopeSpecifierHasTemplateId(SS)) Diag(TemplateLoc, diag::ext_explicit_instantiation_without_qualified_id) << Record << SS.getRange(); - + // C++0x [temp.explicit]p2: // There are two forms of explicit instantiation: an explicit instantiation - // definition and an explicit instantiation declaration. An explicit + // definition and an explicit instantiation declaration. An explicit // instantiation declaration begins with the extern keyword. [...] TemplateSpecializationKind TSK = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - + // C++0x [temp.explicit]p2: // [...] An explicit instantiation shall appear in an enclosing // namespace of its template. [...] // // This is C++ DR 275. CheckExplicitInstantiationScope(*this, Record, NameLoc, true); - + // Verify that it is okay to explicitly instantiate here. - CXXRecordDecl *PrevDecl + CXXRecordDecl *PrevDecl = cast_or_null<CXXRecordDecl>(Record->getPreviousDeclaration()); if (!PrevDecl && Record->getDefinition()) PrevDecl = Record; @@ -4910,23 +5557,23 @@ Sema::ActOnExplicitInstantiation(Scope *S, MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo(); bool HasNoEffect = false; assert(MSInfo && "No member specialization information?"); - if (CheckSpecializationInstantiationRedecl(TemplateLoc, TSK, + if (CheckSpecializationInstantiationRedecl(TemplateLoc, TSK, PrevDecl, MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation(), + MSInfo->getPointOfInstantiation(), HasNoEffect)) return true; if (HasNoEffect) return TagD; } - + CXXRecordDecl *RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition()); if (!RecordDef) { // C++ [temp.explicit]p3: - // A definition of a member class of a class template shall be in scope + // A definition of a member class of a class template shall be in scope // at the point of an explicit instantiation of the member class. - CXXRecordDecl *Def + CXXRecordDecl *Def = cast_or_null<CXXRecordDecl>(Pattern->getDefinition()); if (!Def) { Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member) @@ -4944,8 +5591,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, if (!RecordDef) return true; } - } - + } + // Instantiate all of the members of the class. InstantiateClassMembers(NameLoc, RecordDef, getTemplateInstantiationArgs(Record), TSK); @@ -4974,7 +5621,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::err_explicit_instantiation_requires_name) << D.getDeclSpec().getSourceRange() << D.getSourceRange(); - + return true; } @@ -4989,7 +5636,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, QualType R = T->getType(); 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) @@ -5003,31 +5650,31 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // Presumably, this also applies to member functions of class templates as // well. if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x) - Diag(D.getDeclSpec().getInlineSpecLoc(), + Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_explicit_instantiation_inline) <<FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); - + // FIXME: check for constexpr specifier. - + // C++0x [temp.explicit]p2: // There are two forms of explicit instantiation: an explicit instantiation - // definition and an explicit instantiation declaration. An explicit - // instantiation declaration begins with the extern keyword. [...] + // definition and an explicit instantiation declaration. An explicit + // instantiation declaration begins with the extern keyword. [...] TemplateSpecializationKind TSK = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - + LookupResult Previous(*this, NameInfo, LookupOrdinaryName); LookupParsedName(Previous, S, &D.getCXXScopeSpec()); 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 + // 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 true; - + VarDecl *Prev = Previous.getAsSingle<VarDecl>(); if (!Prev || !Prev->isStaticDataMember()) { // We expect to see a data data member here. @@ -5038,54 +5685,54 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, Diag((*P)->getLocation(), diag::note_explicit_instantiation_here); return true; } - + if (!Prev->getInstantiatedFromStaticDataMember()) { // FIXME: Check for explicit specialization? - Diag(D.getIdentifierLoc(), + 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; } - + // C++0x [temp.explicit]p2: - // If the explicit instantiation is for a member function, a member class + // If the explicit instantiation is for a member function, a member class // or a static data member of a class template specialization, the name of // the class template specialization in the qualified-id for the member // name shall be a simple-template-id. // // C++98 has the same restriction, just worded differently. if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) - Diag(D.getIdentifierLoc(), + Diag(D.getIdentifierLoc(), diag::ext_explicit_instantiation_without_qualified_id) << Prev << D.getCXXScopeSpec().getRange(); - + // Check the scope of this explicit instantiation. CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true); - + // Verify that it is okay to explicitly instantiate here. MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo(); assert(MSInfo && "Missing static data member specialization info?"); bool HasNoEffect = false; if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev, MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation(), + MSInfo->getPointOfInstantiation(), HasNoEffect)) return true; if (HasNoEffect) return (Decl*) 0; - + // Instantiate static data member. Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev); - + // FIXME: Create an ExplicitInstantiation node? return (Decl*) 0; } - - // If the declarator is a template-id, translate the parser's template + + // If the declarator is a template-id, translate the parser's template // argument list into our AST format. bool HasExplicitTemplateArgs = false; TemplateArgumentListInfo TemplateArgs; @@ -5100,11 +5747,11 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, 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 + // 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. UnresolvedSet<8> Matches; for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); @@ -5121,7 +5768,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, } } } - + FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Prev); if (!FunTmpl) continue; @@ -5129,21 +5776,21 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateDeductionInfo Info(Context, D.getIdentifierLoc()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK - = DeduceTemplateArguments(FunTmpl, + = DeduceTemplateArguments(FunTmpl, (HasExplicitTemplateArgs ? &TemplateArgs : 0), R, Specialization, Info)) { // FIXME: Keep track of almost-matches? (void)TDK; continue; } - + Matches.addDecl(Specialization, P.getAccess()); } - + // Find the most specialized function template specialization. UnresolvedSetIterator Result - = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, - D.getIdentifierLoc(), + = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, 0, + D.getIdentifierLoc(), PDiag(diag::err_explicit_instantiation_not_known) << Name, PDiag(diag::err_explicit_instantiation_ambiguous) << Name, PDiag(diag::note_explicit_instantiation_candidate)); @@ -5153,17 +5800,17 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // Ignore access control bits, we don't need them for redeclaration checking. FunctionDecl *Specialization = cast<FunctionDecl>(*Result); - + if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) { - Diag(D.getIdentifierLoc(), + 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; - } - + } + FunctionDecl *PrevDecl = Specialization->getPreviousDeclaration(); if (!PrevDecl && Specialization->isThisDeclarationADefinition()) PrevDecl = Specialization; @@ -5171,12 +5818,12 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (PrevDecl) { bool HasNoEffect = false; if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, - PrevDecl, - PrevDecl->getTemplateSpecializationKind(), + PrevDecl, + PrevDecl->getTemplateSpecializationKind(), PrevDecl->getPointOfInstantiation(), HasNoEffect)) return true; - + // FIXME: We may still want to build some representation of this // explicit specialization. if (HasNoEffect) @@ -5184,12 +5831,12 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, } Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); - + if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization); - + // C++0x [temp.explicit]p2: - // If the explicit instantiation is for a member function, a member class + // If the explicit instantiation is for a member function, a member class // or a static data member of a class template specialization, the name of // the class template specialization in the qualified-id for the member // name shall be a simple-template-id. @@ -5197,18 +5844,18 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // C++98 has the same restriction, just worded differently. FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); if (D.getName().getKind() != UnqualifiedId::IK_TemplateId && !FunTmpl && - D.getCXXScopeSpec().isSet() && + D.getCXXScopeSpec().isSet() && !ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) - Diag(D.getIdentifierLoc(), + Diag(D.getIdentifierLoc(), diag::ext_explicit_instantiation_without_qualified_id) << Specialization << D.getCXXScopeSpec().getRange(); - + CheckExplicitInstantiationScope(*this, - FunTmpl? (NamedDecl *)FunTmpl + FunTmpl? (NamedDecl *)FunTmpl : Specialization->getInstantiatedFromMemberFunction(), - D.getIdentifierLoc(), + D.getIdentifierLoc(), D.getCXXScopeSpec().isSet()); - + // FIXME: Create some kind of ExplicitInstantiationDecl here. return (Decl*) 0; } @@ -5238,8 +5885,8 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } TypeResult -Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, - const CXXScopeSpec &SS, const IdentifierInfo &II, +Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc) { NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); @@ -5249,8 +5896,8 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() && !getLangOptions().CPlusPlus0x) Diag(TypenameLoc, diag::ext_typename_outside_of_template) - << FixItHint::CreateRemoval(TypenameLoc); - + << FixItHint::CreateRemoval(TypenameLoc); + QualType T = CheckTypenameType(ETK_Typename, NNS, II, TypenameLoc, SS.getRange(), IdLoc); if (T.isNull()) @@ -5268,23 +5915,23 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, TL.setQualifierRange(SS.getRange()); cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(IdLoc); } - + return CreateParsedType(T, TSI); } TypeResult -Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, - const CXXScopeSpec &SS, SourceLocation TemplateLoc, +Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, SourceLocation TemplateLoc, ParsedType Ty) { if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() && !getLangOptions().CPlusPlus0x) Diag(TypenameLoc, diag::ext_typename_outside_of_template) - << FixItHint::CreateRemoval(TypenameLoc); - + << FixItHint::CreateRemoval(TypenameLoc); + TypeSourceInfo *InnerTSI = 0; QualType T = GetTypeFromParser(Ty, &InnerTSI); - assert(isa<TemplateSpecializationType>(T) && + assert(isa<TemplateSpecializationType>(T) && "Expected a template specialization type"); if (computeDeclContext(SS, false)) { @@ -5297,7 +5944,8 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, if (InnerTSI) Builder.pushFullCopy(InnerTSI->getTypeLoc()); else - Builder.push<TemplateSpecializationTypeLoc>(T).initialize(TemplateLoc); + Builder.push<TemplateSpecializationTypeLoc>(T).initialize(Context, + TemplateLoc); /* Note: NNS already embedded in template specialization type T. */ T = Context.getElaboratedType(ETK_Typename, /*NNS=*/0, T); @@ -5311,7 +5959,7 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, // TODO: it's really silly that we make a template specialization // type earlier only to drop it again here. - TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T); + const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T); DependentTemplateName *DTN = TST->getTemplateName().getAsDependentTemplateName(); assert(DTN && "dependent template has non-dependent name?"); @@ -5333,7 +5981,8 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, for (unsigned I = 0, E = TST->getNumArgs(); I != E; ++I) TL.setArgLocInfo(I, TSTL.getArgLocInfo(I)); } else { - TL.initializeLocal(SourceLocation()); + // FIXME: Poor source-location information here. + TL.initializeLocal(Context, TemplateLoc); } TL.setKeywordLoc(TypenameLoc); TL.setQualifierRange(SS.getRange()); @@ -5377,13 +6026,30 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, case LookupResult::NotFound: DiagID = diag::err_typename_nested_not_found; break; - + + case LookupResult::FoundUnresolvedValue: { + // We found a using declaration that is a value. Most likely, the using + // declaration itself is meant to have the 'typename' keyword. + SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : NNSRange.getBegin(), + IILoc); + Diag(IILoc, diag::err_typename_refers_to_using_value_decl) + << Name << Ctx << FullRange; + if (UnresolvedUsingValueDecl *Using + = dyn_cast<UnresolvedUsingValueDecl>(Result.getRepresentativeDecl())){ + SourceLocation Loc = Using->getTargetNestedNameRange().getBegin(); + Diag(Loc, diag::note_using_value_decl_missing_typename) + << FixItHint::CreateInsertion(Loc, "typename "); + } + } + // Fall through to create a dependent typename type, from which we can recover + // better. + case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. return Context.getDependentNameType(Keyword, NNS, &II); case LookupResult::Found: - if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { + if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { // We found a type. Build an ElaboratedType, since the // typename-specifier was just sugar. return Context.getElaboratedType(ETK_Typename, NNS, @@ -5394,7 +6060,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, Referenced = Result.getFoundDecl(); break; - case LookupResult::FoundUnresolvedValue: + llvm_unreachable("unresolved using decl in non-dependent context"); return QualType(); @@ -5427,7 +6093,7 @@ namespace { public: typedef TreeTransform<CurrentInstantiationRebuilder> inherited; - + CurrentInstantiationRebuilder(Sema &SemaRef, SourceLocation Loc, DeclarationName Entity) @@ -5507,7 +6173,7 @@ bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(), DeclarationName()); - NestedNameSpecifier *Rebuilt = + NestedNameSpecifier *Rebuilt = Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange()); if (!Rebuilt) return true; @@ -5520,99 +6186,38 @@ bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { std::string Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgumentList &Args) { - // FIXME: For variadic templates, we'll need to get the structured list. - return getTemplateArgumentBindingsText(Params, Args.getFlatArgumentList(), - Args.flat_size()); + return getTemplateArgumentBindingsText(Params, Args.data(), Args.size()); } std::string Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgument *Args, unsigned NumArgs) { - std::string Result; + llvm::SmallString<128> Str; + llvm::raw_svector_ostream Out(Str); if (!Params || Params->size() == 0 || NumArgs == 0) - return Result; - + return std::string(); + for (unsigned I = 0, N = Params->size(); I != N; ++I) { if (I >= NumArgs) break; - + if (I == 0) - Result += "[with "; + Out << "[with "; else - Result += ", "; - + Out << ", "; + if (const IdentifierInfo *Id = Params->getParam(I)->getIdentifier()) { - Result += Id->getName(); + Out << 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::Template: { - std::string Str; - llvm::raw_string_ostream OS(Str); - Args[I].getAsTemplate().print(OS, Context.PrintingPolicy); - Result += OS.str(); - break; - } - - case TemplateArgument::Integral: { - Result += Args[I].getAsIntegral()->toString(10); - break; - } - - case TemplateArgument::Expression: { - // FIXME: This is non-optimal, since we're regurgitating the - // expression we were given. - std::string Str; - { - llvm::raw_string_ostream OS(Str); - Args[I].getAsExpr()->printPretty(OS, Context, 0, - Context.PrintingPolicy); - } - Result += Str; - break; - } - - case TemplateArgument::Pack: - // FIXME: Format template argument packs - Result += "<template argument pack>"; - break; + Out << '$' << I; } + + Out << " = "; + Args[I].print(Context.PrintingPolicy, Out); } - - Result += ']'; - return Result; + + Out << ']'; + return Out.str(); } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 5c77ed6..bd0a618 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -12,6 +12,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/SemaDiagnostic.h" // FIXME: temporary! #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/AST/ASTContext.h" @@ -20,6 +21,8 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "llvm/ADT/BitVector.h" +#include "TreeTransform.h" #include <algorithm> namespace clang { @@ -47,7 +50,10 @@ namespace clang { /// \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 + TDF_SkipNonDependent = 0x08, + /// \brief Whether we are performing template argument deduction for + /// parameters and arguments in a top-level template argument + TDF_TopLevelParameterTypeList = 0x10 }; } @@ -57,9 +63,9 @@ using namespace clang; /// necessary to compare their values regardless of underlying type. static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { if (Y.getBitWidth() > X.getBitWidth()) - X.extend(Y.getBitWidth()); + X = X.extend(Y.getBitWidth()); else if (Y.getBitWidth() < X.getBitWidth()) - Y.extend(X.getBitWidth()); + Y = Y.extend(X.getBitWidth()); // If there is a signedness mismatch, correct it. if (X.isSigned() != Y.isSigned()) { @@ -78,9 +84,54 @@ static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument &Param, - const TemplateArgument &Arg, + TemplateArgument Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced); + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced); + +/// \brief Whether template argument deduction for two reference parameters +/// resulted in the argument type, parameter type, or neither type being more +/// qualified than the other. +enum DeductionQualifierComparison { + NeitherMoreQualified = 0, + ParamMoreQualified, + ArgMoreQualified +}; + +/// \brief Stores the result of comparing two reference parameters while +/// performing template argument deduction for partial ordering of function +/// templates. +struct RefParamPartialOrderingComparison { + /// \brief Whether the parameter type is an rvalue reference type. + bool ParamIsRvalueRef; + /// \brief Whether the argument type is an rvalue reference type. + bool ArgIsRvalueRef; + + /// \brief Whether the parameter or argument (or neither) is more qualified. + DeductionQualifierComparison Qualifiers; +}; + + + +static Sema::TemplateDeductionResult +DeduceTemplateArguments(Sema &S, + TemplateParameterList *TemplateParams, + QualType Param, + QualType Arg, + TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + unsigned TDF, + bool PartialOrdering = false, + llvm::SmallVectorImpl<RefParamPartialOrderingComparison> * + RefParamComparisons = 0); + +static Sema::TemplateDeductionResult +DeduceTemplateArguments(Sema &S, + TemplateParameterList *TemplateParams, + const TemplateArgument *Params, unsigned NumParams, + const TemplateArgument *Args, unsigned NumArgs, + TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + bool NumberOfArgumentsMustMatch = true); /// \brief If the given expression is of a form that permits the deduction /// of a non-type template parameter, return the declaration of that @@ -95,6 +146,141 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { return 0; } +/// \brief Determine whether two declaration pointers refer to the same +/// declaration. +static bool isSameDeclaration(Decl *X, Decl *Y) { + if (!X || !Y) + return !X && !Y; + + if (NamedDecl *NX = dyn_cast<NamedDecl>(X)) + X = NX->getUnderlyingDecl(); + if (NamedDecl *NY = dyn_cast<NamedDecl>(Y)) + Y = NY->getUnderlyingDecl(); + + return X->getCanonicalDecl() == Y->getCanonicalDecl(); +} + +/// \brief Verify that the given, deduced template arguments are compatible. +/// +/// \returns The deduced template argument, or a NULL template argument if +/// the deduced template arguments were incompatible. +static DeducedTemplateArgument +checkDeducedTemplateArguments(ASTContext &Context, + const DeducedTemplateArgument &X, + const DeducedTemplateArgument &Y) { + // We have no deduction for one or both of the arguments; they're compatible. + if (X.isNull()) + return Y; + if (Y.isNull()) + return X; + + switch (X.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Non-deduced template arguments handled above"); + + case TemplateArgument::Type: + // If two template type arguments have the same type, they're compatible. + if (Y.getKind() == TemplateArgument::Type && + Context.hasSameType(X.getAsType(), Y.getAsType())) + return X; + + return DeducedTemplateArgument(); + + case TemplateArgument::Integral: + // If we deduced a constant in one case and either a dependent expression or + // declaration in another case, keep the integral constant. + // If both are integral constants with the same value, keep that value. + if (Y.getKind() == TemplateArgument::Expression || + Y.getKind() == TemplateArgument::Declaration || + (Y.getKind() == TemplateArgument::Integral && + hasSameExtendedValue(*X.getAsIntegral(), *Y.getAsIntegral()))) + return DeducedTemplateArgument(X, + X.wasDeducedFromArrayBound() && + Y.wasDeducedFromArrayBound()); + + // All other combinations are incompatible. + return DeducedTemplateArgument(); + + case TemplateArgument::Template: + if (Y.getKind() == TemplateArgument::Template && + Context.hasSameTemplateName(X.getAsTemplate(), Y.getAsTemplate())) + return X; + + // All other combinations are incompatible. + return DeducedTemplateArgument(); + + case TemplateArgument::TemplateExpansion: + if (Y.getKind() == TemplateArgument::TemplateExpansion && + Context.hasSameTemplateName(X.getAsTemplateOrTemplatePattern(), + Y.getAsTemplateOrTemplatePattern())) + return X; + + // All other combinations are incompatible. + return DeducedTemplateArgument(); + + case TemplateArgument::Expression: + // If we deduced a dependent expression in one case and either an integral + // constant or a declaration in another case, keep the integral constant + // or declaration. + if (Y.getKind() == TemplateArgument::Integral || + Y.getKind() == TemplateArgument::Declaration) + return DeducedTemplateArgument(Y, X.wasDeducedFromArrayBound() && + Y.wasDeducedFromArrayBound()); + + if (Y.getKind() == TemplateArgument::Expression) { + // Compare the expressions for equality + llvm::FoldingSetNodeID ID1, ID2; + X.getAsExpr()->Profile(ID1, Context, true); + Y.getAsExpr()->Profile(ID2, Context, true); + if (ID1 == ID2) + return X; + } + + // All other combinations are incompatible. + return DeducedTemplateArgument(); + + case TemplateArgument::Declaration: + // If we deduced a declaration and a dependent expression, keep the + // declaration. + if (Y.getKind() == TemplateArgument::Expression) + return X; + + // If we deduced a declaration and an integral constant, keep the + // integral constant. + if (Y.getKind() == TemplateArgument::Integral) + return Y; + + // If we deduced two declarations, make sure they they refer to the + // same declaration. + if (Y.getKind() == TemplateArgument::Declaration && + isSameDeclaration(X.getAsDecl(), Y.getAsDecl())) + return X; + + // All other combinations are incompatible. + return DeducedTemplateArgument(); + + case TemplateArgument::Pack: + if (Y.getKind() != TemplateArgument::Pack || + X.pack_size() != Y.pack_size()) + return DeducedTemplateArgument(); + + for (TemplateArgument::pack_iterator XA = X.pack_begin(), + XAEnd = X.pack_end(), + YA = Y.pack_begin(); + XA != XAEnd; ++XA, ++YA) { + if (checkDeducedTemplateArguments(Context, + DeducedTemplateArgument(*XA, X.wasDeducedFromArrayBound()), + DeducedTemplateArgument(*YA, Y.wasDeducedFromArrayBound())) + .isNull()) + return DeducedTemplateArgument(); + } + + return X; + } + + return DeducedTemplateArgument(); +} + /// \brief Deduce the value of the given non-type template parameter /// from the given constant. static Sema::TemplateDeductionResult @@ -107,31 +293,18 @@ DeduceNonTypeTemplateArgument(Sema &S, assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); - if (Deduced[NTTP->getIndex()].isNull()) { - Deduced[NTTP->getIndex()] = DeducedTemplateArgument(Value, ValueType, - DeducedFromArrayBound); - return Sema::TDK_Success; - } - - if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral) { + DeducedTemplateArgument NewDeduced(Value, ValueType, DeducedFromArrayBound); + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + Deduced[NTTP->getIndex()], + NewDeduced); + if (Result.isNull()) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(Value, ValueType); - return Sema::TDK_Inconsistent; - } - - // Extent the smaller of the two values. - llvm::APSInt PrevValue = *Deduced[NTTP->getIndex()].getAsIntegral(); - if (!hasSameExtendedValue(PrevValue, Value)) { - Info.Param = NTTP; - Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(Value, ValueType); + Info.SecondArg = NewDeduced; return Sema::TDK_Inconsistent; } - if (!DeducedFromArrayBound) - Deduced[NTTP->getIndex()].setDeducedFromArrayBound(false); - + Deduced[NTTP->getIndex()] = Result; return Sema::TDK_Success; } @@ -150,30 +323,19 @@ DeduceNonTypeTemplateArgument(Sema &S, assert((Value->isTypeDependent() || Value->isValueDependent()) && "Expression template argument must be type- or value-dependent."); - if (Deduced[NTTP->getIndex()].isNull()) { - Deduced[NTTP->getIndex()] = TemplateArgument(Value->Retain()); - 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 - // dependent expression gives us the constant value. - return Sema::TDK_Success; - } + DeducedTemplateArgument NewDeduced(Value); + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + Deduced[NTTP->getIndex()], + NewDeduced); - if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) { - // Compare the expressions for equality - llvm::FoldingSetNodeID ID1, ID2; - Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, S.Context, true); - Value->Profile(ID2, S.Context, true); - if (ID1 == ID2) - return Sema::TDK_Success; - - // FIXME: Fill in argument mismatch information - return Sema::TDK_NonDeducedMismatch; + if (Result.isNull()) { + Info.Param = NTTP; + Info.FirstArg = Deduced[NTTP->getIndex()]; + Info.SecondArg = NewDeduced; + return Sema::TDK_Inconsistent; } + Deduced[NTTP->getIndex()] = Result; return Sema::TDK_Success; } @@ -189,28 +351,19 @@ DeduceNonTypeTemplateArgument(Sema &S, llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); - - if (Deduced[NTTP->getIndex()].isNull()) { - Deduced[NTTP->getIndex()] = TemplateArgument(D->getCanonicalDecl()); - return Sema::TDK_Success; - } - - if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) { - // Okay, we deduced a declaration in one case and a dependent expression - // in another case. - return Sema::TDK_Success; - } - - if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Declaration) { - // Compare the declarations for equality - if (Deduced[NTTP->getIndex()].getAsDecl()->getCanonicalDecl() == - D->getCanonicalDecl()) - return Sema::TDK_Success; - - // FIXME: Fill in argument mismatch information - return Sema::TDK_NonDeducedMismatch; + + DeducedTemplateArgument NewDeduced(D? D->getCanonicalDecl() : 0); + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + Deduced[NTTP->getIndex()], + NewDeduced); + if (Result.isNull()) { + Info.Param = NTTP; + Info.FirstArg = Deduced[NTTP->getIndex()]; + Info.SecondArg = NewDeduced; + return Sema::TDK_Inconsistent; } - + + Deduced[NTTP->getIndex()] = Result; return Sema::TDK_Success; } @@ -227,33 +380,28 @@ DeduceTemplateArguments(Sema &S, // so there is nothing that we can deduce. return Sema::TDK_Success; } - + if (TemplateTemplateParmDecl *TempParam = dyn_cast<TemplateTemplateParmDecl>(ParamDecl)) { - // Bind the template template parameter to the given template name. - TemplateArgument &ExistingArg = Deduced[TempParam->getIndex()]; - if (ExistingArg.isNull()) { - // This is the first deduction for this template template parameter. - ExistingArg = TemplateArgument(S.Context.getCanonicalTemplateName(Arg)); - return Sema::TDK_Success; + DeducedTemplateArgument NewDeduced(S.Context.getCanonicalTemplateName(Arg)); + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + Deduced[TempParam->getIndex()], + NewDeduced); + if (Result.isNull()) { + Info.Param = TempParam; + Info.FirstArg = Deduced[TempParam->getIndex()]; + Info.SecondArg = NewDeduced; + return Sema::TDK_Inconsistent; } - - // Verify that the previous binding matches this deduction. - assert(ExistingArg.getKind() == TemplateArgument::Template); - if (S.Context.hasSameTemplateName(ExistingArg.getAsTemplate(), Arg)) - return Sema::TDK_Success; - - // Inconsistent deduction. - Info.Param = TempParam; - Info.FirstArg = ExistingArg; - Info.SecondArg = TemplateArgument(Arg); - return Sema::TDK_Inconsistent; + + Deduced[TempParam->getIndex()] = Result; + return Sema::TDK_Success; } - + // Verify that the two template names are equivalent. if (S.Context.hasSameTemplateName(Param, Arg)) return Sema::TDK_Success; - + // Mismatch of non-dependent template parameter to argument. Info.FirstArg = TemplateArgument(Param); Info.SecondArg = TemplateArgument(Arg); @@ -300,17 +448,13 @@ DeduceTemplateArguments(Sema &S, // Perform template argument deduction on each template - // argument. - unsigned NumArgs = std::min(SpecArg->getNumArgs(), Param->getNumArgs()); - for (unsigned I = 0; I != NumArgs; ++I) - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, - Param->getArg(I), - SpecArg->getArg(I), - Info, Deduced)) - return Result; - - return Sema::TDK_Success; + // argument. Ignore any missing/extra arguments, since they could be + // filled in by default arguments. + return DeduceTemplateArguments(S, TemplateParams, + Param->getArgs(), Param->getNumArgs(), + SpecArg->getArgs(), SpecArg->getNumArgs(), + Info, Deduced, + /*NumberOfArgumentsMustMatch=*/false); } // If the argument type is a class template specialization, we @@ -334,20 +478,12 @@ DeduceTemplateArguments(Sema &S, Info, Deduced)) return Result; - 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(S, TemplateParams, - Param->getArg(I), - ArgArgs.get(I), - Info, Deduced)) - return Result; - - return Sema::TDK_Success; + // Perform template argument deduction for the template arguments. + return DeduceTemplateArguments(S, TemplateParams, + Param->getArgs(), Param->getNumArgs(), + SpecArg->getTemplateArgs().data(), + SpecArg->getTemplateArgs().size(), + Info, Deduced); } /// \brief Determines whether the given type is an opaque type that @@ -359,6 +495,7 @@ static bool IsPossiblyOpaquelyQualifiedType(QualType T) { case Type::DependentName: case Type::Decltype: case Type::UnresolvedUsing: + case Type::TemplateTypeParm: return true; case Type::ConstantArray: @@ -373,6 +510,296 @@ static bool IsPossiblyOpaquelyQualifiedType(QualType T) { } } +/// \brief Retrieve the depth and index of a template parameter. +static std::pair<unsigned, unsigned> +getDepthAndIndex(NamedDecl *ND) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) + return std::make_pair(TTP->getDepth(), TTP->getIndex()); + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) + return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); + return std::make_pair(TTP->getDepth(), TTP->getIndex()); +} + +/// \brief Retrieve the depth and index of an unexpanded parameter pack. +static std::pair<unsigned, unsigned> +getDepthAndIndex(UnexpandedParameterPack UPP) { + if (const TemplateTypeParmType *TTP + = UPP.first.dyn_cast<const TemplateTypeParmType *>()) + return std::make_pair(TTP->getDepth(), TTP->getIndex()); + + return getDepthAndIndex(UPP.first.get<NamedDecl *>()); +} + +/// \brief Helper function to build a TemplateParameter when we don't +/// know its type statically. +static TemplateParameter makeTemplateParameter(Decl *D) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D)) + return TemplateParameter(TTP); + else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) + return TemplateParameter(NTTP); + + return TemplateParameter(cast<TemplateTemplateParmDecl>(D)); +} + +/// \brief Prepare to perform template argument deduction for all of the +/// arguments in a set of argument packs. +static void PrepareArgumentPackDeduction(Sema &S, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + const llvm::SmallVectorImpl<unsigned> &PackIndices, + llvm::SmallVectorImpl<DeducedTemplateArgument> &SavedPacks, + llvm::SmallVectorImpl< + llvm::SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks) { + // Save the deduced template arguments for each parameter pack expanded + // by this pack expansion, then clear out the deduction. + for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) { + // Save the previously-deduced argument pack, then clear it out so that we + // can deduce a new argument pack. + SavedPacks[I] = Deduced[PackIndices[I]]; + Deduced[PackIndices[I]] = TemplateArgument(); + + // If the template arugment pack was explicitly specified, add that to + // the set of deduced arguments. + const TemplateArgument *ExplicitArgs; + unsigned NumExplicitArgs; + if (NamedDecl *PartiallySubstitutedPack + = S.CurrentInstantiationScope->getPartiallySubstitutedPack( + &ExplicitArgs, + &NumExplicitArgs)) { + if (getDepthAndIndex(PartiallySubstitutedPack).second == PackIndices[I]) + NewlyDeducedPacks[I].append(ExplicitArgs, + ExplicitArgs + NumExplicitArgs); + } + } +} + +/// \brief Finish template argument deduction for a set of argument packs, +/// producing the argument packs and checking for consistency with prior +/// deductions. +static Sema::TemplateDeductionResult +FinishArgumentPackDeduction(Sema &S, + TemplateParameterList *TemplateParams, + bool HasAnyArguments, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + const llvm::SmallVectorImpl<unsigned> &PackIndices, + llvm::SmallVectorImpl<DeducedTemplateArgument> &SavedPacks, + llvm::SmallVectorImpl< + llvm::SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks, + TemplateDeductionInfo &Info) { + // Build argument packs for each of the parameter packs expanded by this + // pack expansion. + for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) { + if (HasAnyArguments && NewlyDeducedPacks[I].empty()) { + // We were not able to deduce anything for this parameter pack, + // so just restore the saved argument pack. + Deduced[PackIndices[I]] = SavedPacks[I]; + continue; + } + + DeducedTemplateArgument NewPack; + + if (NewlyDeducedPacks[I].empty()) { + // If we deduced an empty argument pack, create it now. + NewPack = DeducedTemplateArgument(TemplateArgument(0, 0)); + } else { + TemplateArgument *ArgumentPack + = new (S.Context) TemplateArgument [NewlyDeducedPacks[I].size()]; + std::copy(NewlyDeducedPacks[I].begin(), NewlyDeducedPacks[I].end(), + ArgumentPack); + NewPack + = DeducedTemplateArgument(TemplateArgument(ArgumentPack, + NewlyDeducedPacks[I].size()), + NewlyDeducedPacks[I][0].wasDeducedFromArrayBound()); + } + + DeducedTemplateArgument Result + = checkDeducedTemplateArguments(S.Context, SavedPacks[I], NewPack); + if (Result.isNull()) { + Info.Param + = makeTemplateParameter(TemplateParams->getParam(PackIndices[I])); + Info.FirstArg = SavedPacks[I]; + Info.SecondArg = NewPack; + return Sema::TDK_Inconsistent; + } + + Deduced[PackIndices[I]] = Result; + } + + return Sema::TDK_Success; +} + +/// \brief Deduce the template arguments by comparing the list of parameter +/// types to the list of argument types, as in the parameter-type-lists of +/// function types (C++ [temp.deduct.type]p10). +/// +/// \param S The semantic analysis object within which we are deducing +/// +/// \param TemplateParams The template parameters that we are deducing +/// +/// \param Params The list of parameter types +/// +/// \param NumParams The number of types in \c Params +/// +/// \param Args The list of argument types +/// +/// \param NumArgs The number of types in \c Args +/// +/// \param Info information about the template argument deduction itself +/// +/// \param Deduced the deduced template arguments +/// +/// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe +/// how template argument deduction is performed. +/// +/// \param PartialOrdering If true, we are performing template argument +/// deduction for during partial ordering for a call +/// (C++0x [temp.deduct.partial]). +/// +/// \param RefParamComparisons If we're performing template argument deduction +/// in the context of partial ordering, the set of qualifier comparisons. +/// +/// \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(Sema &S, + TemplateParameterList *TemplateParams, + const QualType *Params, unsigned NumParams, + const QualType *Args, unsigned NumArgs, + TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + unsigned TDF, + bool PartialOrdering = false, + llvm::SmallVectorImpl<RefParamPartialOrderingComparison> * + RefParamComparisons = 0) { + // Fast-path check to see if we have too many/too few arguments. + if (NumParams != NumArgs && + !(NumParams && isa<PackExpansionType>(Params[NumParams - 1])) && + !(NumArgs && isa<PackExpansionType>(Args[NumArgs - 1]))) + return Sema::TDK_NonDeducedMismatch; + + // C++0x [temp.deduct.type]p10: + // Similarly, if P has a form that contains (T), then each parameter type + // Pi of the respective parameter-type- list of P is compared with the + // corresponding parameter type Ai of the corresponding parameter-type-list + // of A. [...] + unsigned ArgIdx = 0, ParamIdx = 0; + for (; ParamIdx != NumParams; ++ParamIdx) { + // Check argument types. + const PackExpansionType *Expansion + = dyn_cast<PackExpansionType>(Params[ParamIdx]); + if (!Expansion) { + // Simple case: compare the parameter and argument types at this point. + + // Make sure we have an argument. + if (ArgIdx >= NumArgs) + return Sema::TDK_NonDeducedMismatch; + + if (isa<PackExpansionType>(Args[ArgIdx])) { + // C++0x [temp.deduct.type]p22: + // If the original function parameter associated with A is a function + // parameter pack and the function parameter associated with P is not + // a function parameter pack, then template argument deduction fails. + return Sema::TDK_NonDeducedMismatch; + } + + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, + Params[ParamIdx], + Args[ArgIdx], + Info, Deduced, TDF, + PartialOrdering, + RefParamComparisons)) + return Result; + + ++ArgIdx; + continue; + } + + // C++0x [temp.deduct.type]p5: + // The non-deduced contexts are: + // - A function parameter pack that does not occur at the end of the + // parameter-declaration-clause. + if (ParamIdx + 1 < NumParams) + return Sema::TDK_Success; + + // C++0x [temp.deduct.type]p10: + // If the parameter-declaration corresponding to Pi is a function + // parameter pack, then the type of its declarator- id is compared with + // each remaining parameter type in the parameter-type-list of A. Each + // comparison deduces template arguments for subsequent positions in the + // template parameter packs expanded by the function parameter pack. + + // Compute the set of template parameter indices that correspond to + // parameter packs expanded by the pack expansion. + llvm::SmallVector<unsigned, 2> PackIndices; + QualType Pattern = Expansion->getPattern(); + { + llvm::BitVector SawIndices(TemplateParams->size()); + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + S.collectUnexpandedParameterPacks(Pattern, Unexpanded); + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + unsigned Depth, Index; + llvm::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + if (Depth == 0 && !SawIndices[Index]) { + SawIndices[Index] = true; + PackIndices.push_back(Index); + } + } + } + assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?"); + + // Keep track of the deduced template arguments for each parameter pack + // expanded by this pack expansion (the outer index) and for each + // template argument (the inner SmallVectors). + llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2> + NewlyDeducedPacks(PackIndices.size()); + llvm::SmallVector<DeducedTemplateArgument, 2> + SavedPacks(PackIndices.size()); + PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks, + NewlyDeducedPacks); + + bool HasAnyArguments = false; + for (; ArgIdx < NumArgs; ++ArgIdx) { + HasAnyArguments = true; + + // Deduce template arguments from the pattern. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], + Info, Deduced, TDF, PartialOrdering, + RefParamComparisons)) + return Result; + + // Capture the deduced template arguments for each parameter pack expanded + // by this pack expansion, add them to the list of arguments we've deduced + // for that pack, then clear out the deduced argument. + for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) { + DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]]; + if (!DeducedArg.isNull()) { + NewlyDeducedPacks[I].push_back(DeducedArg); + DeducedArg = DeducedTemplateArgument(); + } + } + } + + // Build argument packs for each of the parameter packs expanded by this + // pack expansion. + if (Sema::TemplateDeductionResult Result + = FinishArgumentPackDeduction(S, TemplateParams, HasAnyArguments, + Deduced, PackIndices, SavedPacks, + NewlyDeducedPacks, Info)) + return Result; + } + + // Make sure we don't have any extra arguments. + if (ArgIdx < NumArgs) + return Sema::TDK_NonDeducedMismatch; + + return Sema::TDK_Success; +} + /// \brief Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -391,6 +818,12 @@ static bool IsPossiblyOpaquelyQualifiedType(QualType T) { /// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe /// how template argument deduction is performed. /// +/// \param PartialOrdering Whether we're performing template argument deduction +/// in the context of partial ordering (C++0x [temp.deduct.partial]). +/// +/// \param RefParamComparisons If we're performing template argument deduction +/// in the context of partial ordering, the set of qualifier comparisons. +/// /// \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. @@ -400,31 +833,105 @@ DeduceTemplateArguments(Sema &S, QualType ParamIn, QualType ArgIn, TemplateDeductionInfo &Info, llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, - unsigned TDF) { + unsigned TDF, + bool PartialOrdering, + llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) { // We only want to look at the canonical types, since typedefs and // sugar are not part of template argument deduction. QualType Param = S.Context.getCanonicalType(ParamIn); QualType Arg = S.Context.getCanonicalType(ArgIn); - // 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 - // transformed A. - if (TDF & TDF_ParamWithReferenceType) { - Qualifiers Quals; - QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals); - Quals.setCVRQualifiers(Quals.getCVRQualifiers() & - Arg.getCVRQualifiersThroughArrayTypes()); - Param = S.Context.getQualifiedType(UnqualParam, Quals); + // If the argument type is a pack expansion, look at its pattern. + // This isn't explicitly called out + if (const PackExpansionType *ArgExpansion + = dyn_cast<PackExpansionType>(Arg)) + Arg = ArgExpansion->getPattern(); + + if (PartialOrdering) { + // 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. + const ReferenceType *ParamRef = Param->getAs<ReferenceType>(); + if (ParamRef) + Param = ParamRef->getPointeeType(); + + // - If A is a reference type, A is replaced by the type referred to. + const ReferenceType *ArgRef = Arg->getAs<ReferenceType>(); + if (ArgRef) + Arg = ArgRef->getPointeeType(); + + if (RefParamComparisons && 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. + RefParamPartialOrderingComparison Comparison; + Comparison.ParamIsRvalueRef = ParamRef->getAs<RValueReferenceType>(); + Comparison.ArgIsRvalueRef = ArgRef->getAs<RValueReferenceType>(); + Comparison.Qualifiers = NeitherMoreQualified; + if (Param.isMoreQualifiedThan(Arg)) + Comparison.Qualifiers = ParamMoreQualified; + else if (Arg.isMoreQualifiedThan(Param)) + Comparison.Qualifiers = ArgMoreQualified; + RefParamComparisons->push_back(Comparison); + } + + // 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(); + } else { + // 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 + // transformed A. + if (TDF & TDF_ParamWithReferenceType) { + Qualifiers Quals; + QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals); + Quals.setCVRQualifiers(Quals.getCVRQualifiers() & + Arg.getCVRQualifiers()); + Param = S.Context.getQualifiedType(UnqualParam, Quals); + } + + if ((TDF & TDF_TopLevelParameterTypeList) && !Param->isFunctionType()) { + // C++0x [temp.deduct.type]p10: + // If P and A are function types that originated from deduction when + // taking the address of a function template (14.8.2.2) or when deducing + // template arguments from a function declaration (14.8.2.6) and Pi and + // Ai are parameters of the top-level parameter-type-list of P and A, + // respectively, Pi is adjusted if it is an rvalue reference to a + // cv-unqualified template parameter and Ai is an lvalue reference, in + // which case the type of Pi is changed to be the template parameter + // type (i.e., T&& is changed to simply T). [ Note: As a result, when + // Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be + // deduced as X&. - end note ] + TDF &= ~TDF_TopLevelParameterTypeList; + + if (const RValueReferenceType *ParamRef + = Param->getAs<RValueReferenceType>()) { + if (isa<TemplateTypeParmType>(ParamRef->getPointeeType()) && + !ParamRef->getPointeeType().getQualifiers()) + if (Arg->isLValueReferenceType()) + Param = ParamRef->getPointeeType(); + } + } } // If the parameter type is not dependent, there is nothing to deduce. if (!Param->isDependentType()) { - if (!(TDF & TDF_SkipNonDependent) && Param != Arg) { - + if (!(TDF & TDF_SkipNonDependent) && Param != Arg) return Sema::TDK_NonDeducedMismatch; - } - + return Sema::TDK_Success; } @@ -464,27 +971,24 @@ DeduceTemplateArguments(Sema &S, assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0"); assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function"); QualType DeducedType = Arg; - DeducedType.removeCVRQualifiers(Param.getCVRQualifiers()); + + // local manipulation is okay because it's canonical + DeducedType.removeLocalCVRQualifiers(Param.getCVRQualifiers()); if (RecanonicalizeArg) DeducedType = S.Context.getCanonicalType(DeducedType); - if (Deduced[Index].isNull()) - Deduced[Index] = TemplateArgument(DeducedType); - else { - // 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 - // explicitly specified, template argument deduction fails. - if (Deduced[Index].getAsType() != DeducedType) { - Info.Param - = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); - Info.FirstArg = Deduced[Index]; - Info.SecondArg = TemplateArgument(Arg); - return Sema::TDK_Inconsistent; - } + DeducedTemplateArgument NewDeduced(DeducedType); + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + Deduced[Index], + NewDeduced); + if (Result.isNull()) { + Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); + Info.FirstArg = Deduced[Index]; + Info.SecondArg = NewDeduced; + return Sema::TDK_Inconsistent; } + + Deduced[Index] = Result; return Sema::TDK_Success; } @@ -492,6 +996,13 @@ DeduceTemplateArguments(Sema &S, Info.FirstArg = TemplateArgument(ParamIn); Info.SecondArg = TemplateArgument(ArgIn); + // If the parameter is an already-substituted template parameter + // pack, do nothing: we don't know which of its arguments to look + // at, so we have to wait until all of the parameter packs in this + // expansion have arguments. + if (isa<SubstTemplateTypeParmPackType>(Param)) + return Sema::TDK_Success; + // Check the cv-qualifiers on the parameter and argument types. if (!(TDF & TDF_IgnoreQualifiers)) { if (TDF & TDF_ParamWithReferenceType) { @@ -615,16 +1126,17 @@ DeduceTemplateArguments(Sema &S, if (const ConstantArrayType *ConstantArrayArg = dyn_cast<ConstantArrayType>(ArrayArg)) { llvm::APSInt Size(ConstantArrayArg->getSize()); - return DeduceNonTypeTemplateArgument(S, NTTP, Size, + return DeduceNonTypeTemplateArgument(S, NTTP, Size, S.Context.getSizeType(), /*ArrayBound=*/true, Info, Deduced); } if (const DependentSizedArrayType *DependentArrayArg = dyn_cast<DependentSizedArrayType>(ArrayArg)) - return DeduceNonTypeTemplateArgument(S, NTTP, - DependentArrayArg->getSizeExpr(), - Info, Deduced); + if (DependentArrayArg->getSizeExpr()) + return DeduceNonTypeTemplateArgument(S, NTTP, + DependentArrayArg->getSizeExpr(), + Info, Deduced); // Incomplete type does not match a dependently-sized array type return Sema::TDK_NonDeducedMismatch; @@ -634,6 +1146,7 @@ DeduceTemplateArguments(Sema &S, // T(*)() // T(*)(T) case Type::FunctionProto: { + unsigned SubTDF = TDF & TDF_TopLevelParameterTypeList; const FunctionProtoType *FunctionProtoArg = dyn_cast<FunctionProtoType>(Arg); if (!FunctionProtoArg) @@ -642,14 +1155,11 @@ DeduceTemplateArguments(Sema &S, const FunctionProtoType *FunctionProtoParam = cast<FunctionProtoType>(Param); - if (FunctionProtoParam->getTypeQuals() != - FunctionProtoArg->getTypeQuals()) - return Sema::TDK_NonDeducedMismatch; - - if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs()) - return Sema::TDK_NonDeducedMismatch; - - if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) + if (FunctionProtoParam->getTypeQuals() + != FunctionProtoArg->getTypeQuals() || + FunctionProtoParam->getRefQualifier() + != FunctionProtoArg->getRefQualifier() || + FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) return Sema::TDK_NonDeducedMismatch; // Check return types. @@ -660,17 +1170,12 @@ DeduceTemplateArguments(Sema &S, Info, Deduced, 0)) return Result; - for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) { - // Check argument types. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, - FunctionProtoParam->getArgType(I), - FunctionProtoArg->getArgType(I), - Info, Deduced, 0)) - return Result; - } - - return Sema::TDK_Success; + return DeduceTemplateArguments(S, TemplateParams, + FunctionProtoParam->arg_type_begin(), + FunctionProtoParam->getNumArgs(), + FunctionProtoArg->arg_type_begin(), + FunctionProtoArg->getNumArgs(), + Info, Deduced, SubTDF); } case Type::InjectedClassName: { @@ -721,6 +1226,8 @@ DeduceTemplateArguments(Sema &S, llvm::SmallVector<const RecordType *, 8> ToVisit; ToVisit.push_back(RecordT); bool Successful = false; + llvm::SmallVectorImpl<DeducedTemplateArgument> DeducedOrig(0); + DeducedOrig = Deduced; while (!ToVisit.empty()) { // Retrieve the next class in the inheritance hierarchy. const RecordType *NextT = ToVisit.back(); @@ -738,9 +1245,14 @@ DeduceTemplateArguments(Sema &S, 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) + // note that we had some success. Otherwise, ignore any deductions + // from this base class. + if (BaseResult == Sema::TDK_Success) { Successful = true; + DeducedOrig = Deduced; + } + else + Deduced = DeducedOrig; } // Visit base classes @@ -828,9 +1340,15 @@ static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument &Param, - const TemplateArgument &Arg, + TemplateArgument Arg, TemplateDeductionInfo &Info, llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + // If the template argument is a pack expansion, perform template argument + // deduction against the pattern of that expansion. This only occurs during + // partial ordering. + if (Arg.isPackExpansion()) + Arg = Arg.getPackExpansionPattern(); + switch (Param.getKind()) { case TemplateArgument::Null: assert(false && "Null template argument in parameter list"); @@ -843,22 +1361,26 @@ DeduceTemplateArguments(Sema &S, Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; - + case TemplateArgument::Template: if (Arg.getKind() == TemplateArgument::Template) - return DeduceTemplateArguments(S, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, Param.getAsTemplate(), Arg.getAsTemplate(), Info, Deduced); Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; - + + case TemplateArgument::TemplateExpansion: + llvm_unreachable("caller should handle pack expansions"); + break; + case TemplateArgument::Declaration: if (Arg.getKind() == TemplateArgument::Declaration && Param.getAsDecl()->getCanonicalDecl() == Arg.getAsDecl()->getCanonicalDecl()) return Sema::TDK_Success; - + Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; @@ -898,7 +1420,7 @@ DeduceTemplateArguments(Sema &S, if (Arg.getKind() == TemplateArgument::Declaration) return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsDecl(), Info, Deduced); - + Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; @@ -908,31 +1430,209 @@ DeduceTemplateArguments(Sema &S, return Sema::TDK_Success; } case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; + llvm_unreachable("Argument packs should be expanded by the caller!"); } return Sema::TDK_Success; } +/// \brief Determine whether there is a template argument to be used for +/// deduction. +/// +/// This routine "expands" argument packs in-place, overriding its input +/// parameters so that \c Args[ArgIdx] will be the available template argument. +/// +/// \returns true if there is another template argument (which will be at +/// \c Args[ArgIdx]), false otherwise. +static bool hasTemplateArgumentForDeduction(const TemplateArgument *&Args, + unsigned &ArgIdx, + unsigned &NumArgs) { + if (ArgIdx == NumArgs) + return false; + + const TemplateArgument &Arg = Args[ArgIdx]; + if (Arg.getKind() != TemplateArgument::Pack) + return true; + + assert(ArgIdx == NumArgs - 1 && "Pack not at the end of argument list?"); + Args = Arg.pack_begin(); + NumArgs = Arg.pack_size(); + ArgIdx = 0; + return ArgIdx < NumArgs; +} + +/// \brief Determine whether the given set of template arguments has a pack +/// expansion that is not the last template argument. +static bool hasPackExpansionBeforeEnd(const TemplateArgument *Args, + unsigned NumArgs) { + unsigned ArgIdx = 0; + while (ArgIdx < NumArgs) { + const TemplateArgument &Arg = Args[ArgIdx]; + + // Unwrap argument packs. + if (Args[ArgIdx].getKind() == TemplateArgument::Pack) { + Args = Arg.pack_begin(); + NumArgs = Arg.pack_size(); + ArgIdx = 0; + continue; + } + + ++ArgIdx; + if (ArgIdx == NumArgs) + return false; + + if (Arg.isPackExpansion()) + return true; + } + + return false; +} + static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - const TemplateArgumentList &ParamList, - const TemplateArgumentList &ArgList, + const TemplateArgument *Params, unsigned NumParams, + const TemplateArgument *Args, unsigned NumArgs, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { - assert(ParamList.size() == ArgList.size()); - for (unsigned I = 0, N = ParamList.size(); I != N; ++I) { + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + bool NumberOfArgumentsMustMatch) { + // C++0x [temp.deduct.type]p9: + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a + // non-deduced context. + if (hasPackExpansionBeforeEnd(Params, NumParams)) + return Sema::TDK_Success; + + // C++0x [temp.deduct.type]p9: + // If P has a form that contains <T> or <i>, then each argument Pi of the + // respective template argument list P is compared with the corresponding + // argument Ai of the corresponding template argument list of A. + unsigned ArgIdx = 0, ParamIdx = 0; + for (; hasTemplateArgumentForDeduction(Params, ParamIdx, NumParams); + ++ParamIdx) { + if (!Params[ParamIdx].isPackExpansion()) { + // The simple case: deduce template arguments by matching Pi and Ai. + + // Check whether we have enough arguments. + if (!hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs)) + return NumberOfArgumentsMustMatch? Sema::TDK_NonDeducedMismatch + : Sema::TDK_Success; + + if (Args[ArgIdx].isPackExpansion()) { + // FIXME: We follow the logic of C++0x [temp.deduct.type]p22 here, + // but applied to pack expansions that are template arguments. + return Sema::TDK_NonDeducedMismatch; + } + + // Perform deduction for this Pi/Ai pair. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, + Params[ParamIdx], Args[ArgIdx], + Info, Deduced)) + return Result; + + // Move to the next argument. + ++ArgIdx; + continue; + } + + // The parameter is a pack expansion. + + // C++0x [temp.deduct.type]p9: + // If Pi is a pack expansion, then the pattern of Pi is compared with + // each remaining argument in the template argument list of A. Each + // comparison deduces template arguments for subsequent positions in the + // template parameter packs expanded by Pi. + TemplateArgument Pattern = Params[ParamIdx].getPackExpansionPattern(); + + // Compute the set of template parameter indices that correspond to + // parameter packs expanded by the pack expansion. + llvm::SmallVector<unsigned, 2> PackIndices; + { + llvm::BitVector SawIndices(TemplateParams->size()); + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + S.collectUnexpandedParameterPacks(Pattern, Unexpanded); + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + unsigned Depth, Index; + llvm::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + if (Depth == 0 && !SawIndices[Index]) { + SawIndices[Index] = true; + PackIndices.push_back(Index); + } + } + } + assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?"); + + // FIXME: If there are no remaining arguments, we can bail out early + // and set any deduced parameter packs to an empty argument pack. + // The latter part of this is a (minor) correctness issue. + + // Save the deduced template arguments for each parameter pack expanded + // by this pack expansion, then clear out the deduction. + llvm::SmallVector<DeducedTemplateArgument, 2> + SavedPacks(PackIndices.size()); + llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2> + NewlyDeducedPacks(PackIndices.size()); + PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks, + NewlyDeducedPacks); + + // Keep track of the deduced template arguments for each parameter pack + // expanded by this pack expansion (the outer index) and for each + // template argument (the inner SmallVectors). + bool HasAnyArguments = false; + while (hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs)) { + HasAnyArguments = true; + + // Deduce template arguments from the pattern. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], + Info, Deduced)) + return Result; + + // Capture the deduced template arguments for each parameter pack expanded + // by this pack expansion, add them to the list of arguments we've deduced + // for that pack, then clear out the deduced argument. + for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) { + DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]]; + if (!DeducedArg.isNull()) { + NewlyDeducedPacks[I].push_back(DeducedArg); + DeducedArg = DeducedTemplateArgument(); + } + } + + ++ArgIdx; + } + + // Build argument packs for each of the parameter packs expanded by this + // pack expansion. if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, - ParamList[I], ArgList[I], - Info, Deduced)) + = FinishArgumentPackDeduction(S, TemplateParams, HasAnyArguments, + Deduced, PackIndices, SavedPacks, + NewlyDeducedPacks, Info)) return Result; } + + // If there is an argument remaining, then we had too many arguments. + if (NumberOfArgumentsMustMatch && + hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs)) + return Sema::TDK_NonDeducedMismatch; + return Sema::TDK_Success; } +static Sema::TemplateDeductionResult +DeduceTemplateArguments(Sema &S, + TemplateParameterList *TemplateParams, + const TemplateArgumentList &ParamList, + const TemplateArgumentList &ArgList, + TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + return DeduceTemplateArguments(S, TemplateParams, + ParamList.data(), ParamList.size(), + ArgList.data(), ArgList.size(), + Info, Deduced); +} + /// \brief Determine whether two template arguments are the same. static bool isSameTemplateArg(ASTContext &Context, const TemplateArgument &X, @@ -954,18 +1654,19 @@ static bool isSameTemplateArg(ASTContext &Context, Y.getAsDecl()->getCanonicalDecl(); case TemplateArgument::Template: - return Context.getCanonicalTemplateName(X.getAsTemplate()) - .getAsVoidPointer() == - Context.getCanonicalTemplateName(Y.getAsTemplate()) - .getAsVoidPointer(); - + case TemplateArgument::TemplateExpansion: + return Context.getCanonicalTemplateName( + X.getAsTemplateOrTemplatePattern()).getAsVoidPointer() == + Context.getCanonicalTemplateName( + Y.getAsTemplateOrTemplatePattern()).getAsVoidPointer(); + case TemplateArgument::Integral: return *X.getAsIntegral() == *Y.getAsIntegral(); case TemplateArgument::Expression: { llvm::FoldingSetNodeID XID, YID; X.getAsExpr()->Profile(XID, Context, true); - Y.getAsExpr()->Profile(YID, Context, true); + Y.getAsExpr()->Profile(YID, Context, true); return XID == YID; } @@ -986,51 +1687,192 @@ static bool isSameTemplateArg(ASTContext &Context, return false; } -/// \brief Helper function to build a TemplateParameter when we don't -/// know its type statically. -static TemplateParameter makeTemplateParameter(Decl *D) { - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D)) - return TemplateParameter(TTP); - else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) - return TemplateParameter(NTTP); +/// \brief Allocate a TemplateArgumentLoc where all locations have +/// been initialized to the given location. +/// +/// \param S The semantic analysis object. +/// +/// \param The template argument we are producing template argument +/// location information for. +/// +/// \param NTTPType For a declaration template argument, the type of +/// the non-type template parameter that corresponds to this template +/// argument. +/// +/// \param Loc The source location to use for the resulting template +/// argument. +static TemplateArgumentLoc +getTrivialTemplateArgumentLoc(Sema &S, + const TemplateArgument &Arg, + QualType NTTPType, + SourceLocation Loc) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Can't get a NULL template argument here"); + break; - return TemplateParameter(cast<TemplateTemplateParmDecl>(D)); + case TemplateArgument::Type: + return TemplateArgumentLoc(Arg, + S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); + + case TemplateArgument::Declaration: { + Expr *E + = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) + .takeAs<Expr>(); + return TemplateArgumentLoc(TemplateArgument(E), E); + } + + case TemplateArgument::Integral: { + Expr *E + = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>(); + return TemplateArgumentLoc(TemplateArgument(E), E); + } + + case TemplateArgument::Template: + return TemplateArgumentLoc(Arg, SourceRange(), Loc); + + case TemplateArgument::TemplateExpansion: + return TemplateArgumentLoc(Arg, SourceRange(), Loc, Loc); + + case TemplateArgument::Expression: + return TemplateArgumentLoc(Arg, Arg.getAsExpr()); + + case TemplateArgument::Pack: + return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo()); + } + + return TemplateArgumentLoc(); +} + + +/// \brief Convert the given deduced template argument and add it to the set of +/// fully-converted template arguments. +static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, + DeducedTemplateArgument Arg, + NamedDecl *Template, + QualType NTTPType, + unsigned ArgumentPackIndex, + TemplateDeductionInfo &Info, + bool InFunctionTemplate, + llvm::SmallVectorImpl<TemplateArgument> &Output) { + if (Arg.getKind() == TemplateArgument::Pack) { + // This is a template argument pack, so check each of its arguments against + // the template parameter. + llvm::SmallVector<TemplateArgument, 2> PackedArgsBuilder; + for (TemplateArgument::pack_iterator PA = Arg.pack_begin(), + PAEnd = Arg.pack_end(); + PA != PAEnd; ++PA) { + // When converting the deduced template argument, append it to the + // general output list. We need to do this so that the template argument + // checking logic has all of the prior template arguments available. + DeducedTemplateArgument InnerArg(*PA); + InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound()); + if (ConvertDeducedTemplateArgument(S, Param, InnerArg, Template, + NTTPType, PackedArgsBuilder.size(), + Info, InFunctionTemplate, Output)) + return true; + + // Move the converted template argument into our argument pack. + PackedArgsBuilder.push_back(Output.back()); + Output.pop_back(); + } + + // Create the resulting argument pack. + Output.push_back(TemplateArgument::CreatePackCopy(S.Context, + PackedArgsBuilder.data(), + PackedArgsBuilder.size())); + return false; + } + + // Convert the deduced template argument into a template + // argument that we can check, almost as if the user had written + // the template argument explicitly. + TemplateArgumentLoc ArgLoc = getTrivialTemplateArgumentLoc(S, Arg, NTTPType, + Info.getLocation()); + + // Check the template argument, converting it as necessary. + return S.CheckTemplateArgument(Param, ArgLoc, + Template, + Template->getLocation(), + Template->getSourceRange().getEnd(), + ArgumentPackIndex, + Output, + InFunctionTemplate + ? (Arg.wasDeducedFromArrayBound() + ? Sema::CTAK_DeducedFromArrayBound + : Sema::CTAK_Deduced) + : Sema::CTAK_Specified); } /// Complete template argument deduction for a class template partial /// specialization. static Sema::TemplateDeductionResult -FinishTemplateArgumentDeduction(Sema &S, +FinishTemplateArgumentDeduction(Sema &S, ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, TemplateDeductionInfo &Info) { // Trap errors. Sema::SFINAETrap Trap(S); - + Sema::ContextRAII SavedContext(S, Partial); // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - TemplateArgumentListBuilder Builder(Partial->getTemplateParameters(), - Deduced.size()); - for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { + llvm::SmallVector<TemplateArgument, 4> Builder; + TemplateParameterList *PartialParams = Partial->getTemplateParameters(); + for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) { + NamedDecl *Param = PartialParams->getParam(I); if (Deduced[I].isNull()) { - Decl *Param - = const_cast<NamedDecl *>( - Partial->getTemplateParameters()->getParam(I)); Info.Param = makeTemplateParameter(Param); return Sema::TDK_Incomplete; } - - Builder.Append(Deduced[I]); + + // We have deduced this argument, so it still needs to be + // checked and converted. + + // First, for a non-type template parameter type that is + // initialized by a declaration, we need the type of the + // corresponding non-type template parameter. + QualType NTTPType; + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + NTTPType = NTTP->getType(); + if (NTTPType->isDependentType()) { + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Builder.data(), Builder.size()); + NTTPType = S.SubstType(NTTPType, + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + if (NTTPType.isNull()) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(S.Context, + Builder.data(), + Builder.size())); + return Sema::TDK_SubstitutionFailure; + } + } + } + + if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], + Partial, NTTPType, 0, Info, false, + Builder)) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(), + Builder.size())); + return Sema::TDK_SubstitutionFailure; + } } - + // Form the template argument list from the deduced template arguments. TemplateArgumentList *DeducedArgumentList - = new (S.Context) TemplateArgumentList(S.Context, Builder, - /*TakeArgs=*/true); + = TemplateArgumentList::CreateCopy(S.Context, Builder.data(), + Builder.size()); + Info.reset(DeducedArgumentList); // Substitute the deduced template arguments into the template @@ -1038,60 +1880,40 @@ FinishTemplateArgumentDeduction(Sema &S, // verify that the instantiated template arguments are both valid // and are equivalent to the template arguments originally provided // to the class template. - // FIXME: Do we have to correct the types of deduced non-type template - // arguments (in particular, integral non-type template arguments?). LocalInstantiationScope InstScope(S); ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); const TemplateArgumentLoc *PartialTemplateArgs = Partial->getTemplateArgsAsWritten(); - unsigned N = Partial->getNumTemplateArgsAsWritten(); // Note that we don't provide the langle and rangle locations. TemplateArgumentListInfo InstArgs; - for (unsigned I = 0; I != N; ++I) { - Decl *Param = const_cast<NamedDecl *>( - ClassTemplate->getTemplateParameters()->getParam(I)); - TemplateArgumentLoc InstArg; - if (S.Subst(PartialTemplateArgs[I], InstArg, - MultiLevelTemplateArgumentList(*DeducedArgumentList))) { - Info.Param = makeTemplateParameter(Param); - Info.FirstArg = PartialTemplateArgs[I].getArgument(); - return Sema::TDK_SubstitutionFailure; - } - InstArgs.addArgument(InstArg); - } + if (S.Subst(PartialTemplateArgs, + Partial->getNumTemplateArgsAsWritten(), + InstArgs, MultiLevelTemplateArgumentList(*DeducedArgumentList))) { + unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx; + if (ParamIdx >= Partial->getTemplateParameters()->size()) + ParamIdx = Partial->getTemplateParameters()->size() - 1; - TemplateArgumentListBuilder ConvertedInstArgs( - ClassTemplate->getTemplateParameters(), N); + Decl *Param + = const_cast<NamedDecl *>( + Partial->getTemplateParameters()->getParam(ParamIdx)); + Info.Param = makeTemplateParameter(Param); + Info.FirstArg = PartialTemplateArgs[ArgIdx].getArgument(); + return Sema::TDK_SubstitutionFailure; + } + llvm::SmallVector<TemplateArgument, 4> ConvertedInstArgs; if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), - InstArgs, false, ConvertedInstArgs)) + InstArgs, false, ConvertedInstArgs)) return Sema::TDK_SubstitutionFailure; - - for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) { - TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I]; - - Decl *Param = const_cast<NamedDecl *>( - ClassTemplate->getTemplateParameters()->getParam(I)); - - if (InstArg.getKind() == TemplateArgument::Expression) { - // 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 - = dyn_cast<NonTypeTemplateParmDecl>(Param)) { - if (S.CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) { - Info.Param = makeTemplateParameter(Param); - Info.FirstArg = Partial->getTemplateArgs()[I]; - return Sema::TDK_SubstitutionFailure; - } - } - } + TemplateParameterList *TemplateParams + = ClassTemplate->getTemplateParameters(); + for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { + TemplateArgument InstArg = ConvertedInstArgs.data()[I]; if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) { - Info.Param = makeTemplateParameter(Param); + Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); Info.FirstArg = TemplateArgs[I]; Info.SecondArg = InstArg; return Sema::TDK_NonDeducedMismatch; @@ -1127,14 +1949,14 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, return Result; InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial, - Deduced.data(), Deduced.size()); + Deduced.data(), Deduced.size(), Info); if (Inst) return TDK_InstantiationDepth; if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - - return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs, + + return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs, Deduced, Info); } @@ -1206,26 +2028,24 @@ Sema::SubstituteExplicitTemplateArguments( // 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, - ExplicitTemplateArgs.size()); + llvm::SmallVector<TemplateArgument, 4> Builder; // 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); + ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution, + Info); if (Inst) return TDK_InstantiationDepth; - ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl()); - if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), ExplicitTemplateArgs, true, Builder) || Trap.hasErrorOccurred()) { - unsigned Index = Builder.structuredSize(); + unsigned Index = Builder.size(); if (Index >= TemplateParams->size()) Index = TemplateParams->size() - 1; Info.Param = makeTemplateParameter(TemplateParams->getParam(Index)); @@ -1235,25 +2055,38 @@ Sema::SubstituteExplicitTemplateArguments( // Form the template argument list from the explicitly-specified // template arguments. TemplateArgumentList *ExplicitArgumentList - = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); + = TemplateArgumentList::CreateCopy(Context, Builder.data(), Builder.size()); 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; + // Template argument deduction and the final substitution should be + // done in the context of the templated declaration. Explicit + // argument substitution, on the other hand, needs to happen in the + // calling context. + ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl()); - ParamTypes.push_back(ParamType); + // If we deduced template arguments for a template parameter pack, + // note that the template argument pack is partially substituted and record + // the explicit template arguments. They'll be used as part of deduction + // for this template parameter pack. + for (unsigned I = 0, N = Builder.size(); I != N; ++I) { + const TemplateArgument &Arg = Builder[I]; + if (Arg.getKind() == TemplateArgument::Pack) { + CurrentInstantiationScope->SetPartiallySubstitutedPack( + TemplateParams->getParam(I), + Arg.pack_begin(), + Arg.pack_size()); + break; + } } + // Instantiate the types of each of the function parameters given the + // explicitly-specified template arguments. + if (SubstParmTypes(Function->getLocation(), + Function->param_begin(), Function->getNumParams(), + MultiLevelTemplateArgumentList(*ExplicitArgumentList), + ParamTypes)) + return TDK_SubstitutionFailure; + // If the caller wants a full function type back, instantiate the return // type and form that function type. if (FunctionType) { @@ -1274,6 +2107,7 @@ Sema::SubstituteExplicitTemplateArguments( ParamTypes.data(), ParamTypes.size(), Proto->isVariadic(), Proto->getTypeQuals(), + Proto->getRefQualifier(), Function->getLocation(), Function->getDeclName(), Proto->getExtInfo()); @@ -1287,67 +2121,20 @@ Sema::SubstituteExplicitTemplateArguments( // 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. + // Take all of the explicitly-specified arguments and put them into + // the set of deduced template arguments. Explicitly-specified + // parameter packs, however, will be set to NULL since the deduction + // mechanisms handle explicitly-specified argument packs directly. Deduced.reserve(TemplateParams->size()); - for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) - Deduced.push_back(ExplicitArgumentList->get(I)); - - return TDK_Success; -} - -/// \brief Allocate a TemplateArgumentLoc where all locations have -/// been initialized to the given location. -/// -/// \param S The semantic analysis object. -/// -/// \param The template argument we are producing template argument -/// location information for. -/// -/// \param NTTPType For a declaration template argument, the type of -/// the non-type template parameter that corresponds to this template -/// argument. -/// -/// \param Loc The source location to use for the resulting template -/// argument. -static TemplateArgumentLoc -getTrivialTemplateArgumentLoc(Sema &S, - const TemplateArgument &Arg, - QualType NTTPType, - SourceLocation Loc) { - switch (Arg.getKind()) { - case TemplateArgument::Null: - llvm_unreachable("Can't get a NULL template argument here"); - break; - - case TemplateArgument::Type: - return TemplateArgumentLoc(Arg, - S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); - - case TemplateArgument::Declaration: { - Expr *E - = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) - .takeAs<Expr>(); - return TemplateArgumentLoc(TemplateArgument(E), E); - } - - case TemplateArgument::Integral: { - Expr *E - = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>(); - return TemplateArgumentLoc(TemplateArgument(E), E); - } - - case TemplateArgument::Template: - return TemplateArgumentLoc(Arg, SourceRange(), Loc); - - case TemplateArgument::Expression: - return TemplateArgumentLoc(Arg, Arg.getAsExpr()); - - case TemplateArgument::Pack: - llvm_unreachable("Template parameter packs are not yet supported"); + for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) { + const TemplateArgument &Arg = ExplicitArgumentList->get(I); + if (Arg.getKind() == TemplateArgument::Pack) + Deduced.push_back(DeducedTemplateArgument()); + else + Deduced.push_back(Arg); } - return TemplateArgumentLoc(); + return TDK_Success; } /// \brief Finish template argument deduction for a function template, @@ -1370,7 +2157,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // actual function declaration. InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), FunctionTemplate, Deduced.data(), Deduced.size(), - ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution, + Info); if (Inst) return TDK_InstantiationDepth; @@ -1379,18 +2167,16 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // 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) { - NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I); + llvm::SmallVector<TemplateArgument, 4> Builder; + for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { + NamedDecl *Param = TemplateParams->getParam(I); + if (!Deduced[I].isNull()) { - if (I < NumExplicitlySpecified || - Deduced[I].getKind() == TemplateArgument::Type) { + if (I < NumExplicitlySpecified) { // We have already fully type-checked and converted this - // argument (because it was explicitly-specified) or no - // additional checking is necessary (because it's a template - // type parameter). Just record the presence of this - // parameter. - Builder.Append(Deduced[I]); + // argument, because it was explicitly-specified. Just record the + // presence of this argument. + Builder.push_back(Deduced[I]); continue; } @@ -1401,55 +2187,61 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // initialized by a declaration, we need the type of the // corresponding non-type template parameter. QualType NTTPType; - if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(Param)) { - if (Deduced[I].getKind() == TemplateArgument::Declaration) { - NTTPType = NTTP->getType(); - if (NTTPType->isDependentType()) { - TemplateArgumentList TemplateArgs(Context, Builder, - /*TakeArgs=*/false); - NTTPType = SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); - if (NTTPType.isNull()) { - Info.Param = makeTemplateParameter(Param); - Info.reset(new (Context) TemplateArgumentList(Context, Builder, - /*TakeArgs=*/true)); - return TDK_SubstitutionFailure; - } + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + NTTPType = NTTP->getType(); + if (NTTPType->isDependentType()) { + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Builder.data(), Builder.size()); + NTTPType = SubstType(NTTPType, + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + if (NTTPType.isNull()) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(Context, + Builder.data(), + Builder.size())); + return TDK_SubstitutionFailure; } } } - // Convert the deduced template argument into a template - // argument that we can check, almost as if the user had written - // the template argument explicitly. - TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this, - Deduced[I], - NTTPType, - SourceLocation()); - - // Check the template argument, converting it as necessary. - if (CheckTemplateArgument(Param, Arg, - FunctionTemplate, - FunctionTemplate->getLocation(), - FunctionTemplate->getSourceRange().getEnd(), - Builder, - Deduced[I].wasDeducedFromArrayBound() - ? CTAK_DeducedFromArrayBound - : CTAK_Deduced)) { - Info.Param = makeTemplateParameter( - const_cast<NamedDecl *>(TemplateParams->getParam(I))); - Info.reset(new (Context) TemplateArgumentList(Context, Builder, - /*TakeArgs=*/true)); + if (ConvertDeducedTemplateArgument(*this, Param, Deduced[I], + FunctionTemplate, NTTPType, 0, Info, + true, Builder)) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), + Builder.size())); return TDK_SubstitutionFailure; } continue; } - // Substitute into the default template argument, if available. + // C++0x [temp.arg.explicit]p3: + // A trailing template parameter pack (14.5.3) not otherwise deduced will + // be deduced to an empty sequence of template arguments. + // FIXME: Where did the word "trailing" come from? + if (Param->isTemplateParameterPack()) { + // We may have had explicitly-specified template arguments for this + // template parameter pack. If so, our empty deduction extends the + // explicitly-specified set (C++0x [temp.arg.explicit]p9). + const TemplateArgument *ExplicitArgs; + unsigned NumExplicitArgs; + if (CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs, + &NumExplicitArgs) + == Param) + Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs)); + else + Builder.push_back(TemplateArgument(0, 0)); + + continue; + } + + // Substitute into the default template argument, if available. TemplateArgumentLoc DefArg = SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate, FunctionTemplate->getLocation(), @@ -1463,18 +2255,19 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, const_cast<NamedDecl *>(TemplateParams->getParam(I))); return TDK_Incomplete; } - + // Check whether we can actually use the default argument. if (CheckTemplateArgument(Param, DefArg, FunctionTemplate, FunctionTemplate->getLocation(), FunctionTemplate->getSourceRange().getEnd(), - Builder, + 0, Builder, CTAK_Deduced)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); - Info.reset(new (Context) TemplateArgumentList(Context, Builder, - /*TakeArgs=*/true)); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), + Builder.size())); return TDK_SubstitutionFailure; } @@ -1483,7 +2276,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // Form the template argument list from the deduced template arguments. TemplateArgumentList *DeducedArgumentList - = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); + = TemplateArgumentList::CreateCopy(Context, Builder.data(), Builder.size()); Info.reset(DeducedArgumentList); // Substitute the deduced template arguments into the function template @@ -1497,9 +2290,9 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, if (!Specialization) return TDK_SubstitutionFailure; - assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() == + assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() == FunctionTemplate->getCanonicalDecl()); - + // If the template argument list is owned by the function template // specialization, release it. if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList && @@ -1514,6 +2307,18 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, return TDK_SubstitutionFailure; } + // If we suppressed any diagnostics while performing template argument + // deduction, and if we haven't already instantiated this declaration, + // keep track of these diagnostics. They'll be emitted if this specialization + // is actually used. + if (Info.diag_begin() != Info.diag_end()) { + llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >::iterator + Pos = SuppressedDiagnostics.find(Specialization->getCanonicalDecl()); + if (Pos == SuppressedDiagnostics.end()) + SuppressedDiagnostics[Specialization->getCanonicalDecl()] + .append(Info.diag_begin(), Info.diag_end()); + } + return TDK_Success; } @@ -1544,7 +2349,7 @@ static QualType ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, Expr *Arg, QualType ParamType, bool ParamWasReference) { - + OverloadExpr::FindResult R = OverloadExpr::find(Arg); OverloadExpr *Ovl = R.Expression; @@ -1592,10 +2397,10 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, if (ArgType.isNull()) continue; // Function-to-pointer conversion. - if (!ParamWasReference && ParamType->isPointerType() && + if (!ParamWasReference && ParamType->isPointerType() && ArgType->isFunctionType()) ArgType = S.Context.getPointerType(ArgType); - + // - If the argument is an overload set (not containing function // templates), trial argument deduction is attempted using each // of the members of the set. If deduction succeeds for only one @@ -1608,7 +2413,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // Type deduction is done independently for each P/A pair, and // the deduced template argument values are then combined. // So we do not reject deductions which were made elsewhere. - llvm::SmallVector<DeducedTemplateArgument, 8> + llvm::SmallVector<DeducedTemplateArgument, 8> Deduced(TemplateParams->size()); TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc()); Sema::TemplateDeductionResult Result @@ -1623,6 +2428,113 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, return Match; } +/// \brief Perform the adjustments to the parameter and argument types +/// described in C++ [temp.deduct.call]. +/// +/// \returns true if the caller should not attempt to perform any template +/// argument deduction based on this P/A pair. +static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, + TemplateParameterList *TemplateParams, + QualType &ParamType, + QualType &ArgType, + Expr *Arg, + unsigned &TDF) { + // 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. + if (ParamType.getCVRQualifiers()) + ParamType = ParamType.getLocalUnqualifiedType(); + const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>(); + if (ParamRefType) { + QualType PointeeType = ParamRefType->getPointeeType(); + + // [C++0x] If P is an rvalue reference to a cv-unqualified + // template parameter and the argument is an lvalue, the type + // "lvalue reference to A" is used in place of A for type + // deduction. + if (isa<RValueReferenceType>(ParamType)) { + if (!PointeeType.getQualifiers() && + isa<TemplateTypeParmType>(PointeeType) && + Arg->Classify(S.Context).isLValue()) + ArgType = S.Context.getLValueReferenceType(ArgType); + } + + // [...] If P is a reference type, the type referred to by P is used + // for type deduction. + ParamType = PointeeType; + } + + // Overload sets usually make this parameter an undeduced + // context, but there are sometimes special circumstances. + if (ArgType == S.Context.OverloadTy) { + ArgType = ResolveOverloadForDeduction(S, TemplateParams, + Arg, ParamType, + ParamRefType != 0); + if (ArgType.isNull()) + return true; + } + + if (ParamRefType) { + // C++0x [temp.deduct.call]p3: + // [...] 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 (ParamRefType->isRValueReferenceType() && + ParamRefType->getAs<TemplateTypeParmType>() && + Arg->isLValue()) + ArgType = S.Context.getLValueReferenceType(ArgType); + } else { + // C++ [temp.deduct.call]p2: + // If P is not a reference type: + // - 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 = S.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 + // of A for type deduction; otherwise, + else if (ArgType->isFunctionType()) + ArgType = S.Context.getPointerType(ArgType); + else { + // - If A is a cv-qualified type, the top level cv-qualifiers of A's + // type are ignored for type deduction. + if (ArgType.getCVRQualifiers()) + ArgType = ArgType.getUnqualifiedType(); + } + } + + // 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). [...] + 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 (ParamRefType) + 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 + // conversion (4.4). + if (ArgType->isPointerType() || ArgType->isMemberPointerType() || + ArgType->isObjCObjectPointerType()) + TDF |= TDF_IgnoreQualifiers; + // - 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) && + isSimpleTemplateIdType( + ParamType->getAs<PointerType>()->getPointeeType()))) + TDF |= TDF_DerivedClass; + + return false; +} + /// \brief Perform template argument deduction from a function call /// (C++ [temp.deduct.call]). /// @@ -1639,7 +2551,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, /// \param Name the name of the function being called. This is only significant /// when the function template is a conversion function template, in which /// case this routine will also perform template argument deduction based on -/// the function to which +/// the function to which /// /// \param Specialization if template argument deduction was successful, /// this will be set to the function template specialization produced by @@ -1667,10 +2579,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, else if (NumArgs > Function->getNumParams()) { const FunctionProtoType *Proto = Function->getType()->getAs<FunctionProtoType>(); - if (!Proto->isVariadic()) + if (Proto->isTemplateVariadic()) + /* Do nothing */; + else if (Proto->isVariadic()) + CheckArgs = Function->getNumParams(); + else return TDK_TooManyArguments; - - CheckArgs = Function->getNumParams(); } // The types of the parameters from which we will perform template argument @@ -1695,105 +2609,126 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, NumExplicitlySpecified = Deduced.size(); } else { // Just fill in the parameter types from the function declaration. - for (unsigned I = 0; I != CheckArgs; ++I) + for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) ParamTypes.push_back(Function->getParamDecl(I)->getType()); } // Deduce template arguments from the function parameters. Deduced.resize(TemplateParams->size()); - for (unsigned I = 0; I != CheckArgs; ++I) { - QualType ParamType = ParamTypes[I]; - QualType ArgType = Args[I]->getType(); + unsigned ArgIdx = 0; + for (unsigned ParamIdx = 0, NumParams = ParamTypes.size(); + ParamIdx != NumParams; ++ParamIdx) { + QualType ParamType = ParamTypes[ParamIdx]; + + const PackExpansionType *ParamExpansion + = dyn_cast<PackExpansionType>(ParamType); + if (!ParamExpansion) { + // Simple case: matching a function parameter to a function argument. + if (ArgIdx >= CheckArgs) + break; - // 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. - if (ParamType.getCVRQualifiers()) - ParamType = ParamType.getLocalUnqualifiedType(); - const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>(); - if (ParamRefType) { - // [...] If P is a reference type, the type referred to by P is used - // for type deduction. - ParamType = ParamRefType->getPointeeType(); - } - - // Overload sets usually make this parameter an undeduced - // context, but there are sometimes special circumstances. - if (ArgType == Context.OverloadTy) { - ArgType = ResolveOverloadForDeduction(*this, TemplateParams, - Args[I], ParamType, - ParamRefType != 0); - if (ArgType.isNull()) + Expr *Arg = Args[ArgIdx++]; + QualType ArgType = Arg->getType(); + unsigned TDF = 0; + if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, + ParamType, ArgType, Arg, + TDF)) continue; + + if (TemplateDeductionResult Result + = ::DeduceTemplateArguments(*this, TemplateParams, + ParamType, ArgType, Info, Deduced, + TDF)) + return Result; + + // FIXME: we need to check that the deduced A is the same as A, + // modulo the various allowed differences. + continue; } - if (ParamRefType) { - // C++0x [temp.deduct.call]p3: - // [...] 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 (ParamRefType->isRValueReferenceType() && - ParamRefType->getAs<TemplateTypeParmType>() && - Args[I]->isLvalue(Context) == Expr::LV_Valid) - ArgType = Context.getLValueReferenceType(ArgType); - } else { - // C++ [temp.deduct.call]p2: - // If P is not a reference type: - // - 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 - // of A for type deduction; otherwise, - else if (ArgType->isFunctionType()) - ArgType = Context.getPointerType(ArgType); - else { - // - If A is a cv-qualified type, the top level cv-qualifiers of A’s - // type are ignored for type deduction. - QualType CanonArgType = Context.getCanonicalType(ArgType); - if (ArgType.getCVRQualifiers()) - ArgType = ArgType.getUnqualifiedType(); + // C++0x [temp.deduct.call]p1: + // For a function parameter pack that occurs at the end of the + // parameter-declaration-list, the type A of each remaining argument of + // the call is compared with the type P of the declarator-id of the + // function parameter pack. Each comparison deduces template arguments + // for subsequent positions in the template parameter packs expanded by + // the function parameter pack. For a function parameter pack that does + // not occur at the end of the parameter-declaration-list, the type of + // the parameter pack is a non-deduced context. + if (ParamIdx + 1 < NumParams) + break; + + QualType ParamPattern = ParamExpansion->getPattern(); + llvm::SmallVector<unsigned, 2> PackIndices; + { + llvm::BitVector SawIndices(TemplateParams->size()); + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + collectUnexpandedParameterPacks(ParamPattern, Unexpanded); + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + unsigned Depth, Index; + llvm::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + if (Depth == 0 && !SawIndices[Index]) { + SawIndices[Index] = true; + PackIndices.push_back(Index); + } } } + assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?"); + + // Keep track of the deduced template arguments for each parameter pack + // expanded by this pack expansion (the outer index) and for each + // template argument (the inner SmallVectors). + llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2> + NewlyDeducedPacks(PackIndices.size()); + llvm::SmallVector<DeducedTemplateArgument, 2> + SavedPacks(PackIndices.size()); + PrepareArgumentPackDeduction(*this, Deduced, PackIndices, SavedPacks, + NewlyDeducedPacks); + bool HasAnyArguments = false; + for (; ArgIdx < NumArgs; ++ArgIdx) { + HasAnyArguments = true; + + ParamType = ParamPattern; + Expr *Arg = Args[ArgIdx]; + QualType ArgType = Arg->getType(); + unsigned TDF = 0; + if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, + ParamType, ArgType, Arg, + TDF)) { + // We can't actually perform any deduction for this argument, so stop + // deduction at this point. + ++ArgIdx; + break; + } - // 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 = 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 (ParamRefType) - 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 - // conversion (4.4). - if (ArgType->isPointerType() || ArgType->isMemberPointerType() || - ArgType->isObjCObjectPointerType()) - TDF |= TDF_IgnoreQualifiers; - // - 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) && - isSimpleTemplateIdType( - ParamType->getAs<PointerType>()->getPointeeType()))) - TDF |= TDF_DerivedClass; + if (TemplateDeductionResult Result + = ::DeduceTemplateArguments(*this, TemplateParams, + ParamType, ArgType, Info, Deduced, + TDF)) + return Result; - if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(*this, TemplateParams, - ParamType, ArgType, Info, Deduced, - TDF)) + // Capture the deduced template arguments for each parameter pack expanded + // by this pack expansion, add them to the list of arguments we've deduced + // for that pack, then clear out the deduced argument. + for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) { + DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]]; + if (!DeducedArg.isNull()) { + NewlyDeducedPacks[I].push_back(DeducedArg); + DeducedArg = DeducedTemplateArgument(); + } + } + } + + // Build argument packs for each of the parameter packs expanded by this + // pack expansion. + if (Sema::TemplateDeductionResult Result + = FinishArgumentPackDeduction(*this, TemplateParams, HasAnyArguments, + Deduced, PackIndices, SavedPacks, + NewlyDeducedPacks, Info)) return Result; - // FIXME: we need to check that the deduced A is the same as A, - // modulo the various allowed differences. + // After we've matching against a parameter pack, we're done. + break; } return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, @@ -1808,7 +2743,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, /// \param FunctionTemplate the function template for which we are performing /// template argument deduction. /// -/// \param ExplicitTemplateArguments the explicitly-specified template +/// \param ExplicitTemplateArguments the explicitly-specified template /// arguments. /// /// \param ArgFunctionType the function type that will be used as the @@ -1862,13 +2797,23 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, TemplateParams, FunctionType, ArgFunctionType, Info, - Deduced, 0)) + Deduced, TDF_TopLevelParameterTypeList)) return Result; } - - return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, - NumExplicitlySpecified, - Specialization, Info); + + if (TemplateDeductionResult Result + = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + NumExplicitlySpecified, + Specialization, Info)) + return Result; + + // If the requested function type does not match the actual type of the + // specialization, template argument deduction fails. + if (!ArgFunctionType.isNull() && + !Context.hasSameType(ArgFunctionType, Specialization->getType())) + return TDK_NonDeducedMismatch; + + return TDK_Success; } /// \brief Deduce template arguments for a templated conversion @@ -1915,12 +2860,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, 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. + // 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 + // If A is a cv-qualified type, the top level cv-qualifiers of A's // type are ignored for type deduction. A = A.getUnqualifiedType(); } @@ -1950,7 +2895,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, 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 + // type that can be converted to A via a qualification // conversion. // // (C++0x [temp.deduct.conv]p6 clarifies that this only happens when @@ -1971,7 +2916,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, LocalInstantiationScope InstScope(*this); FunctionDecl *Spec = 0; TemplateDeductionResult Result - = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec, + = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec, Info); Specialization = cast_or_null<CXXConversionDecl>(Spec); return Result; @@ -1983,7 +2928,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, /// \param FunctionTemplate the function template for which we are performing /// template argument deduction. /// -/// \param ExplicitTemplateArguments the explicitly-specified template +/// \param ExplicitTemplateArguments the explicitly-specified template /// arguments. /// /// \param Specialization if template argument deduction was successful, @@ -2003,88 +2948,93 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType(), Specialization, Info); } -/// \brief Stores the result of comparing the qualifiers of two types. -enum DeductionQualifierComparison { - NeitherMoreQualified = 0, - ParamMoreQualified, - ArgMoreQualified -}; +namespace { + /// Substitute the 'auto' type specifier within a type for a given replacement + /// type. + class SubstituteAutoTransform : + public TreeTransform<SubstituteAutoTransform> { + QualType Replacement; + public: + SubstituteAutoTransform(Sema &SemaRef, QualType Replacement) : + TreeTransform<SubstituteAutoTransform>(SemaRef), Replacement(Replacement) { + } + QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { + // If we're building the type pattern to deduce against, don't wrap the + // substituted type in an AutoType. Certain template deduction rules + // apply only when a template type parameter appears directly (and not if + // the parameter is found through desugaring). For instance: + // auto &&lref = lvalue; + // must transform into "rvalue reference to T" not "rvalue reference to + // auto type deduced as T" in order for [temp.deduct.call]p3 to apply. + if (isa<TemplateTypeParmType>(Replacement)) { + QualType Result = Replacement; + TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } else { + QualType Result = RebuildAutoType(Replacement); + AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + } + }; +} -/// \brief Deduce the template arguments during partial ordering by comparing -/// the parameter type and the argument type (C++0x [temp.deduct.partial]). -/// -/// \param S the semantic analysis object within which we are deducing +/// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6) /// -/// \param TemplateParams the template parameters that we are deducing -/// -/// \param ParamIn the parameter type -/// -/// \param ArgIn the argument type +/// \param Type the type pattern using the auto type-specifier. /// -/// \param Info information about the template argument deduction itself +/// \param Init the initializer for the variable whose type is to be deduced. /// -/// \param Deduced the deduced template arguments +/// \param Result if type deduction was successful, this will be set to the +/// deduced type. This may still contain undeduced autos if the type is +/// dependent. /// -/// \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(Sema &S, - TemplateParameterList *TemplateParams, - QualType ParamIn, QualType ArgIn, - TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, - llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) { - CanQualType Param = S.Context.getCanonicalType(ParamIn); - CanQualType Arg = S.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.isNull()) - 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.isNull()) - Arg = ArgRef->getPointeeType(); - - if (QualifierComparisons && !ParamRef.isNull() && !ArgRef.isNull()) { - // 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(S, TemplateParams, Param, Arg, Info, - Deduced, TDF_None); +/// \returns true if deduction succeeded, false if it failed. +bool +Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) { + if (Init->isTypeDependent()) { + Result = Type; + return true; + } + + SourceLocation Loc = Init->getExprLoc(); + + LocalInstantiationScope InstScope(*this); + + // Build template<class TemplParam> void Func(FuncParam); + NamedDecl *TemplParam + = TemplateTypeParmDecl::Create(Context, 0, Loc, 0, 0, 0, false, false); + TemplateParameterList *TemplateParams + = TemplateParameterList::Create(Context, Loc, Loc, &TemplParam, 1, Loc); + + QualType TemplArg = Context.getTemplateTypeParmType(0, 0, false); + QualType FuncParam = + SubstituteAutoTransform(*this, TemplArg).TransformType(Type); + + // Deduce type of TemplParam in Func(Init) + llvm::SmallVector<DeducedTemplateArgument, 1> Deduced; + Deduced.resize(1); + QualType InitType = Init->getType(); + unsigned TDF = 0; + if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, + FuncParam, InitType, Init, + TDF)) + return false; + + TemplateDeductionInfo Info(Context, Loc); + if (::DeduceTemplateArguments(*this, TemplateParams, + FuncParam, InitType, Info, Deduced, + TDF)) + return false; + + QualType DeducedType = Deduced[0].getAsType(); + if (DeducedType.isNull()) + return false; + + Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type); + return true; } static void @@ -2092,7 +3042,31 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, bool OnlyDeduced, unsigned Level, llvm::SmallVectorImpl<bool> &Deduced); - + +/// \brief If this is a non-static member function, +static void MaybeAddImplicitObjectParameterType(ASTContext &Context, + CXXMethodDecl *Method, + llvm::SmallVectorImpl<QualType> &ArgTypes) { + if (Method->isStatic()) + return; + + // C++ [over.match.funcs]p4: + // + // For non-static member functions, the type of the implicit + // object parameter is + // - "lvalue reference to cv X" for functions declared without a + // ref-qualifier or with the & ref-qualifier + // - "rvalue reference to cv X" for functions declared with the + // && ref-qualifier + // + // FIXME: We don't have ref-qualifiers yet, so we don't do that part. + QualType ArgTy = Context.getTypeDeclType(Method->getParent()); + ArgTy = Context.getQualifiedType(ArgTy, + Qualifiers::fromCVRMask(Method->getTypeQualifiers())); + ArgTy = Context.getLValueReferenceType(ArgTy); + ArgTypes.push_back(ArgTy); +} + /// \brief Determine whether the function template \p FT1 is at least as /// specialized as \p FT2. static bool isAtLeastAsSpecializedAs(Sema &S, @@ -2100,12 +3074,13 @@ static bool isAtLeastAsSpecializedAs(Sema &S, FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC, - llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) { + unsigned NumCallArguments, + llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) { FunctionDecl *FD1 = FT1->getTemplatedDecl(); - FunctionDecl *FD2 = FT2->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<DeducedTemplateArgument, 4> Deduced; @@ -2115,55 +3090,89 @@ static bool isAtLeastAsSpecializedAs(Sema &S, // The types used to determine the ordering depend on the context in which // the partial ordering is done: TemplateDeductionInfo Info(S.Context, Loc); + CXXMethodDecl *Method1 = 0; + CXXMethodDecl *Method2 = 0; + bool IsNonStatic2 = false; + bool IsNonStatic1 = false; + unsigned Skip2 = 0; 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, - TemplateParams, - Proto2->getArgType(I), - Proto1->getArgType(I), - Info, - Deduced, - QualifierComparisons)) + Method1 = dyn_cast<CXXMethodDecl>(FD1); + Method2 = dyn_cast<CXXMethodDecl>(FD2); + IsNonStatic1 = Method1 && !Method1->isStatic(); + IsNonStatic2 = Method2 && !Method2->isStatic(); + + // C++0x [temp.func.order]p3: + // [...] If only one of the function templates is a non-static + // member, that function template is considered to have a new + // first parameter inserted in its function parameter list. The + // new parameter is of type "reference to cv A," where cv are + // the cv-qualifiers of the function template (if any) and A is + // the class of which the function template is a member. + // + // C++98/03 doesn't have this provision, so instead we drop the + // first argument of the free function or static member, which + // seems to match existing practice. + llvm::SmallVector<QualType, 4> Args1; + unsigned Skip1 = !S.getLangOptions().CPlusPlus0x && + IsNonStatic2 && !IsNonStatic1; + if (S.getLangOptions().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2) + MaybeAddImplicitObjectParameterType(S.Context, Method1, Args1); + Args1.insert(Args1.end(), + Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end()); + + llvm::SmallVector<QualType, 4> Args2; + Skip2 = !S.getLangOptions().CPlusPlus0x && + IsNonStatic1 && !IsNonStatic2; + if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1) + MaybeAddImplicitObjectParameterType(S.Context, Method2, Args2); + Args2.insert(Args2.end(), + Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end()); + + // C++ [temp.func.order]p5: + // The presence of unused ellipsis and default arguments has no effect on + // the partial ordering of function templates. + if (Args1.size() > NumCallArguments) + Args1.resize(NumCallArguments); + if (Args2.size() > NumCallArguments) + Args2.resize(NumCallArguments); + if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), + Args1.data(), Args1.size(), Info, Deduced, + TDF_None, /*PartialOrdering=*/true, + RefParamComparisons)) 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, - TemplateParams, - Proto2->getResultType(), - Proto1->getResultType(), - Info, - Deduced, - QualifierComparisons)) + if (DeduceTemplateArguments(S, TemplateParams, Proto2->getResultType(), + Proto1->getResultType(), Info, Deduced, + TDF_None, /*PartialOrdering=*/true, + RefParamComparisons)) return false; break; - + case TPOC_Other: - // - In other contexts (14.6.6.2) the function template’s function type + // - In other contexts (14.6.6.2) the function template's function type // is used. - if (DeduceTemplateArgumentsDuringPartialOrdering(S, - TemplateParams, - FD2->getType(), - FD1->getType(), - Info, - Deduced, - QualifierComparisons)) + // FIXME: Don't we actually want to perform the adjustments on the parameter + // types? + if (DeduceTemplateArguments(S, TemplateParams, FD2->getType(), + FD1->getType(), Info, Deduced, TDF_None, + /*PartialOrdering=*/true, RefParamComparisons)) return false; break; } - + // 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 + // 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(); @@ -2172,7 +3181,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, break; if (ArgIdx == NumArgs) { - // All template arguments were deduced. FT1 is at least as specialized + // All template arguments were deduced. FT1 is at least as specialized // as FT2. return true; } @@ -2182,37 +3191,62 @@ static bool isAtLeastAsSpecializedAs(Sema &S, 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, + unsigned NumParams = std::min(NumCallArguments, + std::min(Proto1->getNumArgs(), + Proto2->getNumArgs())); + if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1) + ::MarkUsedTemplateParameters(S, Method2->getThisType(S.Context), false, + TemplateParams->getDepth(), UsedParameters); + for (unsigned I = Skip2; I < NumParams; ++I) + ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false, TemplateParams->getDepth(), UsedParameters); break; } - + case TPOC_Conversion: - ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, + ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, TemplateParams->getDepth(), UsedParameters); break; - + case TPOC_Other: - ::MarkUsedTemplateParameters(S, FD2->getType(), false, + ::MarkUsedTemplateParameters(S, FD2->getType(), false, TemplateParams->getDepth(), UsedParameters); break; } - + 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; - + + return true; +} + +/// \brief Determine whether this a function template whose parameter-type-list +/// ends with a function parameter pack. +static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { + FunctionDecl *Function = FunTmpl->getTemplatedDecl(); + unsigned NumParams = Function->getNumParams(); + if (NumParams == 0) + return false; + + ParmVarDecl *Last = Function->getParamDecl(NumParams - 1); + if (!Last->isParameterPack()) + return false; + + // Make sure that no previous parameter is a parameter pack. + while (--NumParams > 0) { + if (Function->getParamDecl(NumParams - 1)->isParameterPack()) + return false; + } + return true; } - - + /// \brief Returns the more specialized function template according /// to the rules of function template partial ordering (C++ [temp.func.order]). /// @@ -2223,77 +3257,113 @@ static bool isAtLeastAsSpecializedAs(Sema &S, /// \param TPOC the context in which we are performing partial ordering of /// function templates. /// +/// \param NumCallArguments The number of arguments in a call, used only +/// when \c TPOC is \c TPOC_Call. +/// /// \returns the more specialized function template. If neither /// template is more specialized, returns NULL. FunctionTemplateDecl * Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, - TemplatePartialOrderingContext TPOC) { - llvm::SmallVector<DeductionQualifierComparison, 4> QualifierComparisons; - bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, 0); - bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, - &QualifierComparisons); - + TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments) { + llvm::SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons; + bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, + NumCallArguments, 0); + bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, + NumCallArguments, + &RefParamComparisons); + 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 + // 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 + // 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) { + for (unsigned I = 0, N = RefParamComparisons.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; + // types are identical after the transformations above) and both P and A + // were reference types (before being replaced with the type referred to + // above): + + // -- if the type from the argument template was an lvalue reference + // and the type from the parameter template was not, the argument + // type is considered to be more specialized than the other; + // otherwise, + if (!RefParamComparisons[I].ArgIsRvalueRef && + RefParamComparisons[I].ParamIsRvalueRef) { + Better2 = true; + if (Better1) + return 0; + continue; + } else if (!RefParamComparisons[I].ParamIsRvalueRef && + RefParamComparisons[I].ArgIsRvalueRef) { + Better1 = true; + if (Better2) + return 0; + continue; } + + // -- if the type from the argument template is more cv-qualified than + // the type from the parameter template (as described above), the + // argument type is considered to be more specialized than the + // other; otherwise, + switch (RefParamComparisons[I].Qualifiers) { + case NeitherMoreQualified: + break; + + case ParamMoreQualified: + Better1 = true; + if (Better2) + return 0; + continue; + + case ArgMoreQualified: + Better2 = true; + if (Better1) + return 0; + continue; + } + + // -- neither type is more specialized than the other. } - + assert(!(Better1 && Better2) && "Should have broken out in the loop above"); if (Better1) return FT1; else if (Better2) return FT2; - else - return 0; + + // FIXME: This mimics what GCC implements, but doesn't match up with the + // proposed resolution for core issue 692. This area needs to be sorted out, + // but for now we attempt to maintain compatibility. + bool Variadic1 = isVariadicFunctionTemplate(FT1); + bool Variadic2 = isVariadicFunctionTemplate(FT2); + if (Variadic1 != Variadic2) + return Variadic1? FT2 : FT1; + + return 0; } /// \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(); } @@ -2309,7 +3379,10 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { /// \param TPOC the partial ordering context to use to compare the function /// template specializations. /// -/// \param Loc the location where the ambiguity or no-specializations +/// \param NumCallArguments The number of arguments in a call, used only +/// when \c TPOC is \c TPOC_Call. +/// +/// \param Loc the location where the ambiguity or no-specializations /// diagnostic should occur. /// /// \param NoneDiag partial diagnostic used to diagnose cases where there are @@ -2323,35 +3396,38 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { /// 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, +/// \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 +/// \returns the most specialized function template specialization, if /// found. Otherwise, returns SpecEnd. /// -/// \todo FIXME: Consider passing in the "also-ran" candidates that failed +/// \todo FIXME: Consider passing in the "also-ran" candidates that failed /// template argument deduction. UnresolvedSetIterator Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, - UnresolvedSetIterator SpecEnd, + UnresolvedSetIterator SpecEnd, TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments, SourceLocation Loc, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag) { + const PartialDiagnostic &CandidateDiag, + bool Complain) { if (SpecBegin == SpecEnd) { - Diag(Loc, NoneDiag); + if (Complain) + Diag(Loc, NoneDiag); return SpecEnd; } - - if (SpecBegin + 1 == SpecEnd) + + if (SpecBegin + 1 == SpecEnd) return SpecBegin; - + // Find the function template that is better than all of the templates it // has been compared to. UnresolvedSetIterator Best = SpecBegin; - FunctionTemplateDecl *BestTemplate + FunctionTemplateDecl *BestTemplate = cast<FunctionDecl>(*Best)->getPrimaryTemplate(); assert(BestTemplate && "Not a function template specialization?"); for (UnresolvedSetIterator I = SpecBegin + 1; I != SpecEnd; ++I) { @@ -2359,13 +3435,13 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, = cast<FunctionDecl>(*I)->getPrimaryTemplate(); assert(Challenger && "Not a function template specialization?"); if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, - Loc, TPOC), + Loc, TPOC, NumCallArguments), Challenger)) { Best = I; BestTemplate = Challenger; } } - + // Make sure that the "best" function template is more specialized than all // of the others. bool Ambiguous = false; @@ -2373,29 +3449,31 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, FunctionTemplateDecl *Challenger = cast<FunctionDecl>(*I)->getPrimaryTemplate(); if (I != Best && - !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, - Loc, TPOC), + !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, + Loc, TPOC, NumCallArguments), BestTemplate)) { Ambiguous = true; break; } } - + if (!Ambiguous) { // We found an answer. Return it. return Best; } - + // Diagnose the ambiguity. - Diag(Loc, AmbigDiag); - + if (Complain) + Diag(Loc, AmbigDiag); + + if (Complain) // FIXME: Can we order the candidates in some sane way? - for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) - Diag((*I)->getLocation(), CandidateDiag) - << getTemplateArgumentBindingsText( - cast<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(), + for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) + Diag((*I)->getLocation(), CandidateDiag) + << getTemplateArgumentBindingsText( + cast<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(), *cast<FunctionDecl>(*I)->getTemplateSpecializationArgs()); - + return SpecEnd; } @@ -2416,17 +3494,17 @@ Sema::getMoreSpecializedPartialSpecialization( SourceLocation Loc) { // 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 + // 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 + // 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 + // 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 @@ -2443,39 +3521,39 @@ Sema::getMoreSpecializedPartialSpecialization( QualType PT1 = PS1->getInjectedSpecializationType(); QualType PT2 = PS2->getInjectedSpecializationType(); - + // Determine whether PS1 is at least as specialized as PS2 Deduced.resize(PS2->getTemplateParameters()->size()); - bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(*this, - PS2->getTemplateParameters(), - PT2, - PT1, - Info, - Deduced, - 0); - if (Better1) - Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, - PS1->getTemplateArgs(), + bool Better1 = !::DeduceTemplateArguments(*this, PS2->getTemplateParameters(), + PT2, PT1, Info, Deduced, TDF_None, + /*PartialOrdering=*/true, + /*RefParamComparisons=*/0); + if (Better1) { + InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2, + Deduced.data(), Deduced.size(), Info); + Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, + PS1->getTemplateArgs(), Deduced, Info); - + } + // Determine whether PS2 is at least as specialized as PS1 Deduced.clear(); Deduced.resize(PS1->getTemplateParameters()->size()); - bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(*this, - PS1->getTemplateParameters(), - PT1, - PT2, - Info, - Deduced, - 0); - if (Better2) - Better2 = !::FinishTemplateArgumentDeduction(*this, PS1, - PS2->getTemplateArgs(), + bool Better2 = !::DeduceTemplateArguments(*this, PS1->getTemplateParameters(), + PT1, PT2, Info, Deduced, TDF_None, + /*PartialOrdering=*/true, + /*RefParamComparisons=*/0); + if (Better2) { + InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1, + Deduced.data(), Deduced.size(), Info); + Better2 = !::FinishTemplateArgumentDeduction(*this, PS1, + PS2->getTemplateArgs(), Deduced, Info); - + } + if (Better1 == Better2) return 0; - + return Better1? PS1 : PS2; } @@ -2494,7 +3572,15 @@ MarkUsedTemplateParameters(Sema &SemaRef, bool OnlyDeduced, unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { - // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to + // We can deduce from a pack expansion. + if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E)) + E = Expansion->getPattern(); + + // Skip through any implicit casts we added while type-checking. + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + E = ICE->getSubExpr(); + + // 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 (!DRE) @@ -2519,13 +3605,13 @@ MarkUsedTemplateParameters(Sema &SemaRef, llvm::SmallVectorImpl<bool> &Used) { if (!NNS) return; - + MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Depth, Used); - MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0), + MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0), OnlyDeduced, Depth, Used); } - + /// \brief Mark the template parameters that are used by the given /// template name. static void @@ -2542,12 +3628,12 @@ MarkUsedTemplateParameters(Sema &SemaRef, } return; } - + if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) - MarkUsedTemplateParameters(SemaRef, QTN->getQualifier(), OnlyDeduced, + MarkUsedTemplateParameters(SemaRef, QTN->getQualifier(), OnlyDeduced, Depth, Used); if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) - MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, + MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Depth, Used); } @@ -2560,7 +3646,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, llvm::SmallVectorImpl<bool> &Used) { if (T.isNull()) return; - + // Non-dependent types have nothing deducible if (!T->isDependentType()) return; @@ -2626,7 +3712,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, = cast<DependentSizedExtVectorType>(T); MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced, Depth, Used); - MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced, + MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced, Depth, Used); break; } @@ -2648,6 +3734,17 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, break; } + case Type::SubstTemplateTypeParmPack: { + const SubstTemplateTypeParmPackType *Subst + = cast<SubstTemplateTypeParmPackType>(T); + MarkUsedTemplateParameters(SemaRef, + QualType(Subst->getReplacedParameter(), 0), + OnlyDeduced, Depth, Used); + MarkUsedTemplateParameters(SemaRef, Subst->getArgumentPack(), + OnlyDeduced, Depth, Used); + break; + } + case Type::InjectedClassName: T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType(); // fall through @@ -2657,6 +3754,15 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, = cast<TemplateSpecializationType>(T); MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced, Depth, Used); + + // C++0x [temp.deduct.type]p9: + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a + // non-deduced context. + if (OnlyDeduced && + hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs())) + break; + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth, Used); @@ -2665,7 +3771,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, case Type::Complex: if (!OnlyDeduced) - MarkUsedTemplateParameters(SemaRef, + MarkUsedTemplateParameters(SemaRef, cast<ComplexType>(T)->getElementType(), OnlyDeduced, Depth, Used); break; @@ -2683,6 +3789,15 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, Spec->getQualifier(), OnlyDeduced, Depth, Used); + + // C++0x [temp.deduct.type]p9: + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a + // non-deduced context. + if (OnlyDeduced && + hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs())) + break; + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth, Used); @@ -2710,6 +3825,17 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; + case Type::PackExpansion: + MarkUsedTemplateParameters(SemaRef, + cast<PackExpansionType>(T)->getPattern(), + OnlyDeduced, Depth, Used); + break; + + case Type::Auto: + MarkUsedTemplateParameters(SemaRef, + cast<AutoType>(T)->getDeducedType(), + OnlyDeduced, Depth, Used); + // None of these types have any template parameters in them. case Type::Builtin: case Type::VariableArray: @@ -2749,15 +3875,17 @@ MarkUsedTemplateParameters(Sema &SemaRef, break; case TemplateArgument::Template: - MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsTemplate(), + case TemplateArgument::TemplateExpansion: + MarkUsedTemplateParameters(SemaRef, + TemplateArg.getAsTemplateOrTemplatePattern(), OnlyDeduced, Depth, Used); break; case TemplateArgument::Expression: - MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced, + MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced, Depth, Used); break; - + case TemplateArgument::Pack: for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(), PEnd = TemplateArg.pack_end(); @@ -2780,21 +3908,29 @@ void Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { + // C++0x [temp.deduct.type]p9: + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a + // non-deduced context. + if (OnlyDeduced && + hasPackExpansionBeforeEnd(TemplateArgs.data(), TemplateArgs.size())) + return; + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) - ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, + ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Depth, Used); } /// \brief Marks all of the template parameters that will be deduced by a /// call to the given function template. -void +void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVectorImpl<bool> &Deduced) { - TemplateParameterList *TemplateParams + 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(), diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 4d4c181..44f5913 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -147,8 +147,10 @@ Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -159,6 +161,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Inst.TemplateArgs = 0; Inst.NumTemplateArgs = 0; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); } } @@ -169,8 +172,10 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -182,6 +187,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); } } @@ -192,9 +198,12 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, ActiveTemplateInstantiation::InstantiationKind Kind, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) -: SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -204,7 +213,9 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.Entity = reinterpret_cast<uintptr_t>(FunctionTemplate); Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; + Inst.DeductionInfo = &DeductionInfo; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); if (!Inst.isInstantiationRecord()) @@ -217,9 +228,12 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; @@ -228,7 +242,9 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec); Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; + Inst.DeductionInfo = &DeductionInfo; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -241,8 +257,10 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -254,17 +272,22 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); } } Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, + NamedDecl *Template, NonTypeTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, - SourceRange InstantiationRange) : SemaRef(SemaRef) { + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; @@ -275,6 +298,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -283,11 +307,15 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, + NamedDecl *Template, TemplateTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, - SourceRange InstantiationRange) : SemaRef(SemaRef) { + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution; @@ -297,6 +325,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -309,7 +338,11 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, - SourceRange InstantiationRange) : SemaRef(SemaRef) { + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; @@ -320,6 +353,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -332,7 +366,8 @@ void Sema::InstantiatingTemplate::Clear() { assert(SemaRef.NonInstantiationEntries > 0); --SemaRef.NonInstantiationEntries; } - + SemaRef.InNonInstantiationSFINAEContext + = SavedInNonInstantiationSFINAEContext; SemaRef.ActiveTemplateInstantiations.pop_back(); Invalid = true; } @@ -379,7 +414,7 @@ void Sema::PrintInstantiationStack() { if (InstantiationIdx >= SkipStart && InstantiationIdx < SkipEnd) { if (InstantiationIdx == SkipStart) { // Note that we're skipping instantiations. - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + Diags.Report(Active->PointOfInstantiation, diag::note_instantiation_contexts_suppressed) << unsigned(ActiveTemplateInstantiations.size() - Limit); } @@ -393,8 +428,7 @@ 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), - DiagID) + Diags.Report(Active->PointOfInstantiation, DiagID) << Context.getTypeDeclType(Record) << Active->InstantiationRange; } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { @@ -403,12 +437,11 @@ void Sema::PrintInstantiationStack() { DiagID = diag::note_function_template_spec_here; else DiagID = diag::note_template_member_function_here; - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), - DiagID) + Diags.Report(Active->PointOfInstantiation, DiagID) << Function << Active->InstantiationRange; } else { - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + Diags.Report(Active->PointOfInstantiation, diag::note_template_static_data_member_def_here) << cast<VarDecl>(D) << Active->InstantiationRange; @@ -423,7 +456,7 @@ void Sema::PrintInstantiationStack() { Active->TemplateArgs, Active->NumTemplateArgs, Context.PrintingPolicy); - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + Diags.Report(Active->PointOfInstantiation, diag::note_default_arg_instantiation_here) << (Template->getNameAsString() + TemplateArgsStr) << Active->InstantiationRange; @@ -433,7 +466,7 @@ void Sema::PrintInstantiationStack() { case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: { FunctionTemplateDecl *FnTmpl = cast<FunctionTemplateDecl>((Decl *)Active->Entity); - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + Diags.Report(Active->PointOfInstantiation, diag::note_explicit_template_arg_substitution_here) << FnTmpl << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), @@ -447,7 +480,7 @@ void Sema::PrintInstantiationStack() { if (ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast<ClassTemplatePartialSpecializationDecl>( (Decl *)Active->Entity)) { - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + Diags.Report(Active->PointOfInstantiation, diag::note_partial_spec_deduct_instantiation_here) << Context.getTypeDeclType(PartialSpec) << getTemplateArgumentBindingsText( @@ -458,7 +491,7 @@ void Sema::PrintInstantiationStack() { } else { FunctionTemplateDecl *FnTmpl = cast<FunctionTemplateDecl>((Decl *)Active->Entity); - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + Diags.Report(Active->PointOfInstantiation, diag::note_function_template_deduction_instantiation_here) << FnTmpl << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), @@ -477,7 +510,7 @@ void Sema::PrintInstantiationStack() { Active->TemplateArgs, Active->NumTemplateArgs, Context.PrintingPolicy); - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + Diags.Report(Active->PointOfInstantiation, diag::note_default_function_arg_instantiation_here) << (FD->getNameAsString() + TemplateArgsStr) << Active->InstantiationRange; @@ -489,13 +522,19 @@ void Sema::PrintInstantiationStack() { std::string Name; if (!Parm->getName().empty()) Name = std::string(" '") + Parm->getName().str() + "'"; - - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + + TemplateParameterList *TemplateParams = 0; + if (TemplateDecl *Template = dyn_cast<TemplateDecl>(Active->Template)) + TemplateParams = Template->getTemplateParameters(); + else + TemplateParams = + cast<ClassTemplatePartialSpecializationDecl>(Active->Template) + ->getTemplateParameters(); + Diags.Report(Active->PointOfInstantiation, diag::note_prior_template_arg_substitution) << isa<TemplateTemplateParmDecl>(Parm) << Name - << getTemplateArgumentBindingsText( - Active->Template->getTemplateParameters(), + << getTemplateArgumentBindingsText(TemplateParams, Active->TemplateArgs, Active->NumTemplateArgs) << Active->InstantiationRange; @@ -503,10 +542,17 @@ void Sema::PrintInstantiationStack() { } case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking: { - Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + TemplateParameterList *TemplateParams = 0; + if (TemplateDecl *Template = dyn_cast<TemplateDecl>(Active->Template)) + TemplateParams = Template->getTemplateParameters(); + else + TemplateParams = + cast<ClassTemplatePartialSpecializationDecl>(Active->Template) + ->getTemplateParameters(); + + Diags.Report(Active->PointOfInstantiation, diag::note_template_default_arg_checking) - << getTemplateArgumentBindingsText( - Active->Template->getTemplateParameters(), + << getTemplateArgumentBindingsText(TemplateParams, Active->TemplateArgs, Active->NumTemplateArgs) << Active->InstantiationRange; @@ -516,8 +562,11 @@ void Sema::PrintInstantiationStack() { } } -bool Sema::isSFINAEContext() const { +llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { using llvm::SmallVector; + if (InNonInstantiationSFINAEContext) + return llvm::Optional<TemplateDeductionInfo *>(0); + for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); @@ -525,10 +574,10 @@ bool Sema::isSFINAEContext() const { ++Active) { switch(Active->Kind) { - case ActiveTemplateInstantiation::TemplateInstantiation: case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: + case ActiveTemplateInstantiation::TemplateInstantiation: // This is a template instantiation, so there is no SFINAE. - return false; + return llvm::Optional<TemplateDeductionInfo *>(); case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: @@ -542,11 +591,25 @@ bool Sema::isSFINAEContext() const { case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: // We're either substitution explicitly-specified template arguments // or deduced template arguments, so SFINAE applies. - return true; + assert(Active->DeductionInfo && "Missing deduction info pointer"); + return Active->DeductionInfo; } } - return false; + return llvm::Optional<TemplateDeductionInfo *>(); +} + +/// \brief Retrieve the depth and index of a parameter pack. +static std::pair<unsigned, unsigned> +getDepthAndIndex(NamedDecl *ND) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) + return std::make_pair(TTP->getDepth(), TTP->getIndex()); + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) + return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); + return std::make_pair(TTP->getDepth(), TTP->getIndex()); } //===----------------------------------------------------------------------===/ @@ -587,7 +650,58 @@ namespace { this->Loc = Loc; this->Entity = Entity; } + + bool TryExpandParameterPacks(SourceLocation EllipsisLoc, + SourceRange PatternRange, + const UnexpandedParameterPack *Unexpanded, + unsigned NumUnexpanded, + bool &ShouldExpand, + bool &RetainExpansion, + llvm::Optional<unsigned> &NumExpansions) { + return getSema().CheckParameterPacksForExpansion(EllipsisLoc, + PatternRange, Unexpanded, + NumUnexpanded, + TemplateArgs, + ShouldExpand, + RetainExpansion, + NumExpansions); + } + + void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { + SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack); + } + + TemplateArgument ForgetPartiallySubstitutedPack() { + TemplateArgument Result; + if (NamedDecl *PartialPack + = SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()){ + MultiLevelTemplateArgumentList &TemplateArgs + = const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs); + unsigned Depth, Index; + llvm::tie(Depth, Index) = getDepthAndIndex(PartialPack); + if (TemplateArgs.hasTemplateArgument(Depth, Index)) { + Result = TemplateArgs(Depth, Index); + TemplateArgs.setArgument(Depth, Index, TemplateArgument()); + } + } + + return Result; + } + + void RememberPartiallySubstitutedPack(TemplateArgument Arg) { + if (Arg.isNull()) + return; + if (NamedDecl *PartialPack + = SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()){ + MultiLevelTemplateArgumentList &TemplateArgs + = const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs); + unsigned Depth, Index; + llvm::tie(Depth, Index) = getDepthAndIndex(PartialPack); + TemplateArgs.setArgument(Depth, Index, Arg); + } + } + /// \brief Transform the given declaration by instantiating a reference to /// this declaration. Decl *TransformDecl(SourceLocation Loc, Decl *D); @@ -602,10 +716,10 @@ namespace { /// \brief Rebuild the exception declaration and register the declaration /// as an instantiated local. - VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, + VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *Declarator, IdentifierInfo *Name, - SourceLocation Loc, SourceRange TypeRange); + SourceLocation Loc); /// \brief Rebuild the Objective-C exception declaration and register the /// declaration as an instantiated local. @@ -614,25 +728,37 @@ namespace { /// \brief Check for tag mismatches when instantiating an /// elaborated type. - QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword, + QualType RebuildElaboratedType(SourceLocation KeywordLoc, + ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType T); + TemplateName TransformTemplateName(TemplateName Name, + QualType ObjectType = QualType(), + NamedDecl *FirstQualifierInScope = 0); + ExprResult TransformPredefinedExpr(PredefinedExpr *E); ExprResult TransformDeclRefExpr(DeclRefExpr *E); ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E, - NonTypeTemplateParmDecl *D); - + NonTypeTemplateParmDecl *D); + ExprResult TransformSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E); + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL, - QualType ObjectType); - ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm); + FunctionProtoTypeLoc TL); + ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, + llvm::Optional<unsigned> NumExpansions); /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL, - QualType ObjectType); + TemplateTypeParmTypeLoc TL); + + /// \brief Transforms an already-substituted template type parameter pack + /// into either itself (if we aren't substituting into its pack expansion) + /// or the appropriate substituted argument. + QualType TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL); ExprResult TransformCallExpr(CallExpr *CE) { getSema().CallsUndergoingInstantiation.push_back(CE); @@ -669,8 +795,18 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { TTP->getPosition())) return D; - TemplateName Template - = TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate(); + TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition()); + + if (TTP->isParameterPack()) { + assert(Arg.getKind() == TemplateArgument::Pack && + "Missing argument pack"); + + assert(getSema().ArgumentPackSubstitutionIndex >= 0); + assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); + Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex]; + } + + TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && Template.getAsTemplateDecl() && "Wrong kind of template template argument"); return Template.getAsTemplateDecl(); @@ -700,8 +836,23 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, if (TemplateTypeParmDecl *TTPD = dyn_cast_or_null<TemplateTypeParmDecl>(D)) { const TemplateTypeParmType *TTP = cast<TemplateTypeParmType>(getSema().Context.getTypeDeclType(TTPD)); + if (TTP->getDepth() < TemplateArgs.getNumLevels()) { - QualType T = TemplateArgs(TTP->getDepth(), TTP->getIndex()).getAsType(); + // FIXME: This needs testing w/ member access expressions. + TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getIndex()); + + if (TTP->isParameterPack()) { + assert(Arg.getKind() == TemplateArgument::Pack && + "Missing argument pack"); + + if (getSema().ArgumentPackSubstitutionIndex == -1) + return 0; + + assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); + Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex]; + } + + QualType T = Arg.getAsType(); if (T.isNull()) return cast_or_null<NamedDecl>(TransformDecl(Loc, D)); @@ -719,13 +870,11 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, VarDecl * TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, - QualType T, TypeSourceInfo *Declarator, IdentifierInfo *Name, - SourceLocation Loc, - SourceRange TypeRange) { - VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, T, Declarator, - Name, Loc, TypeRange); + SourceLocation Loc) { + VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, Declarator, + Name, Loc); if (Var) getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); return Var; @@ -741,14 +890,14 @@ VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, } QualType -TemplateInstantiator::RebuildElaboratedType(ElaboratedTypeKeyword Keyword, +TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, + ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType T) { 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(); + SourceLocation TagLocation = KeywordLoc; // FIXME: type might be anonymous. IdentifierInfo *Id = TD->getIdentifier(); @@ -767,14 +916,69 @@ TemplateInstantiator::RebuildElaboratedType(ElaboratedTypeKeyword Keyword, } } - return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(Keyword, + return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(KeywordLoc, + Keyword, NNS, T); } +TemplateName TemplateInstantiator::TransformTemplateName(TemplateName Name, + QualType ObjectType, + NamedDecl *FirstQualifierInScope) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) { + if (TTP->getDepth() < TemplateArgs.getNumLevels()) { + // 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 Name; + + TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition()); + + if (TTP->isParameterPack()) { + assert(Arg.getKind() == TemplateArgument::Pack && + "Missing argument pack"); + + if (getSema().ArgumentPackSubstitutionIndex == -1) { + // We have the template argument pack to substitute, but we're not + // actually expanding the enclosing pack expansion yet. So, just + // keep the entire argument pack. + return getSema().Context.getSubstTemplateTemplateParmPack(TTP, Arg); + } + + assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); + Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex]; + } + + TemplateName Template = Arg.getAsTemplate(); + assert(!Template.isNull() && Template.getAsTemplateDecl() && + "Wrong kind of template template argument"); + return Template; + } + } + + if (SubstTemplateTemplateParmPackStorage *SubstPack + = Name.getAsSubstTemplateTemplateParmPack()) { + if (getSema().ArgumentPackSubstitutionIndex == -1) + return Name; + + const TemplateArgument &ArgPack = SubstPack->getArgumentPack(); + assert(getSema().ArgumentPackSubstitutionIndex < (int)ArgPack.pack_size() && + "Pack substitution index out-of-range"); + return ArgPack.pack_begin()[getSema().ArgumentPackSubstitutionIndex] + .getAsTemplate(); + } + + return inherited::TransformTemplateName(Name, ObjectType, + FirstQualifierInScope); +} + ExprResult TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { if (!E->isTypeDependent()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); FunctionDecl *currentDecl = getSema().getCurFunctionDecl(); assert(currentDecl && "Must have current function declaration when " @@ -802,15 +1006,37 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, // arguments left unspecified. if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(), NTTP->getPosition())) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); - const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(), - NTTP->getPosition()); + TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition()); + if (NTTP->isParameterPack()) { + assert(Arg.getKind() == TemplateArgument::Pack && + "Missing argument pack"); + + if (getSema().ArgumentPackSubstitutionIndex == -1) { + // We have an argument pack, but we can't select a particular argument + // out of it yet. Therefore, we'll build an expression to hold on to that + // argument pack. + QualType TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs, + E->getLocation(), + NTTP->getDeclName()); + if (TargetType.isNull()) + return ExprError(); + + return new (SemaRef.Context) SubstNonTypeTemplateParmPackExpr(TargetType, + NTTP, + E->getLocation(), + Arg); + } + + assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); + Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex]; + } // 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()); + return SemaRef.Owned(Arg.getAsExpr()); if (Arg.getKind() == TemplateArgument::Declaration) { ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); @@ -825,9 +1051,19 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, // Derive the type we want the substituted decl to have. This had // better be non-dependent, or these checks will have serious problems. - QualType TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs, - E->getLocation(), - DeclarationName()); + QualType TargetType; + if (NTTP->isExpandedParameterPack()) + TargetType = NTTP->getExpansionType( + getSema().ArgumentPackSubstitutionIndex); + else if (NTTP->isParameterPack() && + isa<PackExpansionType>(NTTP->getType())) { + TargetType = SemaRef.SubstType( + cast<PackExpansionType>(NTTP->getType())->getPattern(), + TemplateArgs, E->getLocation(), + NTTP->getDeclName()); + } else + TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs, + E->getLocation(), NTTP->getDeclName()); assert(!TargetType.isNull() && "type substitution failed for param type"); assert(!TargetType->isDependentType() && "param type still dependent"); return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, @@ -839,6 +1075,50 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, E->getSourceRange().getBegin()); } +ExprResult +TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E) { + if (getSema().ArgumentPackSubstitutionIndex == -1) { + // We aren't expanding the parameter pack, so just return ourselves. + return getSema().Owned(E); + } + + const TemplateArgument &ArgPack = E->getArgumentPack(); + unsigned Index = (unsigned)getSema().ArgumentPackSubstitutionIndex; + assert(Index < ArgPack.pack_size() && "Substitution index out-of-range"); + + const TemplateArgument &Arg = ArgPack.pack_begin()[Index]; + if (Arg.getKind() == TemplateArgument::Expression) + return SemaRef.Owned(Arg.getAsExpr()); + + if (Arg.getKind() == TemplateArgument::Declaration) { + ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); + + // Find the instantiation of the template argument. This is + // required for nested templates. + VD = cast_or_null<ValueDecl>( + getSema().FindInstantiatedDecl(E->getParameterPackLocation(), + VD, TemplateArgs)); + if (!VD) + return ExprError(); + + QualType T; + NonTypeTemplateParmDecl *NTTP = E->getParameterPack(); + if (NTTP->isExpandedParameterPack()) + T = NTTP->getExpansionType(getSema().ArgumentPackSubstitutionIndex); + else if (const PackExpansionType *Expansion + = dyn_cast<PackExpansionType>(NTTP->getType())) + T = SemaRef.SubstType(Expansion->getPattern(), TemplateArgs, + E->getParameterPackLocation(), NTTP->getDeclName()); + else + T = E->getType(); + return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, T, + E->getParameterPackLocation()); + } + + return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg, + E->getParameterPackLocation()); +} ExprResult TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { @@ -865,23 +1145,23 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( } QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL, - QualType ObjectType) { + FunctionProtoTypeLoc TL) { // We need a local instantiation scope for this function prototype. LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformFunctionProtoType(TLB, TL, ObjectType); + return inherited::TransformFunctionProtoType(TLB, TL); } ParmVarDecl * -TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) { - return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs); +TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm, + llvm::Optional<unsigned> NumExpansions) { + return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, + NumExpansions); } QualType TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL, - QualType ObjectType) { - TemplateTypeParmType *T = TL.getTypePtr(); + TemplateTypeParmTypeLoc TL) { + const TemplateTypeParmType *T = TL.getTypePtr(); if (T->getDepth() < TemplateArgs.getNumLevels()) { // Replace the template type parameter with its corresponding // template argument. @@ -897,12 +1177,32 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, return TL.getType(); } - assert(TemplateArgs(T->getDepth(), T->getIndex()).getKind() - == TemplateArgument::Type && + TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex()); + + if (T->isParameterPack()) { + assert(Arg.getKind() == TemplateArgument::Pack && + "Missing argument pack"); + + if (getSema().ArgumentPackSubstitutionIndex == -1) { + // We have the template argument pack, but we're not expanding the + // enclosing pack expansion yet. Just save the template argument + // pack for later substitution. + QualType Result + = getSema().Context.getSubstTemplateTypeParmPackType(T, Arg); + SubstTemplateTypeParmPackTypeLoc NewTL + = TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + + assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); + Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex]; + } + + assert(Arg.getKind() == TemplateArgument::Type && "Template argument kind mismatch"); - QualType Replacement - = TemplateArgs(T->getDepth(), T->getIndex()).getAsType(); + QualType Replacement = Arg.getAsType(); // TODO: only do this uniquing once, at the start of instantiation. QualType Result @@ -928,6 +1228,32 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, return Result; } +QualType +TemplateInstantiator::TransformSubstTemplateTypeParmPackType( + TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL) { + if (getSema().ArgumentPackSubstitutionIndex == -1) { + // We aren't expanding the parameter pack, so just return ourselves. + SubstTemplateTypeParmPackTypeLoc NewTL + = TLB.push<SubstTemplateTypeParmPackTypeLoc>(TL.getType()); + NewTL.setNameLoc(TL.getNameLoc()); + return TL.getType(); + } + + const TemplateArgument &ArgPack = TL.getTypePtr()->getArgumentPack(); + unsigned Index = (unsigned)getSema().ArgumentPackSubstitutionIndex; + assert(Index < ArgPack.pack_size() && "Substitution index out-of-range"); + + QualType Result = ArgPack.pack_begin()[Index].getAsType(); + Result = getSema().Context.getSubstTemplateTypeParmType( + TL.getTypePtr()->getReplacedParameter(), + Result); + SubstTemplateTypeParmTypeLoc NewTL + = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; +} + /// \brief Perform substitution on the type T with a given set of template /// arguments. /// @@ -971,6 +1297,36 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T, return Instantiator.TransformType(T); } +TypeSourceInfo *Sema::SubstType(TypeLoc TL, + const MultiLevelTemplateArgumentList &Args, + SourceLocation Loc, + DeclarationName Entity) { + assert(!ActiveTemplateInstantiations.empty() && + "Cannot perform an instantiation without some context on the " + "instantiation stack"); + + if (TL.getType().isNull()) + return 0; + + if (!TL.getType()->isDependentType() && + !TL.getType()->isVariablyModifiedType()) { + // FIXME: Make a copy of the TypeLoc data here, so that we can + // return a new TypeSourceInfo. Inefficient! + TypeLocBuilder TLB; + TLB.pushFullCopy(TL); + return TLB.getTypeSourceInfo(Context, TL.getType()); + } + + TemplateInstantiator Instantiator(*this, Args, Loc, Entity); + TypeLocBuilder TLB; + TLB.reserve(TL.getFullDataSize()); + QualType Result = Instantiator.TransformType(TLB, TL); + if (Result.isNull()) + return 0; + + return TLB.getTypeSourceInfo(Context, Result); +} + /// Deprecated form of the above. QualType Sema::SubstType(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -992,7 +1348,7 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { if (T->getType()->isDependentType() || T->getType()->isVariablyModifiedType()) return true; - TypeLoc TL = T->getTypeLoc(); + TypeLoc TL = T->getTypeLoc().IgnoreParens(); if (!isa<FunctionProtoTypeLoc>(TL)) return false; @@ -1003,7 +1359,7 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { // TODO: currently we always rebuild expressions. When we // properly get lazier about this, we should use the same // logic to avoid rebuilding prototypes here. - if (P->hasInit()) + if (P->hasDefaultArg()) return true; } @@ -1031,7 +1387,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, TypeLoc TL = T->getTypeLoc(); TLB.reserve(TL.getFullDataSize()); - QualType Result = Instantiator.TransformType(TLB, TL, QualType()); + QualType Result = Instantiator.TransformType(TLB, TL); if (Result.isNull()) return 0; @@ -1039,10 +1395,34 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, } ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, - const MultiLevelTemplateArgumentList &TemplateArgs) { + const MultiLevelTemplateArgumentList &TemplateArgs, + llvm::Optional<unsigned> NumExpansions) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); - TypeSourceInfo *NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(), - OldParm->getDeclName()); + TypeSourceInfo *NewDI = 0; + + TypeLoc OldTL = OldDI->getTypeLoc(); + if (isa<PackExpansionTypeLoc>(OldTL)) { + PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(OldTL); + + // We have a function parameter pack. Substitute into the pattern of the + // expansion. + NewDI = SubstType(ExpansionTL.getPatternLoc(), TemplateArgs, + OldParm->getLocation(), OldParm->getDeclName()); + if (!NewDI) + return 0; + + if (NewDI->getType()->containsUnexpandedParameterPack()) { + // We still have unexpanded parameter packs, which means that + // our function parameter is still a function parameter pack. + // Therefore, make its type a pack expansion type. + NewDI = CheckPackExpansion(NewDI, ExpansionTL.getEllipsisLoc(), + NumExpansions); + } + } else { + NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(), + OldParm->getDeclName()); + } + if (!NewDI) return 0; @@ -1064,12 +1444,24 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, if (OldParm->hasUninstantiatedDefaultArg()) { Expr *Arg = OldParm->getUninstantiatedDefaultArg(); NewParm->setUninstantiatedDefaultArg(Arg); + } else if (OldParm->hasUnparsedDefaultArg()) { + NewParm->setUnparsedDefaultArg(); + UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm); } else if (Expr *Arg = OldParm->getDefaultArg()) NewParm->setUninstantiatedDefaultArg(Arg); NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); - CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); + // FIXME: When OldParm is a parameter pack and NewParm is not a parameter + // pack, we actually have a set of instantiated locations. Maintain this set! + if (OldParm->isParameterPack() && !NewParm->isParameterPack()) { + // Add the new parameter to + CurrentInstantiationScope->InstantiatedLocalPackArg(OldParm, NewParm); + } else { + // Introduce an Old -> New mapping + CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); + } + // FIXME: OldParm may come from a FunctionProtoType, in which case CurContext // can be anything, is this right ? NewParm->setDeclContext(CurContext); @@ -1077,6 +1469,24 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, return NewParm; } +/// \brief Substitute the given template arguments into the given set of +/// parameters, producing the set of parameter types that would be generated +/// from such a substitution. +bool Sema::SubstParmTypes(SourceLocation Loc, + ParmVarDecl **Params, unsigned NumParams, + const MultiLevelTemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl<QualType> &ParamTypes, + llvm::SmallVectorImpl<ParmVarDecl *> *OutParams) { + assert(!ActiveTemplateInstantiations.empty() && + "Cannot perform an instantiation without some context on the " + "instantiation stack"); + + TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, + DeclarationName()); + return Instantiator.TransformFunctionTypeParams(Loc, Params, NumParams, 0, + ParamTypes, OutParams); +} + /// \brief Perform substitution on the base class specifiers of the /// given class template specialization. /// @@ -1093,17 +1503,64 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end(); Base != BaseEnd; ++Base) { if (!Base->getType()->isDependentType()) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - - // Make sure to set the attributes from the base. - SetClassDeclAttributesFromBase(Instantiation, BaseDecl, - Base->isVirtual()); - InstantiatedBases.push_back(new (Context) CXXBaseSpecifier(*Base)); continue; } + SourceLocation EllipsisLoc; + if (Base->isPackExpansion()) { + // This is a pack expansion. See whether we should expand it now, or + // wait until later. + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + collectUnexpandedParameterPacks(Base->getTypeSourceInfo()->getTypeLoc(), + Unexpanded); + bool ShouldExpand = false; + bool RetainExpansion = false; + llvm::Optional<unsigned> NumExpansions; + if (CheckParameterPacksForExpansion(Base->getEllipsisLoc(), + Base->getSourceRange(), + Unexpanded.data(), Unexpanded.size(), + TemplateArgs, ShouldExpand, + RetainExpansion, + NumExpansions)) { + Invalid = true; + continue; + } + + // If we should expand this pack expansion now, do so. + if (ShouldExpand) { + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, I); + + TypeSourceInfo *BaseTypeLoc = SubstType(Base->getTypeSourceInfo(), + TemplateArgs, + Base->getSourceRange().getBegin(), + DeclarationName()); + if (!BaseTypeLoc) { + Invalid = true; + continue; + } + + if (CXXBaseSpecifier *InstantiatedBase + = CheckBaseSpecifier(Instantiation, + Base->getSourceRange(), + Base->isVirtual(), + Base->getAccessSpecifierAsWritten(), + BaseTypeLoc, + SourceLocation())) + InstantiatedBases.push_back(InstantiatedBase); + else + Invalid = true; + } + + continue; + } + + // The resulting base specifier will (still) be a pack expansion. + EllipsisLoc = Base->getEllipsisLoc(); + } + + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1); TypeSourceInfo *BaseTypeLoc = SubstType(Base->getTypeSourceInfo(), TemplateArgs, Base->getSourceRange().getBegin(), @@ -1118,7 +1575,8 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, Base->getSourceRange(), Base->isVirtual(), Base->getAccessSpecifierAsWritten(), - BaseTypeLoc)) + BaseTypeLoc, + EllipsisLoc)) InstantiatedBases.push_back(InstantiatedBase); else Invalid = true; @@ -1221,11 +1679,29 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) Invalid = true; + TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); llvm::SmallVector<Decl*, 4> Fields; for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), MemberEnd = Pattern->decls_end(); Member != MemberEnd; ++Member) { - Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs); + // Don't instantiate members not belonging in this semantic context. + // e.g. for: + // @code + // template <int i> class A { + // class B *g; + // }; + // @endcode + // 'class B' has the template as lexical context but semantically it is + // introduced in namespace scope. + if ((*Member)->getDeclContext() != Pattern) + continue; + + if ((*Member)->isInvalidDecl()) { + Invalid = true; + continue; + } + + Decl *NewMember = Instantiator.Visit(*Member); if (NewMember) { if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) Fields.push_back(Field); @@ -1245,7 +1721,22 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, CheckCompletedCXXClass(Instantiation); if (Instantiation->isInvalidDecl()) Invalid = true; - + else { + // Instantiate any out-of-line class template partial + // specializations now. + for (TemplateDeclInstantiator::delayed_partial_spec_iterator + P = Instantiator.delayed_partial_spec_begin(), + PEnd = Instantiator.delayed_partial_spec_end(); + P != PEnd; ++P) { + if (!Instantiator.InstantiateClassTemplatePartialSpecialization( + P->first, + P->second)) { + Invalid = true; + break; + } + } + } + // Exit the scope of this instantiation. SavedContext.pop(); @@ -1261,6 +1752,15 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, return Invalid; } +namespace { + /// \brief A partial specialization whose template arguments have matched + /// a given template-id. + struct PartialSpecMatchResult { + ClassTemplatePartialSpecializationDecl *Partial; + TemplateArgumentList *Args; + }; +} + bool Sema::InstantiateClassTemplateSpecialization( SourceLocation PointOfInstantiation, @@ -1310,8 +1810,7 @@ Sema::InstantiateClassTemplateSpecialization( // matching the template arguments of the class template // specialization with the template argument lists of the partial // specializations. - typedef std::pair<ClassTemplatePartialSpecializationDecl *, - TemplateArgumentList *> MatchResult; + typedef PartialSpecMatchResult MatchResult; llvm::SmallVector<MatchResult, 4> Matched; llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; Template->getPartialSpecializations(PartialSpecs); @@ -1326,10 +1825,17 @@ Sema::InstantiateClassTemplateSpecialization( // diagnostics, later. (void)Result; } else { - Matched.push_back(std::make_pair(Partial, Info.take())); + Matched.push_back(PartialSpecMatchResult()); + Matched.back().Partial = Partial; + Matched.back().Args = Info.take(); } } + // If we're dealing with a member template where the template parameters + // have been instantiated, this provides the original template parameters + // from which the member template's parameters were instantiated. + llvm::SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters; + if (Matched.size() >= 1) { llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); if (Matched.size() == 1) { @@ -1347,9 +1853,9 @@ Sema::InstantiateClassTemplateSpecialization( for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1, PEnd = Matched.end(); P != PEnd; ++P) { - if (getMoreSpecializedPartialSpecialization(P->first, Best->first, + if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, PointOfInstantiation) - == P->first) + == P->Partial) Best = P; } @@ -1360,9 +1866,9 @@ Sema::InstantiateClassTemplateSpecialization( PEnd = Matched.end(); P != PEnd; ++P) { if (P != Best && - getMoreSpecializedPartialSpecialization(P->first, Best->first, + getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, PointOfInstantiation) - != Best->first) { + != Best->Partial) { Ambiguous = true; break; } @@ -1378,16 +1884,17 @@ Sema::InstantiateClassTemplateSpecialization( 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); + Diag(P->Partial->getLocation(), diag::note_partial_spec_match) + << getTemplateArgumentBindingsText( + P->Partial->getTemplateParameters(), + *P->Args); return true; } } // Instantiate using the best class template partial specialization. - ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->first; + ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->Partial; while (OrigPartialSpec->getInstantiatedFromMember()) { // If we've found an explicit specialization of this class template, // stop here and use that as the pattern. @@ -1398,7 +1905,7 @@ Sema::InstantiateClassTemplateSpecialization( } Pattern = OrigPartialSpec; - ClassTemplateSpec->setInstantiationOf(Best->first, Best->second); + ClassTemplateSpec->setInstantiationOf(Best->Partial, Best->Args); } else { // -- If no matches are found, the instantiation is generated // from the primary template. @@ -1449,7 +1956,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, Function, MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation(), + MSInfo->getPointOfInstantiation(), SuppressNew) || SuppressNew) continue; @@ -1485,7 +1992,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, Var, MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation(), + MSInfo->getPointOfInstantiation(), SuppressNew) || SuppressNew) continue; @@ -1520,11 +2027,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) continue; - + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, Record, MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation(), + MSInfo->getPointOfInstantiation(), SuppressNew) || SuppressNew) continue; @@ -1551,6 +2058,13 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, InstantiateClass(PointOfInstantiation, Record, Pattern, TemplateArgs, TSK); + } else { + if (TSK == TSK_ExplicitInstantiationDefinition && + Record->getTemplateSpecializationKind() == + TSK_ExplicitInstantiationDeclaration) { + Record->setTemplateSpecializationKind(TSK); + MarkVTableUsed(PointOfInstantiation, Record, true); + } } Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition()); @@ -1604,6 +2118,18 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) { return Instantiator.TransformExpr(E); } +bool Sema::SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall, + const MultiLevelTemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl<Expr *> &Outputs) { + if (NumExprs == 0) + return false; + + TemplateInstantiator Instantiator(*this, TemplateArgs, + SourceLocation(), + DeclarationName()); + return Instantiator.TransformExprs(Exprs, NumExprs, IsCall, Outputs); +} + /// \brief Do template substitution on a nested-name-specifier. NestedNameSpecifier * Sema::SubstNestedNameSpecifier(NestedNameSpecifier *NNS, @@ -1631,35 +2157,107 @@ Sema::SubstTemplateName(TemplateName Name, SourceLocation Loc, return Instantiator.TransformTemplateName(Name); } -bool Sema::Subst(const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output, +bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, + TemplateArgumentListInfo &Result, const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), DeclarationName()); - - return Instantiator.TransformTemplateArgument(Input, Output); + + return Instantiator.TransformTemplateArguments(Args, NumArgs, Result); } -Decl *LocalInstantiationScope::getInstantiationOf(const Decl *D) { - for (LocalInstantiationScope *Current = this; Current; +llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> * +LocalInstantiationScope::findInstantiationOf(const Decl *D) { + for (LocalInstantiationScope *Current = this; Current; Current = Current->Outer) { + // Check if we found something within this scope. - llvm::DenseMap<const Decl *, Decl *>::iterator Found - = Current->LocalDecls.find(D); - if (Found != Current->LocalDecls.end()) - return Found->second; - + const Decl *CheckD = D; + do { + LocalDeclsMap::iterator Found = Current->LocalDecls.find(CheckD); + if (Found != Current->LocalDecls.end()) + return &Found->second; + + // If this is a tag declaration, it's possible that we need to look for + // a previous declaration. + if (const TagDecl *Tag = dyn_cast<TagDecl>(CheckD)) + CheckD = Tag->getPreviousDeclaration(); + else + CheckD = 0; + } while (CheckD); + // If we aren't combined with our outer scope, we're done. if (!Current->CombineWithOuterScope) break; } - - assert(D->isInvalidDecl() && - "declaration was not instantiated in this scope!"); + + // If we didn't find the decl, then we either have a sema bug, or we have a + // forward reference to a label declaration. Return null to indicate that + // we have an uninstantiated label. + assert(isa<LabelDecl>(D) && "declaration not instantiated in this scope"); return 0; } void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { - Decl *&Stored = LocalDecls[D]; - assert((!Stored || Stored == Inst)&& "Already instantiated this local"); - Stored = Inst; + llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; + if (Stored.isNull()) + Stored = Inst; + else if (Stored.is<Decl *>()) { + assert(Stored.get<Decl *>() == Inst && "Already instantiated this local"); + Stored = Inst; + } else + LocalDecls[D].get<DeclArgumentPack *>()->push_back(Inst); +} + +void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, + Decl *Inst) { + DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>(); + Pack->push_back(Inst); +} + +void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) { + llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; + assert(Stored.isNull() && "Already instantiated this local"); + DeclArgumentPack *Pack = new DeclArgumentPack; + Stored = Pack; + ArgumentPacks.push_back(Pack); +} + +void LocalInstantiationScope::SetPartiallySubstitutedPack(NamedDecl *Pack, + const TemplateArgument *ExplicitArgs, + unsigned NumExplicitArgs) { + assert((!PartiallySubstitutedPack || PartiallySubstitutedPack == Pack) && + "Already have a partially-substituted pack"); + assert((!PartiallySubstitutedPack + || NumArgsInPartiallySubstitutedPack == NumExplicitArgs) && + "Wrong number of arguments in partially-substituted pack"); + PartiallySubstitutedPack = Pack; + ArgsInPartiallySubstitutedPack = ExplicitArgs; + NumArgsInPartiallySubstitutedPack = NumExplicitArgs; +} + +NamedDecl *LocalInstantiationScope::getPartiallySubstitutedPack( + const TemplateArgument **ExplicitArgs, + unsigned *NumExplicitArgs) const { + if (ExplicitArgs) + *ExplicitArgs = 0; + if (NumExplicitArgs) + *NumExplicitArgs = 0; + + for (const LocalInstantiationScope *Current = this; Current; + Current = Current->Outer) { + if (Current->PartiallySubstitutedPack) { + if (ExplicitArgs) + *ExplicitArgs = Current->ArgsInPartiallySubstitutedPack; + if (NumExplicitArgs) + *NumExplicitArgs = Current->NumArgsInPartiallySubstitutedPack; + + return Current->PartiallySubstitutedPack; + } + + if (!Current->CombineWithOuterScope) + break; + } + + return 0; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 1c7869f..c0150c0 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -25,85 +25,6 @@ using namespace clang; -namespace { - class TemplateDeclInstantiator - : public DeclVisitor<TemplateDeclInstantiator, Decl *> { - Sema &SemaRef; - DeclContext *Owner; - const MultiLevelTemplateArgumentList &TemplateArgs; - - public: - TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, - 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.inc. - Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); - Decl *VisitNamespaceDecl(NamespaceDecl *D); - Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D); - Decl *VisitTypedefDecl(TypedefDecl *D); - Decl *VisitVarDecl(VarDecl *D); - Decl *VisitAccessSpecDecl(AccessSpecDecl *D); - Decl *VisitFieldDecl(FieldDecl *D); - Decl *VisitStaticAssertDecl(StaticAssertDecl *D); - Decl *VisitEnumDecl(EnumDecl *D); - Decl *VisitEnumConstantDecl(EnumConstantDecl *D); - Decl *VisitFriendDecl(FriendDecl *D); - Decl *VisitFunctionDecl(FunctionDecl *D, - TemplateParameterList *TemplateParams = 0); - Decl *VisitCXXRecordDecl(CXXRecordDecl *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 *VisitClassTemplateDecl(ClassTemplateDecl *D); - Decl *VisitClassTemplatePartialSpecializationDecl( - ClassTemplatePartialSpecializationDecl *D); - Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D); - Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); - Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); - Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); - Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D); - Decl *VisitUsingDecl(UsingDecl *D); - Decl *VisitUsingShadowDecl(UsingShadowDecl *D); - Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); - Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); - - // Base case. FIXME: Remove once we can instantiate everything. - Decl *VisitDecl(Decl *D) { - unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID( - Diagnostic::Error, - "cannot instantiate %0 yet"); - SemaRef.Diag(D->getLocation(), DiagID) - << D->getDeclKindName(); - - return 0; - } - - // Helper functions for instantiating methods. - TypeSourceInfo *SubstFunctionType(FunctionDecl *D, - llvm::SmallVectorImpl<ParmVarDecl *> &Params); - bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); - bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); - - TemplateParameterList * - SubstTemplateParams(TemplateParameterList *List); - - bool SubstQualifier(const DeclaratorDecl *OldDecl, - DeclaratorDecl *NewDecl); - bool SubstQualifier(const TagDecl *OldDecl, - TagDecl *NewDecl); - - bool InstantiateClassTemplatePartialSpecialization( - ClassTemplateDecl *ClassTemplate, - ClassTemplatePartialSpecializationDecl *PartialSpec); - }; -} - bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, DeclaratorDecl *NewDecl) { NestedNameSpecifier *OldQual = OldDecl->getQualifier(); @@ -151,15 +72,15 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, if (Aligned->isAlignmentExpr()) { ExprResult Result = SubstExpr(Aligned->getAlignmentExpr(), - TemplateArgs); + TemplateArgs); if (!Result.isInvalid()) AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>()); } else { TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(), - TemplateArgs, - Aligned->getLocation(), - DeclarationName()); + TemplateArgs, + Aligned->getLocation(), + DeclarationName()); if (Result) AddAlignedAttr(Aligned->getLocation(), New, Result); } @@ -180,6 +101,14 @@ TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { } Decl * +TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) { + LabelDecl *Inst = LabelDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier()); + Owner->addDecl(Inst); + return Inst; +} + +Decl * TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) { assert(false && "Namespaces cannot be instantiated"); return D; @@ -222,13 +151,15 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { if (Invalid) Typedef->setInvalidDecl(); - if (const TagType *TT = DI->getType()->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()) - TD->setTypedefForAnonDecl(Typedef); + // If the old typedef was the name for linkage purposes of an anonymous + // tag decl, re-establish that relationship for the new typedef. + if (const TagType *oldTagType = D->getUnderlyingType()->getAs<TagType>()) { + TagDecl *oldTag = oldTagType->getDecl(); + if (oldTag->getTypedefForAnonDecl() == D) { + TagDecl *newTag = DI->getType()->castAs<TagType>()->getDecl(); + assert(!newTag->getIdentifier() && !newTag->getTypedefForAnonDecl()); + newTag->setTypedefForAnonDecl(Typedef); + } } if (TypedefDecl *Prev = D->getPreviousDeclaration()) { @@ -245,35 +176,6 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { return Typedef; } -/// \brief Instantiate the arguments provided as part of initialization. -/// -/// \returns true if an error occurred, false otherwise. -static bool InstantiateInitializationArguments(Sema &SemaRef, - Expr **Args, unsigned NumArgs, - const MultiLevelTemplateArgumentList &TemplateArgs, - llvm::SmallVectorImpl<SourceLocation> &FakeCommaLocs, - ASTOwningVector<Expr*> &InitArgs) { - for (unsigned I = 0; I != NumArgs; ++I) { - // When we hit the first defaulted argument, break out of the loop: - // we don't pass those default arguments on. - if (Args[I]->isDefaultArgument()) - break; - - ExprResult Arg = SemaRef.SubstExpr(Args[I], TemplateArgs); - if (Arg.isInvalid()) - return true; - - Expr *ArgExpr = (Expr *)Arg.get(); - InitArgs.push_back(Arg.release()); - - // FIXME: We're faking all of the comma locations. Do we need them? - FakeCommaLocs.push_back( - SemaRef.PP.getLocForEndOfToken(ArgExpr->getLocEnd())); - } - - return false; -} - /// \brief Instantiate an initializer, breaking it into separate /// initialization arguments. /// @@ -290,8 +192,7 @@ static bool InstantiateInitializationArguments(Sema &SemaRef, static bool InstantiateInitializer(Sema &S, Expr *Init, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation &LParenLoc, - llvm::SmallVector<SourceLocation, 4> &CommaLocs, - ASTOwningVector<Expr*> &NewArgs, + ASTOwningVector<Expr*> &NewArgs, SourceLocation &RParenLoc) { NewArgs.clear(); LParenLoc = SourceLocation(); @@ -300,7 +201,7 @@ static bool InstantiateInitializer(Sema &S, Expr *Init, if (!Init) return false; - if (CXXExprWithTemporaries *ExprTemp = dyn_cast<CXXExprWithTemporaries>(Init)) + if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init)) Init = ExprTemp->getSubExpr(); while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init)) @@ -312,24 +213,19 @@ static bool InstantiateInitializer(Sema &S, Expr *Init, if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { LParenLoc = ParenList->getLParenLoc(); RParenLoc = ParenList->getRParenLoc(); - return InstantiateInitializationArguments(S, ParenList->getExprs(), - ParenList->getNumExprs(), - TemplateArgs, CommaLocs, - NewArgs); + return S.SubstExprs(ParenList->getExprs(), ParenList->getNumExprs(), + true, TemplateArgs, NewArgs); } if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) { if (!isa<CXXTemporaryObjectExpr>(Construct)) { - if (InstantiateInitializationArguments(S, - Construct->getArgs(), - Construct->getNumArgs(), - TemplateArgs, - CommaLocs, NewArgs)) + if (S.SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true, + TemplateArgs, NewArgs)) return true; // FIXME: Fake locations! LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart()); - RParenLoc = CommaLocs.empty()? LParenLoc : CommaLocs.back(); + RParenLoc = LParenLoc; return false; } } @@ -358,6 +254,12 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { if (!DI) return 0; + if (DI->getType()->isFunctionType()) { + SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function) + << D->isStaticDataMember() << DI->getType(); + return 0; + } + // Build the instantiated declaration VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), @@ -419,24 +321,24 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Instantiate the initializer. SourceLocation LParenLoc, RParenLoc; - llvm::SmallVector<SourceLocation, 4> CommaLocs; ASTOwningVector<Expr*> InitArgs(SemaRef); if (!InstantiateInitializer(SemaRef, D->getInit(), TemplateArgs, LParenLoc, - CommaLocs, InitArgs, RParenLoc)) { - // Attach the initializer to the declaration. - if (D->hasCXXDirectInitializer()) { + InitArgs, RParenLoc)) { + bool TypeMayContainAuto = true; + // Attach the initializer to the declaration, if we have one. + if (InitArgs.size() == 0) + SemaRef.ActOnUninitializedDecl(Var, TypeMayContainAuto); + else if (D->hasCXXDirectInitializer()) { // Add the direct initializer to the declaration. SemaRef.AddCXXDirectInitializerToDecl(Var, LParenLoc, move_arg(InitArgs), - CommaLocs.data(), - RParenLoc); - } else if (InitArgs.size() == 1) { - Expr *Init = InitArgs.take()[0]; - SemaRef.AddInitializerToDecl(Var, Init, false); + RParenLoc, + TypeMayContainAuto); } else { - assert(InitArgs.size() == 0); - SemaRef.ActOnUninitializedDecl(Var, false); + assert(InitArgs.size() == 1); + Expr *Init = InitArgs.take()[0]; + SemaRef.AddInitializerToDecl(Var, Init, false, TypeMayContainAuto); } } else { // FIXME: Not too happy about invalidating the declaration @@ -540,6 +442,30 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { return Field; } +Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { + NamedDecl **NamedChain = + new (SemaRef.Context)NamedDecl*[D->getChainingSize()]; + + int i = 0; + for (IndirectFieldDecl::chain_iterator PI = + D->chain_begin(), PE = D->chain_end(); + PI != PE; ++PI) + NamedChain[i++] = (SemaRef.FindInstantiatedDecl(D->getLocation(), + *PI, TemplateArgs)); + + QualType T = cast<FieldDecl>(NamedChain[i-1])->getType(); + IndirectFieldDecl* IndirectField + = IndirectFieldDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier(), T, + NamedChain, D->getChainingSize()); + + + IndirectField->setImplicit(D->isImplicit()); + IndirectField->setAccess(D->getAccess()); + Owner->addDecl(IndirectField); + return IndirectField; +} + Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { // Handle friend type expressions by simply substituting template // parameters into the pattern type and checking the result. @@ -555,6 +481,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { return 0; FD->setAccess(AS_public); + FD->setUnsupportedFriend(D->isUnsupportedFriend()); Owner->addDecl(FD); return FD; } @@ -573,6 +500,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), cast<NamedDecl>(NewND), D->getFriendLoc()); FD->setAccess(AS_public); + FD->setUnsupportedFriend(D->isUnsupportedFriend()); Owner->addDecl(FD); return FD; } @@ -589,7 +517,7 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) { return 0; ExprResult Message(D->getMessage()); - D->getMessage()->Retain(); + D->getMessage(); return SemaRef.ActOnStaticAssertDeclaration(D->getLocation(), InstantiatedAssertExpr.get(), Message.get()); @@ -599,7 +527,31 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), D->getTagKeywordLoc(), - /*PrevDecl=*/0); + /*PrevDecl=*/0, D->isScoped(), + D->isScopedUsingClassTag(), D->isFixed()); + if (D->isFixed()) { + if (TypeSourceInfo* TI = D->getIntegerTypeSourceInfo()) { + // If we have type source information for the underlying type, it means it + // has been explicitly set by the user. Perform substitution on it before + // moving on. + SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); + Enum->setIntegerTypeSourceInfo(SemaRef.SubstType(TI, + TemplateArgs, + UnderlyingLoc, + DeclarationName())); + + if (!Enum->getIntegerTypeSourceInfo()) + Enum->setIntegerType(SemaRef.Context.IntTy); + } + else { + assert(!D->getIntegerType()->isDependentType() + && "Dependent type without type source info"); + Enum->setIntegerType(D->getIntegerType()); + } + } + + SemaRef.InstantiateAttrs(TemplateArgs, D, Enum); + Enum->setInstantiationOfMemberEnum(D); Enum->setAccess(D->getAccess()); if (SubstQualifier(D, Enum)) return 0; @@ -644,6 +596,8 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { } if (EnumConst) { + SemaRef.InstantiateAttrs(TemplateArgs, *EC, EnumConst); + EnumConst->setAccess(Enum->getAccess()); Enum->addDecl(EnumConst); Enumerators.push_back(EnumConst); @@ -699,6 +653,15 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { CXXRecordDecl *PrevDecl = 0; ClassTemplateDecl *PrevClassTemplate = 0; + if (!isFriend && Pattern->getPreviousDeclaration()) { + DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName()); + if (Found.first != Found.second) { + PrevClassTemplate = dyn_cast<ClassTemplateDecl>(*Found.first); + if (PrevClassTemplate) + PrevDecl = PrevClassTemplate->getTemplatedDecl(); + } + } + // If this isn't a friend, then it's a member template, in which // case we just want to build the instantiation in the // specialization. If it is a friend, we want to build it in @@ -813,7 +776,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // friend target decl? } else { Inst->setAccess(D->getAccess()); - Inst->setInstantiatedFromMemberTemplate(D); + if (!PrevClassTemplate) + Inst->setInstantiatedFromMemberTemplate(D); } // Trigger creation of the type for the instantiation. @@ -827,14 +791,18 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { } Owner->addDecl(Inst); - - // Instantiate all of the partial specializations of this member class - // template. - llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; - D->getPartialSpecializations(PartialSpecs); - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) - InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]); - + + if (!PrevClassTemplate) { + // Queue up any out-of-line partial specializations of this member + // class template; the client will force their instantiation once + // the enclosing class has been instantiated. + llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + D->getPartialSpecializations(PartialSpecs); + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) + if (PartialSpecs[I]->isOutOfLine()) + OutOfLinePartialSpecs.push_back(std::make_pair(Inst, PartialSpecs[I])); + } + return Inst; } @@ -855,7 +823,11 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl( if (!InstClassTemplate) return 0; - return InstClassTemplate->findPartialSpecInstantiatedFromMember(D); + if (ClassTemplatePartialSpecializationDecl *Result + = InstClassTemplate->findPartialSpecInstantiatedFromMember(D)) + return Result; + + return InstantiateClassTemplatePartialSpecialization(InstClassTemplate, D); } Decl * @@ -1040,7 +1012,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) - Params[P]->setOwningFunction(Function); + if (Params[P]) + Params[P]->setOwningFunction(Function); Function->setParams(Params.data(), Params.size()); SourceLocation InstantiateAtPOI; @@ -1078,7 +1051,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, std::pair<const TemplateArgument *, unsigned> Innermost = TemplateArgs.getInnermost(); Function->setFunctionTemplateSpecialization(FunctionTemplate, - new (SemaRef.Context) TemplateArgumentList(SemaRef.Context, + TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost.first, Innermost.second), InsertPos); @@ -1092,7 +1065,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Function->setInvalidDecl(); bool Redeclaration = false; - bool OverloadableAttrRequired = false; bool isExplicitSpecialization = false; LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(), @@ -1108,13 +1080,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // Instantiate the explicit template arguments. TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), Info->getRAngleLoc()); - for (unsigned I = 0, E = Info->getNumTemplateArgs(); I != E; ++I) { - TemplateArgumentLoc Loc; - if (SemaRef.Subst(Info->getTemplateArg(I), Loc, TemplateArgs)) - return 0; - - ExplicitArgs.addArgument(Loc); - } + if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(), + ExplicitArgs, TemplateArgs)) + return 0; // Map the candidate templates to their instantiations. for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) { @@ -1148,8 +1116,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous, - isExplicitSpecialization, Redeclaration, - /*FIXME:*/OverloadableAttrRequired); + isExplicitSpecialization, Redeclaration); NamedDecl *PrincipalDecl = (TemplateParams ? cast<NamedDecl>(FunctionTemplate) @@ -1256,6 +1223,20 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); + // Instantiate enclosing template arguments for friends. + llvm::SmallVector<TemplateParameterList *, 4> TempParamLists; + unsigned NumTempParamLists = 0; + if (isFriend && (NumTempParamLists = D->getNumTemplateParameterLists())) { + TempParamLists.set_size(NumTempParamLists); + for (unsigned I = 0; I != NumTempParamLists; ++I) { + TemplateParameterList *TempParams = D->getTemplateParameterList(I); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return NULL; + TempParamLists[I] = InstParams; + } + } + llvm::SmallVector<ParmVarDecl *, 4> Params; TypeSourceInfo *TInfo = D->getTypeSourceInfo(); TInfo = SubstFunctionType(D, Params); @@ -1263,25 +1244,22 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return 0; QualType T = TInfo->getType(); - // \brief If the type of this function is not *directly* a function - // type, then we're instantiating the a function that was declared - // via a typedef, e.g., + // \brief If the type of this function, after ignoring parentheses, + // is not *directly* a function type, then we're instantiating a function + // that was declared via a typedef, e.g., // // typedef int functype(int, int); // functype func; // // In this case, we'll just go instantiate the ParmVarDecls that we // synthesized in the method declaration. - if (!isa<FunctionProtoType>(T)) { + if (!isa<FunctionProtoType>(T.IgnoreParens())) { assert(!Params.size() && "Instantiating type could not yield parameters"); - for (unsigned I = 0, N = D->getNumParams(); I != N; ++I) { - ParmVarDecl *P = SemaRef.SubstParmVarDecl(D->getParamDecl(I), - TemplateArgs); - if (!P) - return 0; - - Params.push_back(P); - } + llvm::SmallVector<QualType, 4> ParamTypes; + if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(), + D->getNumParams(), TemplateArgs, ParamTypes, + &Params)) + return 0; } NestedNameSpecifier *Qualifier = D->getQualifier(); @@ -1299,6 +1277,9 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, SS.setScopeRep(Qualifier); SS.setRange(D->getQualifierRange()); DC = SemaRef.computeDeclContext(SS); + + if (DC && SemaRef.RequireCompleteDeclContext(SS, DC)) + return 0; } else { DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(), @@ -1321,7 +1302,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, - NameInfo, T, + NameInfo, T, TInfo, Destructor->isInlineSpecified(), false); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { @@ -1369,9 +1350,9 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, std::pair<const TemplateArgument *, unsigned> Innermost = TemplateArgs.getInnermost(); Method->setFunctionTemplateSpecialization(FunctionTemplate, - new (SemaRef.Context) TemplateArgumentList(SemaRef.Context, - Innermost.first, - Innermost.second), + TemplateArgumentList::CreateCopy(SemaRef.Context, + Innermost.first, + Innermost.second), InsertPos); } else if (!isFriend) { // Record that this is an instantiation of a member function. @@ -1382,6 +1363,11 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // out-of-line, the instantiation will have the same lexical // context (which will be a namespace scope) as the template. if (isFriend) { + if (NumTempParamLists) + Method->setTemplateParameterListsInfo(SemaRef.Context, + NumTempParamLists, + TempParamLists.data()); + Method->setLexicalDeclContext(Owner); Method->setObjectOfFriendDecl(true); } else if (D->isOutOfLine()) @@ -1410,15 +1396,15 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, } bool Redeclaration = false; - bool OverloadableAttrRequired = false; - SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration, - /*FIXME:*/OverloadableAttrRequired); + SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration); if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); Method->setAccess(D->getAccess()); + SemaRef.CheckOverrideControl(Method); + if (FunctionTemplate) { // If there's a function template, let our caller handle it. } else if (Method->isInvalidDecl() && !Previous.empty()) { @@ -1449,7 +1435,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { } ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { - return SemaRef.SubstParmVarDecl(D, TemplateArgs); + return SemaRef.SubstParmVarDecl(D, TemplateArgs, llvm::Optional<unsigned>()); } Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( @@ -1462,7 +1448,7 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), TTPT->getDepth() - TemplateArgs.getNumLevels(), - TTPT->getIndex(),TTPT->getName(), + TTPT->getIndex(), D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack()); @@ -1479,33 +1465,140 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( NonTypeTemplateParmDecl *D) { // Substitute into the type of the non-type template parameter. + TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc(); + llvm::SmallVector<TypeSourceInfo *, 4> ExpandedParameterPackTypesAsWritten; + llvm::SmallVector<QualType, 4> ExpandedParameterPackTypes; + bool IsExpandedParameterPack = false; + TypeSourceInfo *DI; QualType T; - TypeSourceInfo *DI = D->getTypeSourceInfo(); - if (DI) { - DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), - D->getDeclName()); - if (DI) T = DI->getType(); - } else { - T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(), - D->getDeclName()); - DI = 0; - } - if (T.isNull()) - return 0; - - // Check that this type is acceptable for a non-type template parameter. bool Invalid = false; - T = SemaRef.CheckNonTypeTemplateParameterType(T, D->getLocation()); - if (T.isNull()) { - T = SemaRef.Context.IntTy; - Invalid = true; + + if (D->isExpandedParameterPack()) { + // The non-type template parameter pack is an already-expanded pack + // expansion of types. Substitute into each of the expanded types. + ExpandedParameterPackTypes.reserve(D->getNumExpansionTypes()); + ExpandedParameterPackTypesAsWritten.reserve(D->getNumExpansionTypes()); + for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { + TypeSourceInfo *NewDI =SemaRef.SubstType(D->getExpansionTypeSourceInfo(I), + TemplateArgs, + D->getLocation(), + D->getDeclName()); + if (!NewDI) + return 0; + + ExpandedParameterPackTypesAsWritten.push_back(NewDI); + QualType NewT =SemaRef.CheckNonTypeTemplateParameterType(NewDI->getType(), + D->getLocation()); + if (NewT.isNull()) + return 0; + ExpandedParameterPackTypes.push_back(NewT); + } + + IsExpandedParameterPack = true; + DI = D->getTypeSourceInfo(); + T = DI->getType(); + } else if (isa<PackExpansionTypeLoc>(TL)) { + // The non-type template parameter pack's type is a pack expansion of types. + // Determine whether we need to expand this parameter pack into separate + // types. + PackExpansionTypeLoc Expansion = cast<PackExpansionTypeLoc>(TL); + TypeLoc Pattern = Expansion.getPatternLoc(); + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + llvm::Optional<unsigned> OrigNumExpansions + = Expansion.getTypePtr()->getNumExpansions(); + llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; + if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(), + Pattern.getSourceRange(), + Unexpanded.data(), + Unexpanded.size(), + TemplateArgs, + Expand, RetainExpansion, + NumExpansions)) + return 0; + + if (Expand) { + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); + TypeSourceInfo *NewDI = SemaRef.SubstType(Pattern, TemplateArgs, + D->getLocation(), + D->getDeclName()); + if (!NewDI) + return 0; + + ExpandedParameterPackTypesAsWritten.push_back(NewDI); + QualType NewT = SemaRef.CheckNonTypeTemplateParameterType( + NewDI->getType(), + D->getLocation()); + if (NewT.isNull()) + return 0; + ExpandedParameterPackTypes.push_back(NewT); + } + + // Note that we have an expanded parameter pack. The "type" of this + // expanded parameter pack is the original expansion type, but callers + // will end up using the expanded parameter pack types for type-checking. + IsExpandedParameterPack = true; + DI = D->getTypeSourceInfo(); + T = DI->getType(); + } else { + // We cannot fully expand the pack expansion now, so substitute into the + // pattern and create a new pack expansion type. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); + TypeSourceInfo *NewPattern = SemaRef.SubstType(Pattern, TemplateArgs, + D->getLocation(), + D->getDeclName()); + if (!NewPattern) + return 0; + + DI = SemaRef.CheckPackExpansion(NewPattern, Expansion.getEllipsisLoc(), + NumExpansions); + if (!DI) + return 0; + + T = DI->getType(); + } + } else { + // Simple case: substitution into a parameter that is not a parameter pack. + DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, + D->getLocation(), D->getDeclName()); + if (!DI) + return 0; + + // Check that this type is acceptable for a non-type template parameter. + bool Invalid = false; + T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(), + D->getLocation()); + if (T.isNull()) { + T = SemaRef.Context.IntTy; + Invalid = true; + } } - NonTypeTemplateParmDecl *Param - = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), + NonTypeTemplateParmDecl *Param; + if (IsExpandedParameterPack) + Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, + D->getLocation(), D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), D->getIdentifier(), T, - DI); + D->getPosition(), + D->getIdentifier(), T, + DI, + ExpandedParameterPackTypes.data(), + ExpandedParameterPackTypes.size(), + ExpandedParameterPackTypesAsWritten.data()); + else + Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, + D->getLocation(), + D->getDepth() - TemplateArgs.getNumLevels(), + D->getPosition(), + D->getIdentifier(), T, + D->isParameterPack(), DI); + if (Invalid) Param->setInvalidDecl(); @@ -1536,8 +1629,8 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), D->getIdentifier(), - InstParams); + D->getPosition(), D->isParameterPack(), + D->getIdentifier(), InstParams); Param->setDefaultArgument(D->getDefaultArgument(), false); // Introduce this template parameter's instantiation into the instantiation @@ -1562,8 +1655,24 @@ Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { } Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { - // The nested name specifier is non-dependent, so no transformation - // is required. The same holds for the name info. + + // The nested name specifier may be dependent, for example + // template <typename T> struct t { + // struct s1 { T f1(); }; + // struct s2 : s1 { using s1::f1; }; + // }; + // template struct t<int>; + // Here, in using s1::f1, s1 refers to t<T>::s1; + // we need to substitute for t<int>::s1. + NestedNameSpecifier *NNS = + SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameDecl(), + D->getNestedNameRange(), + TemplateArgs); + if (!NNS) + return 0; + + // The name info is non-dependent, so no transformation + // is required. DeclarationNameInfo NameInfo = D->getNameInfo(); // We only need to do redeclaration lookups if we're in a class @@ -1577,12 +1686,12 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner, D->getNestedNameRange(), D->getUsingLocation(), - D->getTargetNestedNameDecl(), + NNS, NameInfo, D->isTypeName()); CXXScopeSpec SS; - SS.setScopeRep(D->getTargetNestedNameDecl()); + SS.setScopeRep(NNS); SS.setRange(D->getNestedNameRange()); if (CheckRedeclaration) { @@ -1746,8 +1855,9 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { /// \param PartialSpec the (uninstantiated) class template partial /// specialization that we are instantiating. /// -/// \returns true if there was an error, false otherwise. -bool +/// \returns The instantiated partial specialization, if successful; otherwise, +/// NULL to indicate an error. +ClassTemplatePartialSpecializationDecl * TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( ClassTemplateDecl *ClassTemplate, ClassTemplatePartialSpecializationDecl *PartialSpec) { @@ -1761,47 +1871,39 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( TemplateParameterList *TempParams = PartialSpec->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) - return true; + return 0; // Substitute into the template arguments of the class template partial // specialization. - const TemplateArgumentLoc *PartialSpecTemplateArgs - = PartialSpec->getTemplateArgsAsWritten(); - unsigned N = PartialSpec->getNumTemplateArgsAsWritten(); - TemplateArgumentListInfo InstTemplateArgs; // no angle locations - for (unsigned I = 0; I != N; ++I) { - TemplateArgumentLoc Loc; - if (SemaRef.Subst(PartialSpecTemplateArgs[I], Loc, TemplateArgs)) - return true; - InstTemplateArgs.addArgument(Loc); - } + if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(), + PartialSpec->getNumTemplateArgsAsWritten(), + InstTemplateArgs, TemplateArgs)) + return 0; - // Check that the template argument list is well-formed for this // class template. - TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), - InstTemplateArgs.size()); + llvm::SmallVector<TemplateArgument, 4> Converted; if (SemaRef.CheckTemplateArgumentList(ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs, false, Converted)) - return true; + return 0; // Figure out where to insert this class template partial specialization // in the member template's set of class template partial specializations. void *InsertPos = 0; ClassTemplateSpecializationDecl *PrevDecl - = ClassTemplate->findPartialSpecialization(Converted.getFlatArguments(), - Converted.flatSize(), InsertPos); + = ClassTemplate->findPartialSpecialization(Converted.data(), + Converted.size(), InsertPos); // Build the canonical type that describes the converted template // arguments of the class template partial specialization. QualType CanonType = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), - Converted.getFlatArguments(), - Converted.flatSize()); + Converted.data(), + Converted.size()); // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization @@ -1834,10 +1936,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // Outer<int, int> outer; // error: the partial specializations of Inner // // have the same signature. SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared) - << WrittenTy; + << WrittenTy->getType(); SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here) << SemaRef.Context.getTypeDeclType(PrevDecl); - return true; + return 0; } @@ -1849,7 +1951,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( PartialSpec->getLocation(), InstParams, ClassTemplate, - Converted, + Converted.data(), + Converted.size(), InstTemplateArgs, CanonType, 0, @@ -1864,7 +1967,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // Add this partial specialization to the set of class template partial // specializations. ClassTemplate->AddPartialSpecialization(InstPartialSpec, InsertPos); - return false; + return InstPartialSpec; } TypeSourceInfo* @@ -1882,25 +1985,47 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, if (NewTInfo != OldTInfo) { // Get parameters from the new type info. - TypeLoc OldTL = OldTInfo->getTypeLoc(); + TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens(); if (FunctionProtoTypeLoc *OldProtoLoc = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) { - TypeLoc NewTL = NewTInfo->getTypeLoc(); + TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens(); FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL); assert(NewProtoLoc && "Missing prototype?"); - for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) { - // FIXME: Variadic templates will break this. - Params.push_back(NewProtoLoc->getArg(i)); - SemaRef.CurrentInstantiationScope->InstantiatedLocal( - OldProtoLoc->getArg(i), - NewProtoLoc->getArg(i)); + unsigned NewIdx = 0, NumNewParams = NewProtoLoc->getNumArgs(); + for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc->getNumArgs(); + OldIdx != NumOldParams; ++OldIdx) { + ParmVarDecl *OldParam = OldProtoLoc->getArg(OldIdx); + if (!OldParam->isParameterPack() || + (NewIdx < NumNewParams && + NewProtoLoc->getArg(NewIdx)->isParameterPack())) { + // Simple case: normal parameter, or a parameter pack that's + // instantiated to a (still-dependent) parameter pack. + ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++); + Params.push_back(NewParam); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParam, + NewParam); + continue; + } + + // Parameter pack: make the instantiation an argument pack. + SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack( + OldParam); + unsigned NumArgumentsInExpansion + = SemaRef.getNumArgumentsInExpansion(OldParam->getType(), + TemplateArgs); + while (NumArgumentsInExpansion--) { + ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++); + Params.push_back(NewParam); + SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg(OldParam, + NewParam); + } } } } else { // The function type itself was not dependent and therefore no // substitution occurred. However, we still need to instantiate // the function parameters themselves. - TypeLoc OldTL = OldTInfo->getTypeLoc(); + TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens(); if (FunctionProtoTypeLoc *OldProtoLoc = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) { for (unsigned i = 0, i_end = OldProtoLoc->getNumArgs(); i != i_end; ++i) { @@ -1957,6 +2082,67 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, llvm::SmallVector<QualType, 4> Exceptions; for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { // FIXME: Poor location information! + if (const PackExpansionType *PackExpansion + = Proto->getExceptionType(I)->getAs<PackExpansionType>()) { + // We have a pack expansion. Instantiate it. + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), + Unexpanded); + assert(!Unexpanded.empty() && + "Pack expansion without parameter packs?"); + + bool Expand = false; + bool RetainExpansion = false; + llvm::Optional<unsigned> NumExpansions + = PackExpansion->getNumExpansions(); + if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), + SourceRange(), + Unexpanded.data(), + Unexpanded.size(), + TemplateArgs, + Expand, + RetainExpansion, + NumExpansions)) + break; + + if (!Expand) { + // We can't expand this pack expansion into separate arguments yet; + // just substitute into the pattern and create a new pack expansion + // type. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull()) + break; + + T = SemaRef.Context.getPackExpansionType(T, NumExpansions); + Exceptions.push_back(T); + continue; + } + + // Substitute into the pack expansion pattern for each template + bool Invalid = false; + for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx); + + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull()) { + Invalid = true; + break; + } + + Exceptions.push_back(T); + } + + if (Invalid) + break; + + continue; + } + QualType T = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, New->getLocation(), New->getDeclName()); @@ -1969,19 +2155,20 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, // Rebuild the function type + FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); + EPI.HasExceptionSpec = Proto->hasExceptionSpec(); + EPI.HasAnyExceptionSpec = Proto->hasAnyExceptionSpec(); + EPI.NumExceptions = Exceptions.size(); + EPI.Exceptions = Exceptions.data(); + EPI.ExtInfo = Proto->getExtInfo(); + const FunctionProtoType *NewProto = New->getType()->getAs<FunctionProtoType>(); assert(NewProto && "Template instantiation without function prototype?"); New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), NewProto->arg_type_begin(), NewProto->getNumArgs(), - NewProto->isVariadic(), - NewProto->getTypeQuals(), - Proto->hasExceptionSpec(), - Proto->hasAnyExceptionSpec(), - Exceptions.size(), - Exceptions.data(), - Proto->getExtInfo())); + EPI)); } SemaRef.InstantiateAttrs(TemplateArgs, Tmpl, New); @@ -2000,10 +2187,9 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, if (InitFunctionInstantiation(New, Tmpl)) return true; - CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); New->setAccess(Tmpl->getAccess()); if (Tmpl->isVirtualAsWritten()) - Record->setMethodAsVirtual(New); + New->setVirtualAsWritten(true); // FIXME: attributes // FIXME: New needs a pointer to Tmpl @@ -2084,9 +2270,12 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // 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. + llvm::SmallVector<VTableUse, 16> SavedVTableUses; std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; - if (Recursive) + if (Recursive) { + VTableUses.swap(SavedVTableUses); PendingInstantiations.swap(SavedPendingInstantiations); + } EnterExpressionEvaluationContext EvalContext(*this, Sema::PotentiallyEvaluated); @@ -2105,17 +2294,33 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Introduce the instantiated function parameters into the local // instantiation scope, and set the parameter names to those used // in the template. + unsigned FParamIdx = 0; for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) { const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I); - ParmVarDecl *FunctionParam = Function->getParamDecl(I); - FunctionParam->setDeclName(PatternParam->getDeclName()); - Scope.InstantiatedLocal(PatternParam, FunctionParam); + if (!PatternParam->isParameterPack()) { + // Simple case: not a parameter pack. + assert(FParamIdx < Function->getNumParams()); + ParmVarDecl *FunctionParam = Function->getParamDecl(I); + FunctionParam->setDeclName(PatternParam->getDeclName()); + Scope.InstantiatedLocal(PatternParam, FunctionParam); + ++FParamIdx; + continue; + } + + // Expand the parameter pack. + Scope.MakeInstantiatedLocalArgPack(PatternParam); + for (unsigned NumFParams = Function->getNumParams(); + FParamIdx < NumFParams; + ++FParamIdx) { + ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); + FunctionParam->setDeclName(PatternParam->getDeclName()); + Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); + } } // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. - DeclContext *PreviousContext = CurContext; - CurContext = Function; + Sema::ContextRAII savedContext(*this, Function); MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Function, 0, false, PatternDecl); @@ -2138,7 +2343,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, PerformDependentDiagnostics(PatternDecl, TemplateArgs); - CurContext = PreviousContext; + savedContext.pop(); DeclGroupRef DG(Function); Consumer.HandleTopLevelDecl(DG); @@ -2149,10 +2354,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Scope.Exit(); if (Recursive) { + // Define any pending vtables. + DefineUsedVTables(); + // Instantiate any pending implicit instantiations found during the // instantiation of this template. PerformPendingInstantiations(); + // Restore the set of pending vtables. + VTableUses.swap(SavedVTableUses); + // Restore the set of pending implicit instantiations. PendingInstantiations.swap(SavedPendingInstantiations); } @@ -2233,13 +2444,13 @@ void Sema::InstantiateStaticDataMemberDefinition( // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. - DeclContext *PreviousContext = CurContext; - CurContext = Var->getDeclContext(); + ContextRAII previousContext(*this, Var->getDeclContext()); VarDecl *OldVar = Var; Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(), - getTemplateInstantiationArgs(Var))); - CurContext = PreviousContext; + getTemplateInstantiationArgs(Var))); + + previousContext.pop(); if (Var) { MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo(); @@ -2272,7 +2483,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(), InitsEnd = Tmpl->init_end(); Inits != InitsEnd; ++Inits) { - CXXBaseOrMemberInitializer *Init = *Inits; + CXXCtorInitializer *Init = *Inits; // Only instantiate written initializers, let Sema re-construct implicit // ones. @@ -2281,11 +2492,75 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, SourceLocation LParenLoc, RParenLoc; ASTOwningVector<Expr*> NewArgs(*this); - llvm::SmallVector<SourceLocation, 4> CommaLocs; + + SourceLocation EllipsisLoc; + + if (Init->isPackExpansion()) { + // This is a pack expansion. We should expand it now. + TypeLoc BaseTL = Init->getBaseClassInfo()->getTypeLoc(); + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + collectUnexpandedParameterPacks(BaseTL, Unexpanded); + bool ShouldExpand = false; + bool RetainExpansion = false; + llvm::Optional<unsigned> NumExpansions; + if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(), + BaseTL.getSourceRange(), + Unexpanded.data(), + Unexpanded.size(), + TemplateArgs, ShouldExpand, + RetainExpansion, + NumExpansions)) { + AnyErrors = true; + New->setInvalidDecl(); + continue; + } + assert(ShouldExpand && "Partial instantiation of base initializer?"); + + // Loop over all of the arguments in the argument pack(s), + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, I); + + // Instantiate the initializer. + if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs, + LParenLoc, NewArgs, RParenLoc)) { + AnyErrors = true; + break; + } + + // Instantiate the base type. + TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), + TemplateArgs, + Init->getSourceLocation(), + New->getDeclName()); + if (!BaseTInfo) { + AnyErrors = true; + break; + } + + // Build the initializer. + MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(), + BaseTInfo, + (Expr **)NewArgs.data(), + NewArgs.size(), + Init->getLParenLoc(), + Init->getRParenLoc(), + New->getParent(), + SourceLocation()); + if (NewInit.isInvalid()) { + AnyErrors = true; + break; + } + + NewInits.push_back(NewInit.get()); + NewArgs.clear(); + } + + continue; + } // Instantiate the initializer. if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs, - LParenLoc, CommaLocs, NewArgs, RParenLoc)) { + LParenLoc, NewArgs, RParenLoc)) { AnyErrors = true; continue; } @@ -2307,24 +2582,30 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, NewArgs.size(), Init->getLParenLoc(), Init->getRParenLoc(), - New->getParent()); + New->getParent(), + EllipsisLoc); } else if (Init->isMemberInitializer()) { - FieldDecl *Member; - - // Is this an anonymous union? - if (FieldDecl *UnionInit = Init->getAnonUnionMember()) - Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMemberLocation(), - UnionInit, TemplateArgs)); - else - Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMemberLocation(), - Init->getMember(), - TemplateArgs)); + FieldDecl *Member = cast<FieldDecl>(FindInstantiatedDecl( + Init->getMemberLocation(), + Init->getMember(), + TemplateArgs)); NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(), NewArgs.size(), Init->getSourceLocation(), Init->getLParenLoc(), Init->getRParenLoc()); + } else if (Init->isIndirectMemberInitializer()) { + IndirectFieldDecl *IndirectMember = + cast<IndirectFieldDecl>(FindInstantiatedDecl( + Init->getMemberLocation(), + Init->getIndirectMember(), TemplateArgs)); + + NewInit = BuildMemberInitializer(IndirectMember, (Expr **)NewArgs.data(), + NewArgs.size(), + Init->getSourceLocation(), + Init->getLParenLoc(), + Init->getRParenLoc()); } if (NewInit.isInvalid()) { @@ -2589,7 +2870,27 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, (ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext())) { // D is a local of some kind. Look into the map of local // declarations to their instantiations. - return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D)); + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; + llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found + = CurrentInstantiationScope->findInstantiationOf(D); + + if (Found) { + if (Decl *FD = Found->dyn_cast<Decl *>()) + return cast<NamedDecl>(FD); + + unsigned PackIdx = ArgumentPackSubstitutionIndex; + return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]); + } + + // If we didn't find the decl, then we must have a label decl that hasn't + // been found yet. Lazily instantiate it and return it now. + assert(isa<LabelDecl>(D)); + + Decl *Inst = SubstDecl(D, CurContext, TemplateArgs); + assert(Inst && "Failed to instantiate label??"); + + CurrentInstantiationScope->InstantiatedLocal(D, Inst); + return cast<LabelDecl>(Inst); } if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { @@ -2693,6 +2994,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (!Tag->isBeingDefined() && RequireCompleteType(Loc, T, diag::err_incomplete_type)) return 0; + + ParentDC = Tag->getDecl(); } } @@ -2800,4 +3103,3 @@ void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, } } } - diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp new file mode 100644 index 0000000..0da801c --- /dev/null +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -0,0 +1,748 @@ +//===------- SemaTemplateVariadic.cpp - C++ Variadic 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++0x variadic templates. +//===----------------------------------------------------------------------===/ + +#include "clang/Sema/Sema.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Template.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/TypeLoc.h" + +using namespace clang; + +//---------------------------------------------------------------------------- +// Visitor that collects unexpanded parameter packs +//---------------------------------------------------------------------------- + +namespace { + /// \brief A class that collects unexpanded parameter packs. + class CollectUnexpandedParameterPacksVisitor : + public RecursiveASTVisitor<CollectUnexpandedParameterPacksVisitor> + { + typedef RecursiveASTVisitor<CollectUnexpandedParameterPacksVisitor> + inherited; + + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded; + + public: + explicit CollectUnexpandedParameterPacksVisitor( + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) + : Unexpanded(Unexpanded) { } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + //------------------------------------------------------------------------ + // Recording occurrences of (unexpanded) parameter packs. + //------------------------------------------------------------------------ + + /// \brief Record occurrences of template type parameter packs. + bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + if (TL.getTypePtr()->isParameterPack()) + Unexpanded.push_back(std::make_pair(TL.getTypePtr(), TL.getNameLoc())); + return true; + } + + /// \brief Record occurrences of template type parameter packs + /// when we don't have proper source-location information for + /// them. + /// + /// Ideally, this routine would never be used. + bool VisitTemplateTypeParmType(TemplateTypeParmType *T) { + if (T->isParameterPack()) + Unexpanded.push_back(std::make_pair(T, SourceLocation())); + + return true; + } + + /// \brief Record occurrences of function and non-type template + /// parameter packs in an expression. + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (E->getDecl()->isParameterPack()) + Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation())); + + return true; + } + + // \brief Record occurrences of function and non-type template parameter + // packs in a block-captured expression. + bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { + if (E->getDecl()->isParameterPack()) + Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation())); + + return true; + } + + /// \brief Record occurrences of template template parameter packs. + bool TraverseTemplateName(TemplateName Template) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast_or_null<TemplateTemplateParmDecl>( + Template.getAsTemplateDecl())) + if (TTP->isParameterPack()) + Unexpanded.push_back(std::make_pair(TTP, SourceLocation())); + + return inherited::TraverseTemplateName(Template); + } + + //------------------------------------------------------------------------ + // Pruning the search for unexpanded parameter packs. + //------------------------------------------------------------------------ + + /// \brief Suppress traversal into statements and expressions that + /// do not contain unexpanded parameter packs. + bool TraverseStmt(Stmt *S) { + if (Expr *E = dyn_cast_or_null<Expr>(S)) + if (E->containsUnexpandedParameterPack()) + return inherited::TraverseStmt(E); + + return true; + } + + /// \brief Suppress traversal into types that do not contain + /// unexpanded parameter packs. + bool TraverseType(QualType T) { + if (!T.isNull() && T->containsUnexpandedParameterPack()) + return inherited::TraverseType(T); + + return true; + } + + /// \brief Suppress traversel into types with location information + /// that do not contain unexpanded parameter packs. + bool TraverseTypeLoc(TypeLoc TL) { + if (!TL.getType().isNull() && + TL.getType()->containsUnexpandedParameterPack()) + return inherited::TraverseTypeLoc(TL); + + return true; + } + + /// \brief Suppress traversal of non-parameter declarations, since + /// they cannot contain unexpanded parameter packs. + bool TraverseDecl(Decl *D) { + if (D && isa<ParmVarDecl>(D)) + return inherited::TraverseDecl(D); + + return true; + } + + /// \brief Suppress traversal of template argument pack expansions. + bool TraverseTemplateArgument(const TemplateArgument &Arg) { + if (Arg.isPackExpansion()) + return true; + + return inherited::TraverseTemplateArgument(Arg); + } + + /// \brief Suppress traversal of template argument pack expansions. + bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) { + if (ArgLoc.getArgument().isPackExpansion()) + return true; + + return inherited::TraverseTemplateArgumentLoc(ArgLoc); + } + }; +} + +/// \brief Diagnose all of the unexpanded parameter packs in the given +/// vector. +static void +DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc, + Sema::UnexpandedParameterPackContext UPPC, + const llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + llvm::SmallVector<SourceLocation, 4> Locations; + llvm::SmallVector<IdentifierInfo *, 4> Names; + llvm::SmallPtrSet<IdentifierInfo *, 4> NamesKnown; + + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + IdentifierInfo *Name = 0; + if (const TemplateTypeParmType *TTP + = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) + Name = TTP->getName(); + else + Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier(); + + if (Name && NamesKnown.insert(Name)) + Names.push_back(Name); + + if (Unexpanded[I].second.isValid()) + Locations.push_back(Unexpanded[I].second); + } + + DiagnosticBuilder DB + = Names.size() == 0? S.Diag(Loc, diag::err_unexpanded_parameter_pack_0) + << (int)UPPC + : Names.size() == 1? S.Diag(Loc, diag::err_unexpanded_parameter_pack_1) + << (int)UPPC << Names[0] + : Names.size() == 2? S.Diag(Loc, diag::err_unexpanded_parameter_pack_2) + << (int)UPPC << Names[0] << Names[1] + : S.Diag(Loc, diag::err_unexpanded_parameter_pack_3_or_more) + << (int)UPPC << Names[0] << Names[1]; + + for (unsigned I = 0, N = Locations.size(); I != N; ++I) + DB << SourceRange(Locations[I]); +} + +bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, + TypeSourceInfo *T, + UnexpandedParameterPackContext UPPC) { + // C++0x [temp.variadic]p5: + // An appearance of a name of a parameter pack that is not expanded is + // ill-formed. + if (!T->getType()->containsUnexpandedParameterPack()) + return false; + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc( + T->getTypeLoc()); + assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + DiagnoseUnexpandedParameterPacks(*this, Loc, UPPC, Unexpanded); + return true; +} + +bool Sema::DiagnoseUnexpandedParameterPack(Expr *E, + UnexpandedParameterPackContext UPPC) { + // C++0x [temp.variadic]p5: + // An appearance of a name of a parameter pack that is not expanded is + // ill-formed. + if (!E->containsUnexpandedParameterPack()) + return false; + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E); + assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + DiagnoseUnexpandedParameterPacks(*this, E->getLocStart(), UPPC, Unexpanded); + return true; +} + +bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, + UnexpandedParameterPackContext UPPC) { + // C++0x [temp.variadic]p5: + // An appearance of a name of a parameter pack that is not expanded is + // ill-formed. + if (!SS.getScopeRep() || + !SS.getScopeRep()->containsUnexpandedParameterPack()) + return false; + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseNestedNameSpecifier(SS.getScopeRep()); + assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + DiagnoseUnexpandedParameterPacks(*this, SS.getRange().getBegin(), + UPPC, Unexpanded); + return true; +} + +bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, + UnexpandedParameterPackContext UPPC) { + // C++0x [temp.variadic]p5: + // An appearance of a name of a parameter pack that is not expanded is + // ill-formed. + switch (NameInfo.getName().getNameKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + return false; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + // FIXME: We shouldn't need this null check! + if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo()) + return DiagnoseUnexpandedParameterPack(NameInfo.getLoc(), TSInfo, UPPC); + + if (!NameInfo.getName().getCXXNameType()->containsUnexpandedParameterPack()) + return false; + + break; + } + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseType(NameInfo.getName().getCXXNameType()); + assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + DiagnoseUnexpandedParameterPacks(*this, NameInfo.getLoc(), UPPC, Unexpanded); + return true; +} + +bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, + TemplateName Template, + UnexpandedParameterPackContext UPPC) { + + if (Template.isNull() || !Template.containsUnexpandedParameterPack()) + return false; + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseTemplateName(Template); + assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + DiagnoseUnexpandedParameterPacks(*this, Loc, UPPC, Unexpanded); + return true; +} + +bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, + UnexpandedParameterPackContext UPPC) { + if (Arg.getArgument().isNull() || + !Arg.getArgument().containsUnexpandedParameterPack()) + return false; + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseTemplateArgumentLoc(Arg); + assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + DiagnoseUnexpandedParameterPacks(*this, Arg.getLocation(), UPPC, Unexpanded); + return true; +} + +void Sema::collectUnexpandedParameterPacks(TemplateArgument Arg, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseTemplateArgument(Arg); +} + +void Sema::collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseTemplateArgumentLoc(Arg); +} + +void Sema::collectUnexpandedParameterPacks(QualType T, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(T); +} + +void Sema::collectUnexpandedParameterPacks(TypeLoc TL, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL); +} + +ParsedTemplateArgument +Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg, + SourceLocation EllipsisLoc) { + if (Arg.isInvalid()) + return Arg; + + switch (Arg.getKind()) { + case ParsedTemplateArgument::Type: { + TypeResult Result = ActOnPackExpansion(Arg.getAsType(), EllipsisLoc); + if (Result.isInvalid()) + return ParsedTemplateArgument(); + + return ParsedTemplateArgument(Arg.getKind(), Result.get().getAsOpaquePtr(), + Arg.getLocation()); + } + + case ParsedTemplateArgument::NonType: { + ExprResult Result = ActOnPackExpansion(Arg.getAsExpr(), EllipsisLoc); + if (Result.isInvalid()) + return ParsedTemplateArgument(); + + return ParsedTemplateArgument(Arg.getKind(), Result.get(), + Arg.getLocation()); + } + + case ParsedTemplateArgument::Template: + if (!Arg.getAsTemplate().get().containsUnexpandedParameterPack()) { + SourceRange R(Arg.getLocation()); + if (Arg.getScopeSpec().isValid()) + R.setBegin(Arg.getScopeSpec().getBeginLoc()); + Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << R; + return ParsedTemplateArgument(); + } + + return Arg.getTemplatePackExpansion(EllipsisLoc); + } + llvm_unreachable("Unhandled template argument kind?"); + return ParsedTemplateArgument(); +} + +TypeResult Sema::ActOnPackExpansion(ParsedType Type, + SourceLocation EllipsisLoc) { + TypeSourceInfo *TSInfo; + GetTypeFromParser(Type, &TSInfo); + if (!TSInfo) + return true; + + TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc, + llvm::Optional<unsigned>()); + if (!TSResult) + return true; + + return CreateParsedType(TSResult->getType(), TSResult); +} + +TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern, + SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions) { + // Create the pack expansion type and source-location information. + QualType Result = CheckPackExpansion(Pattern->getType(), + Pattern->getTypeLoc().getSourceRange(), + EllipsisLoc, NumExpansions); + if (Result.isNull()) + return 0; + + TypeSourceInfo *TSResult = Context.CreateTypeSourceInfo(Result); + PackExpansionTypeLoc TL = cast<PackExpansionTypeLoc>(TSResult->getTypeLoc()); + TL.setEllipsisLoc(EllipsisLoc); + + // Copy over the source-location information from the type. + memcpy(TL.getNextTypeLoc().getOpaqueData(), + Pattern->getTypeLoc().getOpaqueData(), + Pattern->getTypeLoc().getFullDataSize()); + return TSResult; +} + +QualType Sema::CheckPackExpansion(QualType Pattern, + SourceRange PatternRange, + SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions) { + // C++0x [temp.variadic]p5: + // The pattern of a pack expansion shall name one or more + // parameter packs that are not expanded by a nested pack + // expansion. + if (!Pattern->containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << PatternRange; + return QualType(); + } + + return Context.getPackExpansionType(Pattern, NumExpansions); +} + +ExprResult Sema::ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc) { + return CheckPackExpansion(Pattern, EllipsisLoc, llvm::Optional<unsigned>()); +} + +ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions) { + if (!Pattern) + return ExprError(); + + // C++0x [temp.variadic]p5: + // The pattern of a pack expansion shall name one or more + // parameter packs that are not expanded by a nested pack + // expansion. + if (!Pattern->containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << Pattern->getSourceRange(); + return ExprError(); + } + + // Create the pack expansion expression and source-location information. + return Owned(new (Context) PackExpansionExpr(Context.DependentTy, Pattern, + EllipsisLoc, NumExpansions)); +} + +/// \brief Retrieve the depth and index of a parameter pack. +static std::pair<unsigned, unsigned> +getDepthAndIndex(NamedDecl *ND) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) + return std::make_pair(TTP->getDepth(), TTP->getIndex()); + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) + return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); + return std::make_pair(TTP->getDepth(), TTP->getIndex()); +} + +bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, + SourceRange PatternRange, + const UnexpandedParameterPack *Unexpanded, + unsigned NumUnexpanded, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool &ShouldExpand, + bool &RetainExpansion, + llvm::Optional<unsigned> &NumExpansions) { + ShouldExpand = true; + RetainExpansion = false; + std::pair<IdentifierInfo *, SourceLocation> FirstPack; + bool HaveFirstPack = false; + + for (unsigned I = 0; I != NumUnexpanded; ++I) { + // Compute the depth and index for this parameter pack. + unsigned Depth = 0, Index = 0; + IdentifierInfo *Name; + bool IsFunctionParameterPack = false; + + if (const TemplateTypeParmType *TTP + = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { + Depth = TTP->getDepth(); + Index = TTP->getIndex(); + Name = TTP->getName(); + } else { + NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); + if (isa<ParmVarDecl>(ND)) + IsFunctionParameterPack = true; + else + llvm::tie(Depth, Index) = getDepthAndIndex(ND); + + Name = ND->getIdentifier(); + } + + // Determine the size of this argument pack. + unsigned NewPackSize; + if (IsFunctionParameterPack) { + // Figure out whether we're instantiating to an argument pack or not. + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; + + llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation + = CurrentInstantiationScope->findInstantiationOf( + Unexpanded[I].first.get<NamedDecl *>()); + if (Instantiation->is<DeclArgumentPack *>()) { + // We could expand this function parameter pack. + NewPackSize = Instantiation->get<DeclArgumentPack *>()->size(); + } else { + // We can't expand this function parameter pack, so we can't expand + // the pack expansion. + ShouldExpand = false; + continue; + } + } else { + // If we don't have a template argument at this depth/index, then we + // cannot expand the pack expansion. Make a note of this, but we still + // want to check any parameter packs we *do* have arguments for. + if (Depth >= TemplateArgs.getNumLevels() || + !TemplateArgs.hasTemplateArgument(Depth, Index)) { + ShouldExpand = false; + continue; + } + + // Determine the size of the argument pack. + NewPackSize = TemplateArgs(Depth, Index).pack_size(); + } + + // C++0x [temp.arg.explicit]p9: + // Template argument deduction can extend the sequence of template + // arguments corresponding to a template parameter pack, even when the + // sequence contains explicitly specified template arguments. + if (!IsFunctionParameterPack) { + if (NamedDecl *PartialPack + = CurrentInstantiationScope->getPartiallySubstitutedPack()){ + unsigned PartialDepth, PartialIndex; + llvm::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack); + if (PartialDepth == Depth && PartialIndex == Index) + RetainExpansion = true; + } + } + + if (!NumExpansions) { + // The is the first pack we've seen for which we have an argument. + // Record it. + NumExpansions = NewPackSize; + FirstPack.first = Name; + FirstPack.second = Unexpanded[I].second; + HaveFirstPack = true; + continue; + } + + if (NewPackSize != *NumExpansions) { + // C++0x [temp.variadic]p5: + // All of the parameter packs expanded by a pack expansion shall have + // the same number of arguments specified. + if (HaveFirstPack) + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) + << FirstPack.first << Name << *NumExpansions << NewPackSize + << SourceRange(FirstPack.second) << SourceRange(Unexpanded[I].second); + else + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) + << Name << *NumExpansions << NewPackSize + << SourceRange(Unexpanded[I].second); + return true; + } + } + + return false; +} + +unsigned Sema::getNumArgumentsInExpansion(QualType T, + const MultiLevelTemplateArgumentList &TemplateArgs) { + QualType Pattern = cast<PackExpansionType>(T)->getPattern(); + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern); + + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + // Compute the depth and index for this parameter pack. + unsigned Depth; + unsigned Index; + + if (const TemplateTypeParmType *TTP + = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { + Depth = TTP->getDepth(); + Index = TTP->getIndex(); + } else { + NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); + if (isa<ParmVarDecl>(ND)) { + // Function parameter pack. + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; + + llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation + = CurrentInstantiationScope->findInstantiationOf( + Unexpanded[I].first.get<NamedDecl *>()); + if (Instantiation->is<DeclArgumentPack *>()) + return Instantiation->get<DeclArgumentPack *>()->size(); + + continue; + } + + llvm::tie(Depth, Index) = getDepthAndIndex(ND); + } + if (Depth >= TemplateArgs.getNumLevels() || + !TemplateArgs.hasTemplateArgument(Depth, Index)) + continue; + + // Determine the size of the argument pack. + return TemplateArgs(Depth, Index).pack_size(); + } + + llvm_unreachable("No unexpanded parameter packs in type expansion."); + return 0; +} + +bool Sema::containsUnexpandedParameterPacks(Declarator &D) { + const DeclSpec &DS = D.getDeclSpec(); + switch (DS.getTypeSpecType()) { + case TST_typename: + case TST_typeofType: { + QualType T = DS.getRepAsType().get(); + if (!T.isNull() && T->containsUnexpandedParameterPack()) + return true; + break; + } + + case TST_typeofExpr: + case TST_decltype: + if (DS.getRepAsExpr() && + DS.getRepAsExpr()->containsUnexpandedParameterPack()) + return true; + break; + + case TST_unspecified: + case TST_void: + case TST_char: + case TST_wchar: + case TST_char16: + case TST_char32: + case TST_int: + case TST_float: + case TST_double: + case TST_bool: + case TST_decimal32: + case TST_decimal64: + case TST_decimal128: + case TST_enum: + case TST_union: + case TST_struct: + case TST_class: + case TST_auto: + case TST_error: + break; + } + + for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) { + const DeclaratorChunk &Chunk = D.getTypeObject(I); + switch (Chunk.Kind) { + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::Paren: + // These declarator chunks cannot contain any parameter packs. + break; + + case DeclaratorChunk::Array: + case DeclaratorChunk::Function: + case DeclaratorChunk::BlockPointer: + // Syntactically, these kinds of declarator chunks all come after the + // declarator-id (conceptually), so the parser should not invoke this + // routine at this time. + llvm_unreachable("Could not have seen this kind of declarator chunk"); + break; + + case DeclaratorChunk::MemberPointer: + if (Chunk.Mem.Scope().getScopeRep() && + Chunk.Mem.Scope().getScopeRep()->containsUnexpandedParameterPack()) + return true; + break; + } + } + + return false; +} + +/// \brief Called when an expression computing the size of a parameter pack +/// is parsed. +/// +/// \code +/// template<typename ...Types> struct count { +/// static const unsigned value = sizeof...(Types); +/// }; +/// \endcode +/// +// +/// \param OpLoc The location of the "sizeof" keyword. +/// \param Name The name of the parameter pack whose size will be determined. +/// \param NameLoc The source location of the name of the parameter pack. +/// \param RParenLoc The location of the closing parentheses. +ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S, + SourceLocation OpLoc, + IdentifierInfo &Name, + SourceLocation NameLoc, + SourceLocation RParenLoc) { + // C++0x [expr.sizeof]p5: + // The identifier in a sizeof... expression shall name a parameter pack. + LookupResult R(*this, &Name, NameLoc, LookupOrdinaryName); + LookupName(R, S); + + NamedDecl *ParameterPack = 0; + switch (R.getResultKind()) { + case LookupResult::Found: + ParameterPack = R.getFoundDecl(); + break; + + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + if (DeclarationName CorrectedName = CorrectTypo(R, S, 0, 0, false, + CTC_NoKeywords)) { + if (NamedDecl *CorrectedResult = R.getAsSingle<NamedDecl>()) + if (CorrectedResult->isParameterPack()) { + ParameterPack = CorrectedResult; + Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest) + << &Name << CorrectedName + << FixItHint::CreateReplacement(NameLoc, + CorrectedName.getAsString()); + Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here) + << CorrectedName; + } + } + + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + break; + + case LookupResult::Ambiguous: + DiagnoseAmbiguousLookup(R); + return ExprError(); + } + + if (!ParameterPack || !ParameterPack->isParameterPack()) { + Diag(NameLoc, diag::err_sizeof_pack_no_pack_name) + << &Name; + return ExprError(); + } + + return new (Context) SizeOfPackExpr(Context.getSizeType(), OpLoc, + ParameterPack, NameLoc, RParenLoc); +} diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index aa30b5c..c88baa5 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -70,37 +70,455 @@ static bool isOmittedBlockReturnType(const Declarator &D) { return false; } -typedef std::pair<const AttributeList*,QualType> DelayedAttribute; -typedef llvm::SmallVectorImpl<DelayedAttribute> DelayedAttributeSet; - -static void ProcessTypeAttributeList(Sema &S, QualType &Type, - bool IsDeclSpec, - const AttributeList *Attrs, - DelayedAttributeSet &DelayedFnAttrs); -static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr); - -static void ProcessDelayedFnAttrs(Sema &S, QualType &Type, - DelayedAttributeSet &Attrs) { - for (DelayedAttributeSet::iterator I = Attrs.begin(), - E = Attrs.end(); I != E; ++I) - if (ProcessFnAttr(S, Type, *I->first)) { - S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type) - << I->first->getName() << I->second; - // Avoid any further processing of this attribute. - I->first->setInvalid(); - } - Attrs.clear(); +// objc_gc applies to Objective-C pointers or, otherwise, to the +// smallest available pointer type (i.e. 'void*' in 'void**'). +#define OBJC_POINTER_TYPE_ATTRS_CASELIST \ + case AttributeList::AT_objc_gc + +// Function type attributes. +#define FUNCTION_TYPE_ATTRS_CASELIST \ + case AttributeList::AT_noreturn: \ + case AttributeList::AT_cdecl: \ + case AttributeList::AT_fastcall: \ + case AttributeList::AT_stdcall: \ + case AttributeList::AT_thiscall: \ + case AttributeList::AT_pascal: \ + case AttributeList::AT_regparm + +namespace { + /// An object which stores processing state for the entire + /// GetTypeForDeclarator process. + class TypeProcessingState { + Sema &sema; + + /// The declarator being processed. + Declarator &declarator; + + /// The index of the declarator chunk we're currently processing. + /// May be the total number of valid chunks, indicating the + /// DeclSpec. + unsigned chunkIndex; + + /// Whether there are non-trivial modifications to the decl spec. + bool trivial; + + /// The original set of attributes on the DeclSpec. + llvm::SmallVector<AttributeList*, 2> savedAttrs; + + /// A list of attributes to diagnose the uselessness of when the + /// processing is complete. + llvm::SmallVector<AttributeList*, 2> ignoredTypeAttrs; + + public: + TypeProcessingState(Sema &sema, Declarator &declarator) + : sema(sema), declarator(declarator), + chunkIndex(declarator.getNumTypeObjects()), + trivial(true) {} + + Sema &getSema() const { + return sema; + } + + Declarator &getDeclarator() const { + return declarator; + } + + unsigned getCurrentChunkIndex() const { + return chunkIndex; + } + + void setCurrentChunkIndex(unsigned idx) { + assert(idx <= declarator.getNumTypeObjects()); + chunkIndex = idx; + } + + AttributeList *&getCurrentAttrListRef() const { + assert(chunkIndex <= declarator.getNumTypeObjects()); + if (chunkIndex == declarator.getNumTypeObjects()) + return getMutableDeclSpec().getAttributes().getListRef(); + return declarator.getTypeObject(chunkIndex).getAttrListRef(); + } + + /// Save the current set of attributes on the DeclSpec. + void saveDeclSpecAttrs() { + // Don't try to save them multiple times. + if (!savedAttrs.empty()) return; + + DeclSpec &spec = getMutableDeclSpec(); + for (AttributeList *attr = spec.getAttributes().getList(); attr; + attr = attr->getNext()) + savedAttrs.push_back(attr); + trivial &= savedAttrs.empty(); + } + + /// Record that we had nowhere to put the given type attribute. + /// We will diagnose such attributes later. + void addIgnoredTypeAttr(AttributeList &attr) { + ignoredTypeAttrs.push_back(&attr); + } + + /// Diagnose all the ignored type attributes, given that the + /// declarator worked out to the given type. + void diagnoseIgnoredTypeAttrs(QualType type) const { + for (llvm::SmallVectorImpl<AttributeList*>::const_iterator + i = ignoredTypeAttrs.begin(), e = ignoredTypeAttrs.end(); + i != e; ++i) { + AttributeList &attr = **i; + getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type) + << attr.getName() << type; + } + } + + ~TypeProcessingState() { + if (trivial) return; + + restoreDeclSpecAttrs(); + } + + private: + DeclSpec &getMutableDeclSpec() const { + return const_cast<DeclSpec&>(declarator.getDeclSpec()); + } + + void restoreDeclSpecAttrs() { + assert(!savedAttrs.empty()); + getMutableDeclSpec().getAttributes().set(savedAttrs[0]); + for (unsigned i = 0, e = savedAttrs.size() - 1; i != e; ++i) + savedAttrs[i]->setNext(savedAttrs[i+1]); + savedAttrs.back()->setNext(0); + } + }; + + /// Basically std::pair except that we really want to avoid an + /// implicit operator= for safety concerns. It's also a minor + /// link-time optimization for this to be a private type. + struct AttrAndList { + /// The attribute. + AttributeList &first; + + /// The head of the list the attribute is currently in. + AttributeList *&second; + + AttrAndList(AttributeList &attr, AttributeList *&head) + : first(attr), second(head) {} + }; +} + +namespace llvm { + template <> struct isPodLike<AttrAndList> { + static const bool value = true; + }; +} + +static void spliceAttrIntoList(AttributeList &attr, AttributeList *&head) { + attr.setNext(head); + head = &attr; +} + +static void spliceAttrOutOfList(AttributeList &attr, AttributeList *&head) { + if (head == &attr) { + head = attr.getNext(); + return; + } + + AttributeList *cur = head; + while (true) { + assert(cur && cur->getNext() && "ran out of attrs?"); + if (cur->getNext() == &attr) { + cur->setNext(attr.getNext()); + return; + } + cur = cur->getNext(); + } +} + +static void moveAttrFromListToList(AttributeList &attr, + AttributeList *&fromList, + AttributeList *&toList) { + spliceAttrOutOfList(attr, fromList); + spliceAttrIntoList(attr, toList); +} + +static void processTypeAttrs(TypeProcessingState &state, + QualType &type, bool isDeclSpec, + AttributeList *attrs); + +static bool handleFunctionTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType &type); + +static bool handleObjCGCTypeAttr(TypeProcessingState &state, + AttributeList &attr, QualType &type); + +static bool handleObjCPointerTypeAttr(TypeProcessingState &state, + AttributeList &attr, QualType &type) { + // Right now, we have exactly one of these attributes: objc_gc. + assert(attr.getKind() == AttributeList::AT_objc_gc); + return handleObjCGCTypeAttr(state, attr, type); +} + +/// Given that an objc_gc attribute was written somewhere on a +/// declaration *other* than on the declarator itself (for which, use +/// distributeObjCPointerTypeAttrFromDeclarator), and given that it +/// didn't apply in whatever position it was written in, try to move +/// it to a more appropriate position. +static void distributeObjCPointerTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType type) { + Declarator &declarator = state.getDeclarator(); + for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) { + DeclaratorChunk &chunk = declarator.getTypeObject(i-1); + switch (chunk.Kind) { + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + moveAttrFromListToList(attr, state.getCurrentAttrListRef(), + chunk.getAttrListRef()); + return; + + case DeclaratorChunk::Paren: + case DeclaratorChunk::Array: + continue; + + // Don't walk through these. + case DeclaratorChunk::Reference: + case DeclaratorChunk::Function: + case DeclaratorChunk::MemberPointer: + goto error; + } + } + error: + + state.getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type) + << attr.getName() << type; +} + +/// Distribute an objc_gc type attribute that was written on the +/// declarator. +static void +distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state, + AttributeList &attr, + QualType &declSpecType) { + Declarator &declarator = state.getDeclarator(); + + // objc_gc goes on the innermost pointer to something that's not a + // pointer. + unsigned innermost = -1U; + bool considerDeclSpec = true; + for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &chunk = declarator.getTypeObject(i); + switch (chunk.Kind) { + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + innermost = i; + continue; + + case DeclaratorChunk::Reference: + case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Paren: + case DeclaratorChunk::Array: + continue; + + case DeclaratorChunk::Function: + considerDeclSpec = false; + goto done; + } + } + done: + + // That might actually be the decl spec if we weren't blocked by + // anything in the declarator. + if (considerDeclSpec) { + if (handleObjCPointerTypeAttr(state, attr, declSpecType)) + return; + } + + // Otherwise, if we found an appropriate chunk, splice the attribute + // into it. + if (innermost != -1U) { + moveAttrFromListToList(attr, declarator.getAttrListRef(), + declarator.getTypeObject(innermost).getAttrListRef()); + return; + } + + // Otherwise, diagnose when we're done building the type. + spliceAttrOutOfList(attr, declarator.getAttrListRef()); + state.addIgnoredTypeAttr(attr); +} + +/// A function type attribute was written somewhere in a declaration +/// *other* than on the declarator itself or in the decl spec. Given +/// that it didn't apply in whatever position it was written in, try +/// to move it to a more appropriate position. +static void distributeFunctionTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType type) { + Declarator &declarator = state.getDeclarator(); + + // Try to push the attribute from the return type of a function to + // the function itself. + for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) { + DeclaratorChunk &chunk = declarator.getTypeObject(i-1); + switch (chunk.Kind) { + case DeclaratorChunk::Function: + moveAttrFromListToList(attr, state.getCurrentAttrListRef(), + chunk.getAttrListRef()); + return; + + case DeclaratorChunk::Paren: + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::Array: + case DeclaratorChunk::Reference: + case DeclaratorChunk::MemberPointer: + continue; + } + } + + state.getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type) + << attr.getName() << type; +} + +/// Try to distribute a function type attribute to the innermost +/// function chunk or type. Returns true if the attribute was +/// distributed, false if no location was found. +static bool +distributeFunctionTypeAttrToInnermost(TypeProcessingState &state, + AttributeList &attr, + AttributeList *&attrList, + QualType &declSpecType) { + Declarator &declarator = state.getDeclarator(); + + // Put it on the innermost function chunk, if there is one. + for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &chunk = declarator.getTypeObject(i); + if (chunk.Kind != DeclaratorChunk::Function) continue; + + moveAttrFromListToList(attr, attrList, chunk.getAttrListRef()); + return true; + } + + return handleFunctionTypeAttr(state, attr, declSpecType); +} + +/// A function type attribute was written in the decl spec. Try to +/// apply it somewhere. +static void +distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state, + AttributeList &attr, + QualType &declSpecType) { + state.saveDeclSpecAttrs(); + + // Try to distribute to the innermost. + if (distributeFunctionTypeAttrToInnermost(state, attr, + state.getCurrentAttrListRef(), + declSpecType)) + return; + + // If that failed, diagnose the bad attribute when the declarator is + // fully built. + state.addIgnoredTypeAttr(attr); } -static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) { - for (DelayedAttributeSet::iterator I = Attrs.begin(), - E = Attrs.end(); I != E; ++I) { - S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type) - << I->first->getName() << I->second; - // Avoid any further processing of this attribute. - I->first->setInvalid(); +/// A function type attribute was written on the declarator. Try to +/// apply it somewhere. +static void +distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, + AttributeList &attr, + QualType &declSpecType) { + Declarator &declarator = state.getDeclarator(); + + // Try to distribute to the innermost. + if (distributeFunctionTypeAttrToInnermost(state, attr, + declarator.getAttrListRef(), + declSpecType)) + return; + + // If that failed, diagnose the bad attribute when the declarator is + // fully built. + spliceAttrOutOfList(attr, declarator.getAttrListRef()); + state.addIgnoredTypeAttr(attr); +} + +/// \brief Given that there are attributes written on the declarator +/// itself, try to distribute any type attributes to the appropriate +/// declarator chunk. +/// +/// These are attributes like the following: +/// int f ATTR; +/// int (f ATTR)(); +/// but not necessarily this: +/// int f() ATTR; +static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, + QualType &declSpecType) { + // Collect all the type attributes from the declarator itself. + assert(state.getDeclarator().getAttributes() && "declarator has no attrs!"); + AttributeList *attr = state.getDeclarator().getAttributes(); + AttributeList *next; + do { + next = attr->getNext(); + + switch (attr->getKind()) { + OBJC_POINTER_TYPE_ATTRS_CASELIST: + distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType); + break; + + FUNCTION_TYPE_ATTRS_CASELIST: + distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType); + break; + + default: + break; + } + } while ((attr = next)); +} + +/// Add a synthetic '()' to a block-literal declarator if it is +/// required, given the return type. +static void maybeSynthesizeBlockSignature(TypeProcessingState &state, + QualType declSpecType) { + Declarator &declarator = state.getDeclarator(); + + // First, check whether the declarator would produce a function, + // i.e. whether the innermost semantic chunk is a function. + if (declarator.isFunctionDeclarator()) { + // If so, make that declarator a prototyped declarator. + declarator.getFunctionTypeInfo().hasPrototype = true; + return; } - Attrs.clear(); + + // If there are any type objects, the type as written won't name a + // function, regardless of the decl spec type. This is because a + // block signature declarator is always an abstract-declarator, and + // abstract-declarators can't just be parentheses chunks. Therefore + // we need to build a function chunk unless there are no type + // objects and the decl spec type is a function. + if (!declarator.getNumTypeObjects() && declSpecType->isFunctionType()) + return; + + // Note that there *are* cases with invalid declarators where + // declarators consist solely of parentheses. In general, these + // occur only in failed efforts to make function declarators, so + // faking up the function chunk is still the right thing to do. + + // Otherwise, we need to fake up a function declarator. + SourceLocation loc = declarator.getSourceRange().getBegin(); + + // ...and *prepend* it to the declarator. + declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction( + ParsedAttributes(), + /*proto*/ true, + /*variadic*/ false, SourceLocation(), + /*args*/ 0, 0, + /*type quals*/ 0, + /*ref-qualifier*/true, SourceLocation(), + /*EH*/ false, SourceLocation(), false, 0, 0, 0, + /*parens*/ loc, loc, + declarator)); + + // For consistency, make sure the state still has us as processing + // the decl spec. + assert(state.getCurrentChunkIndex() == declarator.getNumTypeObjects() - 1); + state.setCurrentChunkIndex(declarator.getNumTypeObjects()); } /// \brief Convert the specified declspec to the appropriate type @@ -108,17 +526,17 @@ static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) { /// \param D the declarator containing the declaration specifier. /// \returns The type described by the declaration specifiers. This function /// never returns null. -static QualType ConvertDeclSpecToType(Sema &TheSema, - Declarator &TheDeclarator, - DelayedAttributeSet &Delayed) { +static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. - const DeclSpec &DS = TheDeclarator.getDeclSpec(); - SourceLocation DeclLoc = TheDeclarator.getIdentifierLoc(); + + Declarator &declarator = state.getDeclarator(); + const DeclSpec &DS = declarator.getDeclSpec(); + SourceLocation DeclLoc = declarator.getIdentifierLoc(); if (DeclLoc.isInvalid()) DeclLoc = DS.getSourceRange().getBegin(); - ASTContext &Context = TheSema.Context; + ASTContext &Context = S.Context; QualType Result; switch (DS.getTypeSpecType()) { @@ -140,13 +558,13 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.WCharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) { - TheSema.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getSignedWCharType(); } else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); - TheSema.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getUnsignedWCharType(); } @@ -173,7 +591,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // If this is a missing declspec in a block literal return context, then it // is inferred from the return statements inside the block. - if (isOmittedBlockReturnType(TheDeclarator)) { + if (isOmittedBlockReturnType(declarator)) { Result = Context.DependentTy; break; } @@ -185,11 +603,11 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // allowed to be completely missing a declspec. This is handled in the // parser already though by it pretending to have seen an 'int' in this // case. - if (TheSema.getLangOptions().ImplicitInt) { + if (S.getLangOptions().ImplicitInt) { // In C89 mode, we only warn if there is a completely missing declspec // when one is not allowed. if (DS.isEmpty()) { - TheSema.Diag(DeclLoc, diag::ext_missing_declspec) + S.Diag(DeclLoc, diag::ext_missing_declspec) << DS.getSourceRange() << FixItHint::CreateInsertion(DS.getSourceRange().getBegin(), "int"); } @@ -199,17 +617,17 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // specifiers in each declaration, and in the specifier-qualifier list in // each struct declaration and type name." // FIXME: Does Microsoft really have the implicit int extension in C++? - if (TheSema.getLangOptions().CPlusPlus && - !TheSema.getLangOptions().Microsoft) { - TheSema.Diag(DeclLoc, diag::err_missing_type_specifier) + if (S.getLangOptions().CPlusPlus && + !S.getLangOptions().Microsoft) { + S.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. - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); } else { - TheSema.Diag(DeclLoc, diag::ext_missing_type_specifier) + S.Diag(DeclLoc, diag::ext_missing_type_specifier) << DS.getSourceRange(); } } @@ -225,9 +643,9 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Result = Context.LongLongTy; // long long is a C99 feature. - if (!TheSema.getLangOptions().C99 && - !TheSema.getLangOptions().CPlusPlus0x) - TheSema.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); + if (!S.getLangOptions().C99 && + !S.getLangOptions().CPlusPlus0x) + S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); break; } } else { @@ -239,9 +657,9 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Result = Context.UnsignedLongLongTy; // long long is a C99 feature. - if (!TheSema.getLangOptions().C99 && - !TheSema.getLangOptions().CPlusPlus0x) - TheSema.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); + if (!S.getLangOptions().C99 && + !S.getLangOptions().CPlusPlus0x) + S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); break; } } @@ -253,14 +671,19 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Result = Context.LongDoubleTy; else Result = Context.DoubleTy; + + if (S.getLangOptions().OpenCL && !S.getOpenCLOptions().cl_khr_fp64) { + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_double_requires_fp64); + declarator.setInvalidType(true); + } break; case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool case DeclSpec::TST_decimal32: // _Decimal32 case DeclSpec::TST_decimal64: // _Decimal64 case DeclSpec::TST_decimal128: // _Decimal128 - TheSema.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); Result = Context.IntTy; - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); break; case DeclSpec::TST_class: case DeclSpec::TST_enum: @@ -270,12 +693,12 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, if (!D) { // This can happen in C++ with ambiguous lookups. Result = Context.IntTy; - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); break; } // If the type is deprecated or unavailable, diagnose it. - TheSema.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc()); + S.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc()); assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "No qualifiers on tag names!"); @@ -284,23 +707,22 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Result = Context.getTypeDeclType(D); // In C++, make an ElaboratedType. - if (TheSema.getLangOptions().CPlusPlus) { + if (S.getLangOptions().CPlusPlus) { ElaboratedTypeKeyword Keyword = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); - Result = TheSema.getElaboratedType(Keyword, DS.getTypeSpecScope(), - Result); + Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result); } if (D->isInvalidDecl()) - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(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 = TheSema.GetTypeFromParser(DS.getRepAsType()); + Result = S.GetTypeFromParser(DS.getRepAsType()); if (Result.isNull()) - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); else if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) { @@ -326,9 +748,9 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Result); } else { - TheSema.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) + S.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) << DS.getSourceRange(); - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); } } @@ -337,8 +759,11 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, } case DeclSpec::TST_typeofType: // FIXME: Preserve type source info. - Result = TheSema.GetTypeFromParser(DS.getRepAsType()); + Result = S.GetTypeFromParser(DS.getRepAsType()); assert(!Result.isNull() && "Didn't get a type for typeof?"); + if (!Result->isDependentType()) + if (const TagType *TT = Result->getAs<TagType>()) + S.DiagnoseUseOfDecl(TT->getDecl(), DS.getTypeSpecTypeLoc()); // TypeQuals handled by caller. Result = Context.getTypeOfType(Result); break; @@ -346,10 +771,10 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. - Result = TheSema.BuildTypeofExprType(E); + Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); } break; } @@ -357,48 +782,55 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. - Result = TheSema.BuildDecltypeType(E); + Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); } break; } case DeclSpec::TST_auto: { // TypeQuals handled by caller. - Result = Context.UndeducedAutoTy; + Result = Context.getAutoType(QualType()); break; } case DeclSpec::TST_error: Result = Context.IntTy; - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); break; } // Handle complex types. if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { - if (TheSema.getLangOptions().Freestanding) - TheSema.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); + if (S.getLangOptions().Freestanding) + S.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); Result = Context.getComplexType(Result); } else if (DS.isTypeAltiVecVector()) { unsigned typeSize = static_cast<unsigned>(Context.getTypeSize(Result)); assert(typeSize > 0 && "type size for vector must be greater than 0 bits"); - VectorType::AltiVecSpecific AltiVecSpec = VectorType::AltiVec; + VectorType::VectorKind VecKind = VectorType::AltiVecVector; if (DS.isTypeAltiVecPixel()) - AltiVecSpec = VectorType::Pixel; + VecKind = VectorType::AltiVecPixel; else if (DS.isTypeAltiVecBool()) - AltiVecSpec = VectorType::Bool; - Result = Context.getVectorType(Result, 128/typeSize, AltiVecSpec); + VecKind = VectorType::AltiVecBool; + Result = Context.getVectorType(Result, 128/typeSize, VecKind); } - assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary && - "FIXME: imaginary types not supported yet!"); + // FIXME: Imaginary. + if (DS.getTypeSpecComplex() == DeclSpec::TSC_imaginary) + S.Diag(DS.getTypeSpecComplexLoc(), diag::err_imaginary_not_supported); - // 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(TheSema, Result, true, AL, Delayed); + // Before we process any type attributes, synthesize a block literal + // function declarator if necessary. + if (declarator.getContext() == Declarator::BlockLiteralContext) + maybeSynthesizeBlockSignature(state, Result); + + // Apply any type attributes from the decl spec. This may cause the + // list of type attributes to be temporarily saved while the type + // attributes are pushed around. + if (AttributeList *attrs = DS.getAttributes().getList()) + processTypeAttrs(state, Result, true, attrs); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -419,14 +851,14 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // If we have a pointer or reference, the pointee must have an object // incomplete type. if (!EltTy->isIncompleteOrObjectType()) { - TheSema.Diag(DS.getRestrictSpecLoc(), + S.Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_invalid_pointee) << EltTy << DS.getSourceRange(); TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } } else { - TheSema.Diag(DS.getRestrictSpecLoc(), - diag::err_typecheck_invalid_restrict_not_pointer) + S.Diag(DS.getRestrictSpecLoc(), + diag::err_typecheck_invalid_restrict_not_pointer) << Result << DS.getSourceRange(); TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } @@ -447,7 +879,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, "Has CVR quals but not C, V, or R?"); Loc = DS.getRestrictSpecLoc(); } - TheSema.Diag(Loc, diag::warn_typecheck_function_qualifiers) + S.Diag(Loc, diag::warn_typecheck_function_qualifiers) << Result << DS.getSourceRange(); } @@ -516,6 +948,11 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, return Context.getQualifiedType(T, Qs); } +/// \brief Build a paren type including \p T. +QualType Sema::BuildParenType(QualType T) { + return Context.getParenType(T); +} + /// \brief Build a pointer type. /// /// \param T The type to which we'll be building a pointer. @@ -560,14 +997,14 @@ QualType Sema::BuildPointerType(QualType T, QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, SourceLocation Loc, DeclarationName Entity) { + // C++0x [dcl.ref]p6: + // If a typedef (7.1.3), a type template-parameter (14.3.1), or a + // decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a + // type T, an attempt to create the type "lvalue reference to cv TR" creates + // the type "lvalue reference to T", while an attempt to create the type + // "rvalue reference to cv TR" creates the type TR. bool LValueRef = SpelledAsLValue || T->getAs<LValueReferenceType>(); - // 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. - // C++ [dcl.ref]p4: There shall be no references to references. // // According to C++ DR 106, references to references are only @@ -579,8 +1016,8 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, // // 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. + // collapsing of references-to-references as described in C++0x. + // DR 106 and 540 introduce reference-collapsing into C++98/03. // C++ [dcl.ref]p1: // A declarator that specifies the type "reference to cv void" @@ -654,9 +1091,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } - if (Context.getCanonicalType(T) == Context.UndeducedAutoTy) { - Diag(Loc, diag::err_illegal_decl_array_of_auto) - << getPrintableNameForEntity(Entity); + if (T->getContainedAutoType()) { + Diag(Loc, diag::err_illegal_decl_array_of_auto) + << getPrintableNameForEntity(Entity) << T; return QualType(); } @@ -670,9 +1107,15 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } + // Do lvalue-to-rvalue conversions on the array size expression. + if (ArraySize && !ArraySize->isRValue()) + DefaultLvalueConversion(ArraySize); + // C99 6.7.5.2p1: The size expression shall have integer type. + // TODO: in theory, if we were insane, we could allow contextual + // conversions to integer type here. if (ArraySize && !ArraySize->isTypeDependent() && - !ArraySize->getType()->isIntegerType()) { + !ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) { Diag(ArraySize->getLocStart(), diag::err_array_size_non_int) << ArraySize->getType() << ArraySize->getSourceRange(); return QualType(); @@ -695,9 +1138,12 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, // C99 6.7.5.2p1: If the expression is a constant expression, it shall // have a value greater than zero. if (ConstVal.isSigned() && ConstVal.isNegative()) { - Diag(ArraySize->getLocStart(), - diag::err_typecheck_negative_array_size) - << ArraySize->getSourceRange(); + if (Entity) + Diag(ArraySize->getLocStart(), diag::err_decl_negative_array_size) + << getPrintableNameForEntity(Entity) << ArraySize->getSourceRange(); + else + Diag(ArraySize->getLocStart(), diag::err_typecheck_negative_array_size) + << ArraySize->getSourceRange(); return QualType(); } if (ConstVal == 0) { @@ -818,8 +1264,9 @@ QualType Sema::BuildFunctionType(QualType T, QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, unsigned Quals, + RefQualifierKind RefQualifier, SourceLocation Loc, DeclarationName Entity, - const FunctionType::ExtInfo &Info) { + FunctionType::ExtInfo Info) { if (T->isArrayType() || T->isFunctionType()) { Diag(Loc, diag::err_func_returning_array_function) << T->isFunctionType() << T; @@ -840,8 +1287,13 @@ QualType Sema::BuildFunctionType(QualType T, if (Invalid) return QualType(); - return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, - Quals, false, false, 0, 0, Info); + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = Variadic; + EPI.TypeQuals = Quals; + EPI.RefQualifier = RefQualifier; + EPI.ExtInfo = Info; + + return Context.getFunctionType(T, ParamTypes, NumParamTypes, EPI); } /// \brief Build a member pointer type \c T Class::*. @@ -934,7 +1386,7 @@ QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) { } TypeSourceInfo *DI = 0; - if (LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) { + if (const LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) { QT = LIT->getType(); DI = LIT->getTypeSourceInfo(); } @@ -953,20 +1405,21 @@ QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) { /// The result of this call will never be null, but the associated /// type may be a null type if there's an unrecoverable error. TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, - TagDecl **OwnedDecl) { + TagDecl **OwnedDecl, + bool AutoAllowedInTypeName) { // Determine the type of the declarator. Not all forms of declarator // have a type. QualType T; TypeSourceInfo *ReturnTypeInfo = 0; - - llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec; + + TypeProcessingState state(*this, D); switch (D.getName().getKind()) { case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: - T = ConvertDeclSpecToType(*this, D, FnAttrsFromDeclSpec); + T = ConvertDeclSpecToType(*this, state); if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) { TagDecl* Owned = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); @@ -993,11 +1446,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, &ReturnTypeInfo); break; } - - if (T.isNull()) - return Context.getNullTypeSourceInfo(); - if (T == Context.UndeducedAutoTy) { + if (D.getAttributes()) + distributeTypeAttrsFromDeclarator(state, T); + + if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && + !D.isFunctionDeclarator()) { int Error = -1; switch (D.getContext()) { @@ -1022,13 +1476,19 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Error = 5; // Template parameter break; case Declarator::BlockLiteralContext: - Error = 6; // Block literal + Error = 6; // Block literal + break; + case Declarator::TemplateTypeArgContext: + Error = 7; // Template type argument + break; + case Declarator::TypeNameContext: + if (!AutoAllowedInTypeName) + Error = 8; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: case Declarator::ForContext: case Declarator::ConditionContext: - case Declarator::TypeNameContext: break; } @@ -1040,20 +1500,26 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } + if (T.isNull()) + return Context.getNullTypeSourceInfo(); + // The name we're declaring, if any. DeclarationName Name; if (D.getIdentifier()) Name = D.getIdentifier(); - llvm::SmallVector<DelayedAttribute,4> FnAttrsFromPreviousChunk; - // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { - DeclaratorChunk &DeclType = D.getTypeObject(e-i-1); + unsigned chunkIndex = e - i - 1; + state.setCurrentChunkIndex(chunkIndex); + DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); + case DeclaratorChunk::Paren: + T = BuildParenType(T); + break; case DeclaratorChunk::BlockPointer: // If blocks are disabled, emit an error. if (!LangOpts.Blocks) @@ -1080,6 +1546,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T = BuildPointerType(T, DeclType.Loc, Name); if (DeclType.Ptr.TypeQuals) T = BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); + break; case DeclaratorChunk::Reference: { // Verify that we're not building a reference to pointer to function with @@ -1137,12 +1604,43 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // For conversion functions, we'll diagnose this particular error later. if ((T->isArrayType() || T->isFunctionType()) && (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) { - Diag(DeclType.Loc, diag::err_func_returning_array_function) - << T->isFunctionType() << T; + unsigned diagID = diag::err_func_returning_array_function; + // Last processing chunk in block context means this function chunk + // represents the block. + if (chunkIndex == 0 && + D.getContext() == Declarator::BlockLiteralContext) + diagID = diag::err_block_returning_array_function; + Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; T = Context.IntTy; D.setInvalidType(true); } + // Check for auto functions and trailing return type and adjust the + // return type accordingly. + if (!D.isInvalidType()) { + // trailing-return-type is only required if we're declaring a function, + // and not, for instance, a pointer to a function. + if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && + !FTI.TrailingReturnType && chunkIndex == 0) { + Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + diag::err_auto_missing_trailing_return); + T = Context.IntTy; + D.setInvalidType(true); + } else if (FTI.TrailingReturnType) { + if (T.hasQualifiers() || !isa<AutoType>(T)) { + // T must be exactly 'auto' at this point. See CWG issue 681. + Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + diag::err_trailing_return_without_auto) + << T << D.getDeclSpec().getSourceRange(); + D.setInvalidType(true); + } + + T = GetTypeFromParser( + ParsedType::getFromOpaquePtr(FTI.TrailingReturnType), + &ReturnTypeInfo); + } + } + // cv-qualifiers on return types are pointless except when the type is a // class type in C++. if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() && @@ -1229,6 +1727,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = FTI.isVariadic; + EPI.TypeQuals = FTI.TypeQuals; + EPI.RefQualifier = !FTI.hasRefQualifier()? RQ_None + : FTI.RefQualifierIsLValueRef? RQ_LValue + : RQ_RValue; + // Otherwise, we have a function with an argument list that is // potentially variadic. llvm::SmallVector<QualType, 16> ArgTys; @@ -1280,30 +1785,25 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } llvm::SmallVector<QualType, 4> Exceptions; - Exceptions.reserve(FTI.NumExceptions); - for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { - // FIXME: Preserve type source info. - QualType ET = GetTypeFromParser(FTI.Exceptions[ei].Ty); - // Check that the type is valid for an exception spec, and drop it if - // not. - if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) - Exceptions.push_back(ET); + if (FTI.hasExceptionSpec) { + EPI.HasExceptionSpec = FTI.hasExceptionSpec; + EPI.HasAnyExceptionSpec = FTI.hasAnyExceptionSpec; + Exceptions.reserve(FTI.NumExceptions); + for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { + // FIXME: Preserve type source info. + QualType ET = GetTypeFromParser(FTI.Exceptions[ei].Ty); + // Check that the type is valid for an exception spec, and + // drop it if not. + if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) + Exceptions.push_back(ET); + } + EPI.NumExceptions = Exceptions.size(); + EPI.Exceptions = Exceptions.data(); } - T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), - FTI.isVariadic, FTI.TypeQuals, - FTI.hasExceptionSpec, - FTI.hasAnyExceptionSpec, - Exceptions.size(), Exceptions.data(), - FunctionType::ExtInfo()); + T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI); } - // For GCC compatibility, we allow attributes that apply only to - // function types to be placed on a function's return type - // instead (as long as that type doesn't happen to be function - // or function-pointer itself). - ProcessDelayedFnAttrs(*this, T, FnAttrsFromPreviousChunk); - break; } case DeclaratorChunk::MemberPointer: @@ -1364,61 +1864,190 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T = Context.IntTy; } - DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk); - // See if there are any attributes on this declarator chunk. - if (const AttributeList *AL = DeclType.getAttrs()) - ProcessTypeAttributeList(*this, T, false, AL, FnAttrsFromPreviousChunk); + if (AttributeList *attrs = const_cast<AttributeList*>(DeclType.getAttrs())) + processTypeAttrs(state, T, false, attrs); } if (getLangOptions().CPlusPlus && T->isFunctionType()) { 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 - // for a nonstatic member function, the function type to which a pointer - // to member refers, or the top-level function type of a function typedef - // declaration. - bool FreeFunction = (D.getContext() != Declarator::MemberContext && - (!D.getCXXScopeSpec().isSet() || - !computeDeclContext(D.getCXXScopeSpec(), /*FIXME:*/true)->isRecord())); - if (FnTy->getTypeQuals() != 0 && + // C++ 8.3.5p4: + // A cv-qualifier-seq shall only be part of the function type + // for a nonstatic member function, the function type to which a pointer + // to member refers, or the top-level function type of a function typedef + // declaration. + // + // Core issue 547 also allows cv-qualifiers on function types that are + // top-level template type arguments. + bool FreeFunction; + if (!D.getCXXScopeSpec().isSet()) { + FreeFunction = (D.getContext() != Declarator::MemberContext || + D.getDeclSpec().isFriendSpecified()); + } else { + DeclContext *DC = computeDeclContext(D.getCXXScopeSpec()); + FreeFunction = (DC && !DC->isRecord()); + } + + // C++0x [dcl.fct]p6: + // A ref-qualifier shall only be part of the function type for a + // non-static member function, the function type to which a pointer to + // member refers, or the top-level function type of a function typedef + // declaration. + if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) && + !(D.getContext() == Declarator::TemplateTypeArgContext && + !D.isFunctionDeclarator()) && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && (FreeFunction || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) { - if (D.isFunctionDeclarator()) - Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); - else - Diag(D.getIdentifierLoc(), - diag::err_invalid_qualified_typedef_function_type_use) - << FreeFunction; + if (D.getContext() == Declarator::TemplateTypeArgContext) { + // Accept qualified function types as template type arguments as a GNU + // extension. This is also the subject of C++ core issue 547. + std::string Quals; + if (FnTy->getTypeQuals() != 0) + Quals = Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString(); + + switch (FnTy->getRefQualifier()) { + case RQ_None: + break; + + case RQ_LValue: + if (!Quals.empty()) + Quals += ' '; + Quals += '&'; + break; + + case RQ_RValue: + if (!Quals.empty()) + Quals += ' '; + Quals += "&&"; + break; + } + + Diag(D.getIdentifierLoc(), + diag::ext_qualified_function_type_template_arg) + << Quals; + } else { + if (FnTy->getTypeQuals() != 0) { + if (D.isFunctionDeclarator()) + Diag(D.getIdentifierLoc(), + diag::err_invalid_qualified_function_type); + else + Diag(D.getIdentifierLoc(), + diag::err_invalid_qualified_typedef_function_type_use) + << FreeFunction; + } + + if (FnTy->getRefQualifier()) { + if (D.isFunctionDeclarator()) { + SourceLocation Loc = D.getIdentifierLoc(); + for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) { + const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1); + if (Chunk.Kind == DeclaratorChunk::Function && + Chunk.Fun.hasRefQualifier()) { + Loc = Chunk.Fun.getRefQualifierLoc(); + break; + } + } - // Strip the cv-quals from the type. - T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), - FnTy->getNumArgs(), FnTy->isVariadic(), 0, - false, false, 0, 0, FunctionType::ExtInfo()); + Diag(Loc, diag::err_invalid_ref_qualifier_function_type) + << (FnTy->getRefQualifier() == RQ_LValue) + << FixItHint::CreateRemoval(Loc); + } else { + Diag(D.getIdentifierLoc(), + diag::err_invalid_ref_qualifier_typedef_function_type_use) + << FreeFunction + << (FnTy->getRefQualifier() == RQ_LValue); + } + } + + // Strip the cv-qualifiers and ref-qualifiers from the type. + FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); + EPI.TypeQuals = 0; + EPI.RefQualifier = RQ_None; + + T = Context.getFunctionType(FnTy->getResultType(), + FnTy->arg_type_begin(), + FnTy->getNumArgs(), EPI); + } } } + // Apply any undistributed attributes from the declarator. + if (!T.isNull()) + if (AttributeList *attrs = D.getAttributes()) + processTypeAttrs(state, T, false, attrs); + + // Diagnose any ignored type attributes. + if (!T.isNull()) state.diagnoseIgnoredTypeAttrs(T); + // If there's a constexpr specifier, treat it as a top-level const. if (D.getDeclSpec().isConstexprSpecified()) { T.addConst(); } - // Process any function attributes we might have delayed from the - // declaration-specifiers. - ProcessDelayedFnAttrs(*this, T, FnAttrsFromDeclSpec); - - // If there were any type attributes applied to the decl itself, not - // the type, apply them to the result type. But don't do this for - // block-literal expressions, which are parsed wierdly. - if (D.getContext() != Declarator::BlockLiteralContext) - if (const AttributeList *Attrs = D.getAttributes()) - ProcessTypeAttributeList(*this, T, false, Attrs, - FnAttrsFromPreviousChunk); - - DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk); - + // If there was an ellipsis in the declarator, the declaration declares a + // parameter pack whose type may be a pack expansion type. + if (D.hasEllipsis() && !T.isNull()) { + // C++0x [dcl.fct]p13: + // A declarator-id or abstract-declarator containing an ellipsis shall + // only be used in a parameter-declaration. Such a parameter-declaration + // is a parameter pack (14.5.3). [...] + switch (D.getContext()) { + case Declarator::PrototypeContext: + // C++0x [dcl.fct]p13: + // [...] When it is part of a parameter-declaration-clause, the + // parameter pack is a function parameter pack (14.5.3). The type T + // of the declarator-id of the function parameter pack shall contain + // a template parameter pack; each template parameter pack in T is + // expanded by the function parameter pack. + // + // We represent function parameter packs as function parameters whose + // type is a pack expansion. + if (!T->containsUnexpandedParameterPack()) { + Diag(D.getEllipsisLoc(), + diag::err_function_parameter_pack_without_parameter_packs) + << T << D.getSourceRange(); + D.setEllipsisLoc(SourceLocation()); + } else { + T = Context.getPackExpansionType(T, llvm::Optional<unsigned>()); + } + break; + + case Declarator::TemplateParamContext: + // C++0x [temp.param]p15: + // If a template-parameter is a [...] is a parameter-declaration that + // declares a parameter pack (8.3.5), then the template-parameter is a + // template parameter pack (14.5.3). + // + // Note: core issue 778 clarifies that, if there are any unexpanded + // parameter packs in the type of the non-type template parameter, then + // it expands those parameter packs. + if (T->containsUnexpandedParameterPack()) + T = Context.getPackExpansionType(T, llvm::Optional<unsigned>()); + else if (!getLangOptions().CPlusPlus0x) + Diag(D.getEllipsisLoc(), diag::ext_variadic_templates); + break; + + case Declarator::FileContext: + case Declarator::KNRTypeListContext: + case Declarator::TypeNameContext: + case Declarator::MemberContext: + case Declarator::BlockContext: + case Declarator::ForContext: + case Declarator::ConditionContext: + case Declarator::CXXCatchContext: + case Declarator::BlockLiteralContext: + case Declarator::TemplateTypeArgContext: + // FIXME: We may want to allow parameter packs in block-literal contexts + // in the future. + Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter); + D.setEllipsisLoc(SourceLocation()); + break; + } + } + if (T.isNull()) return Context.getNullTypeSourceInfo(); else if (D.isInvalidType()) @@ -1428,10 +2057,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, namespace { class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> { + ASTContext &Context; const DeclSpec &DS; public: - TypeSpecLocFiller(const DeclSpec &DS) : DS(DS) {} + TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS) + : Context(Context), DS(DS) {} void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { Visit(TL.getUnqualifiedLoc()); @@ -1446,7 +2077,7 @@ namespace { // Handle the base type, which might not have been written explicitly. if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { TL.setHasBaseTypeAsWritten(false); - TL.getBaseLoc().initialize(SourceLocation()); + TL.getBaseLoc().initialize(Context, SourceLocation()); } else { TL.setHasBaseTypeAsWritten(true); Visit(TL.getBaseLoc()); @@ -1477,7 +2108,7 @@ namespace { // If we got no declarator info from previous Sema routines, // just fill with the typespec loc. if (!TInfo) { - TL.initialize(DS.getTypeSpecTypeLoc()); + TL.initialize(Context, DS.getTypeSpecTypeLoc()); return; } @@ -1523,7 +2154,7 @@ namespace { void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { ElaboratedTypeKeyword Keyword = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType()); - if (Keyword == ETK_Typename) { + if (DS.getTypeSpecType() == TST_typename) { TypeSourceInfo *TInfo = 0; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); if (TInfo) { @@ -1541,7 +2172,7 @@ namespace { void VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { ElaboratedTypeKeyword Keyword = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType()); - if (Keyword == ETK_Typename) { + if (DS.getTypeSpecType() == TST_typename) { TypeSourceInfo *TInfo = 0; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); if (TInfo) { @@ -1570,7 +2201,7 @@ namespace { return; } } - TL.initializeLocal(SourceLocation()); + TL.initializeLocal(Context, SourceLocation()); TL.setKeywordLoc(Keyword != ETK_None ? DS.getTypeSpecTypeLoc() : SourceLocation()); @@ -1582,7 +2213,7 @@ namespace { void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. - TL.initialize(DS.getTypeSpecTypeLoc()); + TL.initialize(Context, DS.getTypeSpecTypeLoc()); } }; @@ -1634,6 +2265,7 @@ namespace { assert(Chunk.Kind == DeclaratorChunk::Function); TL.setLParenLoc(Chunk.Loc); TL.setRParenLoc(Chunk.EndLoc); + TL.setTrailingReturn(!!Chunk.Fun.TrailingReturnType); const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun; for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) { @@ -1642,6 +2274,11 @@ namespace { } // FIXME: exception specs } + void VisitParenTypeLoc(ParenTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Paren); + TL.setLParenLoc(Chunk.Loc); + TL.setRParenLoc(Chunk.EndLoc); + } void VisitTypeLoc(TypeLoc TL) { llvm_unreachable("unsupported TypeLoc kind in declarator!"); @@ -1663,6 +2300,12 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); + // Handle parameter packs whose type is a pack expansion. + if (isa<PackExpansionType>(T)) { + cast<PackExpansionTypeLoc>(CurrTL).setEllipsisLoc(D.getEllipsisLoc()); + CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); + } + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); @@ -1675,7 +2318,7 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, assert(TL.getFullDataSize() == CurrTL.getFullDataSize()); memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize()); } else { - TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL); + TypeSpecLocFiller(Context, D.getDeclSpec()).Visit(CurrTL); } return TInfo; @@ -1686,7 +2329,8 @@ ParsedType Sema::CreateParsedType(QualType T, TypeSourceInfo *TInfo) { // 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); + LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType), + TypeAlignment); new (LocT) LocInfoType(T, TInfo); assert(LocT->getTypeClass() != T->getTypeClass() && "LocInfoType's TypeClass conflicts with an existing Type class"); @@ -1787,160 +2431,291 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, 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, - const AttributeList &Attr, Sema &S) { - if (Type.getObjCGCAttr() != Qualifiers::GCNone) { - S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc); - Attr.setInvalid(); - return; +/// handleObjCGCTypeAttr - Process the __attribute__((objc_gc)) type +/// attribute on the specified type. Returns true to indicate that +/// the attribute was handled, false to indicate that the type does +/// not permit the attribute. +static bool handleObjCGCTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType &type) { + Sema &S = state.getSema(); + + // Delay if this isn't some kind of pointer. + if (!type->isPointerType() && + !type->isObjCObjectPointerType() && + !type->isBlockPointerType()) + return false; + + if (type.getObjCGCAttr() != Qualifiers::GCNone) { + S.Diag(attr.getLoc(), diag::err_attribute_multiple_objc_gc); + attr.setInvalid(); + return true; } // Check the attribute arguments. - if (!Attr.getParameterName()) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) + if (!attr.getParameterName()) { + S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) << "objc_gc" << 1; - Attr.setInvalid(); - return; + attr.setInvalid(); + return true; } Qualifiers::GC GCAttr; - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; - Attr.setInvalid(); - return; + if (attr.getNumArgs() != 0) { + S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + attr.setInvalid(); + return true; } - if (Attr.getParameterName()->isStr("weak")) + if (attr.getParameterName()->isStr("weak")) GCAttr = Qualifiers::Weak; - else if (Attr.getParameterName()->isStr("strong")) + else if (attr.getParameterName()->isStr("strong")) GCAttr = Qualifiers::Strong; else { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << "objc_gc" << Attr.getParameterName(); - Attr.setInvalid(); - return; + S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported) + << "objc_gc" << attr.getParameterName(); + attr.setInvalid(); + return true; } - Type = S.Context.getObjCGCQualType(Type, GCAttr); + type = S.Context.getObjCGCQualType(type, GCAttr); + return true; } -/// Process an individual function attribute. Returns true if the -/// attribute does not make sense to apply to this type. -bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { - if (Attr.getKind() == AttributeList::AT_noreturn) { - // Complain immediately if the arg count is wrong. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - Attr.setInvalid(); - return false; +namespace { + /// A helper class to unwrap a type down to a function for the + /// purposes of applying attributes there. + /// + /// Use: + /// FunctionTypeUnwrapper unwrapped(SemaRef, T); + /// if (unwrapped.isFunctionType()) { + /// const FunctionType *fn = unwrapped.get(); + /// // change fn somehow + /// T = unwrapped.wrap(fn); + /// } + struct FunctionTypeUnwrapper { + enum WrapKind { + Desugar, + Parens, + Pointer, + BlockPointer, + Reference, + MemberPointer + }; + + QualType Original; + const FunctionType *Fn; + llvm::SmallVector<unsigned char /*WrapKind*/, 8> Stack; + + FunctionTypeUnwrapper(Sema &S, QualType T) : Original(T) { + while (true) { + const Type *Ty = T.getTypePtr(); + if (isa<FunctionType>(Ty)) { + Fn = cast<FunctionType>(Ty); + return; + } else if (isa<ParenType>(Ty)) { + T = cast<ParenType>(Ty)->getInnerType(); + Stack.push_back(Parens); + } else if (isa<PointerType>(Ty)) { + T = cast<PointerType>(Ty)->getPointeeType(); + Stack.push_back(Pointer); + } else if (isa<BlockPointerType>(Ty)) { + T = cast<BlockPointerType>(Ty)->getPointeeType(); + Stack.push_back(BlockPointer); + } else if (isa<MemberPointerType>(Ty)) { + T = cast<MemberPointerType>(Ty)->getPointeeType(); + Stack.push_back(MemberPointer); + } else if (isa<ReferenceType>(Ty)) { + T = cast<ReferenceType>(Ty)->getPointeeType(); + Stack.push_back(Reference); + } else { + const Type *DTy = Ty->getUnqualifiedDesugaredType(); + if (Ty == DTy) { + Fn = 0; + return; + } + + T = QualType(DTy, 0); + Stack.push_back(Desugar); + } + } } - // Delay if this is not a function or pointer to block. - if (!Type->isFunctionPointerType() - && !Type->isBlockPointerType() - && !Type->isFunctionType() - && !Type->isMemberFunctionPointerType()) - return true; - - // Otherwise we can process right away. - Type = S.Context.getNoReturnType(Type); - return false; - } + bool isFunctionType() const { return (Fn != 0); } + const FunctionType *get() const { return Fn; } - if (Attr.getKind() == AttributeList::AT_regparm) { - // The warning is emitted elsewhere - if (Attr.getNumArgs() != 1) { - return false; + QualType wrap(Sema &S, const FunctionType *New) { + // If T wasn't modified from the unwrapped type, do nothing. + if (New == get()) return Original; + + Fn = New; + return wrap(S.Context, Original, 0); + } + + private: + QualType wrap(ASTContext &C, QualType Old, unsigned I) { + if (I == Stack.size()) + return C.getQualifiedType(Fn, Old.getQualifiers()); + + // Build up the inner type, applying the qualifiers from the old + // type to the new type. + SplitQualType SplitOld = Old.split(); + + // As a special case, tail-recurse if there are no qualifiers. + if (SplitOld.second.empty()) + return wrap(C, SplitOld.first, I); + return C.getQualifiedType(wrap(C, SplitOld.first, I), SplitOld.second); + } + + QualType wrap(ASTContext &C, const Type *Old, unsigned I) { + if (I == Stack.size()) return QualType(Fn, 0); + + switch (static_cast<WrapKind>(Stack[I++])) { + case Desugar: + // This is the point at which we potentially lose source + // information. + return wrap(C, Old->getUnqualifiedDesugaredType(), I); + + case Parens: { + QualType New = wrap(C, cast<ParenType>(Old)->getInnerType(), I); + return C.getParenType(New); + } + + case Pointer: { + QualType New = wrap(C, cast<PointerType>(Old)->getPointeeType(), I); + return C.getPointerType(New); + } + + case BlockPointer: { + QualType New = wrap(C, cast<BlockPointerType>(Old)->getPointeeType(),I); + return C.getBlockPointerType(New); + } + + case MemberPointer: { + const MemberPointerType *OldMPT = cast<MemberPointerType>(Old); + QualType New = wrap(C, OldMPT->getPointeeType(), I); + return C.getMemberPointerType(New, OldMPT->getClass()); + } + + case Reference: { + const ReferenceType *OldRef = cast<ReferenceType>(Old); + QualType New = wrap(C, OldRef->getPointeeType(), I); + if (isa<LValueReferenceType>(OldRef)) + return C.getLValueReferenceType(New, OldRef->isSpelledAsLValue()); + else + return C.getRValueReferenceType(New); + } + } + + llvm_unreachable("unknown wrapping kind"); + return QualType(); } + }; +} + +/// Process an individual function attribute. Returns true to +/// indicate that the attribute was handled, false if it wasn't. +static bool handleFunctionTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType &type) { + Sema &S = state.getSema(); - // Delay if this is not a function or pointer to block. - if (!Type->isFunctionPointerType() - && !Type->isBlockPointerType() - && !Type->isFunctionType() - && !Type->isMemberFunctionPointerType()) + FunctionTypeUnwrapper unwrapped(S, type); + + if (attr.getKind() == AttributeList::AT_noreturn) { + if (S.CheckNoReturnAttr(attr)) return true; + // Delay if this is not a function type. + if (!unwrapped.isFunctionType()) + return false; + // Otherwise we can process right away. - Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0)); - llvm::APSInt NumParams(32); + FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withNoReturn(true); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + return true; + } - // The warning is emitted elsewhere - if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() || - !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) + if (attr.getKind() == AttributeList::AT_regparm) { + unsigned value; + if (S.CheckRegparmAttr(attr, value)) + return true; + + // Delay if this is not a function type. + if (!unwrapped.isFunctionType()) return false; - Type = S.Context.getRegParmType(Type, NumParams.getZExtValue()); - return false; - } + // Diagnose regparm with fastcall. + const FunctionType *fn = unwrapped.get(); + CallingConv CC = fn->getCallConv(); + if (CC == CC_X86FastCall) { + S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) + << FunctionType::getNameForCallConv(CC) + << "regparm"; + attr.setInvalid(); + return true; + } - // Otherwise, a calling convention. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - Attr.setInvalid(); - return false; + FunctionType::ExtInfo EI = + unwrapped.get()->getExtInfo().withRegParm(value); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + return true; } - QualType T = Type; - if (const PointerType *PT = Type->getAs<PointerType>()) - T = PT->getPointeeType(); - else if (const BlockPointerType *BPT = Type->getAs<BlockPointerType>()) - T = BPT->getPointeeType(); - else if (const MemberPointerType *MPT = Type->getAs<MemberPointerType>()) - T = MPT->getPointeeType(); - else if (const ReferenceType *RT = Type->getAs<ReferenceType>()) - T = RT->getPointeeType(); - const FunctionType *Fn = T->getAs<FunctionType>(); + // Otherwise, a calling convention. + CallingConv CC; + if (S.CheckCallingConvAttr(attr, CC)) + return true; // Delay if the type didn't work out to a function. - if (!Fn) return true; + if (!unwrapped.isFunctionType()) return false; - // TODO: diagnose uses of these conventions on the wrong target. - CallingConv CC; - switch (Attr.getKind()) { - case AttributeList::AT_cdecl: CC = CC_C; break; - case AttributeList::AT_fastcall: CC = CC_X86FastCall; break; - case AttributeList::AT_stdcall: CC = CC_X86StdCall; break; - case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break; - case AttributeList::AT_pascal: CC = CC_X86Pascal; break; - default: llvm_unreachable("unexpected attribute kind"); return false; - } - - CallingConv CCOld = Fn->getCallConv(); + const FunctionType *fn = unwrapped.get(); + CallingConv CCOld = fn->getCallConv(); if (S.Context.getCanonicalCallConv(CC) == S.Context.getCanonicalCallConv(CCOld)) { - Attr.setInvalid(); - return false; + FunctionType::ExtInfo EI= unwrapped.get()->getExtInfo().withCallingConv(CC); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + return true; } if (CCOld != CC_Default) { // Should we diagnose reapplications of the same convention? - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) << FunctionType::getNameForCallConv(CC) << FunctionType::getNameForCallConv(CCOld); - Attr.setInvalid(); - return false; + attr.setInvalid(); + return true; } // Diagnose the use of X86 fastcall on varargs or unprototyped functions. if (CC == CC_X86FastCall) { - if (isa<FunctionNoProtoType>(Fn)) { - S.Diag(Attr.getLoc(), diag::err_cconv_knr) + if (isa<FunctionNoProtoType>(fn)) { + S.Diag(attr.getLoc(), diag::err_cconv_knr) << FunctionType::getNameForCallConv(CC); - Attr.setInvalid(); - return false; + attr.setInvalid(); + return true; } - const FunctionProtoType *FnP = cast<FunctionProtoType>(Fn); + const FunctionProtoType *FnP = cast<FunctionProtoType>(fn); if (FnP->isVariadic()) { - S.Diag(Attr.getLoc(), diag::err_cconv_varargs) + S.Diag(attr.getLoc(), diag::err_cconv_varargs) << FunctionType::getNameForCallConv(CC); - Attr.setInvalid(); - return false; + attr.setInvalid(); + return true; + } + + // Also diagnose fastcall with regparm. + if (fn->getRegParmType()) { + S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) + << "regparm" + << FunctionType::getNameForCallConv(CC); + attr.setInvalid(); + return true; } } - Type = S.Context.getCallConvType(Type, CC); - return false; + FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + return true; } /// HandleVectorSizeAttribute - this attribute is only applicable to integral @@ -1952,7 +2727,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { /// this routine will return a new vector type. static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, Sema &S) { - // Check the attribute arugments. + // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; Attr.setInvalid(); @@ -1994,50 +2769,121 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, // 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, - VectorType::NotAltiVec); + VectorType::GenericVector); } -void ProcessTypeAttributeList(Sema &S, QualType &Result, - bool IsDeclSpec, const AttributeList *AL, - DelayedAttributeSet &FnAttrs) { +/// HandleNeonVectorTypeAttr - The "neon_vector_type" and +/// "neon_polyvector_type" attributes are used to create vector types that +/// are mangled according to ARM's ABI. Otherwise, these types are identical +/// to those created with the "vector_size" attribute. Unlike "vector_size" +/// the argument to these Neon attributes is the number of vector elements, +/// not the vector size in bytes. The vector width and element type must +/// match one of the standard Neon vector types. +static void HandleNeonVectorTypeAttr(QualType& CurType, + const AttributeList &Attr, Sema &S, + VectorType::VectorKind VecKind, + const char *AttrName) { + // Check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + Attr.setInvalid(); + return; + } + // The number of elements must be an ICE. + Expr *numEltsExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt numEltsInt(32); + if (numEltsExpr->isTypeDependent() || numEltsExpr->isValueDependent() || + !numEltsExpr->isIntegerConstantExpr(numEltsInt, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << AttrName << numEltsExpr->getSourceRange(); + Attr.setInvalid(); + return; + } + // Only certain element types are supported for Neon vectors. + const BuiltinType* BTy = CurType->getAs<BuiltinType>(); + if (!BTy || + (VecKind == VectorType::NeonPolyVector && + BTy->getKind() != BuiltinType::SChar && + BTy->getKind() != BuiltinType::Short) || + (BTy->getKind() != BuiltinType::SChar && + BTy->getKind() != BuiltinType::UChar && + BTy->getKind() != BuiltinType::Short && + BTy->getKind() != BuiltinType::UShort && + BTy->getKind() != BuiltinType::Int && + BTy->getKind() != BuiltinType::UInt && + BTy->getKind() != BuiltinType::LongLong && + BTy->getKind() != BuiltinType::ULongLong && + BTy->getKind() != BuiltinType::Float)) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) <<CurType; + Attr.setInvalid(); + return; + } + // The total size of the vector must be 64 or 128 bits. + unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType)); + unsigned numElts = static_cast<unsigned>(numEltsInt.getZExtValue()); + unsigned vecSize = typeSize * numElts; + if (vecSize != 64 && vecSize != 128) { + S.Diag(Attr.getLoc(), diag::err_attribute_bad_neon_vector_size) << CurType; + Attr.setInvalid(); + return; + } + + CurType = S.Context.getVectorType(CurType, numElts, VecKind); +} + +static void processTypeAttrs(TypeProcessingState &state, QualType &type, + bool isDeclSpec, AttributeList *attrs) { // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the // type, but others can be present in the type specifiers even though they // apply to the decl. Here we apply type attributes and ignore the rest. - for (; AL; AL = AL->getNext()) { + + AttributeList *next; + do { + AttributeList &attr = *attrs; + next = attr.getNext(); + // Skip attributes that were marked to be invalid. - if (AL->isInvalid()) + if (attr.isInvalid()) continue; // If this is an attribute we can handle, do so now, // otherwise, add it to the FnAttrs list for rechaining. - switch (AL->getKind()) { + switch (attr.getKind()) { default: break; case AttributeList::AT_address_space: - HandleAddressSpaceTypeAttribute(Result, *AL, S); + HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); break; - case AttributeList::AT_objc_gc: - HandleObjCGCTypeAttribute(Result, *AL, S); + OBJC_POINTER_TYPE_ATTRS_CASELIST: + if (!handleObjCPointerTypeAttr(state, attr, type)) + distributeObjCPointerTypeAttr(state, attr, type); break; case AttributeList::AT_vector_size: - HandleVectorSizeAttr(Result, *AL, S); + HandleVectorSizeAttr(type, attr, state.getSema()); + break; + case AttributeList::AT_neon_vector_type: + HandleNeonVectorTypeAttr(type, attr, state.getSema(), + VectorType::NeonVector, "neon_vector_type"); break; + case AttributeList::AT_neon_polyvector_type: + HandleNeonVectorTypeAttr(type, attr, state.getSema(), + VectorType::NeonPolyVector, + "neon_polyvector_type"); + break; + + FUNCTION_TYPE_ATTRS_CASELIST: + // Never process function type attributes as part of the + // declaration-specifiers. + if (isDeclSpec) + distributeFunctionTypeAttrFromDeclSpec(state, attr, type); - case AttributeList::AT_noreturn: - case AttributeList::AT_cdecl: - case AttributeList::AT_fastcall: - case AttributeList::AT_stdcall: - case AttributeList::AT_thiscall: - case AttributeList::AT_pascal: - case AttributeList::AT_regparm: - // Don't process these on the DeclSpec. - if (IsDeclSpec || - ProcessFnAttr(S, Result, *AL)) - FnAttrs.push_back(DelayedAttribute(AL, Result)); + // Otherwise, handle the possible delays. + else if (!handleFunctionTypeAttr(state, attr, type)) + distributeFunctionTypeAttr(state, attr, type); break; } - } + } while ((attrs = next)); } /// @brief Ensure that the type T is a complete type. @@ -2110,16 +2956,19 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, if (diag == 0) return true; - const TagType *Tag = 0; - if (const RecordType *Record = T->getAs<RecordType>()) - Tag = Record; - else if (const EnumType *Enum = T->getAs<EnumType>()) - Tag = Enum; + const TagType *Tag = T->getAs<TagType>(); // Avoid diagnosing invalid decls as incomplete. if (Tag && Tag->getDecl()->isInvalidDecl()) return true; + // Give the external AST source a chance to complete the type. + if (Tag && Tag->getDecl()->hasExternalLexicalStorage()) { + Context.getExternalSource()->CompleteType(Tag->getDecl()); + if (!Tag->isIncompleteType()) + return false; + } + // We have an incomplete type. Produce a diagnostic. Diag(Loc, PD) << T; @@ -2167,48 +3016,23 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, return Context.getElaboratedType(Keyword, NNS, T); } -QualType Sema::BuildTypeofExprType(Expr *E) { - if (E->getType() == Context.OverloadTy) { - // C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a - // function template specialization wherever deduction cannot occur. - if (FunctionDecl *Specialization - = ResolveSingleFunctionTemplateSpecialization(E)) { - // The access doesn't really matter in this case. - DeclAccessPair Found = DeclAccessPair::make(Specialization, - Specialization->getAccess()); - E = FixOverloadedFunctionReference(E, Found, Specialization); - if (!E) - return QualType(); - } else { - Diag(E->getLocStart(), - diag::err_cannot_determine_declared_type_of_overloaded_function) - << false << E->getSourceRange(); - return QualType(); - } +QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { + ExprResult ER = CheckPlaceholderExpr(E, Loc); + if (ER.isInvalid()) return QualType(); + E = ER.take(); + + if (!E->isTypeDependent()) { + QualType T = E->getType(); + if (const TagType *TT = T->getAs<TagType>()) + DiagnoseUseOfDecl(TT->getDecl(), E->getExprLoc()); } - return Context.getTypeOfExprType(E); } -QualType Sema::BuildDecltypeType(Expr *E) { - if (E->getType() == Context.OverloadTy) { - // C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a - // function template specialization wherever deduction cannot occur. - if (FunctionDecl *Specialization - = ResolveSingleFunctionTemplateSpecialization(E)) { - // The access doesn't really matter in this case. - DeclAccessPair Found = DeclAccessPair::make(Specialization, - Specialization->getAccess()); - E = FixOverloadedFunctionReference(E, Found, Specialization); - if (!E) - return QualType(); - } else { - Diag(E->getLocStart(), - diag::err_cannot_determine_declared_type_of_overloaded_function) - << true << E->getSourceRange(); - return QualType(); - } - } +QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) { + ExprResult ER = CheckPlaceholderExpr(E, Loc); + if (ER.isInvalid()) return QualType(); + E = ER.take(); return Context.getDecltypeType(E); } diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp index 1854e74..c3415cb 100644 --- a/lib/Sema/TargetAttributesSema.cpp +++ b/lib/Sema/TargetAttributesSema.cpp @@ -71,6 +71,55 @@ namespace { }; } +static void HandleMBlazeInterruptHandlerAttr(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) << 1; + return; + } + + // FIXME: Check for decl - it should be void ()(void). + + d->addAttr(::new (S.Context) MBlazeInterruptHandlerAttr(Attr.getLoc(), + S.Context)); + d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); +} + +static void HandleMBlazeSaveVolatilesAttr(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) << 1; + return; + } + + // FIXME: Check for decl - it should be void ()(void). + + d->addAttr(::new (S.Context) MBlazeSaveVolatilesAttr(Attr.getLoc(), + S.Context)); + d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); +} + + +namespace { + class MBlazeAttributesSema : public TargetAttributesSema { + public: + MBlazeAttributesSema() { } + bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, + Sema &S) const { + if (Attr.getName()->getName() == "interrupt_handler") { + HandleMBlazeInterruptHandlerAttr(D, Attr, S); + return true; + } else if (Attr.getName()->getName() == "save_volatiles") { + HandleMBlazeSaveVolatilesAttr(D, Attr, S); + return true; + } + return false; + } + }; +} + static void HandleX86ForceAlignArgPointerAttr(Decl *D, const AttributeList& Attr, Sema &S) { @@ -189,8 +238,7 @@ namespace { const AttributeList &Attr, Sema &S) const { const llvm::Triple &Triple(S.Context.Target.getTriple()); if (Triple.getOS() == llvm::Triple::Win32 || - Triple.getOS() == llvm::Triple::MinGW32 || - Triple.getOS() == llvm::Triple::MinGW64) { + Triple.getOS() == llvm::Triple::MinGW32) { switch (Attr.getKind()) { case AttributeList::AT_dllimport: HandleDLLImportAttr(D, Attr, S); return true; @@ -220,8 +268,9 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const { case llvm::Triple::msp430: return *(TheTargetAttributesSema = new MSP430AttributesSema); + case llvm::Triple::mblaze: + return *(TheTargetAttributesSema = new MBlazeAttributesSema); case llvm::Triple::x86: return *(TheTargetAttributesSema = new X86AttributesSema); } } - diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index e7bfbe6..944e6a1 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1,20 +1,22 @@ -//===------- TreeTransform.h - Semantic Tree Transformation -----*- C++ -*-===/ +//===------- TreeTransform.h - Semantic Tree Transformation -----*- 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 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 "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/ScopeInfo.h" #include "clang/AST/Decl.h" @@ -25,11 +27,11 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" -#include "clang/AST/TypeLocBuilder.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Designator.h" #include "clang/Lex/Preprocessor.h" #include "llvm/Support/ErrorHandling.h" +#include "TypeLocBuilder.h" #include <algorithm> namespace clang { @@ -88,9 +90,26 @@ using namespace sema; /// (\c getBaseLocation(), \c getBaseEntity()). template<typename Derived> class TreeTransform { + /// \brief Private RAII object that helps us forget and then re-remember + /// the template argument corresponding to a partially-substituted parameter + /// pack. + class ForgetPartiallySubstitutedPackRAII { + Derived &Self; + TemplateArgument Old; + + public: + ForgetPartiallySubstitutedPackRAII(Derived &Self) : Self(Self) { + Old = Self.ForgetPartiallySubstitutedPack(); + } + + ~ForgetPartiallySubstitutedPackRAII() { + Self.RememberPartiallySubstitutedPack(Old); + } + }; + protected: Sema &SemaRef; - + public: /// \brief Initializes a new tree transformer. TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { } @@ -151,7 +170,9 @@ public: DeclarationName Entity) : Self(Self) { OldLocation = Self.getDerived().getBaseLocation(); OldEntity = Self.getDerived().getBaseEntity(); - Self.getDerived().setBase(Location, Entity); + + if (Location.isValid()) + Self.getDerived().setBase(Location, Entity); } ~TemporaryBase() { @@ -180,6 +201,77 @@ public: return E->isDefaultArgument(); } + /// \brief Determine whether we should expand a pack expansion with the + /// given set of parameter packs into separate arguments by repeatedly + /// transforming the pattern. + /// + /// By default, the transformer never tries to expand pack expansions. + /// Subclasses can override this routine to provide different behavior. + /// + /// \param EllipsisLoc The location of the ellipsis that identifies the + /// pack expansion. + /// + /// \param PatternRange The source range that covers the entire pattern of + /// the pack expansion. + /// + /// \param Unexpanded The set of unexpanded parameter packs within the + /// pattern. + /// + /// \param NumUnexpanded The number of unexpanded parameter packs in + /// \p Unexpanded. + /// + /// \param ShouldExpand Will be set to \c true if the transformer should + /// expand the corresponding pack expansions into separate arguments. When + /// set, \c NumExpansions must also be set. + /// + /// \param RetainExpansion Whether the caller should add an unexpanded + /// pack expansion after all of the expanded arguments. This is used + /// when extending explicitly-specified template argument packs per + /// C++0x [temp.arg.explicit]p9. + /// + /// \param NumExpansions The number of separate arguments that will be in + /// the expanded form of the corresponding pack expansion. This is both an + /// input and an output parameter, which can be set by the caller if the + /// number of expansions is known a priori (e.g., due to a prior substitution) + /// and will be set by the callee when the number of expansions is known. + /// The callee must set this value when \c ShouldExpand is \c true; it may + /// set this value in other cases. + /// + /// \returns true if an error occurred (e.g., because the parameter packs + /// are to be instantiated with arguments of different lengths), false + /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) + /// must be set. + bool TryExpandParameterPacks(SourceLocation EllipsisLoc, + SourceRange PatternRange, + const UnexpandedParameterPack *Unexpanded, + unsigned NumUnexpanded, + bool &ShouldExpand, + bool &RetainExpansion, + llvm::Optional<unsigned> &NumExpansions) { + ShouldExpand = false; + return false; + } + + /// \brief "Forget" about the partially-substituted pack template argument, + /// when performing an instantiation that must preserve the parameter pack + /// use. + /// + /// This routine is meant to be overridden by the template instantiator. + TemplateArgument ForgetPartiallySubstitutedPack() { + return TemplateArgument(); + } + + /// \brief "Remember" the partially-substituted pack template argument + /// after performing an instantiation that must preserve the parameter pack + /// use. + /// + /// This routine is meant to be overridden by the template instantiator. + void RememberPartiallySubstitutedPack(TemplateArgument Arg) { } + + /// \brief Note to the derived class when a function parameter pack is + /// being expanded. + void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { } + /// \brief Transforms the given type into another type. /// /// By default, this routine transforms a type by creating a @@ -189,7 +281,7 @@ public: /// switched to storing TypeSourceInfos. /// /// \returns the transformed type. - QualType TransformType(QualType T, QualType ObjectType = QualType()); + QualType TransformType(QualType T); /// \brief Transforms the given type-with-location into a new /// type-with-location. @@ -199,15 +291,13 @@ public: /// may override this function (to take over all type /// transformations) or some set of the TransformXXXType functions /// to alter the transformation. - TypeSourceInfo *TransformType(TypeSourceInfo *DI, - QualType ObjectType = QualType()); + TypeSourceInfo *TransformType(TypeSourceInfo *DI); /// \brief Transform the given type-with-location into a new /// type, collecting location information in the given builder /// as necessary. /// - QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL, - QualType ObjectType = QualType()); + QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL); /// \brief Transform the given statement. /// @@ -230,6 +320,33 @@ public: /// \returns the transformed expression. ExprResult TransformExpr(Expr *E); + /// \brief Transform the given list of expressions. + /// + /// This routine transforms a list of expressions by invoking + /// \c TransformExpr() for each subexpression. However, it also provides + /// support for variadic templates by expanding any pack expansions (if the + /// derived class permits such expansion) along the way. When pack expansions + /// are present, the number of outputs may not equal the number of inputs. + /// + /// \param Inputs The set of expressions to be transformed. + /// + /// \param NumInputs The number of expressions in \c Inputs. + /// + /// \param IsCall If \c true, then this transform is being performed on + /// function-call arguments, and any arguments that should be dropped, will + /// be. + /// + /// \param Outputs The transformed input expressions will be added to this + /// vector. + /// + /// \param ArgChanged If non-NULL, will be set \c true if any argument changed + /// due to transformation. + /// + /// \returns true if an error occurred, false otherwise. + bool TransformExprs(Expr **Inputs, unsigned NumInputs, bool IsCall, + llvm::SmallVectorImpl<Expr *> &Outputs, + bool *ArgChanged = 0); + /// \brief Transform the given declaration, which is referenced from a type /// or expression. /// @@ -275,8 +392,7 @@ public: /// Identifiers and selectors are returned unmodified. Sublcasses may /// override this function to provide alternate behavior. DeclarationNameInfo - TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo, - QualType ObjectType = QualType()); + TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo); /// \brief Transform the given template name. /// @@ -284,7 +400,8 @@ public: /// 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()); + QualType ObjectType = QualType(), + NamedDecl *FirstQualifierInScope = 0); /// \brief Transform the given template argument. /// @@ -297,6 +414,49 @@ public: bool TransformTemplateArgument(const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output); + /// \brief Transform the given set of template arguments. + /// + /// By default, this operation transforms all of the template arguments + /// in the input set using \c TransformTemplateArgument(), and appends + /// the transformed arguments to the output list. + /// + /// Note that this overload of \c TransformTemplateArguments() is merely + /// a convenience function. Subclasses that wish to override this behavior + /// should override the iterator-based member template version. + /// + /// \param Inputs The set of template arguments to be transformed. + /// + /// \param NumInputs The number of template arguments in \p Inputs. + /// + /// \param Outputs The set of transformed template arguments output by this + /// routine. + /// + /// Returns true if an error occurred. + bool TransformTemplateArguments(const TemplateArgumentLoc *Inputs, + unsigned NumInputs, + TemplateArgumentListInfo &Outputs) { + return TransformTemplateArguments(Inputs, Inputs + NumInputs, Outputs); + } + + /// \brief Transform the given set of template arguments. + /// + /// By default, this operation transforms all of the template arguments + /// in the input set using \c TransformTemplateArgument(), and appends + /// the transformed arguments to the output list. + /// + /// \param First An iterator to the first template argument. + /// + /// \param Last An iterator one step past the last template argument. + /// + /// \param Outputs The set of transformed template arguments output by this + /// routine. + /// + /// Returns true if an error occurred. + template<typename InputIterator> + bool TransformTemplateArguments(InputIterator First, + InputIterator Last, + TemplateArgumentListInfo &Outputs); + /// \brief Fakes up a TemplateArgumentLoc for a given TemplateArgument. void InventTemplateArgumentLoc(const TemplateArgument &Arg, TemplateArgumentLoc &ArgLoc); @@ -309,10 +469,19 @@ public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T, \ - QualType ObjectType = QualType()); + QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" + QualType + TransformTemplateSpecializationType(TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, + TemplateName Template); + + QualType + TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, + DependentTemplateSpecializationTypeLoc TL, + NestedNameSpecifier *Prefix); + /// \brief Transforms the parameters of a function type into the /// given vectors. /// @@ -320,20 +489,18 @@ public: /// variables vector are acceptable. /// /// Return true on error. - bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + bool TransformFunctionTypeParams(SourceLocation Loc, + ParmVarDecl **Params, unsigned NumParams, + const QualType *ParamTypes, llvm::SmallVectorImpl<QualType> &PTypes, - llvm::SmallVectorImpl<ParmVarDecl*> &PVars); + llvm::SmallVectorImpl<ParmVarDecl*> *PVars); /// \brief Transforms a single function-type parameter. Return null /// on error. - ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm); + ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, + llvm::Optional<unsigned> NumExpansions); - QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL, - QualType ObjectType); - - QualType - TransformTemplateSpecializationType(const TemplateSpecializationType *T, - QualType ObjectType); + QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL); StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E); @@ -440,7 +607,7 @@ public: /// 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, - VectorType::AltiVecSpecific AltiVecSpec); + VectorType::VectorKind VecKind); /// \brief Build a new extended vector type given the element type and /// number of elements. @@ -467,6 +634,7 @@ public: QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, unsigned Quals, + RefQualifierKind RefQualifier, const FunctionType::ExtInfo &Info); /// \brief Build a new unprototyped function type. @@ -495,7 +663,7 @@ public: /// /// By default, performs semantic analysis when building the typeof type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildTypeOfExprType(Expr *Underlying); + QualType RebuildTypeOfExprType(Expr *Underlying, SourceLocation Loc); /// \brief Build a new typeof(type) type. /// @@ -506,7 +674,14 @@ public: /// /// By default, performs semantic analysis when building the decltype type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildDecltypeType(Expr *Underlying); + QualType RebuildDecltypeType(Expr *Underlying, SourceLocation Loc); + + /// \brief Build a new C++0x auto type. + /// + /// By default, builds a new AutoType with the given deduced type. + QualType RebuildAutoType(QualType Deduced) { + return SemaRef.Context.getAutoType(Deduced); + } /// \brief Build a new template specialization type. /// @@ -517,12 +692,21 @@ public: SourceLocation TemplateLoc, const TemplateArgumentListInfo &Args); + /// \brief Build a new parenthesized type. + /// + /// By default, builds a new ParenType type from the inner type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildParenType(QualType InnerType) { + return SemaRef.Context.getParenType(InnerType); + } + /// \brief Build a new qualified name type. /// /// By default, builds a new ElaboratedType type from the keyword, /// the nested-name-specifier and the named type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword, + QualType RebuildElaboratedType(SourceLocation KeywordLoc, + ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType Named) { return SemaRef.Context.getElaboratedType(Keyword, NNS, Named); } @@ -534,14 +718,16 @@ public: /// this routine to provide different behavior. QualType RebuildDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, const IdentifierInfo *Name, SourceLocation NameLoc, const TemplateArgumentListInfo &Args) { // Rebuild the template name. // TODO: avoid TemplateName abstraction TemplateName InstName = - getDerived().RebuildTemplateName(NNS, *Name, QualType()); + getDerived().RebuildTemplateName(Qualifier, QualifierRange, *Name, + QualType(), 0); if (InstName.isNull()) return QualType(); @@ -549,7 +735,7 @@ public: // If it's still dependent, make a dependent specialization. if (InstName.getAsDependentTemplateName()) return SemaRef.Context.getDependentTemplateSpecializationType( - Keyword, NNS, Name, Args); + Keyword, Qualifier, Name, Args); // Otherwise, make an elaborated type wrapping a non-dependent // specialization. @@ -621,9 +807,28 @@ public: } if (!Tag) { - // FIXME: Would be nice to highlight just the source range. - SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope) - << Kind << Id << DC; + // Check where the name exists but isn't a tag type and use that to emit + // better diagnostics. + LookupResult Result(SemaRef, Id, IdLoc, Sema::LookupTagName); + SemaRef.LookupQualifiedName(Result, DC); + switch (Result.getResultKind()) { + case LookupResult::Found: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: { + NamedDecl *SomeDecl = Result.getRepresentativeDecl(); + unsigned Kind = 0; + if (isa<TypedefDecl>(SomeDecl)) Kind = 1; + else if (isa<ClassTemplateDecl>(SomeDecl)) Kind = 2; + SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind; + SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at); + break; + } + default: + // FIXME: Would be nice to highlight just the source range. + SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope) + << Kind << Id << DC; + break; + } return QualType(); } @@ -638,6 +843,18 @@ public: return SemaRef.Context.getElaboratedType(Keyword, NNS, T); } + /// \brief Build a new pack expansion type. + /// + /// By default, builds a new PackExpansionType type from the given pattern. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildPackExpansionType(QualType Pattern, + SourceRange PatternRange, + SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions) { + return getSema().CheckPackExpansion(Pattern, PatternRange, EllipsisLoc, + NumExpansions); + } + /// \brief Build a new nested-name-specifier given the prefix and an /// identifier that names the next step in the nested-name-specifier. /// @@ -689,8 +906,10 @@ public: /// template name. Subclasses may override this routine to provide different /// behavior. TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, const IdentifierInfo &II, - QualType ObjectType); + QualType ObjectType, + NamedDecl *FirstQualifierInScope); /// \brief Build a new template name given a nested name specifier and the /// overloaded operator name that is referred to as a template. @@ -702,7 +921,19 @@ public: TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, OverloadedOperatorKind Operator, QualType ObjectType); - + + /// \brief Build a new template name given a template template parameter pack + /// and the + /// + /// 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(TemplateTemplateParmDecl *Param, + const TemplateArgument &ArgPack) { + return getSema().Context.getSubstTemplateTemplateParmPack(Param, ArgPack); + } + /// \brief Build a new compound statement. /// /// By default, performs semantic analysis to build the new statement. @@ -752,11 +983,9 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildLabelStmt(SourceLocation IdentLoc, - IdentifierInfo *Id, - SourceLocation ColonLoc, - Stmt *SubStmt) { - return SemaRef.ActOnLabelStmt(IdentLoc, Id, ColonLoc, SubStmt); + StmtResult RebuildLabelStmt(SourceLocation IdentLoc, LabelDecl *L, + SourceLocation ColonLoc, Stmt *SubStmt) { + return SemaRef.ActOnLabelStmt(IdentLoc, L, ColonLoc, SubStmt); } /// \brief Build a new "if" statement. @@ -764,8 +993,8 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond, - VarDecl *CondVar, Stmt *Then, - SourceLocation ElseLoc, Stmt *Else) { + VarDecl *CondVar, Stmt *Then, + SourceLocation ElseLoc, Stmt *Else) { return getSema().ActOnIfStmt(IfLoc, Cond, CondVar, Then, ElseLoc, Else); } @@ -774,7 +1003,7 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, - Expr *Cond, VarDecl *CondVar) { + Expr *Cond, VarDecl *CondVar) { return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Cond, CondVar); } @@ -784,7 +1013,7 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildSwitchStmtBody(SourceLocation SwitchLoc, - Stmt *Switch, Stmt *Body) { + Stmt *Switch, Stmt *Body) { return getSema().ActOnFinishSwitchStmt(SwitchLoc, Switch, Body); } @@ -792,10 +1021,8 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildWhileStmt(SourceLocation WhileLoc, - Sema::FullExprArg Cond, - VarDecl *CondVar, - Stmt *Body) { + StmtResult RebuildWhileStmt(SourceLocation WhileLoc, Sema::FullExprArg Cond, + VarDecl *CondVar, Stmt *Body) { return getSema().ActOnWhileStmt(WhileLoc, Cond, CondVar, Body); } @@ -804,10 +1031,8 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildDoStmt(SourceLocation DoLoc, Stmt *Body, - SourceLocation WhileLoc, - SourceLocation LParenLoc, - Expr *Cond, - SourceLocation RParenLoc) { + SourceLocation WhileLoc, SourceLocation LParenLoc, + Expr *Cond, SourceLocation RParenLoc) { return getSema().ActOnDoStmt(DoLoc, Body, WhileLoc, LParenLoc, Cond, RParenLoc); } @@ -816,24 +1041,21 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildForStmt(SourceLocation ForLoc, - SourceLocation LParenLoc, - Stmt *Init, Sema::FullExprArg Cond, - VarDecl *CondVar, Sema::FullExprArg Inc, - SourceLocation RParenLoc, Stmt *Body) { + StmtResult RebuildForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, + Stmt *Init, Sema::FullExprArg Cond, + VarDecl *CondVar, Sema::FullExprArg Inc, + SourceLocation RParenLoc, Stmt *Body) { return getSema().ActOnForStmt(ForLoc, LParenLoc, Init, Cond, - CondVar, - Inc, RParenLoc, Body); + CondVar, Inc, RParenLoc, 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. - StmtResult RebuildGotoStmt(SourceLocation GotoLoc, - SourceLocation LabelLoc, - LabelStmt *Label) { - return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label->getID()); + StmtResult RebuildGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, + LabelDecl *Label) { + return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label); } /// \brief Build a new indirect goto statement. @@ -841,8 +1063,8 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildIndirectGotoStmt(SourceLocation GotoLoc, - SourceLocation StarLoc, - Expr *Target) { + SourceLocation StarLoc, + Expr *Target) { return getSema().ActOnIndirectGotoStmt(GotoLoc, StarLoc, Target); } @@ -850,9 +1072,7 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildReturnStmt(SourceLocation ReturnLoc, - Expr *Result) { - + StmtResult RebuildReturnStmt(SourceLocation ReturnLoc, Expr *Result) { return getSema().ActOnReturnStmt(ReturnLoc, Result); } @@ -977,13 +1197,11 @@ public: /// /// 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, + VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *Declarator, IdentifierInfo *Name, - SourceLocation Loc, - SourceRange TypeRange) { - return getSema().BuildExceptionDeclaration(0, T, Declarator, Name, Loc, - TypeRange); + SourceLocation Loc) { + return getSema().BuildExceptionDeclaration(0, Declarator, Name, Loc); } /// \brief Build a new C++ catch statement. @@ -1126,10 +1344,10 @@ public: /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc, MultiExprArg Args, - SourceLocation *CommaLocs, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + Expr *ExecConfig = 0) { return getSema().ActOnCallExpr(/*Scope=*/0, Callee, LParenLoc, - move(Args), CommaLocs, RParenLoc); + move(Args), RParenLoc, ExecConfig); } /// \brief Build a new member access expression. @@ -1137,26 +1355,32 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildMemberExpr(Expr *Base, SourceLocation OpLoc, - bool isArrow, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - const DeclarationNameInfo &MemberNameInfo, - ValueDecl *Member, - NamedDecl *FoundDecl, + bool isArrow, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + const DeclarationNameInfo &MemberNameInfo, + ValueDecl *Member, + NamedDecl *FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, - NamedDecl *FirstQualifierInScope) { + NamedDecl *FirstQualifierInScope) { if (!Member->getDeclName()) { - // We have a reference to an unnamed field. + // We have a reference to an unnamed field. This is always the + // base of an anonymous struct/union member access, i.e. the + // field is always of record type. assert(!Qualifier && "Can't have an unnamed field with a qualifier!"); + assert(Member->getType()->isRecordType() && + "unnamed member not of record type?"); if (getSema().PerformObjectMemberConversion(Base, Qualifier, FoundDecl, Member)) return ExprError(); + ExprValueKind VK = isArrow ? VK_LValue : Base->getValueKind(); MemberExpr *ME = new (getSema().Context) MemberExpr(Base, isArrow, Member, MemberNameInfo, - cast<FieldDecl>(Member)->getType()); + cast<FieldDecl>(Member)->getType(), + VK, OK_Ordinary); return getSema().Owned(ME); } @@ -1195,10 +1419,10 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildConditionalOperator(Expr *Cond, - SourceLocation QuestionLoc, - Expr *LHS, - SourceLocation ColonLoc, - Expr *RHS) { + SourceLocation QuestionLoc, + Expr *LHS, + SourceLocation ColonLoc, + Expr *RHS) { return getSema().ActOnConditionalOp(QuestionLoc, ColonLoc, Cond, LHS, RHS); } @@ -1322,9 +1546,8 @@ public: /// rather than attempting to map the label statement itself. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildAddrLabelExpr(SourceLocation AmpAmpLoc, - SourceLocation LabelLoc, - LabelStmt *Label) { - return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc, Label->getID()); + SourceLocation LabelLoc, LabelDecl *Label) { + return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc, Label); } /// \brief Build a new GNU statement expression. @@ -1337,19 +1560,6 @@ public: return getSema().ActOnStmtExpr(LParenLoc, 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. - ExprResult RebuildTypesCompatibleExpr(SourceLocation BuiltinLoc, - TypeSourceInfo *TInfo1, - TypeSourceInfo *TInfo2, - SourceLocation RParenLoc) { - return getSema().BuildTypesCompatibleExpr(BuiltinLoc, - TInfo1, TInfo2, - RParenLoc); - } - /// \brief Build a new __builtin_choose_expr expression. /// /// By default, performs semantic analysis to build the new expression. @@ -1492,16 +1702,12 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildCXXFunctionalCastExpr(SourceRange TypeRange, - TypeSourceInfo *TInfo, - SourceLocation LParenLoc, - Expr *Sub, - SourceLocation RParenLoc) { - return getSema().ActOnCXXTypeConstructExpr(TypeRange, - ParsedType::make(TInfo->getType()), - LParenLoc, + ExprResult RebuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, + SourceLocation LParenLoc, + Expr *Sub, + SourceLocation RParenLoc) { + return getSema().BuildCXXTypeConstructExpr(TInfo, LParenLoc, MultiExprArg(&Sub, 1), - /*CommaLocs=*/0, RParenLoc); } @@ -1517,6 +1723,7 @@ public: RParenLoc); } + /// \brief Build a new C++ typeid(expr) expression. /// /// By default, performs semantic analysis to build the new expression. @@ -1529,14 +1736,38 @@ public: RParenLoc); } + /// \brief Build a new C++ __uuidof(type) expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { + return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand, + RParenLoc); + } + + /// \brief Build a new C++ __uuidof(expr) expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *Operand, + SourceLocation RParenLoc) { + return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand, + RParenLoc); + } + /// \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. ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc, - QualType ThisType, - bool isImplicit) { + QualType ThisType, + bool isImplicit) { return getSema().Owned( new (getSema().Context) CXXThisExpr(ThisLoc, ThisType, isImplicit)); @@ -1565,14 +1796,12 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildCXXScalarValueInitExpr(SourceLocation TypeStartLoc, - SourceLocation LParenLoc, - QualType T, - SourceLocation RParenLoc) { - return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeStartLoc), - ParsedType::make(T), LParenLoc, + ExprResult RebuildCXXScalarValueInitExpr(TypeSourceInfo *TSInfo, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, MultiExprArg(getSema(), 0, 0), - 0, RParenLoc); + RParenLoc); } /// \brief Build a new C++ "new" expression. @@ -1580,26 +1809,24 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXNewExpr(SourceLocation StartLoc, - bool UseGlobal, - SourceLocation PlacementLParen, - MultiExprArg PlacementArgs, - SourceLocation PlacementRParen, - SourceRange TypeIdParens, - QualType AllocType, - SourceLocation TypeLoc, - SourceRange TypeRange, - Expr *ArraySize, - SourceLocation ConstructorLParen, - MultiExprArg ConstructorArgs, - SourceLocation ConstructorRParen) { + bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + SourceRange TypeIdParens, + QualType AllocatedType, + TypeSourceInfo *AllocatedTypeInfo, + Expr *ArraySize, + SourceLocation ConstructorLParen, + MultiExprArg ConstructorArgs, + SourceLocation ConstructorRParen) { return getSema().BuildCXXNew(StartLoc, UseGlobal, PlacementLParen, move(PlacementArgs), PlacementRParen, TypeIdParens, - AllocType, - TypeLoc, - TypeRange, + AllocatedType, + AllocatedTypeInfo, ArraySize, ConstructorLParen, move(ConstructorArgs), @@ -1623,12 +1850,22 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildUnaryTypeTrait(UnaryTypeTrait Trait, - SourceLocation StartLoc, - SourceLocation LParenLoc, - QualType T, - SourceLocation RParenLoc) { - return getSema().ActOnUnaryTypeTrait(Trait, StartLoc, LParenLoc, - ParsedType::make(T), RParenLoc); + SourceLocation StartLoc, + TypeSourceInfo *T, + SourceLocation RParenLoc) { + return getSema().BuildUnaryTypeTrait(Trait, StartLoc, T, RParenLoc); + } + + /// \brief Build a new binary type trait expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildBinaryTypeTrait(BinaryTypeTrait Trait, + SourceLocation StartLoc, + TypeSourceInfo *LhsT, + TypeSourceInfo *RhsT, + SourceLocation RParenLoc) { + return getSema().BuildBinaryTypeTrait(Trait, StartLoc, LhsT, RhsT, RParenLoc); } /// \brief Build a new (previously unresolved) declaration reference @@ -1672,7 +1909,8 @@ public: bool IsElidable, MultiExprArg Args, bool RequiresZeroInit, - CXXConstructExpr::ConstructionKind ConstructKind) { + CXXConstructExpr::ConstructionKind ConstructKind, + SourceRange ParenRange) { ASTOwningVector<Expr*> ConvertedArgs(SemaRef); if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc, ConvertedArgs)) @@ -1680,24 +1918,21 @@ public: return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable, move_arg(ConvertedArgs), - RequiresZeroInit, ConstructKind); + RequiresZeroInit, ConstructKind, + ParenRange); } /// \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. - ExprResult RebuildCXXTemporaryObjectExpr(SourceLocation TypeBeginLoc, - QualType T, - SourceLocation LParenLoc, - MultiExprArg Args, - SourceLocation *Commas, - SourceLocation RParenLoc) { - return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeBeginLoc), - ParsedType::make(T), + ExprResult RebuildCXXTemporaryObjectExpr(TypeSourceInfo *TSInfo, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc) { + return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, move(Args), - Commas, RParenLoc); } @@ -1705,18 +1940,13 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildCXXUnresolvedConstructExpr(SourceLocation TypeBeginLoc, - QualType T, - SourceLocation LParenLoc, - MultiExprArg Args, - SourceLocation *Commas, - SourceLocation RParenLoc) { - return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeBeginLoc, - /*FIXME*/LParenLoc), - ParsedType::make(T), + ExprResult RebuildCXXUnresolvedConstructExpr(TypeSourceInfo *TSInfo, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc) { + return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, move(Args), - Commas, RParenLoc); } @@ -1767,6 +1997,24 @@ public: R, TemplateArgs); } + /// \brief Build a new noexcept expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCXXNoexceptExpr(SourceRange Range, Expr *Arg) { + return SemaRef.BuildCXXNoexceptExpr(Range.getBegin(), Arg, Range.getEnd()); + } + + /// \brief Build a new expression to compute the length of a parameter pack. + ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack, + SourceLocation PackLoc, + SourceLocation RParenLoc, + unsigned Length) { + return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(), + OperatorLoc, Pack, PackLoc, + RParenLoc, Length); + } + /// \brief Build a new Objective-C @encode expression. /// /// By default, performs semantic analysis to build the new expression. @@ -1781,6 +2029,7 @@ public: /// \brief Build a new Objective-C class message. ExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo, Selector Sel, + SourceLocation SelectorLoc, ObjCMethodDecl *Method, SourceLocation LBracLoc, MultiExprArg Args, @@ -1788,13 +2037,14 @@ public: return SemaRef.BuildClassMessage(ReceiverTypeInfo, ReceiverTypeInfo->getType(), /*SuperLoc=*/SourceLocation(), - Sel, Method, LBracLoc, RBracLoc, - move(Args)); + Sel, Method, LBracLoc, SelectorLoc, + RBracLoc, move(Args)); } /// \brief Build a new Objective-C instance message. ExprResult RebuildObjCMessageExpr(Expr *Receiver, Selector Sel, + SourceLocation SelectorLoc, ObjCMethodDecl *Method, SourceLocation LBracLoc, MultiExprArg Args, @@ -1802,8 +2052,8 @@ public: return SemaRef.BuildInstanceMessage(Receiver, Receiver->getType(), /*SuperLoc=*/SourceLocation(), - Sel, Method, LBracLoc, RBracLoc, - move(Args)); + Sel, Method, LBracLoc, SelectorLoc, + RBracLoc, move(Args)); } /// \brief Build a new Objective-C ivar reference expression. @@ -1864,24 +2114,20 @@ public: /*TemplateArgs=*/0); } - /// \brief Build a new Objective-C implicit setter/getter reference - /// expression. + /// \brief Build a new Objective-C property reference expression. /// /// By default, performs semantic analysis to build the new expression. - /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildObjCImplicitSetterGetterRefExpr( - ObjCMethodDecl *Getter, - QualType T, - ObjCMethodDecl *Setter, - SourceLocation NameLoc, - Expr *Base) { - // Since these expressions can only be value-dependent, we do not need to - // perform semantic analysis again. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildObjCPropertyRefExpr(Expr *Base, QualType T, + ObjCMethodDecl *Getter, + ObjCMethodDecl *Setter, + SourceLocation PropertyLoc) { + // Since these expressions can only be value-dependent, we do not + // need to perform semantic analysis again. return Owned( - new (getSema().Context) ObjCImplicitSetterGetterRefExpr(Getter, T, - Setter, - NameLoc, - Base)); + new (getSema().Context) ObjCPropertyRefExpr(Getter, Setter, T, + VK_LValue, OK_ObjCProperty, + PropertyLoc, Base)); } /// \brief Build a new Objective-C "isa" expression. @@ -1915,8 +2161,8 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildShuffleVectorExpr(SourceLocation BuiltinLoc, - MultiExprArg SubExprs, - SourceLocation RParenLoc) { + MultiExprArg SubExprs, + SourceLocation RParenLoc) { // Find the declaration for __builtin_shufflevector const IdentifierInfo &Name = SemaRef.Context.Idents.get("__builtin_shufflevector"); @@ -1928,7 +2174,7 @@ public: FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first); Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(), - BuiltinLoc); + VK_LValue, BuiltinLoc); SemaRef.UsualUnaryConversions(Callee); // Build the CallExpr @@ -1937,6 +2183,7 @@ public: CallExpr *TheCall = new (SemaRef.Context) CallExpr(SemaRef.Context, Callee, Subs, NumSubExprs, Builtin->getCallResultType(), + Expr::getValueKindForType(Builtin->getResultType()), RParenLoc); ExprResult OwnedCall(SemaRef.Owned(TheCall)); @@ -1948,6 +2195,74 @@ public: OwnedCall.release(); return move(Result); } + + /// \brief Build a new template argument pack expansion. + /// + /// By default, performs semantic analysis to build a new pack expansion + /// for a template argument. Subclasses may override this routine to provide + /// different behavior. + TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern, + SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions) { + switch (Pattern.getArgument().getKind()) { + case TemplateArgument::Expression: { + ExprResult Result + = getSema().CheckPackExpansion(Pattern.getSourceExpression(), + EllipsisLoc, NumExpansions); + if (Result.isInvalid()) + return TemplateArgumentLoc(); + + return TemplateArgumentLoc(Result.get(), Result.get()); + } + + case TemplateArgument::Template: + return TemplateArgumentLoc(TemplateArgument( + Pattern.getArgument().getAsTemplate(), + NumExpansions), + Pattern.getTemplateQualifierRange(), + Pattern.getTemplateNameLoc(), + EllipsisLoc); + + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Declaration: + case TemplateArgument::Pack: + case TemplateArgument::TemplateExpansion: + llvm_unreachable("Pack expansion pattern has no parameter packs"); + + case TemplateArgument::Type: + if (TypeSourceInfo *Expansion + = getSema().CheckPackExpansion(Pattern.getTypeSourceInfo(), + EllipsisLoc, + NumExpansions)) + return TemplateArgumentLoc(TemplateArgument(Expansion->getType()), + Expansion); + break; + } + + return TemplateArgumentLoc(); + } + + /// \brief Build a new expression pack expansion. + /// + /// By default, performs semantic analysis to build a new pack expansion + /// for an expression. Subclasses may override this routine to provide + /// different behavior. + ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions) { + return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions); + } + +private: + QualType TransformTypeInObjectScope(QualType T, + QualType ObjectType, + NamedDecl *FirstQualifierInScope, + NestedNameSpecifier *Prefix); + + TypeSourceInfo *TransformTypeInObjectScope(TypeSourceInfo *T, + QualType ObjectType, + NamedDecl *FirstQualifierInScope, + NestedNameSpecifier *Prefix); }; template<typename Derived> @@ -1961,6 +2276,7 @@ StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) { // Transform individual statement nodes #define STMT(Node, Parent) \ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S)); +#define ABSTRACT_STMT(Node) #define EXPR(Node, Parent) #include "clang/AST/StmtNodes.inc" @@ -1978,7 +2294,7 @@ StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) { } } - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); } @@ -1996,7 +2312,101 @@ ExprResult TreeTransform<Derived>::TransformExpr(Expr *E) { #include "clang/AST/StmtNodes.inc" } - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); +} + +template<typename Derived> +bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, + unsigned NumInputs, + bool IsCall, + llvm::SmallVectorImpl<Expr *> &Outputs, + bool *ArgChanged) { + for (unsigned I = 0; I != NumInputs; ++I) { + // If requested, drop call arguments that need to be dropped. + if (IsCall && getDerived().DropCallArgument(Inputs[I])) { + if (ArgChanged) + *ArgChanged = true; + + break; + } + + if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(Inputs[I])) { + Expr *Pattern = Expansion->getPattern(); + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + llvm::Optional<unsigned> OrigNumExpansions + = Expansion->getNumExpansions(); + llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; + if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(), + Pattern->getSourceRange(), + Unexpanded.data(), + Unexpanded.size(), + Expand, RetainExpansion, + NumExpansions)) + return true; + + if (!Expand) { + // The transform has determined that we should perform a simple + // transformation on the pack expansion, producing another pack + // expansion. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + ExprResult OutPattern = getDerived().TransformExpr(Pattern); + if (OutPattern.isInvalid()) + return true; + + ExprResult Out = getDerived().RebuildPackExpansion(OutPattern.get(), + Expansion->getEllipsisLoc(), + NumExpansions); + if (Out.isInvalid()) + return true; + + if (ArgChanged) + *ArgChanged = true; + Outputs.push_back(Out.get()); + continue; + } + + // The transform has determined that we should perform an elementwise + // expansion of the pattern. Do so. + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); + ExprResult Out = getDerived().TransformExpr(Pattern); + if (Out.isInvalid()) + return true; + + if (Out.get()->containsUnexpandedParameterPack()) { + Out = RebuildPackExpansion(Out.get(), Expansion->getEllipsisLoc(), + OrigNumExpansions); + if (Out.isInvalid()) + return true; + } + + if (ArgChanged) + *ArgChanged = true; + Outputs.push_back(Out.get()); + } + + continue; + } + + ExprResult Result = getDerived().TransformExpr(Inputs[I]); + if (Result.isInvalid()) + return true; + + if (Result.get() != Inputs[I] && ArgChanged) + *ArgChanged = true; + + Outputs.push_back(Result.get()); + } + + return false; } template<typename Derived> @@ -2005,26 +2415,26 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range, QualType ObjectType, NamedDecl *FirstQualifierInScope) { - if (!NNS) - return 0; + NestedNameSpecifier *Prefix = NNS->getPrefix(); // 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: + if (Prefix) { + // The object type and qualifier-in-scope really apply to the + // leftmost entity. + ObjectType = QualType(); + FirstQualifierInScope = 0; + } + assert((Prefix || !ObjectType.isNull()) && "Identifier nested-name-specifier with no prefix or object type"); if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() && @@ -2057,8 +2467,10 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { TemporaryBase Rebase(*this, Range.getBegin(), DeclarationName()); - QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0), - ObjectType); + QualType T = TransformTypeInObjectScope(QualType(NNS->getAsType(), 0), + ObjectType, + FirstQualifierInScope, + Prefix); if (T.isNull()) return 0; @@ -2080,8 +2492,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, template<typename Derived> DeclarationNameInfo TreeTransform<Derived> -::TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo, - QualType ObjectType) { +::TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo) { DeclarationName Name = NameInfo.getName(); if (!Name) return DeclarationNameInfo(); @@ -2102,16 +2513,15 @@ TreeTransform<Derived> TypeSourceInfo *NewTInfo; CanQualType NewCanTy; if (TypeSourceInfo *OldTInfo = NameInfo.getNamedTypeInfo()) { - NewTInfo = getDerived().TransformType(OldTInfo, ObjectType); - if (!NewTInfo) - return DeclarationNameInfo(); - NewCanTy = SemaRef.Context.getCanonicalType(NewTInfo->getType()); + NewTInfo = getDerived().TransformType(OldTInfo); + if (!NewTInfo) + return DeclarationNameInfo(); + NewCanTy = SemaRef.Context.getCanonicalType(NewTInfo->getType()); } else { NewTInfo = 0; TemporaryBase Rebase(*this, NameInfo.getLoc(), Name); - QualType NewT = getDerived().TransformType(Name.getCXXNameType(), - ObjectType); + QualType NewT = getDerived().TransformType(Name.getCXXNameType()); if (NewT.isNull()) return DeclarationNameInfo(); NewCanTy = SemaRef.Context.getCanonicalType(NewT); @@ -2134,14 +2544,16 @@ TreeTransform<Derived> template<typename Derived> TemplateName TreeTransform<Derived>::TransformTemplateName(TemplateName Name, - QualType ObjectType) { + QualType ObjectType, + NamedDecl *FirstQualifierInScope) { SourceLocation Loc = getDerived().getBaseLocation(); if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(), - /*FIXME:*/SourceRange(getDerived().getBaseLocation()), - ObjectType); + /*FIXME*/ SourceRange(Loc), + ObjectType, + FirstQualifierInScope); if (!NNS) return TemplateName(); @@ -2161,25 +2573,36 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, } // These should be getting filtered out before they make it into the AST. - assert(false && "overloaded template name survived to here"); + llvm_unreachable("overloaded template name survived to here"); } if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { - NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(DTN->getQualifier(), - /*FIXME:*/SourceRange(getDerived().getBaseLocation()), - ObjectType); - if (!NNS && DTN->getQualifier()) - return TemplateName(); + NestedNameSpecifier *NNS = DTN->getQualifier(); + if (NNS) { + NNS = getDerived().TransformNestedNameSpecifier(NNS, + /*FIXME:*/SourceRange(Loc), + ObjectType, + FirstQualifierInScope); + if (!NNS) return TemplateName(); + + // These apply to the scope specifier, not the template. + ObjectType = QualType(); + FirstQualifierInScope = 0; + } if (!getDerived().AlwaysRebuild() && NNS == DTN->getQualifier() && ObjectType.isNull()) return Name; - if (DTN->isIdentifier()) - return getDerived().RebuildTemplateName(NNS, *DTN->getIdentifier(), - ObjectType); + if (DTN->isIdentifier()) { + // FIXME: Bad range + SourceRange QualifierRange(getDerived().getBaseLocation()); + return getDerived().RebuildTemplateName(NNS, QualifierRange, + *DTN->getIdentifier(), + ObjectType, + FirstQualifierInScope); + } return getDerived().RebuildTemplateName(NNS, DTN->getOperator(), ObjectType); @@ -2198,8 +2621,24 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, return TemplateName(TransTemplate); } + if (SubstTemplateTemplateParmPackStorage *SubstPack + = Name.getAsSubstTemplateTemplateParmPack()) { + TemplateTemplateParmDecl *TransParam + = cast_or_null<TemplateTemplateParmDecl>( + getDerived().TransformDecl(Loc, SubstPack->getParameterPack())); + if (!TransParam) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + TransParam == SubstPack->getParameterPack()) + return Name; + + return getDerived().RebuildTemplateName(TransParam, + SubstPack->getArgumentPack()); + } + // These should be getting filtered out before they reach the AST. - assert(false && "overloaded function decl survived to here"); + llvm_unreachable("overloaded function decl survived to here"); return TemplateName(); } @@ -2222,7 +2661,11 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc( case TemplateArgument::Template: Output = TemplateArgumentLoc(Arg, SourceRange(), Loc); break; - + + case TemplateArgument::TemplateExpansion: + Output = TemplateArgumentLoc(Arg, SourceRange(), Loc, Loc); + break; + case TemplateArgument::Expression: Output = TemplateArgumentLoc(Arg, Arg.getAsExpr()); break; @@ -2291,7 +2734,10 @@ bool TreeTransform<Derived>::TransformTemplateArgument( Input.getTemplateNameLoc()); return false; } - + + case TemplateArgument::TemplateExpansion: + llvm_unreachable("Caller should expand pack expansions"); + case TemplateArgument::Expression: { // Template argument expressions are not potentially evaluated. EnterExpressionEvaluationContext Unevaluated(getSema(), @@ -2325,10 +2771,14 @@ bool TreeTransform<Derived>::TransformTemplateArgument( TransformedArgs.push_back(OutputArg.getArgument()); } - TemplateArgument Result; - Result.setArgumentPack(TransformedArgs.data(), TransformedArgs.size(), - true); - Output = TemplateArgumentLoc(Result, Input.getLocInfo()); + + TemplateArgument *TransformedArgsPtr + = new (getSema().Context) TemplateArgument[TransformedArgs.size()]; + std::copy(TransformedArgs.begin(), TransformedArgs.end(), + TransformedArgsPtr); + Output = TemplateArgumentLoc(TemplateArgument(TransformedArgsPtr, + TransformedArgs.size()), + Input.getLocInfo()); return false; } } @@ -2337,22 +2787,201 @@ bool TreeTransform<Derived>::TransformTemplateArgument( return true; } +/// \brief Iterator adaptor that invents template argument location information +/// for each of the template arguments in its underlying iterator. +template<typename Derived, typename InputIterator> +class TemplateArgumentLocInventIterator { + TreeTransform<Derived> &Self; + InputIterator Iter; + +public: + typedef TemplateArgumentLoc value_type; + typedef TemplateArgumentLoc reference; + typedef typename std::iterator_traits<InputIterator>::difference_type + difference_type; + typedef std::input_iterator_tag iterator_category; + + class pointer { + TemplateArgumentLoc Arg; + + public: + explicit pointer(TemplateArgumentLoc Arg) : Arg(Arg) { } + + const TemplateArgumentLoc *operator->() const { return &Arg; } + }; + + TemplateArgumentLocInventIterator() { } + + explicit TemplateArgumentLocInventIterator(TreeTransform<Derived> &Self, + InputIterator Iter) + : Self(Self), Iter(Iter) { } + + TemplateArgumentLocInventIterator &operator++() { + ++Iter; + return *this; + } + + TemplateArgumentLocInventIterator operator++(int) { + TemplateArgumentLocInventIterator Old(*this); + ++(*this); + return Old; + } + + reference operator*() const { + TemplateArgumentLoc Result; + Self.InventTemplateArgumentLoc(*Iter, Result); + return Result; + } + + pointer operator->() const { return pointer(**this); } + + friend bool operator==(const TemplateArgumentLocInventIterator &X, + const TemplateArgumentLocInventIterator &Y) { + return X.Iter == Y.Iter; + } + + friend bool operator!=(const TemplateArgumentLocInventIterator &X, + const TemplateArgumentLocInventIterator &Y) { + return X.Iter != Y.Iter; + } +}; + +template<typename Derived> +template<typename InputIterator> +bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First, + InputIterator Last, + TemplateArgumentListInfo &Outputs) { + for (; First != Last; ++First) { + TemplateArgumentLoc Out; + TemplateArgumentLoc In = *First; + + if (In.getArgument().getKind() == TemplateArgument::Pack) { + // Unpack argument packs, which we translate them into separate + // arguments. + // FIXME: We could do much better if we could guarantee that the + // TemplateArgumentLocInfo for the pack expansion would be usable for + // all of the template arguments in the argument pack. + typedef TemplateArgumentLocInventIterator<Derived, + TemplateArgument::pack_iterator> + PackLocIterator; + if (TransformTemplateArguments(PackLocIterator(*this, + In.getArgument().pack_begin()), + PackLocIterator(*this, + In.getArgument().pack_end()), + Outputs)) + return true; + + continue; + } + + if (In.getArgument().isPackExpansion()) { + // We have a pack expansion, for which we will be substituting into + // the pattern. + SourceLocation Ellipsis; + llvm::Optional<unsigned> OrigNumExpansions; + TemplateArgumentLoc Pattern + = In.getPackExpansionPattern(Ellipsis, OrigNumExpansions, + getSema().Context); + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; + if (getDerived().TryExpandParameterPacks(Ellipsis, + Pattern.getSourceRange(), + Unexpanded.data(), + Unexpanded.size(), + Expand, + RetainExpansion, + NumExpansions)) + return true; + + if (!Expand) { + // The transform has determined that we should perform a simple + // transformation on the pack expansion, producing another pack + // expansion. + TemplateArgumentLoc OutPattern; + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + if (getDerived().TransformTemplateArgument(Pattern, OutPattern)) + return true; + + Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis, + NumExpansions); + if (Out.getArgument().isNull()) + return true; + + Outputs.addArgument(Out); + continue; + } + + // The transform has determined that we should perform an elementwise + // expansion of the pattern. Do so. + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); + + if (getDerived().TransformTemplateArgument(Pattern, Out)) + return true; + + if (Out.getArgument().containsUnexpandedParameterPack()) { + Out = getDerived().RebuildPackExpansion(Out, Ellipsis, + OrigNumExpansions); + if (Out.getArgument().isNull()) + return true; + } + + Outputs.addArgument(Out); + } + + // If we're supposed to retain a pack expansion, do so by temporarily + // forgetting the partially-substituted parameter pack. + if (RetainExpansion) { + ForgetPartiallySubstitutedPackRAII Forget(getDerived()); + + if (getDerived().TransformTemplateArgument(Pattern, Out)) + return true; + + Out = getDerived().RebuildPackExpansion(Out, Ellipsis, + OrigNumExpansions); + if (Out.getArgument().isNull()) + return true; + + Outputs.addArgument(Out); + } + + continue; + } + + // The simple case: + if (getDerived().TransformTemplateArgument(In, Out)) + return true; + + Outputs.addArgument(Out); + } + + return false; + +} + //===----------------------------------------------------------------------===// // Type transformation //===----------------------------------------------------------------------===// template<typename Derived> -QualType TreeTransform<Derived>::TransformType(QualType T, - QualType ObjectType) { +QualType TreeTransform<Derived>::TransformType(QualType T) { if (getDerived().AlreadyTransformed(T)) return T; // Temporary workaround. All of these transformations should // eventually turn into transformations on TypeLocs. - TypeSourceInfo *DI = getSema().Context.CreateTypeSourceInfo(T); - DI->getTypeLoc().initialize(getDerived().getBaseLocation()); + TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo(T, + getDerived().getBaseLocation()); - TypeSourceInfo *NewDI = getDerived().TransformType(DI, ObjectType); + TypeSourceInfo *NewDI = getDerived().TransformType(DI); if (!NewDI) return QualType(); @@ -2361,8 +2990,7 @@ QualType TreeTransform<Derived>::TransformType(QualType T, } template<typename Derived> -TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI, - QualType ObjectType) { +TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) { if (getDerived().AlreadyTransformed(DI->getType())) return DI; @@ -2371,7 +2999,7 @@ TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI, TypeLoc TL = DI->getTypeLoc(); TLB.reserve(TL.getFullDataSize()); - QualType Result = getDerived().TransformType(TLB, TL, ObjectType); + QualType Result = getDerived().TransformType(TLB, TL); if (Result.isNull()) return 0; @@ -2380,14 +3008,12 @@ TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI, template<typename Derived> QualType -TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T, - QualType ObjectType) { +TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) { switch (T.getTypeLocClass()) { #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ case TypeLoc::CLASS: \ - return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T), \ - ObjectType); + return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T)); #include "clang/AST/TypeLocNodes.def" } @@ -2403,12 +3029,10 @@ TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T, template<typename Derived> QualType TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, - QualifiedTypeLoc T, - QualType ObjectType) { + QualifiedTypeLoc T) { Qualifiers Quals = T.getType().getLocalQualifiers(); - QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc(), - ObjectType); + QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc()); if (Result.isNull()) return QualType(); @@ -2427,6 +3051,77 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, return Result; } +/// \brief Transforms a type that was written in a scope specifier, +/// given an object type, the results of unqualified lookup, and +/// an already-instantiated prefix. +/// +/// The object type is provided iff the scope specifier qualifies the +/// member of a dependent member-access expression. The prefix is +/// provided iff the the scope specifier in which this appears has a +/// prefix. +/// +/// This is private to TreeTransform. +template<typename Derived> +QualType +TreeTransform<Derived>::TransformTypeInObjectScope(QualType T, + QualType ObjectType, + NamedDecl *UnqualLookup, + NestedNameSpecifier *Prefix) { + if (getDerived().AlreadyTransformed(T)) + return T; + + TypeSourceInfo *TSI = + SemaRef.Context.getTrivialTypeSourceInfo(T, getDerived().getBaseLocation()); + + TSI = getDerived().TransformTypeInObjectScope(TSI, ObjectType, + UnqualLookup, Prefix); + if (!TSI) return QualType(); + return TSI->getType(); +} + +template<typename Derived> +TypeSourceInfo * +TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSI, + QualType ObjectType, + NamedDecl *UnqualLookup, + NestedNameSpecifier *Prefix) { + // TODO: in some cases, we might be some verification to do here. + if (ObjectType.isNull()) + return getDerived().TransformType(TSI); + + QualType T = TSI->getType(); + if (getDerived().AlreadyTransformed(T)) + return TSI; + + TypeLocBuilder TLB; + QualType Result; + + if (isa<TemplateSpecializationType>(T)) { + TemplateSpecializationTypeLoc TL + = cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc()); + + TemplateName Template = + getDerived().TransformTemplateName(TL.getTypePtr()->getTemplateName(), + ObjectType, UnqualLookup); + if (Template.isNull()) return 0; + + Result = getDerived() + .TransformTemplateSpecializationType(TLB, TL, Template); + } else if (isa<DependentTemplateSpecializationType>(T)) { + DependentTemplateSpecializationTypeLoc TL + = cast<DependentTemplateSpecializationTypeLoc>(TSI->getTypeLoc()); + + Result = getDerived() + .TransformDependentTemplateSpecializationType(TLB, TL, Prefix); + } else { + // Nothing special needs to be done for these. + Result = getDerived().TransformType(TLB, TSI->getTypeLoc()); + } + + if (Result.isNull()) return 0; + return TLB.getTypeSourceInfo(SemaRef.Context, Result); +} + template <class TyLoc> static inline QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { TyLoc NewT = TLB.push<TyLoc>(T.getType()); @@ -2436,8 +3131,7 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { template<typename Derived> QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, - BuiltinTypeLoc T, - QualType ObjectType) { + BuiltinTypeLoc T) { BuiltinTypeLoc NewT = TLB.push<BuiltinTypeLoc>(T.getType()); NewT.setBuiltinLoc(T.getBuiltinLoc()); if (T.needsExtraLocalData()) @@ -2447,16 +3141,14 @@ QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB, - ComplexTypeLoc T, - QualType ObjectType) { + ComplexTypeLoc T) { // FIXME: recurse? return TransformTypeSpecType(TLB, T); } template<typename Derived> QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, - PointerTypeLoc TL, - QualType ObjectType) { + PointerTypeLoc TL) { QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); if (PointeeType.isNull()) @@ -2474,7 +3166,7 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, NewT.setStarLoc(TL.getStarLoc()); return Result; } - + if (getDerived().AlwaysRebuild() || PointeeType != TL.getPointeeLoc().getType()) { Result = getDerived().RebuildPointerType(PointeeType, TL.getSigilLoc()); @@ -2490,8 +3182,7 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, - BlockPointerTypeLoc TL, - QualType ObjectType) { + BlockPointerTypeLoc TL) { QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); if (PointeeType.isNull()) @@ -2518,8 +3209,7 @@ TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB, - ReferenceTypeLoc TL, - QualType ObjectType) { + ReferenceTypeLoc TL) { const ReferenceType *T = TL.getTypePtr(); // Note that this works with the pointee-as-written. @@ -2551,25 +3241,22 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformLValueReferenceType(TypeLocBuilder &TLB, - LValueReferenceTypeLoc TL, - QualType ObjectType) { - return TransformReferenceType(TLB, TL, ObjectType); + LValueReferenceTypeLoc TL) { + return TransformReferenceType(TLB, TL); } template<typename Derived> QualType TreeTransform<Derived>::TransformRValueReferenceType(TypeLocBuilder &TLB, - RValueReferenceTypeLoc TL, - QualType ObjectType) { - return TransformReferenceType(TLB, TL, ObjectType); + RValueReferenceTypeLoc TL) { + return TransformReferenceType(TLB, TL); } template<typename Derived> QualType TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB, - MemberPointerTypeLoc TL, - QualType ObjectType) { - MemberPointerType *T = TL.getTypePtr(); + MemberPointerTypeLoc TL) { + const MemberPointerType *T = TL.getTypePtr(); QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); if (PointeeType.isNull()) @@ -2600,9 +3287,8 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB, - ConstantArrayTypeLoc TL, - QualType ObjectType) { - ConstantArrayType *T = TL.getTypePtr(); + ConstantArrayTypeLoc TL) { + const ConstantArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); @@ -2636,9 +3322,8 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformIncompleteArrayType( TypeLocBuilder &TLB, - IncompleteArrayTypeLoc TL, - QualType ObjectType) { - IncompleteArrayType *T = TL.getTypePtr(); + IncompleteArrayTypeLoc TL) { + const IncompleteArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); @@ -2665,9 +3350,8 @@ QualType TreeTransform<Derived>::TransformIncompleteArrayType( template<typename Derived> QualType TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB, - VariableArrayTypeLoc TL, - QualType ObjectType) { - VariableArrayType *T = TL.getTypePtr(); + VariableArrayTypeLoc TL) { + const VariableArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); @@ -2706,9 +3390,8 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, - DependentSizedArrayTypeLoc TL, - QualType ObjectType) { - DependentSizedArrayType *T = TL.getTypePtr(); + DependentSizedArrayTypeLoc TL) { + const DependentSizedArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); @@ -2716,33 +3399,36 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, // Array bounds are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); - ExprResult SizeResult - = getDerived().TransformExpr(T->getSizeExpr()); - if (SizeResult.isInvalid()) + // Prefer the expression from the TypeLoc; the other may have been uniqued. + Expr *origSize = TL.getSizeExpr(); + if (!origSize) origSize = T->getSizeExpr(); + + ExprResult sizeResult + = getDerived().TransformExpr(origSize); + if (sizeResult.isInvalid()) return QualType(); - Expr *Size = static_cast<Expr*>(SizeResult.get()); + Expr *size = sizeResult.get(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || - Size != T->getSizeExpr()) { + size != origSize) { Result = getDerived().RebuildDependentSizedArrayType(ElementType, T->getSizeModifier(), - Size, + size, T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); if (Result.isNull()) return QualType(); } - else SizeResult.take(); // We might have any sort of array type now, but fortunately they // all have the same location layout. ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result); NewTL.setLBracketLoc(TL.getLBracketLoc()); NewTL.setRBracketLoc(TL.getRBracketLoc()); - NewTL.setSizeExpr(Size); + NewTL.setSizeExpr(size); return Result; } @@ -2750,9 +3436,8 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( TypeLocBuilder &TLB, - DependentSizedExtVectorTypeLoc TL, - QualType ObjectType) { - DependentSizedExtVectorType *T = TL.getTypePtr(); + DependentSizedExtVectorTypeLoc TL) { + const DependentSizedExtVectorType *T = TL.getTypePtr(); // FIXME: ext vector locs should be nested QualType ElementType = getDerived().TransformType(T->getElementType()); @@ -2792,9 +3477,8 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( template<typename Derived> QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB, - VectorTypeLoc TL, - QualType ObjectType) { - VectorType *T = TL.getTypePtr(); + VectorTypeLoc TL) { + const VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); @@ -2803,7 +3487,7 @@ QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB, if (getDerived().AlwaysRebuild() || ElementType != T->getElementType()) { Result = getDerived().RebuildVectorType(ElementType, T->getNumElements(), - T->getAltiVecSpecific()); + T->getVectorKind()); if (Result.isNull()) return QualType(); } @@ -2816,9 +3500,8 @@ QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB, - ExtVectorTypeLoc TL, - QualType ObjectType) { - VectorType *T = TL.getTypePtr(); + ExtVectorTypeLoc TL) { + const VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); @@ -2841,9 +3524,38 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB, template<typename Derived> ParmVarDecl * -TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm) { +TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm, + llvm::Optional<unsigned> NumExpansions) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); - TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); + TypeSourceInfo *NewDI = 0; + + if (NumExpansions && isa<PackExpansionType>(OldDI->getType())) { + // If we're substituting into a pack expansion type and we know the + TypeLoc OldTL = OldDI->getTypeLoc(); + PackExpansionTypeLoc OldExpansionTL = cast<PackExpansionTypeLoc>(OldTL); + + TypeLocBuilder TLB; + TypeLoc NewTL = OldDI->getTypeLoc(); + TLB.reserve(NewTL.getFullDataSize()); + + QualType Result = getDerived().TransformType(TLB, + OldExpansionTL.getPatternLoc()); + if (Result.isNull()) + return 0; + + Result = RebuildPackExpansionType(Result, + OldExpansionTL.getPatternLoc().getSourceRange(), + OldExpansionTL.getEllipsisLoc(), + NumExpansions); + if (Result.isNull()) + return 0; + + PackExpansionTypeLoc NewExpansionTL + = TLB.push<PackExpansionTypeLoc>(Result); + NewExpansionTL.setEllipsisLoc(OldExpansionTL.getEllipsisLoc()); + NewDI = TLB.getTypeSourceInfo(SemaRef.Context, Result); + } else + NewDI = getDerived().TransformType(OldDI); if (!NewDI) return 0; @@ -2863,75 +3575,226 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm) { template<typename Derived> bool TreeTransform<Derived>:: - TransformFunctionTypeParams(FunctionProtoTypeLoc TL, - llvm::SmallVectorImpl<QualType> &PTypes, - llvm::SmallVectorImpl<ParmVarDecl*> &PVars) { - FunctionProtoType *T = TL.getTypePtr(); - - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { - ParmVarDecl *OldParm = TL.getArg(i); - - QualType NewType; - ParmVarDecl *NewParm; - - if (OldParm) { - NewParm = getDerived().TransformFunctionTypeParam(OldParm); + TransformFunctionTypeParams(SourceLocation Loc, + ParmVarDecl **Params, unsigned NumParams, + const QualType *ParamTypes, + llvm::SmallVectorImpl<QualType> &OutParamTypes, + llvm::SmallVectorImpl<ParmVarDecl*> *PVars) { + for (unsigned i = 0; i != NumParams; ++i) { + if (ParmVarDecl *OldParm = Params[i]) { + llvm::Optional<unsigned> NumExpansions; + if (OldParm->isParameterPack()) { + // We have a function parameter pack that may need to be expanded. + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + + // Find the parameter packs that could be expanded. + TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc(); + PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(TL); + TypeLoc Pattern = ExpansionTL.getPatternLoc(); + SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); + + // Determine whether we should expand the parameter packs. + bool ShouldExpand = false; + bool RetainExpansion = false; + llvm::Optional<unsigned> OrigNumExpansions + = ExpansionTL.getTypePtr()->getNumExpansions(); + NumExpansions = OrigNumExpansions; + if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), + Pattern.getSourceRange(), + Unexpanded.data(), + Unexpanded.size(), + ShouldExpand, + RetainExpansion, + NumExpansions)) { + return true; + } + + if (ShouldExpand) { + // Expand the function parameter pack into multiple, separate + // parameters. + getDerived().ExpandingFunctionParameterPack(OldParm); + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); + ParmVarDecl *NewParm + = getDerived().TransformFunctionTypeParam(OldParm, + OrigNumExpansions); + if (!NewParm) + return true; + + OutParamTypes.push_back(NewParm->getType()); + if (PVars) + PVars->push_back(NewParm); + } + + // If we're supposed to retain a pack expansion, do so by temporarily + // forgetting the partially-substituted parameter pack. + if (RetainExpansion) { + ForgetPartiallySubstitutedPackRAII Forget(getDerived()); + ParmVarDecl *NewParm + = getDerived().TransformFunctionTypeParam(OldParm, + OrigNumExpansions); + if (!NewParm) + return true; + + OutParamTypes.push_back(NewParm->getType()); + if (PVars) + PVars->push_back(NewParm); + } + + // We're done with the pack expansion. + continue; + } + + // We'll substitute the parameter now without expanding the pack + // expansion. + } + + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm, + NumExpansions); if (!NewParm) return true; - NewType = NewParm->getType(); + + OutParamTypes.push_back(NewParm->getType()); + if (PVars) + PVars->push_back(NewParm); + continue; + } // Deal with the possibility that we don't have a parameter // declaration for this parameter. - } else { - NewParm = 0; - - QualType OldType = T->getArgType(i); - NewType = getDerived().TransformType(OldType); - if (NewType.isNull()) + QualType OldType = ParamTypes[i]; + bool IsPackExpansion = false; + llvm::Optional<unsigned> NumExpansions; + if (const PackExpansionType *Expansion + = dyn_cast<PackExpansionType>(OldType)) { + // We have a function parameter pack that may need to be expanded. + QualType Pattern = Expansion->getPattern(); + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); + + // Determine whether we should expand the parameter packs. + bool ShouldExpand = false; + bool RetainExpansion = false; + if (getDerived().TryExpandParameterPacks(Loc, SourceRange(), + Unexpanded.data(), + Unexpanded.size(), + ShouldExpand, + RetainExpansion, + NumExpansions)) { return true; + } + + if (ShouldExpand) { + // Expand the function parameter pack into multiple, separate + // parameters. + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); + QualType NewType = getDerived().TransformType(Pattern); + if (NewType.isNull()) + return true; + + OutParamTypes.push_back(NewType); + if (PVars) + PVars->push_back(0); + } + + // We're done with the pack expansion. + continue; + } + + // If we're supposed to retain a pack expansion, do so by temporarily + // forgetting the partially-substituted parameter pack. + if (RetainExpansion) { + ForgetPartiallySubstitutedPackRAII Forget(getDerived()); + QualType NewType = getDerived().TransformType(Pattern); + if (NewType.isNull()) + return true; + + OutParamTypes.push_back(NewType); + if (PVars) + PVars->push_back(0); + } + + // We'll substitute the parameter now without expanding the pack + // expansion. + OldType = Expansion->getPattern(); + IsPackExpansion = true; } + + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + QualType NewType = getDerived().TransformType(OldType); + if (NewType.isNull()) + return true; - PTypes.push_back(NewType); - PVars.push_back(NewParm); + if (IsPackExpansion) + NewType = getSema().Context.getPackExpansionType(NewType, + NumExpansions); + + OutParamTypes.push_back(NewType); + if (PVars) + PVars->push_back(0); } return false; -} + } template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL, - QualType ObjectType) { + FunctionProtoTypeLoc TL) { // Transform the parameters and return type. // // We instantiate in source order, with the return type first followed by // the parameters, because users tend to expect this (even if they shouldn't // rely on it!). // - // FIXME: When we implement late-specified return types, we'll need to - // instantiate the return tpe *after* the parameter types in that case, - // since the return type can then refer to the parameters themselves (via - // decltype, sizeof, etc.). + // When the function has a trailing return type, we instantiate the + // parameters before the return type, since the return type can then refer + // to the parameters themselves (via decltype, sizeof, etc.). + // llvm::SmallVector<QualType, 4> ParamTypes; llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; - FunctionProtoType *T = TL.getTypePtr(); - QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); - if (ResultType.isNull()) - return QualType(); + const FunctionProtoType *T = TL.getTypePtr(); + + QualType ResultType; + + if (TL.getTrailingReturn()) { + if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(), + TL.getParmArray(), + TL.getNumArgs(), + TL.getTypePtr()->arg_type_begin(), + ParamTypes, &ParamDecls)) + return QualType(); + + ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + } + else { + ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + + if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(), + TL.getParmArray(), + TL.getNumArgs(), + TL.getTypePtr()->arg_type_begin(), + ParamTypes, &ParamDecls)) + return QualType(); + } - if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) - return QualType(); - QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getResultType() || + T->getNumArgs() != ParamTypes.size() || !std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) { Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes.data(), ParamTypes.size(), T->isVariadic(), T->getTypeQuals(), + T->getRefQualifier(), T->getExtInfo()); if (Result.isNull()) return QualType(); @@ -2940,6 +3803,7 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setTrailingReturn(TL.getTrailingReturn()); for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i) NewTL.setArg(i, ParamDecls[i]); @@ -2949,9 +3813,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionNoProtoType( TypeLocBuilder &TLB, - FunctionNoProtoTypeLoc TL, - QualType ObjectType) { - FunctionNoProtoType *T = TL.getTypePtr(); + FunctionNoProtoTypeLoc TL) { + const FunctionNoProtoType *T = TL.getTypePtr(); QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); if (ResultType.isNull()) return QualType(); @@ -2964,15 +3827,15 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType( FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setTrailingReturn(false); return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB, - UnresolvedUsingTypeLoc TL, - QualType ObjectType) { - UnresolvedUsingType *T = TL.getTypePtr(); + UnresolvedUsingTypeLoc TL) { + const UnresolvedUsingType *T = TL.getTypePtr(); Decl *D = getDerived().TransformDecl(TL.getNameLoc(), T->getDecl()); if (!D) return QualType(); @@ -2994,9 +3857,8 @@ TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB, - TypedefTypeLoc TL, - QualType ObjectType) { - TypedefType *T = TL.getTypePtr(); + TypedefTypeLoc TL) { + const TypedefType *T = TL.getTypePtr(); TypedefDecl *Typedef = cast_or_null<TypedefDecl>(getDerived().TransformDecl(TL.getNameLoc(), T->getDecl())); @@ -3019,8 +3881,7 @@ QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, - TypeOfExprTypeLoc TL, - QualType ObjectType) { + TypeOfExprTypeLoc TL) { // typeof expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); @@ -3031,7 +3892,7 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || E.get() != TL.getUnderlyingExpr()) { - Result = getDerived().RebuildTypeOfExprType(E.get()); + Result = getDerived().RebuildTypeOfExprType(E.get(), TL.getTypeofLoc()); if (Result.isNull()) return QualType(); } @@ -3047,8 +3908,7 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB, - TypeOfTypeLoc TL, - QualType ObjectType) { + TypeOfTypeLoc TL) { TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo(); TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI); if (!New_Under_TI) @@ -3072,9 +3932,8 @@ QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, - DecltypeTypeLoc TL, - QualType ObjectType) { - DecltypeType *T = TL.getTypePtr(); + DecltypeTypeLoc TL) { + const DecltypeType *T = TL.getTypePtr(); // decltype expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); @@ -3086,7 +3945,7 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || E.get() != T->getUnderlyingExpr()) { - Result = getDerived().RebuildDecltypeType(E.get()); + Result = getDerived().RebuildDecltypeType(E.get(), TL.getNameLoc()); if (Result.isNull()) return QualType(); } @@ -3099,10 +3958,34 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, } template<typename Derived> +QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, + AutoTypeLoc TL) { + const AutoType *T = TL.getTypePtr(); + QualType OldDeduced = T->getDeducedType(); + QualType NewDeduced; + if (!OldDeduced.isNull()) { + NewDeduced = getDerived().TransformType(OldDeduced); + if (NewDeduced.isNull()) + return QualType(); + } + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced) { + Result = getDerived().RebuildAutoType(NewDeduced); + if (Result.isNull()) + return QualType(); + } + + AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB, - RecordTypeLoc TL, - QualType ObjectType) { - RecordType *T = TL.getTypePtr(); + RecordTypeLoc TL) { + const RecordType *T = TL.getTypePtr(); RecordDecl *Record = cast_or_null<RecordDecl>(getDerived().TransformDecl(TL.getNameLoc(), T->getDecl())); @@ -3125,9 +4008,8 @@ QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB, - EnumTypeLoc TL, - QualType ObjectType) { - EnumType *T = TL.getTypePtr(); + EnumTypeLoc TL) { + const EnumType *T = TL.getTypePtr(); EnumDecl *Enum = cast_or_null<EnumDecl>(getDerived().TransformDecl(TL.getNameLoc(), T->getDecl())); @@ -3151,8 +4033,7 @@ QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformInjectedClassNameType( TypeLocBuilder &TLB, - InjectedClassNameTypeLoc TL, - QualType ObjectType) { + InjectedClassNameTypeLoc TL) { Decl *D = getDerived().TransformDecl(TL.getNameLoc(), TL.getTypePtr()->getDecl()); if (!D) return QualType(); @@ -3162,73 +4043,122 @@ QualType TreeTransform<Derived>::TransformInjectedClassNameType( return T; } - template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateTypeParmType( TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL, - QualType ObjectType) { + TemplateTypeParmTypeLoc TL) { return TransformTypeSpecType(TLB, TL); } template<typename Derived> QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType( TypeLocBuilder &TLB, - SubstTemplateTypeParmTypeLoc TL, - QualType ObjectType) { + SubstTemplateTypeParmTypeLoc TL) { return TransformTypeSpecType(TLB, TL); } template<typename Derived> -QualType TreeTransform<Derived>::TransformTemplateSpecializationType( - const TemplateSpecializationType *TST, - QualType ObjectType) { - // FIXME: this entire method is a temporary workaround; callers - // should be rewritten to provide real type locs. - - // Fake up a TemplateSpecializationTypeLoc. - TypeLocBuilder TLB; - TemplateSpecializationTypeLoc TL - = TLB.push<TemplateSpecializationTypeLoc>(QualType(TST, 0)); - - SourceLocation BaseLoc = getDerived().getBaseLocation(); - - TL.setTemplateNameLoc(BaseLoc); - TL.setLAngleLoc(BaseLoc); - TL.setRAngleLoc(BaseLoc); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { - const TemplateArgument &TA = TST->getArg(i); - TemplateArgumentLoc TAL; - getDerived().InventTemplateArgumentLoc(TA, TAL); - TL.setArgLocInfo(i, TAL.getLocInfo()); - } - - TypeLocBuilder IgnoredTLB; - return TransformTemplateSpecializationType(IgnoredTLB, TL, ObjectType); +QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType( + TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL) { + return TransformTypeSpecType(TLB, TL); } - + template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateSpecializationType( TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL, - QualType ObjectType) { + TemplateSpecializationTypeLoc TL) { const TemplateSpecializationType *T = TL.getTypePtr(); TemplateName Template - = getDerived().TransformTemplateName(T->getTemplateName(), ObjectType); + = getDerived().TransformTemplateName(T->getTemplateName()); if (Template.isNull()) return QualType(); + return getDerived().TransformTemplateSpecializationType(TLB, TL, Template); +} + +namespace { + /// \brief Simple iterator that traverses the template arguments in a + /// container that provides a \c getArgLoc() member function. + /// + /// This iterator is intended to be used with the iterator form of + /// \c TreeTransform<Derived>::TransformTemplateArguments(). + template<typename ArgLocContainer> + class TemplateArgumentLocContainerIterator { + ArgLocContainer *Container; + unsigned Index; + + public: + typedef TemplateArgumentLoc value_type; + typedef TemplateArgumentLoc reference; + typedef int difference_type; + typedef std::input_iterator_tag iterator_category; + + class pointer { + TemplateArgumentLoc Arg; + + public: + explicit pointer(TemplateArgumentLoc Arg) : Arg(Arg) { } + + const TemplateArgumentLoc *operator->() const { + return &Arg; + } + }; + + + TemplateArgumentLocContainerIterator() {} + + TemplateArgumentLocContainerIterator(ArgLocContainer &Container, + unsigned Index) + : Container(&Container), Index(Index) { } + + TemplateArgumentLocContainerIterator &operator++() { + ++Index; + return *this; + } + + TemplateArgumentLocContainerIterator operator++(int) { + TemplateArgumentLocContainerIterator Old(*this); + ++(*this); + return Old; + } + + TemplateArgumentLoc operator*() const { + return Container->getArgLoc(Index); + } + + pointer operator->() const { + return pointer(Container->getArgLoc(Index)); + } + + friend bool operator==(const TemplateArgumentLocContainerIterator &X, + const TemplateArgumentLocContainerIterator &Y) { + return X.Container == Y.Container && X.Index == Y.Index; + } + + friend bool operator!=(const TemplateArgumentLocContainerIterator &X, + const TemplateArgumentLocContainerIterator &Y) { + return !(X == Y); + } + }; +} + + +template <typename Derived> +QualType TreeTransform<Derived>::TransformTemplateSpecializationType( + TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, + TemplateName Template) { TemplateArgumentListInfo NewTemplateArgs; NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); - - for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) { - TemplateArgumentLoc Loc; - if (getDerived().TransformTemplateArgument(TL.getArgLoc(i), Loc)) - return QualType(); - NewTemplateArgs.addArgument(Loc); - } + typedef TemplateArgumentLocContainerIterator<TemplateSpecializationTypeLoc> + ArgIterator; + if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), + ArgIterator(TL, TL.getNumArgs()), + NewTemplateArgs)) + return QualType(); // FIXME: maybe don't rebuild if all the template arguments are the same. @@ -3253,46 +4183,28 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( template<typename Derived> QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, - ElaboratedTypeLoc TL, - QualType ObjectType) { - ElaboratedType *T = TL.getTypePtr(); + ElaboratedTypeLoc TL) { + const ElaboratedType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = 0; // NOTE: the qualifier in an ElaboratedType is optional. if (T->getQualifier() != 0) { NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - TL.getQualifierRange(), - ObjectType); + TL.getQualifierRange()); if (!NNS) return QualType(); } - QualType NamedT; - // FIXME: this test is meant to workaround a problem (failing assertion) - // occurring if directly executing the code in the else branch. - if (isa<TemplateSpecializationTypeLoc>(TL.getNamedTypeLoc())) { - TemplateSpecializationTypeLoc OldNamedTL - = cast<TemplateSpecializationTypeLoc>(TL.getNamedTypeLoc()); - const TemplateSpecializationType* OldTST - = OldNamedTL.getType()->template getAs<TemplateSpecializationType>(); - NamedT = TransformTemplateSpecializationType(OldTST, ObjectType); - if (NamedT.isNull()) - return QualType(); - TemplateSpecializationTypeLoc NewNamedTL - = TLB.push<TemplateSpecializationTypeLoc>(NamedT); - NewNamedTL.copy(OldNamedTL); - } - else { - NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc()); - if (NamedT.isNull()) - return QualType(); - } + QualType NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc()); + if (NamedT.isNull()) + return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || NNS != T->getQualifier() || NamedT != T->getNamedType()) { - Result = getDerived().RebuildElaboratedType(T->getKeyword(), NNS, NamedT); + Result = getDerived().RebuildElaboratedType(TL.getKeywordLoc(), + T->getKeyword(), NNS, NamedT); if (Result.isNull()) return QualType(); } @@ -3305,15 +4217,72 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, } template<typename Derived> +QualType TreeTransform<Derived>::TransformAttributedType( + TypeLocBuilder &TLB, + AttributedTypeLoc TL) { + const AttributedType *oldType = TL.getTypePtr(); + QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc()); + if (modifiedType.isNull()) + return QualType(); + + QualType result = TL.getType(); + + // FIXME: dependent operand expressions? + if (getDerived().AlwaysRebuild() || + modifiedType != oldType->getModifiedType()) { + // TODO: this is really lame; we should really be rebuilding the + // equivalent type from first principles. + QualType equivalentType + = getDerived().TransformType(oldType->getEquivalentType()); + if (equivalentType.isNull()) + return QualType(); + result = SemaRef.Context.getAttributedType(oldType->getAttrKind(), + modifiedType, + equivalentType); + } + + AttributedTypeLoc newTL = TLB.push<AttributedTypeLoc>(result); + newTL.setAttrNameLoc(TL.getAttrNameLoc()); + if (TL.hasAttrOperand()) + newTL.setAttrOperandParensRange(TL.getAttrOperandParensRange()); + if (TL.hasAttrExprOperand()) + newTL.setAttrExprOperand(TL.getAttrExprOperand()); + else if (TL.hasAttrEnumOperand()) + newTL.setAttrEnumOperandLoc(TL.getAttrEnumOperandLoc()); + + return result; +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformParenType(TypeLocBuilder &TLB, + ParenTypeLoc TL) { + QualType Inner = getDerived().TransformType(TLB, TL.getInnerLoc()); + if (Inner.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Inner != TL.getInnerLoc().getType()) { + Result = getDerived().RebuildParenType(Inner); + if (Result.isNull()) + return QualType(); + } + + ParenTypeLoc NewTL = TLB.push<ParenTypeLoc>(Result); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + return Result; +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB, - DependentNameTypeLoc TL, - QualType ObjectType) { - DependentNameType *T = TL.getTypePtr(); + DependentNameTypeLoc TL) { + const DependentNameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - TL.getQualifierRange(), - ObjectType); + TL.getQualifierRange()); if (!NNS) return QualType(); @@ -3345,34 +4314,44 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>:: TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, - DependentTemplateSpecializationTypeLoc TL, - QualType ObjectType) { - DependentTemplateSpecializationType *T = TL.getTypePtr(); + DependentTemplateSpecializationTypeLoc TL) { + const DependentTemplateSpecializationType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - TL.getQualifierRange(), - ObjectType); + TL.getQualifierRange()); if (!NNS) return QualType(); + return getDerived() + .TransformDependentTemplateSpecializationType(TLB, TL, NNS); +} + +template<typename Derived> +QualType TreeTransform<Derived>:: + TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, + DependentTemplateSpecializationTypeLoc TL, + NestedNameSpecifier *NNS) { + const DependentTemplateSpecializationType *T = TL.getTypePtr(); + TemplateArgumentListInfo NewTemplateArgs; NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); + + typedef TemplateArgumentLocContainerIterator< + DependentTemplateSpecializationTypeLoc> ArgIterator; + if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), + ArgIterator(TL, TL.getNumArgs()), + NewTemplateArgs)) + return QualType(); - for (unsigned I = 0, E = T->getNumArgs(); I != E; ++I) { - TemplateArgumentLoc Loc; - if (getDerived().TransformTemplateArgument(TL.getArgLoc(I), Loc)) - return QualType(); - NewTemplateArgs.addArgument(Loc); - } - - QualType Result = getDerived().RebuildDependentTemplateSpecializationType( - T->getKeyword(), - NNS, - T->getIdentifier(), - TL.getNameLoc(), - NewTemplateArgs); + QualType Result + = getDerived().RebuildDependentTemplateSpecializationType(T->getKeyword(), + NNS, + TL.getQualifierRange(), + T->getIdentifier(), + TL.getNameLoc(), + NewTemplateArgs); if (Result.isNull()) return QualType(); @@ -3399,10 +4378,33 @@ QualType TreeTransform<Derived>:: } template<typename Derived> +QualType TreeTransform<Derived>::TransformPackExpansionType(TypeLocBuilder &TLB, + PackExpansionTypeLoc TL) { + QualType Pattern + = getDerived().TransformType(TLB, TL.getPatternLoc()); + if (Pattern.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Pattern != TL.getPatternLoc().getType()) { + Result = getDerived().RebuildPackExpansionType(Pattern, + TL.getPatternLoc().getSourceRange(), + TL.getEllipsisLoc(), + TL.getTypePtr()->getNumExpansions()); + if (Result.isNull()) + return QualType(); + } + + PackExpansionTypeLoc NewT = TLB.push<PackExpansionTypeLoc>(Result); + NewT.setEllipsisLoc(TL.getEllipsisLoc()); + return Result; +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, - ObjCInterfaceTypeLoc TL, - QualType ObjectType) { + ObjCInterfaceTypeLoc TL) { // ObjCInterfaceType is never dependent. TLB.pushFullCopy(TL); return TL.getType(); @@ -3411,8 +4413,7 @@ TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, - ObjCObjectTypeLoc TL, - QualType ObjectType) { + ObjCObjectTypeLoc TL) { // ObjCObjectType is never dependent. TLB.pushFullCopy(TL); return TL.getType(); @@ -3421,8 +4422,7 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, - ObjCObjectPointerTypeLoc TL, - QualType ObjectType) { + ObjCObjectPointerTypeLoc TL) { // ObjCObjectPointerType is never dependent. TLB.pushFullCopy(TL); return TL.getType(); @@ -3434,7 +4434,7 @@ TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, template<typename Derived> StmtResult TreeTransform<Derived>::TransformNullStmt(NullStmt *S) { - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); } template<typename Derived> @@ -3473,7 +4473,7 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S, if (!getDerived().AlwaysRebuild() && !SubStmtChanged) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); return getDerived().RebuildCompoundStmt(S->getLBracLoc(), move_arg(Statements), @@ -3540,9 +4540,15 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { if (SubStmt.isInvalid()) return StmtError(); + Decl *LD = getDerived().TransformDecl(S->getDecl()->getLocation(), + S->getDecl()); + if (!LD) + return StmtError(); + + // FIXME: Pass the real colon location in. - SourceLocation ColonLoc = SemaRef.PP.getLocForEndOfToken(S->getIdentLoc()); - return getDerived().RebuildLabelStmt(S->getIdentLoc(), S->getID(), ColonLoc, + return getDerived().RebuildLabelStmt(S->getIdentLoc(), + cast<LabelDecl>(LD), SourceLocation(), SubStmt.get()); } @@ -3568,9 +4574,8 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { // Convert the condition to a boolean value. if (S->getCond()) { - ExprResult CondE = getSema().ActOnBooleanCondition(0, - S->getIfLoc(), - Cond.get()); + ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getIfLoc(), + Cond.get()); if (CondE.isInvalid()) return StmtError(); @@ -3597,7 +4602,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { ConditionVar == S->getConditionVariable() && Then.get() == S->getThen() && Else.get() == S->getElse()) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, ConditionVar, Then.get(), @@ -3664,9 +4669,8 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { if (S->getCond()) { // Convert the condition to a boolean value. - ExprResult CondE = getSema().ActOnBooleanCondition(0, - S->getWhileLoc(), - Cond.get()); + ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getWhileLoc(), + Cond.get()); if (CondE.isInvalid()) return StmtError(); Cond = CondE; @@ -3708,7 +4712,7 @@ TreeTransform<Derived>::TransformDoStmt(DoStmt *S) { if (!getDerived().AlwaysRebuild() && Cond.get() == S->getCond() && Body.get() == S->getBody()) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); return getDerived().RebuildDoStmt(S->getDoLoc(), Body.get(), S->getWhileLoc(), /*FIXME:*/S->getWhileLoc(), Cond.get(), @@ -3742,9 +4746,8 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { if (S->getCond()) { // Convert the condition to a boolean value. - ExprResult CondE = getSema().ActOnBooleanCondition(0, - S->getForLoc(), - Cond.get()); + ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getForLoc(), + Cond.get()); if (CondE.isInvalid()) return StmtError(); @@ -3775,7 +4778,7 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { FullCond.get() == S->getCond() && Inc.get() == S->getInc() && Body.get() == S->getBody()) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(), Init.get(), FullCond, ConditionVar, @@ -3785,9 +4788,14 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { template<typename Derived> StmtResult TreeTransform<Derived>::TransformGotoStmt(GotoStmt *S) { + Decl *LD = getDerived().TransformDecl(S->getLabel()->getLocation(), + S->getLabel()); + if (!LD) + return StmtError(); + // Goto statements must always be rebuilt, to resolve the label. return getDerived().RebuildGotoStmt(S->getGotoLoc(), S->getLabelLoc(), - S->getLabel()); + cast<LabelDecl>(LD)); } template<typename Derived> @@ -3799,7 +4807,7 @@ TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) { if (!getDerived().AlwaysRebuild() && Target.get() == S->getTarget()) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); return getDerived().RebuildIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(), Target.get()); @@ -3808,13 +4816,13 @@ TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) { template<typename Derived> StmtResult TreeTransform<Derived>::TransformContinueStmt(ContinueStmt *S) { - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); } template<typename Derived> StmtResult TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) { - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); } template<typename Derived> @@ -3848,7 +4856,7 @@ TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) { } if (!getDerived().AlwaysRebuild() && !DeclChanged) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); return getDerived().RebuildDeclStmt(Decls.data(), Decls.size(), S->getStartLoc(), S->getEndLoc()); @@ -3856,13 +4864,6 @@ TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) { template<typename Derived> StmtResult -TreeTransform<Derived>::TransformSwitchCase(SwitchCase *S) { - assert(false && "SwitchCase is abstract and cannot be transformed"); - return SemaRef.Owned(S->Retain()); -} - -template<typename Derived> -StmtResult TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { ASTOwningVector<Expr*> Constraints(getSema()); @@ -3879,7 +4880,7 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { Names.push_back(S->getOutputIdentifier(I)); // No need to transform the constraint literal. - Constraints.push_back(S->getOutputConstraintLiteral(I)->Retain()); + Constraints.push_back(S->getOutputConstraintLiteral(I)); // Transform the output expr. Expr *OutputExpr = S->getOutputExpr(I); @@ -3897,7 +4898,7 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { Names.push_back(S->getInputIdentifier(I)); // No need to transform the constraint literal. - Constraints.push_back(S->getInputConstraintLiteral(I)->Retain()); + Constraints.push_back(S->getInputConstraintLiteral(I)); // Transform the input expr. Expr *InputExpr = S->getInputExpr(I); @@ -3911,11 +4912,11 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { } if (!getDerived().AlwaysRebuild() && !ExprsChanged) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); // Go through the clobbers. for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I) - Clobbers.push_back(S->getClobber(I)->Retain()); + Clobbers.push_back(S->getClobber(I)); // No need to transform the asm string literal. AsmString = SemaRef.Owned(S->getAsmString()); @@ -3968,7 +4969,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { TryBody.get() == S->getTryBody() && !AnyCatchChanged && Finally.get() == S->getFinallyStmt()) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); // Build a new statement. return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), TryBody.get(), @@ -4022,7 +5023,7 @@ TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { // If nothing changed, just retain this statement. if (!getDerived().AlwaysRebuild() && Body.get() == S->getFinallyBody()) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); // Build a new statement. return getDerived().RebuildObjCAtFinallyStmt(S->getAtFinallyLoc(), @@ -4041,7 +5042,7 @@ TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) { if (!getDerived().AlwaysRebuild() && Operand.get() == S->getThrowExpr()) - return getSema().Owned(S->Retain()); + return getSema().Owned(S); return getDerived().RebuildObjCAtThrowStmt(S->getThrowLoc(), Operand.get()); } @@ -4064,7 +5065,7 @@ TreeTransform<Derived>::TransformObjCAtSynchronizedStmt( if (!getDerived().AlwaysRebuild() && Object.get() == S->getSynchExpr() && Body.get() == S->getSynchBody()) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); // Build a new statement. return getDerived().RebuildObjCAtSynchronizedStmt(S->getAtSynchronizedLoc(), @@ -4095,7 +5096,7 @@ TreeTransform<Derived>::TransformObjCForCollectionStmt( Element.get() == S->getElement() && Collection.get() == S->getCollection() && Body.get() == S->getBody()) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); // Build a new statement. return getDerived().RebuildObjCForCollectionStmt(S->getForLoc(), @@ -4114,20 +5115,14 @@ TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) { 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()) + TypeSourceInfo *T = getDerived().TransformType( + ExceptionDecl->getTypeSourceInfo()); + if (!T) return StmtError(); - Var = getDerived().RebuildExceptionDecl(ExceptionDecl, - T, - ExceptionDecl->getTypeSourceInfo(), + Var = getDerived().RebuildExceptionDecl(ExceptionDecl, T, ExceptionDecl->getIdentifier(), - ExceptionDecl->getLocation(), - /*FIXME: Inaccurate*/ - SourceRange(ExceptionDecl->getLocation())); + ExceptionDecl->getLocation()); if (!Var || Var->isInvalidDecl()) return StmtError(); } @@ -4140,7 +5135,7 @@ TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) { if (!getDerived().AlwaysRebuild() && !Var && Handler.get() == S->getHandlerBlock()) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); return getDerived().RebuildCXXCatchStmt(S->getCatchLoc(), Var, @@ -4172,7 +5167,7 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) { if (!getDerived().AlwaysRebuild() && TryBlock.get() == S->getTryBlock() && !HandlerChanged) - return SemaRef.Owned(S->Retain()); + return SemaRef.Owned(S); return getDerived().RebuildCXXTryStmt(S->getTryLoc(), TryBlock.get(), move_arg(Handlers)); @@ -4184,7 +5179,7 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> @@ -4221,7 +5216,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { // FIXME: this is a bit instantiation-specific. SemaRef.MarkDeclarationReferenced(E->getLocation(), ND); - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } TemplateArgumentListInfo TransArgs, *TemplateArgs = 0; @@ -4229,12 +5224,10 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { TemplateArgs = &TransArgs; TransArgs.setLAngleLoc(E->getLAngleLoc()); TransArgs.setRAngleLoc(E->getRAngleLoc()); - for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - TemplateArgumentLoc Loc; - if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc)) - return ExprError(); - TransArgs.addArgument(Loc); - } + if (getDerived().TransformTemplateArguments(E->getTemplateArgs(), + E->getNumTemplateArgs(), + TransArgs)) + return ExprError(); } return getDerived().RebuildDeclRefExpr(Qualifier, E->getQualifierRange(), @@ -4244,31 +5237,31 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> @@ -4279,7 +5272,7 @@ TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) { return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildParenExpr(SubExpr.get(), E->getLParen(), E->getRParen()); @@ -4293,7 +5286,7 @@ TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) { return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildUnaryOperator(E->getOperatorLoc(), E->getOpcode(), @@ -4358,7 +5351,7 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) { if (!getDerived().AlwaysRebuild() && Type == E->getTypeSourceInfo() && !ExprChanged) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); // Build a new offsetof expression. return getDerived().RebuildOffsetOfExpr(E->getOperatorLoc(), Type, @@ -4368,6 +5361,14 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) { + assert(getDerived().AlreadyTransformed(E->getType()) && + "opaque value expression requires transformation"); + return SemaRef.Owned(E); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (E->isArgumentType()) { TypeSourceInfo *OldT = E->getArgumentTypeInfo(); @@ -4377,7 +5378,7 @@ TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return ExprError(); if (!getDerived().AlwaysRebuild() && OldT == NewT) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildSizeOfAlignOf(NewT, E->getOperatorLoc(), E->isSizeOf(), @@ -4396,7 +5397,7 @@ TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getArgumentExpr()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } return getDerived().RebuildSizeOfAlignOf(SubExpr.get(), E->getOperatorLoc(), @@ -4419,7 +5420,7 @@ TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { if (!getDerived().AlwaysRebuild() && LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildArraySubscriptExpr(LHS.get(), /*FIXME:*/E->getLHS()->getLocStart(), @@ -4438,31 +5439,20 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { // Transform arguments. bool ArgChanged = false; ASTOwningVector<Expr*> Args(SemaRef); - llvm::SmallVector<SourceLocation, 4> FakeCommaLocs; - for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { - ExprResult Arg = getDerived().TransformExpr(E->getArg(I)); - if (Arg.isInvalid()) - return 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.get()); - } - + if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, + &ArgChanged)) + return ExprError(); + if (!getDerived().AlwaysRebuild() && Callee.get() == E->getCallee() && !ArgChanged) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); // FIXME: Wrong source location information for the '('. SourceLocation FakeLParenLoc = ((Expr *)Callee.get())->getSourceRange().getBegin(); return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc, move_arg(Args), - FakeCommaLocs.data(), E->getRParenLoc()); } @@ -4508,19 +5498,17 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { // Mark it referenced in the new context regardless. // FIXME: this is a bit instantiation-specific. SemaRef.MarkDeclarationReferenced(E->getMemberLoc(), Member); - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } TemplateArgumentListInfo TransArgs; if (E->hasExplicitTemplateArgs()) { TransArgs.setLAngleLoc(E->getLAngleLoc()); TransArgs.setRAngleLoc(E->getRAngleLoc()); - for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - TemplateArgumentLoc Loc; - if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc)) - return ExprError(); - TransArgs.addArgument(Loc); - } + if (getDerived().TransformTemplateArguments(E->getTemplateArgs(), + E->getNumTemplateArgs(), + TransArgs)) + return ExprError(); } // FIXME: Bogus source location for the operator @@ -4559,7 +5547,7 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { if (!getDerived().AlwaysRebuild() && LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get()); @@ -4573,6 +5561,32 @@ TreeTransform<Derived>::TransformCompoundAssignOperator( } template<typename Derived> +ExprResult TreeTransform<Derived>:: +TransformBinaryConditionalOperator(BinaryConditionalOperator *e) { + // Just rebuild the common and RHS expressions and see whether we + // get any changes. + + ExprResult commonExpr = getDerived().TransformExpr(e->getCommon()); + if (commonExpr.isInvalid()) + return ExprError(); + + ExprResult rhs = getDerived().TransformExpr(e->getFalseExpr()); + if (rhs.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + commonExpr.get() == e->getCommon() && + rhs.get() == e->getFalseExpr()) + return SemaRef.Owned(e); + + return getDerived().RebuildConditionalOperator(commonExpr.take(), + e->getQuestionLoc(), + 0, + e->getColonLoc(), + rhs.get()); +} + +template<typename Derived> ExprResult TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) { ExprResult Cond = getDerived().TransformExpr(E->getCond()); @@ -4591,7 +5605,7 @@ TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) { Cond.get() == E->getCond() && LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildConditionalOperator(Cond.get(), E->getQuestionLoc(), @@ -4611,32 +5625,22 @@ TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { - TypeSourceInfo *OldT; - TypeSourceInfo *NewT; - { - // FIXME: Source location isn't quite accurate. - SourceLocation TypeStartLoc - = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); - TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName()); - - OldT = E->getTypeInfoAsWritten(); - NewT = getDerived().TransformType(OldT); - if (!NewT) - return ExprError(); - } - + TypeSourceInfo *Type = getDerived().TransformType(E->getTypeInfoAsWritten()); + if (!Type) + return ExprError(); + ExprResult SubExpr = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && - OldT == NewT && + Type == E->getTypeInfoAsWritten() && SubExpr.get() == E->getSubExpr()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildCStyleCastExpr(E->getLParenLoc(), - NewT, + Type, E->getRParenLoc(), SubExpr.get()); } @@ -4656,7 +5660,7 @@ TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { if (!getDerived().AlwaysRebuild() && OldT == NewT && Init.get() == E->getInitializer()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); // Note: the expression type doesn't necessarily match the // type-as-written, but that's okay, because it should always be @@ -4676,7 +5680,7 @@ TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) { if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); // FIXME: Bad source location SourceLocation FakeOperatorLoc @@ -4692,17 +5696,12 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { bool InitChanged = false; ASTOwningVector<Expr*, 4> Inits(SemaRef); - for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) { - ExprResult Init = getDerived().TransformExpr(E->getInit(I)); - if (Init.isInvalid()) - return ExprError(); - - InitChanged = InitChanged || Init.get() != E->getInit(I); - Inits.push_back(Init.get()); - } - + if (getDerived().TransformExprs(E->getInits(), E->getNumInits(), false, + Inits, &InitChanged)) + return ExprError(); + if (!getDerived().AlwaysRebuild() && !InitChanged) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildInitList(E->getLBraceLoc(), move_arg(Inits), E->getRBraceLoc(), E->getType()); @@ -4769,7 +5768,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { if (!getDerived().AlwaysRebuild() && Init.get() == E->getInit() && !ExprChanged) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildDesignatedInitExpr(Desig, move_arg(ArrayExprs), E->getEqualOrColonLoc(), @@ -4790,7 +5789,7 @@ TreeTransform<Derived>::TransformImplicitValueInitExpr( if (!getDerived().AlwaysRebuild() && T == E->getType()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildImplicitValueInitExpr(T); } @@ -4809,7 +5808,7 @@ TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) { if (!getDerived().AlwaysRebuild() && TInfo == E->getWrittenTypeInfo() && SubExpr.get() == E->getSubExpr()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildVAArgExpr(E->getBuiltinLoc(), SubExpr.get(), TInfo, E->getRParenLoc()); @@ -4820,15 +5819,10 @@ ExprResult TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) { bool ArgumentChanged = false; ASTOwningVector<Expr*, 4> Inits(SemaRef); - for (unsigned I = 0, N = E->getNumExprs(); I != N; ++I) { - ExprResult Init = getDerived().TransformExpr(E->getExpr(I)); - if (Init.isInvalid()) - return ExprError(); - - ArgumentChanged = ArgumentChanged || Init.get() != E->getExpr(I); - Inits.push_back(Init.get()); - } - + if (TransformExprs(E->getExprs(), E->getNumExprs(), true, Inits, + &ArgumentChanged)) + return ExprError(); + return getDerived().RebuildParenListExpr(E->getLParenLoc(), move_arg(Inits), E->getRParenLoc()); @@ -4842,8 +5836,13 @@ TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) { + Decl *LD = getDerived().TransformDecl(E->getLabel()->getLocation(), + E->getLabel()); + if (!LD) + return ExprError(); + return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(), - E->getLabel()); + cast<LabelDecl>(LD)); } template<typename Derived> @@ -4856,7 +5855,7 @@ TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) { if (!getDerived().AlwaysRebuild() && SubStmt.get() == E->getSubStmt()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildStmtExpr(E->getLParenLoc(), SubStmt.get(), @@ -4865,30 +5864,6 @@ TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) { template<typename Derived> ExprResult -TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) { - TypeSourceInfo *TInfo1; - TypeSourceInfo *TInfo2; - - TInfo1 = getDerived().TransformType(E->getArgTInfo1()); - if (!TInfo1) - return ExprError(); - - TInfo2 = getDerived().TransformType(E->getArgTInfo2()); - if (!TInfo2) - return ExprError(); - - if (!getDerived().AlwaysRebuild() && - TInfo1 == E->getArgTInfo1() && - TInfo2 == E->getArgTInfo2()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildTypesCompatibleExpr(E->getBuiltinLoc(), - TInfo1, TInfo2, - E->getRParenLoc()); -} - -template<typename Derived> -ExprResult TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) { ExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) @@ -4906,7 +5881,7 @@ TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) { Cond.get() == E->getCond() && LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildChooseExpr(E->getBuiltinLoc(), Cond.get(), LHS.get(), RHS.get(), @@ -4916,7 +5891,7 @@ TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> @@ -4946,26 +5921,12 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { // Transform the call arguments. ASTOwningVector<Expr*> Args(SemaRef); - llvm::SmallVector<SourceLocation, 4> FakeCommaLocs; - for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) { - if (getDerived().DropCallArgument(E->getArg(I))) - break; - - ExprResult Arg = getDerived().TransformExpr(E->getArg(I)); - if (Arg.isInvalid()) - return ExprError(); - - // FIXME: Poor source location information. - SourceLocation FakeCommaLoc - = SemaRef.PP.getLocForEndOfToken( - static_cast<Expr *>(Arg.get())->getLocEnd()); - FakeCommaLocs.push_back(FakeCommaLoc); - Args.push_back(Arg.release()); - } + if (getDerived().TransformExprs(E->getArgs() + 1, E->getNumArgs() - 1, true, + Args)) + return ExprError(); return getDerived().RebuildCallExpr(Object.get(), FakeLParenLoc, move_arg(Args), - FakeCommaLocs.data(), E->getLocEnd()); } @@ -5006,7 +5967,7 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { Callee.get() == E->getCallee() && First.get() == E->getArg(0) && (E->getNumArgs() != 2 || Second.get() == E->getArg(1))) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(), E->getOperatorLoc(), @@ -5023,30 +5984,53 @@ TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) { template<typename Derived> ExprResult -TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { - TypeSourceInfo *OldT; - TypeSourceInfo *NewT; - { - // FIXME: Source location isn't quite accurate. - SourceLocation TypeStartLoc - = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc()); - TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName()); +TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) { + // Transform the callee. + ExprResult Callee = getDerived().TransformExpr(E->getCallee()); + if (Callee.isInvalid()) + return ExprError(); - OldT = E->getTypeInfoAsWritten(); - NewT = getDerived().TransformType(OldT); - if (!NewT) - return ExprError(); - } + // Transform exec config. + ExprResult EC = getDerived().TransformCallExpr(E->getConfig()); + if (EC.isInvalid()) + return ExprError(); + // Transform arguments. + bool ArgChanged = false; + ASTOwningVector<Expr*> Args(SemaRef); + if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, + &ArgChanged)) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + Callee.get() == E->getCallee() && + !ArgChanged) + return SemaRef.Owned(E); + + // FIXME: Wrong source location information for the '('. + SourceLocation FakeLParenLoc + = ((Expr *)Callee.get())->getSourceRange().getBegin(); + return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc, + move_arg(Args), + E->getRParenLoc(), EC.get()); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { + TypeSourceInfo *Type = getDerived().TransformType(E->getTypeInfoAsWritten()); + if (!Type) + return ExprError(); + ExprResult SubExpr = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && - OldT == NewT && + Type == E->getTypeInfoAsWritten() && SubExpr.get() == E->getSubExpr()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); // FIXME: Poor source location information here. SourceLocation FakeLAngleLoc @@ -5058,7 +6042,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(), E->getStmtClass(), FakeLAngleLoc, - NewT, + Type, FakeRAngleLoc, FakeRAngleLoc, SubExpr.get(), @@ -5094,16 +6078,9 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXFunctionalCastExpr( CXXFunctionalCastExpr *E) { - TypeSourceInfo *OldT; - TypeSourceInfo *NewT; - { - TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); - - OldT = E->getTypeInfoAsWritten(); - NewT = getDerived().TransformType(OldT); - if (!NewT) - return ExprError(); - } + TypeSourceInfo *Type = getDerived().TransformType(E->getTypeInfoAsWritten()); + if (!Type) + return ExprError(); ExprResult SubExpr = getDerived().TransformExpr(E->getSubExprAsWritten()); @@ -5111,14 +6088,11 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr( return ExprError(); if (!getDerived().AlwaysRebuild() && - OldT == NewT && + Type == E->getTypeInfoAsWritten() && SubExpr.get() == E->getSubExpr()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); - // FIXME: The end of the type's source range is wrong - return getDerived().RebuildCXXFunctionalCastExpr( - /*FIXME:*/SourceRange(E->getTypeBeginLoc()), - NewT, + return getDerived().RebuildCXXFunctionalCastExpr(Type, /*FIXME:*/E->getSubExpr()->getLocStart(), SubExpr.get(), E->getRParenLoc()); @@ -5135,7 +6109,7 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { if (!getDerived().AlwaysRebuild() && TInfo == E->getTypeOperandSourceInfo()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildCXXTypeidExpr(E->getType(), E->getLocStart(), @@ -5155,7 +6129,7 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getExprOperand()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildCXXTypeidExpr(E->getType(), E->getLocStart(), @@ -5165,29 +6139,64 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformCXXUuidofExpr(CXXUuidofExpr *E) { + if (E->isTypeOperand()) { + TypeSourceInfo *TInfo + = getDerived().TransformType(E->getTypeOperandSourceInfo()); + if (!TInfo) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + TInfo == E->getTypeOperandSourceInfo()) + return SemaRef.Owned(E); + + return getDerived().RebuildCXXTypeidExpr(E->getType(), + E->getLocStart(), + TInfo, + 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, Sema::Unevaluated); + + ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand()); + if (SubExpr.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + SubExpr.get() == E->getExprOperand()) + return SemaRef.Owned(E); + + return getDerived().RebuildCXXUuidofExpr(E->getType(), + E->getLocStart(), + SubExpr.get(), + E->getLocEnd()); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr( CXXNullPtrLiteralExpr *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { - TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); + DeclContext *DC = getSema().getFunctionLevelDeclContext(); + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC); + QualType T = MD->getThisType(getSema().Context); - QualType T = getDerived().TransformType(E->getType()); - if (T.isNull()) - return ExprError(); - - if (!getDerived().AlwaysRebuild() && - T == E->getType()) - return SemaRef.Owned(E->Retain()); + if (!getDerived().AlwaysRebuild() && T == E->getType()) + return SemaRef.Owned(E); return getDerived().RebuildCXXThisExpr(E->getLocStart(), T, E->isImplicit()); } @@ -5201,7 +6210,7 @@ TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) { if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), SubExpr.get()); } @@ -5217,27 +6226,25 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { if (!getDerived().AlwaysRebuild() && Param == E->getParam()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param); } template<typename Derived> ExprResult -TreeTransform<Derived>::TransformCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { - TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); - - QualType T = getDerived().TransformType(E->getType()); - if (T.isNull()) +TreeTransform<Derived>::TransformCXXScalarValueInitExpr( + CXXScalarValueInitExpr *E) { + TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo()); + if (!T) return ExprError(); - + if (!getDerived().AlwaysRebuild() && - T == E->getType()) - return SemaRef.Owned(E->Retain()); + T == E->getTypeSourceInfo()) + return SemaRef.Owned(E); - return getDerived().RebuildCXXScalarValueInitExpr(E->getTypeBeginLoc(), - /*FIXME:*/E->getTypeBeginLoc(), - T, + return getDerived().RebuildCXXScalarValueInitExpr(T, + /*FIXME:*/T->getTypeLoc().getEndLoc(), E->getRParenLoc()); } @@ -5245,9 +6252,9 @@ template<typename Derived> ExprResult 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()) + TypeSourceInfo *AllocTypeInfo + = getDerived().TransformType(E->getAllocatedTypeSourceInfo()); + if (!AllocTypeInfo) return ExprError(); // Transform the size of the array we're allocating (if any). @@ -5258,28 +6265,16 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { // Transform the placement arguments (if any). bool ArgumentChanged = false; ASTOwningVector<Expr*> PlacementArgs(SemaRef); - for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) { - ExprResult Arg = getDerived().TransformExpr(E->getPlacementArg(I)); - if (Arg.isInvalid()) - return ExprError(); - - ArgumentChanged = ArgumentChanged || Arg.get() != E->getPlacementArg(I); - PlacementArgs.push_back(Arg.take()); - } + if (getDerived().TransformExprs(E->getPlacementArgs(), + E->getNumPlacementArgs(), true, + PlacementArgs, &ArgumentChanged)) + return ExprError(); // transform the constructor arguments (if any). ASTOwningVector<Expr*> ConstructorArgs(SemaRef); - for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) { - if (getDerived().DropCallArgument(E->getConstructorArg(I))) - break; - - ExprResult Arg = getDerived().TransformExpr(E->getConstructorArg(I)); - if (Arg.isInvalid()) - return ExprError(); - - ArgumentChanged = ArgumentChanged || Arg.get() != E->getConstructorArg(I); - ConstructorArgs.push_back(Arg.take()); - } + if (TransformExprs(E->getConstructorArgs(), E->getNumConstructorArgs(), true, + ConstructorArgs, &ArgumentChanged)) + return ExprError(); // Transform constructor, new operator, and delete operator. CXXConstructorDecl *Constructor = 0; @@ -5310,7 +6305,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { } if (!getDerived().AlwaysRebuild() && - AllocType == E->getAllocatedType() && + AllocTypeInfo == E->getAllocatedTypeSourceInfo() && ArraySize.get() == E->getArraySize() && Constructor == E->getConstructor() && OperatorNew == E->getOperatorNew() && @@ -5324,9 +6319,10 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorNew); if (OperatorDelete) SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete); - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } + QualType AllocType = AllocTypeInfo->getType(); if (!ArraySize.get()) { // If no array size was specified, but the new expression was // instantiated with an array type (e.g., "new T" where T is @@ -5347,11 +6343,12 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { } else if (const DependentSizedArrayType *DepArrayT = dyn_cast<DependentSizedArrayType>(ArrayT)) { if (DepArrayT->getSizeExpr()) { - ArraySize = SemaRef.Owned(DepArrayT->getSizeExpr()->Retain()); + ArraySize = SemaRef.Owned(DepArrayT->getSizeExpr()); AllocType = DepArrayT->getElementType(); } } } + return getDerived().RebuildCXXNewExpr(E->getLocStart(), E->isGlobalNew(), /*FIXME:*/E->getLocStart(), @@ -5359,8 +6356,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { /*FIXME:*/E->getLocStart(), E->getTypeIdParens(), AllocType, - /*FIXME:*/E->getLocStart(), - /*FIXME:*/SourceRange(), + AllocTypeInfo, ArraySize.get(), /*FIXME:*/E->getLocStart(), move_arg(ConstructorArgs), @@ -5391,7 +6387,18 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { // FIXME: instantiation-specific. if (OperatorDelete) SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete); - return SemaRef.Owned(E->Retain()); + + if (!E->getArgument()->isTypeDependent()) { + QualType Destroyed = SemaRef.Context.getBaseElementType( + E->getDestroyedType()); + if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl()); + SemaRef.MarkDeclarationReferenced(E->getLocStart(), + SemaRef.LookupDestructor(Record)); + } + } + + return SemaRef.Owned(E); } return getDerived().RebuildCXXDeleteExpr(E->getLocStart(), @@ -5419,17 +6426,21 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( return ExprError(); QualType ObjectType = ObjectTypePtr.get(); - NestedNameSpecifier *Qualifier - = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange(), - ObjectType); - if (E->getQualifier() && !Qualifier) - return ExprError(); + NestedNameSpecifier *Qualifier = E->getQualifier(); + if (Qualifier) { + Qualifier + = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange(), + ObjectType); + if (!Qualifier) + return ExprError(); + } PseudoDestructorTypeStorage Destroyed; if (E->getDestroyedTypeInfo()) { TypeSourceInfo *DestroyedTypeInfo - = getDerived().TransformType(E->getDestroyedTypeInfo(), ObjectType); + = getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(), + ObjectType, 0, Qualifier); if (!DestroyedTypeInfo) return ExprError(); Destroyed = DestroyedTypeInfo; @@ -5462,8 +6473,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( TypeSourceInfo *ScopeTypeInfo = 0; if (E->getScopeTypeInfo()) { - ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo(), - ObjectType); + ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo()); if (!ScopeTypeInfo) return ExprError(); } @@ -5550,12 +6560,10 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr( // If we have template arguments, rebuild them, then rebuild the // templateid expression. TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc()); - for (unsigned I = 0, N = Old->getNumTemplateArgs(); I != N; ++I) { - TemplateArgumentLoc Loc; - if (getDerived().TransformTemplateArgument(Old->getTemplateArgs()[I], Loc)) - return ExprError(); - TransArgs.addArgument(Loc); - } + if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(), + Old->getNumTemplateArgs(), + TransArgs)) + return ExprError(); return getDerived().RebuildTemplateIdExpr(SS, R, Old->requiresADL(), TransArgs); @@ -5564,29 +6572,43 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr( template<typename Derived> ExprResult TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { - TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); - - QualType T = getDerived().TransformType(E->getQueriedType()); - if (T.isNull()) + TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo()); + if (!T) return ExprError(); if (!getDerived().AlwaysRebuild() && - T == E->getQueriedType()) - return SemaRef.Owned(E->Retain()); - - // FIXME: Bad location information - SourceLocation FakeLParenLoc - = SemaRef.PP.getLocForEndOfToken(E->getLocStart()); + T == E->getQueriedTypeSourceInfo()) + return SemaRef.Owned(E); return getDerived().RebuildUnaryTypeTrait(E->getTrait(), E->getLocStart(), - /*FIXME:*/FakeLParenLoc, T, E->getLocEnd()); } template<typename Derived> ExprResult +TreeTransform<Derived>::TransformBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { + TypeSourceInfo *LhsT = getDerived().TransformType(E->getLhsTypeSourceInfo()); + if (!LhsT) + return ExprError(); + + TypeSourceInfo *RhsT = getDerived().TransformType(E->getRhsTypeSourceInfo()); + if (!RhsT) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + LhsT == E->getLhsTypeSourceInfo() && RhsT == E->getRhsTypeSourceInfo()) + return SemaRef.Owned(E); + + return getDerived().RebuildBinaryTypeTrait(E->getTrait(), + E->getLocStart(), + LhsT, RhsT, + E->getLocEnd()); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *E) { NestedNameSpecifier *NNS @@ -5595,6 +6617,10 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( if (!NNS) return ExprError(); + // TODO: If this is a conversion-function-id, verify that the + // destination type name (if present) resolves the same way after + // instantiation as it did in the local scope. + DeclarationNameInfo NameInfo = getDerived().TransformDeclarationNameInfo(E->getNameInfo()); if (!NameInfo.getName()) @@ -5606,7 +6632,7 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( // Note: it is sufficient to compare the Name component of NameInfo: // if name has not changed, DNLoc has not changed either. NameInfo.getName() == E->getDeclName()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildDependentScopeDeclRefExpr(NNS, E->getQualifierRange(), @@ -5615,12 +6641,10 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( } TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); - for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - TemplateArgumentLoc Loc; - if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc)) - return ExprError(); - TransArgs.addArgument(Loc); - } + if (getDerived().TransformTemplateArguments(E->getTemplateArgs(), + E->getNumTemplateArgs(), + TransArgs)) + return ExprError(); return getDerived().RebuildDependentScopeDeclRefExpr(NNS, E->getQualifierRange(), @@ -5652,22 +6676,10 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { bool ArgumentChanged = false; ASTOwningVector<Expr*> Args(SemaRef); - for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(), - ArgEnd = E->arg_end(); - Arg != ArgEnd; ++Arg) { - if (getDerived().DropCallArgument(*Arg)) { - ArgumentChanged = true; - break; - } - - ExprResult TransArg = getDerived().TransformExpr(*Arg); - if (TransArg.isInvalid()) - return ExprError(); - - ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg; - Args.push_back(TransArg.get()); - } - + if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, + &ArgumentChanged)) + return ExprError(); + if (!getDerived().AlwaysRebuild() && T == E->getType() && Constructor == E->getConstructor() && @@ -5675,14 +6687,15 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { // Mark the constructor as referenced. // FIXME: Instantiation-specific SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor); - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(), Constructor, E->isElidable(), move_arg(Args), E->requiresZeroInitialization(), - E->getConstructionKind()); + E->getConstructionKind(), + E->getParenRange()); } /// \brief Transform a C++ temporary-binding expression. @@ -5695,25 +6708,23 @@ TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { return getDerived().TransformExpr(E->getSubExpr()); } -/// \brief Transform a C++ expression that contains temporaries that should -/// be destroyed after the expression is evaluated. +/// \brief Transform a C++ expression that contains cleanups that should +/// be run after the expression is evaluated. /// -/// Since CXXExprWithTemporaries nodes are implicitly generated, we +/// Since ExprWithCleanups nodes are implicitly generated, we /// just transform the subexpression and return that. template<typename Derived> ExprResult -TreeTransform<Derived>::TransformCXXExprWithTemporaries( - CXXExprWithTemporaries *E) { +TreeTransform<Derived>::TransformExprWithCleanups(ExprWithCleanups *E) { return getDerived().TransformExpr(E->getSubExpr()); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( - CXXTemporaryObjectExpr *E) { - TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); - QualType T = getDerived().TransformType(E->getType()); - if (T.isNull()) + CXXTemporaryObjectExpr *E) { + TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo()); + if (!T) return ExprError(); CXXConstructorDecl *Constructor @@ -5726,43 +6737,22 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( bool ArgumentChanged = false; ASTOwningVector<Expr*> Args(SemaRef); Args.reserve(E->getNumArgs()); - for (CXXTemporaryObjectExpr::arg_iterator Arg = E->arg_begin(), - ArgEnd = E->arg_end(); - Arg != ArgEnd; ++Arg) { - if (getDerived().DropCallArgument(*Arg)) { - ArgumentChanged = true; - break; - } - - ExprResult TransArg = getDerived().TransformExpr(*Arg); - if (TransArg.isInvalid()) - return ExprError(); - - ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg; - Args.push_back((Expr *)TransArg.release()); - } + if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, + &ArgumentChanged)) + return ExprError(); if (!getDerived().AlwaysRebuild() && - T == E->getType() && + T == E->getTypeSourceInfo() && Constructor == E->getConstructor() && !ArgumentChanged) { // FIXME: Instantiation-specific - SemaRef.MarkDeclarationReferenced(E->getTypeBeginLoc(), Constructor); - return SemaRef.MaybeBindToTemporary(E->Retain()); - } - - // FIXME: Bogus location information - SourceLocation CommaLoc; - if (Args.size() > 1) { - Expr *First = (Expr *)Args[0]; - CommaLoc - = SemaRef.PP.getLocForEndOfToken(First->getSourceRange().getEnd()); + SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor); + return SemaRef.MaybeBindToTemporary(E); } - return getDerived().RebuildCXXTemporaryObjectExpr(E->getTypeBeginLoc(), - T, - /*FIXME:*/E->getTypeBeginLoc(), + + return getDerived().RebuildCXXTemporaryObjectExpr(T, + /*FIXME:*/T->getTypeLoc().getEndLoc(), move_arg(Args), - &CommaLoc, E->getLocEnd()); } @@ -5770,38 +6760,26 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( CXXUnresolvedConstructExpr *E) { - TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); - QualType T = getDerived().TransformType(E->getTypeAsWritten()); - if (T.isNull()) + TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo()); + if (!T) return ExprError(); bool ArgumentChanged = false; ASTOwningVector<Expr*> Args(SemaRef); - llvm::SmallVector<SourceLocation, 8> FakeCommaLocs; - for (CXXUnresolvedConstructExpr::arg_iterator Arg = E->arg_begin(), - ArgEnd = E->arg_end(); - Arg != ArgEnd; ++Arg) { - ExprResult TransArg = getDerived().TransformExpr(*Arg); - if (TransArg.isInvalid()) - return ExprError(); - - ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg; - FakeCommaLocs.push_back( - SemaRef.PP.getLocForEndOfToken((*Arg)->getLocEnd())); - Args.push_back(TransArg.get()); - } - + Args.reserve(E->arg_size()); + if (getDerived().TransformExprs(E->arg_begin(), E->arg_size(), true, Args, + &ArgumentChanged)) + return ExprError(); + if (!getDerived().AlwaysRebuild() && - T == E->getTypeAsWritten() && + T == E->getTypeSourceInfo() && !ArgumentChanged) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); // FIXME: we're faking the locations of the commas - return getDerived().RebuildCXXUnresolvedConstructExpr(E->getTypeBeginLoc(), - T, + return getDerived().RebuildCXXUnresolvedConstructExpr(T, E->getLParenLoc(), move_arg(Args), - FakeCommaLocs.data(), E->getRParenLoc()); } @@ -5856,9 +6834,12 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( return ExprError(); } + // TODO: If this is a conversion-function-id, verify that the + // destination type name (if present) resolves the same way after + // instantiation as it did in the local scope. + DeclarationNameInfo NameInfo - = getDerived().TransformDeclarationNameInfo(E->getMemberNameInfo(), - ObjectType); + = getDerived().TransformDeclarationNameInfo(E->getMemberNameInfo()); if (!NameInfo.getName()) return ExprError(); @@ -5871,7 +6852,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( Qualifier == E->getQualifier() && NameInfo.getName() == E->getMember() && FirstQualifierInScope == E->getFirstQualifierFoundInScope()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(), BaseType, @@ -5885,12 +6866,10 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( } TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); - for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - TemplateArgumentLoc Loc; - if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc)) - return ExprError(); - TransArgs.addArgument(Loc); - } + if (getDerived().TransformTemplateArguments(E->getTemplateArgs(), + E->getNumTemplateArgs(), + TransArgs)) + return ExprError(); return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(), BaseType, @@ -5975,13 +6954,10 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) if (Old->hasExplicitTemplateArgs()) { TransArgs.setLAngleLoc(Old->getLAngleLoc()); TransArgs.setRAngleLoc(Old->getRAngleLoc()); - for (unsigned I = 0, N = Old->getNumTemplateArgs(); I != N; ++I) { - TemplateArgumentLoc Loc; - if (getDerived().TransformTemplateArgument(Old->getTemplateArgs()[I], - Loc)) - return ExprError(); - TransArgs.addArgument(Loc); - } + if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(), + Old->getNumTemplateArgs(), + TransArgs)) + return ExprError(); } // FIXME: to do this check properly, we will need to preserve the @@ -6004,8 +6980,74 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) template<typename Derived> ExprResult +TreeTransform<Derived>::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) { + ExprResult SubExpr = getDerived().TransformExpr(E->getOperand()); + if (SubExpr.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getOperand()) + return SemaRef.Owned(E); + + return getDerived().RebuildCXXNoexceptExpr(E->getSourceRange(),SubExpr.get()); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformPackExpansionExpr(PackExpansionExpr *E) { + ExprResult Pattern = getDerived().TransformExpr(E->getPattern()); + if (Pattern.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && Pattern.get() == E->getPattern()) + return SemaRef.Owned(E); + + return getDerived().RebuildPackExpansion(Pattern.get(), E->getEllipsisLoc(), + E->getNumExpansions()); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { + // If E is not value-dependent, then nothing will change when we transform it. + // Note: This is an instantiation-centric view. + if (!E->isValueDependent()) + return SemaRef.Owned(E); + + // Note: None of the implementations of TryExpandParameterPacks can ever + // produce a diagnostic when given only a single unexpanded parameter pack, + // so + UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc()); + bool ShouldExpand = false; + bool RetainExpansion = false; + llvm::Optional<unsigned> NumExpansions; + if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(), + &Unexpanded, 1, + ShouldExpand, RetainExpansion, + NumExpansions)) + return ExprError(); + + if (!ShouldExpand || RetainExpansion) + return SemaRef.Owned(E); + + // We now know the length of the parameter pack, so build a new expression + // that stores that length. + return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), + E->getPackLoc(), E->getRParenLoc(), + *NumExpansions); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E) { + // Default behavior is to do nothing with this transformation. + return SemaRef.Owned(E); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> @@ -6018,7 +7060,7 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { if (!getDerived().AlwaysRebuild() && EncodedTypeInfo == E->getEncodedTypeSourceInfo()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildObjCEncodeExpr(E->getAtLoc(), EncodedTypeInfo, @@ -6031,15 +7073,11 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { // Transform arguments. bool ArgChanged = false; ASTOwningVector<Expr*> Args(SemaRef); - for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { - ExprResult Arg = getDerived().TransformExpr(E->getArg(I)); - if (Arg.isInvalid()) - return ExprError(); - - ArgChanged = ArgChanged || Arg.get() != E->getArg(I); - Args.push_back(Arg.get()); - } - + Args.reserve(E->getNumArgs()); + if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), false, Args, + &ArgChanged)) + return ExprError(); + if (E->getReceiverKind() == ObjCMessageExpr::Class) { // Class message: transform the receiver type. TypeSourceInfo *ReceiverTypeInfo @@ -6050,11 +7088,12 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { // If nothing changed, just retain the existing message send. if (!getDerived().AlwaysRebuild() && ReceiverTypeInfo == E->getClassReceiverTypeInfo() && !ArgChanged) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); // Build a new class message send. return getDerived().RebuildObjCMessageExpr(ReceiverTypeInfo, E->getSelector(), + E->getSelectorLoc(), E->getMethodDecl(), E->getLeftLoc(), move_arg(Args), @@ -6072,11 +7111,12 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { // If nothing changed, just retain the existing message send. if (!getDerived().AlwaysRebuild() && Receiver.get() == E->getInstanceReceiver() && !ArgChanged) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); // Build a new instance message send. return getDerived().RebuildObjCMessageExpr(Receiver.get(), E->getSelector(), + E->getSelectorLoc(), E->getMethodDecl(), E->getLeftLoc(), move_arg(Args), @@ -6086,13 +7126,13 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } template<typename Derived> @@ -6108,7 +7148,7 @@ TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { // If nothing changed, just retain the existing expression. if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildObjCIvarRefExpr(Base.get(), E->getDecl(), E->getLocation(), @@ -6118,6 +7158,11 @@ TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + // 'super' and types never change. Property never changes. Just + // retain the existing expression. + if (!E->isObjectReceiver()) + return SemaRef.Owned(E); + // Transform the base expression. ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) @@ -6128,47 +7173,18 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { // If nothing changed, just retain the existing expression. if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildObjCPropertyRefExpr(Base.get(), E->getProperty(), - E->getLocation()); -} + return SemaRef.Owned(E); -template<typename Derived> -ExprResult -TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *E) { - // If this implicit setter/getter refers to class methods, it cannot have any - // dependent parts. Just retain the existing declaration. - if (E->getInterfaceDecl()) - return SemaRef.Owned(E->Retain()); - - // Transform the base expression. - ExprResult Base = getDerived().TransformExpr(E->getBase()); - if (Base.isInvalid()) - return ExprError(); - - // We don't need to transform the getters/setters; they will never change. - - // If nothing changed, just retain the existing expression. - if (!getDerived().AlwaysRebuild() && - Base.get() == E->getBase()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildObjCImplicitSetterGetterRefExpr( - E->getGetterMethod(), - E->getType(), - E->getSetterMethod(), - E->getLocation(), - Base.get()); - -} + if (E->isExplicitProperty()) + return getDerived().RebuildObjCPropertyRefExpr(Base.get(), + E->getExplicitProperty(), + E->getLocation()); -template<typename Derived> -ExprResult -TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) { - // Can never occur in a dependent context. - return SemaRef.Owned(E->Retain()); + return getDerived().RebuildObjCPropertyRefExpr(Base.get(), + E->getType(), + E->getImplicitPropertyGetter(), + E->getImplicitPropertySetter(), + E->getLocation()); } template<typename Derived> @@ -6182,7 +7198,7 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { // If nothing changed, just retain the existing expression. if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildObjCIsaExpr(Base.get(), E->getIsaMemberLoc(), E->isArrow()); @@ -6193,18 +7209,14 @@ ExprResult TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { bool ArgumentChanged = false; ASTOwningVector<Expr*> SubExprs(SemaRef); - for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) { - ExprResult SubExpr = getDerived().TransformExpr(E->getExpr(I)); - if (SubExpr.isInvalid()) - return ExprError(); - - ArgumentChanged = ArgumentChanged || SubExpr.get() != E->getExpr(I); - SubExprs.push_back(SubExpr.get()); - } + SubExprs.reserve(E->getNumSubExprs()); + if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false, + SubExprs, &ArgumentChanged)) + return ExprError(); if (!getDerived().AlwaysRebuild() && !ArgumentChanged) - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); return getDerived().RebuildShuffleVectorExpr(E->getBuiltinLoc(), move_arg(SubExprs), @@ -6214,52 +7226,92 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { - SourceLocation CaretLoc(E->getExprLoc()); + BlockDecl *oldBlock = E->getBlockDecl(); - SemaRef.ActOnBlockStart(CaretLoc, /*Scope=*/0); - BlockScopeInfo *CurBlock = SemaRef.getCurBlock(); - CurBlock->TheDecl->setIsVariadic(E->getBlockDecl()->isVariadic()); - llvm::SmallVector<ParmVarDecl*, 4> Params; - llvm::SmallVector<QualType, 4> ParamTypes; + SemaRef.ActOnBlockStart(E->getCaretLocation(), /*Scope=*/0); + BlockScopeInfo *blockScope = SemaRef.getCurBlock(); + + blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic()); + llvm::SmallVector<ParmVarDecl*, 4> params; + llvm::SmallVector<QualType, 4> paramTypes; // Parameter substitution. - const BlockDecl *BD = E->getBlockDecl(); - for (BlockDecl::param_const_iterator P = BD->param_begin(), - EN = BD->param_end(); P != EN; ++P) { - ParmVarDecl *OldParm = (*P); - ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm); - QualType NewType = NewParm->getType(); - Params.push_back(NewParm); - ParamTypes.push_back(NewParm->getType()); + if (getDerived().TransformFunctionTypeParams(E->getCaretLocation(), + oldBlock->param_begin(), + oldBlock->param_size(), + 0, paramTypes, ¶ms)) + return true; + + const FunctionType *exprFunctionType = E->getFunctionType(); + QualType exprResultType = exprFunctionType->getResultType(); + if (!exprResultType.isNull()) { + if (!exprResultType->isDependentType()) + blockScope->ReturnType = exprResultType; + else if (exprResultType != getSema().Context.DependentTy) + blockScope->ReturnType = getDerived().TransformType(exprResultType); } - const FunctionType *BExprFunctionType = E->getFunctionType(); - QualType BExprResultType = BExprFunctionType->getResultType(); - if (!BExprResultType.isNull()) { - if (!BExprResultType->isDependentType()) - CurBlock->ReturnType = BExprResultType; - else if (BExprResultType != SemaRef.Context.DependentTy) - CurBlock->ReturnType = getDerived().TransformType(BExprResultType); - } - - // Transform the body - StmtResult Body = getDerived().TransformStmt(E->getBody()); - if (Body.isInvalid()) + // If the return type has not been determined yet, leave it as a dependent + // type; it'll get set when we process the body. + if (blockScope->ReturnType.isNull()) + blockScope->ReturnType = getSema().Context.DependentTy; + + // Don't allow returning a objc interface by value. + if (blockScope->ReturnType->isObjCObjectType()) { + getSema().Diag(E->getCaretLocation(), + diag::err_object_cannot_be_passed_returned_by_value) + << 0 << blockScope->ReturnType; return ExprError(); + } + + QualType functionType = getDerived().RebuildFunctionProtoType( + blockScope->ReturnType, + paramTypes.data(), + paramTypes.size(), + oldBlock->isVariadic(), + 0, RQ_None, + exprFunctionType->getExtInfo()); + blockScope->FunctionType = functionType; + // Set the parameters on the block decl. - if (!Params.empty()) - CurBlock->TheDecl->setParams(Params.data(), Params.size()); - - QualType FunctionType = getDerived().RebuildFunctionProtoType( - CurBlock->ReturnType, - ParamTypes.data(), - ParamTypes.size(), - BD->isVariadic(), - 0, - BExprFunctionType->getExtInfo()); + if (!params.empty()) + blockScope->TheDecl->setParams(params.data(), params.size()); + + // If the return type wasn't explicitly set, it will have been marked as a + // dependent type (DependentTy); clear out the return type setting so + // we will deduce the return type when type-checking the block's body. + if (blockScope->ReturnType == getSema().Context.DependentTy) + blockScope->ReturnType = QualType(); - CurBlock->FunctionType = FunctionType; - return SemaRef.ActOnBlockStmtExpr(CaretLoc, Body.get(), /*Scope=*/0); + // Transform the body + StmtResult body = getDerived().TransformStmt(E->getBody()); + if (body.isInvalid()) + return ExprError(); + +#ifndef NDEBUG + // In builds with assertions, make sure that we captured everything we + // captured before. + + if (oldBlock->capturesCXXThis()) assert(blockScope->CapturesCXXThis); + + for (BlockDecl::capture_iterator i = oldBlock->capture_begin(), + e = oldBlock->capture_end(); i != e; ++i) { + VarDecl *oldCapture = i->getVariable(); + + // Ignore parameter packs. + if (isa<ParmVarDecl>(oldCapture) && + cast<ParmVarDecl>(oldCapture)->isParameterPack()) + continue; + + VarDecl *newCapture = + cast<VarDecl>(getDerived().TransformDecl(E->getCaretLocation(), + oldCapture)); + assert(blockScope->CaptureMap.count(newCapture)); + } +#endif + + return SemaRef.ActOnBlockStmtExpr(E->getCaretLocation(), body.get(), + /*Scope=*/0); } template<typename Derived> @@ -6279,7 +7331,7 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { // FIXME: this is a bit instantiation-specific. SemaRef.MarkDeclarationReferenced(E->getLocation(), ND); - return SemaRef.Owned(E->Retain()); + return SemaRef.Owned(E); } DeclarationNameInfo NameInfo(E->getDecl()->getDeclName(), E->getLocation()); @@ -6403,10 +7455,10 @@ TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType, template<typename Derived> QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType, - unsigned NumElements, - VectorType::AltiVecSpecific AltiVecSpec) { + unsigned NumElements, + VectorType::VectorKind VecKind) { // FIXME: semantic checking! - return SemaRef.Context.getVectorType(ElementType, NumElements, AltiVecSpec); + return SemaRef.Context.getVectorType(ElementType, NumElements, VecKind); } template<typename Derived> @@ -6435,9 +7487,10 @@ QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T, unsigned NumParamTypes, bool Variadic, unsigned Quals, + RefQualifierKind RefQualifier, const FunctionType::ExtInfo &Info) { return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic, - Quals, + Quals, RefQualifier, getDerived().getBaseLocation(), getDerived().getBaseEntity(), Info); @@ -6474,8 +7527,9 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) { } template<typename Derived> -QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E) { - return SemaRef.BuildTypeofExprType(E); +QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E, + SourceLocation Loc) { + return SemaRef.BuildTypeofExprType(E, Loc); } template<typename Derived> @@ -6484,8 +7538,9 @@ QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) { } template<typename Derived> -QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E) { - return SemaRef.BuildDecltypeType(E); +QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, + SourceLocation Loc) { + return SemaRef.BuildDecltypeType(E, Loc); } template<typename Derived> @@ -6552,10 +7607,12 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, template<typename Derived> TemplateName TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, const IdentifierInfo &II, - QualType ObjectType) { + QualType ObjectType, + NamedDecl *FirstQualifierInScope) { CXXScopeSpec SS; - SS.setRange(SourceRange(getDerived().getBaseLocation())); + SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); UnqualifiedId Name; Name.setIdentifier(&II, /*FIXME:*/getDerived().getBaseLocation()); @@ -6567,7 +7624,7 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, ParsedType::make(ObjectType), /*EnteringContext=*/false, Template); - return Template.template getAsVal<TemplateName>(); + return Template.get(); } template<typename Derived> diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h new file mode 100644 index 0000000..3d20a52 --- /dev/null +++ b/lib/Sema/TypeLocBuilder.h @@ -0,0 +1,180 @@ +//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files defines TypeLocBuilder, a class for building TypeLocs +// bottom-up. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_TYPELOCBUILDER_H +#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H + +#include "clang/AST/TypeLoc.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/AST/ASTContext.h" + +namespace clang { + +class TypeLocBuilder { + enum { InlineCapacity = 8 * sizeof(SourceLocation) }; + + /// The underlying location-data buffer. Data grows from the end + /// of the buffer backwards. + char *Buffer; + + /// The capacity of the current buffer. + size_t Capacity; + + /// The index of the first occupied byte in the buffer. + size_t Index; + +#ifndef NDEBUG + /// The last type pushed on this builder. + QualType LastTy; +#endif + + /// The inline buffer. + char InlineBuffer[InlineCapacity]; + + public: + TypeLocBuilder() + : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) + {} + + ~TypeLocBuilder() { + if (Buffer != InlineBuffer) + delete[] Buffer; + } + + /// Ensures that this buffer has at least as much capacity as described. + void reserve(size_t Requested) { + if (Requested > Capacity) + // For now, match the request exactly. + grow(Requested); + } + + /// Pushes a copy of the given TypeLoc onto this builder. The builder + /// must be empty for this to work. + void pushFullCopy(TypeLoc L) { + size_t Size = L.getFullDataSize(); + TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size); + memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size); + } + + /// Pushes uninitialized space for the given type. The builder must + /// be empty. + TypeLoc pushFullUninitialized(QualType T) { + return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T)); + } + + /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs + /// previously retrieved from this builder. + TypeSpecTypeLoc pushTypeSpec(QualType T) { + size_t LocalSize = TypeSpecTypeLoc::LocalDataSize; + return cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize)); + } + + /// Resets this builder to the newly-initialized state. + void clear() { +#ifndef NDEBUG + LastTy = QualType(); +#endif + Index = Capacity; + } + + /// Pushes space for a new TypeLoc of the given type. Invalidates + /// any TypeLocs previously retrieved from this builder. + template <class TyLocType> TyLocType push(QualType T) { + size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize(); + return cast<TyLocType>(pushImpl(T, LocalSize)); + } + + /// Creates a TypeSourceInfo for the given type. + TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) { +#ifndef NDEBUG + assert(T == LastTy && "type doesn't match last type pushed!"); +#endif + + size_t FullDataSize = Capacity - Index; + TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize); + memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); + return DI; + } + +private: + TypeLoc pushImpl(QualType T, size_t LocalSize) { +#ifndef NDEBUG + QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType(); + assert(TLast == LastTy && + "mismatch between last type and new type's inner type"); + LastTy = T; +#endif + + // If we need to grow, grow by a factor of 2. + if (LocalSize > Index) { + size_t RequiredCapacity = Capacity + (LocalSize - Index); + size_t NewCapacity = Capacity * 2; + while (RequiredCapacity > NewCapacity) + NewCapacity *= 2; + grow(NewCapacity); + } + + Index -= LocalSize; + + return getTypeLoc(T); + } + + /// Grow to the given capacity. + void grow(size_t NewCapacity) { + assert(NewCapacity > Capacity); + + // Allocate the new buffer and copy the old data into it. + char *NewBuffer = new char[NewCapacity]; + unsigned NewIndex = Index + NewCapacity - Capacity; + memcpy(&NewBuffer[NewIndex], + &Buffer[Index], + Capacity - Index); + + if (Buffer != InlineBuffer) + delete[] Buffer; + + Buffer = NewBuffer; + Capacity = NewCapacity; + Index = NewIndex; + } + + TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) { +#ifndef NDEBUG + assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder"); + LastTy = T; +#endif + assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder"); + + reserve(Size); + Index -= Size; + + return getTypeLoc(T); + } + + + // This is private because, when we kill off TypeSourceInfo in favor + // of TypeLoc, we'll want an interface that creates a TypeLoc given + // an ASTContext, and we don't want people to think they can just + // use this as an equivalent. + TypeLoc getTypeLoc(QualType T) { +#ifndef NDEBUG + assert(LastTy == T && "type doesn't match last type pushed!"); +#endif + return TypeLoc(T, &Buffer[Index]); + } +}; + +} + +#endif |