aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp208
-rw-r--r--lib/Sema/AttributeList.cpp51
-rw-r--r--lib/Sema/CMakeLists.txt3
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp353
-rw-r--r--lib/Sema/DeclSpec.cpp114
-rw-r--r--lib/Sema/JumpDiagnostics.cpp62
-rw-r--r--lib/Sema/Sema.cpp267
-rw-r--r--lib/Sema/SemaAccess.cpp95
-rw-r--r--lib/Sema/SemaAttr.cpp81
-rw-r--r--lib/Sema/SemaCXXCast.cpp496
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp30
-rw-r--r--lib/Sema/SemaChecking.cpp806
-rw-r--r--lib/Sema/SemaCodeComplete.cpp3315
-rw-r--r--lib/Sema/SemaDecl.cpp2809
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1150
-rw-r--r--lib/Sema/SemaDeclCXX.cpp1969
-rw-r--r--lib/Sema/SemaDeclObjC.cpp354
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp37
-rw-r--r--lib/Sema/SemaExpr.cpp4525
-rw-r--r--lib/Sema/SemaExprCXX.cpp1736
-rw-r--r--lib/Sema/SemaExprObjC.cpp378
-rw-r--r--lib/Sema/SemaInit.cpp1322
-rw-r--r--lib/Sema/SemaLookup.cpp1007
-rw-r--r--lib/Sema/SemaObjCProperty.cpp218
-rw-r--r--lib/Sema/SemaOverload.cpp3982
-rw-r--r--lib/Sema/SemaStmt.cpp561
-rw-r--r--lib/Sema/SemaTemplate.cpp2303
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp2586
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp858
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp874
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp748
-rw-r--r--lib/Sema/SemaType.cpp1532
-rw-r--r--lib/Sema/TargetAttributesSema.cpp55
-rw-r--r--lib/Sema/TreeTransform.h2985
-rw-r--r--lib/Sema/TypeLocBuilder.h180
35 files changed, 26122 insertions, 11928 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index cfebed6a05b2..63f561d6ab19 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 8ccb2ca586eb..c0a305365afc 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 e65bb227f159..0d66e259d484 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 58a1627b478a..b7037ce83e7f 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 b46e8af9db86..bc289ec42c99 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 b23f615af7b7..b73f0e9f1452 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 17817d41691b..23a3c24804e6 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 e629f0fd35bf..4f9bf1c5edd7 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 0921156b932f..794b0b1f1cfa 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 21b1a73aa3bc..506d2612ffbc 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 631308eebb04..aa0efcdc70e1 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 a0b4b988dbeb..556665483e64 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 f00d1cd20f1e..bab665a38da7 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 f5e045a722a0..dd30c1261ed7 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 25af73ae13d3..cbc940f2f0ac 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 63acdb5f1cc6..e8abab847654 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 a6902a3e391c..66f6f2b960d1 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 c902e7787096..5d7993b1afba 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 80b465230e14..65b57c30cd7d 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 5720d931b66b..f9c2c9a62ea3 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 b56159c453b5..4d03b068ca85 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 a28fd7fe12bd..b9a6a5713b8b 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 306e95a497e8..0fd0e08ac830 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 7181d58f7fb0..b086ca751406 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 11b4bb3b92c6..6fb789cfd8a1 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 083e4dba85e3..e995e8f207df 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 0fc83927b79c..f0a0103205d5 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 5c77ed61060b..bd0a618283b3 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 4d4c18130b01..44f5913d55c7 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 1c7869fecd86..c0150c07bbf1 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 000000000000..0da801c7e343
--- /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 aa30b5c2da30..c88baa540f52 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 1854e7430853..c3415cb847ab 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 e7bfbe6fe955..944e6a13e113 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, &params))
+ 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 000000000000..3d20a5273d6d
--- /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