summaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2009-10-14 18:03:49 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2009-10-14 18:03:49 +0000
commit4c8b24812ddcd1dedaca343a6d4e76f91f398981 (patch)
tree137ebebcae16fb0ce7ab4af456992bbd8d22fced /lib/Sema
parent5362a71c02e7d448a8ce98cf00c47e353fba5d04 (diff)
Notes
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/CMakeLists.txt12
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp184
-rw-r--r--lib/Sema/IdentifierResolver.cpp18
-rw-r--r--lib/Sema/IdentifierResolver.h10
-rw-r--r--lib/Sema/JumpDiagnostics.cpp62
-rw-r--r--lib/Sema/ParseAST.cpp37
-rw-r--r--lib/Sema/Sema.cpp329
-rw-r--r--lib/Sema/Sema.h1874
-rw-r--r--lib/Sema/SemaAccess.cpp89
-rw-r--r--lib/Sema/SemaAttr.cpp84
-rw-r--r--lib/Sema/SemaCXXCast.cpp1128
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp381
-rw-r--r--lib/Sema/SemaChecking.cpp530
-rw-r--r--lib/Sema/SemaCodeComplete.cpp1432
-rw-r--r--lib/Sema/SemaDecl.cpp2571
-rw-r--r--lib/Sema/SemaDeclAttr.cpp544
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2665
-rw-r--r--lib/Sema/SemaDeclObjC.cpp832
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp320
-rw-r--r--lib/Sema/SemaExpr.cpp2800
-rw-r--r--lib/Sema/SemaExprCXX.cpp1129
-rw-r--r--lib/Sema/SemaExprObjC.cpp446
-rw-r--r--lib/Sema/SemaInit.cpp462
-rw-r--r--lib/Sema/SemaLookup.cpp1482
-rw-r--r--lib/Sema/SemaOverload.cpp2271
-rw-r--r--lib/Sema/SemaOverload.h37
-rw-r--r--lib/Sema/SemaStmt.cpp405
-rw-r--r--lib/Sema/SemaTemplate.cpp2545
-rw-r--r--lib/Sema/SemaTemplate.h104
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp1857
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp1238
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp1342
-rw-r--r--lib/Sema/SemaType.cpp797
-rw-r--r--lib/Sema/TreeTransform.h4829
34 files changed, 25627 insertions, 9219 deletions
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 85c67df8f1de5..fd3265d874ce5 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -1,33 +1,33 @@
set(LLVM_NO_RTTI 1)
add_clang_library(clangSema
+ CodeCompleteConsumer.cpp
IdentifierResolver.cpp
JumpDiagnostics.cpp
ParseAST.cpp
Sema.cpp
SemaAccess.cpp
SemaAttr.cpp
- SemaChecking.cpp
+ SemaCXXCast.cpp
SemaCXXScopeSpec.cpp
- SemaDeclAttr.cpp
+ SemaChecking.cpp
+ SemaCodeComplete.cpp
SemaDecl.cpp
+ SemaDeclAttr.cpp
SemaDeclCXX.cpp
SemaDeclObjC.cpp
+ SemaExceptionSpec.cpp
SemaExpr.cpp
SemaExprCXX.cpp
SemaExprObjC.cpp
- SemaInherit.cpp
SemaInit.cpp
SemaLookup.cpp
- SemaNamedCast.cpp
SemaOverload.cpp
SemaStmt.cpp
SemaTemplate.cpp
SemaTemplateDeduction.cpp
SemaTemplateInstantiate.cpp
SemaTemplateInstantiateDecl.cpp
- SemaTemplateInstantiateExpr.cpp
- SemaTemplateInstantiateStmt.cpp
SemaType.cpp
)
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
new file mode 100644
index 0000000000000..c78ab5b3e959e
--- /dev/null
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -0,0 +1,184 @@
+//===--- CodeCompleteConsumer.cpp - Code Completion Interface ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the CodeCompleteConsumer class.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Lex/Preprocessor.h"
+#include "Sema.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstring>
+#include <functional>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Code completion string implementation
+//===----------------------------------------------------------------------===//
+CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text)
+ : Kind(Kind), Text(0)
+{
+ assert((Kind == CK_Text || Kind == CK_Placeholder || Kind == CK_Informative)
+ && "Invalid text chunk kind");
+ char *New = new char [std::strlen(Text) + 1];
+ std::strcpy(New, Text);
+ this->Text = New;
+}
+
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreateText(const char *Text) {
+ return Chunk(CK_Text, Text);
+}
+
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreateOptional(
+ std::auto_ptr<CodeCompletionString> Optional) {
+ Chunk Result;
+ Result.Kind = CK_Optional;
+ Result.Optional = Optional.release();
+ return Result;
+}
+
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {
+ return Chunk(CK_Placeholder, Placeholder);
+}
+
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreateInformative(const char *Informative) {
+ return Chunk(CK_Informative, Informative);
+}
+
+void
+CodeCompletionString::Chunk::Destroy() {
+ switch (Kind) {
+ case CK_Optional:
+ delete Optional;
+ break;
+
+ case CK_Text:
+ case CK_Placeholder:
+ case CK_Informative:
+ delete [] Text;
+ break;
+ }
+}
+
+CodeCompletionString::~CodeCompletionString() {
+ std::for_each(Chunks.begin(), Chunks.end(),
+ std::mem_fun_ref(&Chunk::Destroy));
+}
+
+std::string CodeCompletionString::getAsString() const {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+
+ for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
+ switch (C->Kind) {
+ case CK_Text: OS << C->Text; break;
+ case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
+ case CK_Placeholder: OS << "<#" << C->Text << "#>"; break;
+ case CK_Informative: OS << "[#" << C->Text << "#]"; break;
+ }
+ }
+ OS.flush();
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// Code completion overload candidate implementation
+//===----------------------------------------------------------------------===//
+FunctionDecl *
+CodeCompleteConsumer::OverloadCandidate::getFunction() const {
+ if (getKind() == CK_Function)
+ return Function;
+ else if (getKind() == CK_FunctionTemplate)
+ return FunctionTemplate->getTemplatedDecl();
+ else
+ return 0;
+}
+
+const FunctionType *
+CodeCompleteConsumer::OverloadCandidate::getFunctionType() const {
+ switch (Kind) {
+ case CK_Function:
+ return Function->getType()->getAs<FunctionType>();
+
+ case CK_FunctionTemplate:
+ return FunctionTemplate->getTemplatedDecl()->getType()
+ ->getAs<FunctionType>();
+
+ case CK_FunctionType:
+ return Type;
+ }
+
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Code completion consumer implementation
+//===----------------------------------------------------------------------===//
+
+CodeCompleteConsumer::~CodeCompleteConsumer() { }
+
+void
+PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
+ unsigned NumResults) {
+ // Print the results.
+ for (unsigned I = 0; I != NumResults; ++I) {
+ OS << "COMPLETION: ";
+ switch (Results[I].Kind) {
+ case Result::RK_Declaration:
+ OS << Results[I].Declaration->getNameAsString() << " : "
+ << Results[I].Rank;
+ if (Results[I].Hidden)
+ OS << " (Hidden)";
+ if (CodeCompletionString *CCS
+ = Results[I].CreateCodeCompletionString(SemaRef)) {
+ OS << " : " << CCS->getAsString();
+ delete CCS;
+ }
+
+ OS << '\n';
+ break;
+
+ case Result::RK_Keyword:
+ OS << Results[I].Keyword << " : " << Results[I].Rank << '\n';
+ break;
+ }
+ }
+
+ // Once we've printed the code-completion results, suppress remaining
+ // diagnostics.
+ // FIXME: Move this somewhere else!
+ SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
+}
+
+void
+PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg,
+ OverloadCandidate *Candidates,
+ unsigned NumCandidates) {
+ for (unsigned I = 0; I != NumCandidates; ++I) {
+ if (CodeCompletionString *CCS
+ = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
+ OS << "OVERLOAD: " << CCS->getAsString() << "\n";
+ delete CCS;
+ }
+ }
+
+ // Once we've printed the code-completion results, suppress remaining
+ // diagnostics.
+ // FIXME: Move this somewhere else!
+ SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
+}
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index ceab859c90aa0..0dbf21961fe9f 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -32,7 +32,7 @@ class IdentifierResolver::IdDeclInfoMap {
// New vectors are added when the current one is full.
std::list< std::vector<IdDeclInfo> > IDIVecs;
unsigned int CurIndex;
-
+
public:
IdDeclInfoMap() : CurIndex(VECTOR_SIZE) {}
@@ -75,7 +75,7 @@ void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) {
assert(0 && "Didn't find this decl on its identifier's chain!");
}
-bool
+bool
IdentifierResolver::IdDeclInfo::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) {
if (Old == *(I-1)) {
@@ -108,7 +108,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
if (Ctx->isFunctionOrMethod()) {
// Ignore the scopes associated within transparent declaration contexts.
- while (S->getEntity() &&
+ while (S->getEntity() &&
((DeclContext *)S->getEntity())->isTransparentContext())
S = S->getParent();
@@ -134,7 +134,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
return false;
}
- return D->getDeclContext()->getLookupContext() == Ctx->getPrimaryContext();
+ return D->getDeclContext()->getLookupContext()->Equals(Ctx);
}
/// AddDecl - Link the decl to its shadowed decl chain.
@@ -200,14 +200,14 @@ void IdentifierResolver::RemoveDecl(NamedDecl *D) {
Name.setFETokenInfo(NULL);
return;
}
-
+
return toIdDeclInfo(Ptr)->RemoveDecl(D);
}
bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
- assert(Old->getDeclName() == New->getDeclName() &&
+ assert(Old->getDeclName() == New->getDeclName() &&
"Cannot replace a decl with another decl of a different name");
-
+
DeclarationName Name = Old->getDeclName();
void *Ptr = Name.getFETokenInfo<void>();
@@ -222,7 +222,7 @@ bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
return false;
}
- return toIdDeclInfo(Ptr)->ReplaceDecl(Old, New);
+ return toIdDeclInfo(Ptr)->ReplaceDecl(Old, New);
}
/// begin - Returns an iterator for decls with name 'Name'.
@@ -243,7 +243,7 @@ IdentifierResolver::begin(DeclarationName Name) {
return end();
}
-void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II,
+void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II,
NamedDecl *D) {
void *Ptr = II->getFETokenInfo<void>();
diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h
index 0b0e6b388dde7..65f3256c2138f 100644
--- a/lib/Sema/IdentifierResolver.h
+++ b/lib/Sema/IdentifierResolver.h
@@ -99,7 +99,7 @@ public:
assert(isIterator() && "Ptr not an iterator!");
return reinterpret_cast<BaseIter>(Ptr & ~0x3);
}
-
+
friend class IdentifierResolver;
public:
iterator() : Ptr(0) {}
@@ -110,14 +110,14 @@ public:
else
return reinterpret_cast<NamedDecl*>(Ptr);
}
-
+
bool operator==(const iterator &RHS) const {
return Ptr == RHS.Ptr;
}
bool operator!=(const iterator &RHS) const {
return Ptr != RHS.Ptr;
}
-
+
// Preincrement.
iterator& operator++() {
if (!isIterator()) // common case.
@@ -127,7 +127,7 @@ public:
void *InfoPtr = D->getDeclName().getFETokenInfo<void>();
assert(!isDeclPtr(InfoPtr) && "Decl with wrong id ?");
IdDeclInfo *Info = toIdDeclInfo(InfoPtr);
-
+
BaseIter I = getIterator();
if (I != Info->decls_begin())
*this = iterator(I-1);
@@ -138,7 +138,7 @@ public:
}
uintptr_t getAsOpaqueValue() const { return Ptr; }
-
+
static iterator getFromOpaqueValue(uintptr_t P) {
iterator Result;
Result.Ptr = P;
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index ae863f2df1ee1..a8e31d2cfa2b8 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -28,7 +28,7 @@ namespace {
///
class JumpScopeChecker {
Sema &S;
-
+
/// GotoScope - This is a record that we use to keep track of all of the
/// scopes that are introduced by VLAs and other things that scope jumps like
/// gotos. This scope tree has nothing to do with the source scope tree,
@@ -38,17 +38,17 @@ class JumpScopeChecker {
/// ParentScope - The index in ScopeMap of the parent scope. This is 0 for
/// the parent scope is the function body.
unsigned ParentScope;
-
+
/// Diag - The diagnostic to emit if there is a jump into this scope.
unsigned Diag;
-
+
/// Loc - Location to emit the diagnostic.
SourceLocation Loc;
-
+
GotoScope(unsigned parentScope, unsigned diag, SourceLocation L)
: ParentScope(parentScope), Diag(diag), Loc(L) {}
};
-
+
llvm::SmallVector<GotoScope, 48> Scopes;
llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
llvm::SmallVector<Stmt*, 16> Jumps;
@@ -66,15 +66,15 @@ private:
JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
// Add a scope entry for function scope.
Scopes.push_back(GotoScope(~0U, ~0U, SourceLocation()));
-
+
// Build information for the top level compound statement, so that we have a
// defined scope record for every "goto" and label.
BuildScopeInformation(Body, 0);
-
+
// Check that all jumps we saw are kosher.
VerifyJumps();
}
-
+
/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
/// diagnostic that should be emitted if control goes over it. If not, return 0.
static unsigned GetDiagForGotoScopeDecl(const Decl *D) {
@@ -83,11 +83,13 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D) {
return diag::note_protected_by_vla;
if (VD->hasAttr<CleanupAttr>())
return diag::note_protected_by_cleanup;
+ if (VD->hasAttr<BlocksAttr>())
+ return diag::note_protected_by___block;
} else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
return diag::note_protected_by_vla_typedef;
}
-
+
return 0;
}
@@ -97,7 +99,7 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D) {
/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively
/// walking the AST as needed.
void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
-
+
// If we found a label, remember that it is in ParentScope scope.
if (isa<LabelStmt>(S) || isa<DefaultStmt>(S) || isa<CaseStmt>(S)) {
LabelAndGotoScopes[S] = ParentScope;
@@ -108,12 +110,12 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
LabelAndGotoScopes[S] = ParentScope;
Jumps.push_back(S);
}
-
+
for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E;
++CI) {
Stmt *SubStmt = *CI;
if (SubStmt == 0) continue;
-
+
// FIXME: diagnose jumps past initialization: required in C++, warning in C.
// goto L; int X = 4; L: ;
@@ -129,7 +131,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation()));
ParentScope = Scopes.size()-1;
}
-
+
// If the decl has an initializer, walk it with the potentially new
// scope we just installed.
if (VarDecl *VD = dyn_cast<VarDecl>(*I))
@@ -154,10 +156,10 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_catch,
AC->getAtCatchLoc()));
- // @catches are nested and it isn't
+ // @catches are nested and it isn't
BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1);
}
-
+
// Jump from the finally to the try or catch is not valid.
if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) {
Scopes.push_back(GotoScope(ParentScope,
@@ -165,17 +167,17 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
AF->getAtFinallyLoc()));
BuildScopeInformation(AF, Scopes.size()-1);
}
-
+
continue;
}
-
+
// Disallow jumps into the protected statement of an @synchronized, but
// allow jumps into the object expression it protects.
if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){
// Recursively walk the AST for the @synchronized object expr, it is
// evaluated in the normal scope.
BuildScopeInformation(AS->getSynchExpr(), ParentScope);
-
+
// Recursively walk the AST for the @synchronized part, protected by a new
// scope.
Scopes.push_back(GotoScope(ParentScope,
@@ -194,7 +196,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
BuildScopeInformation(TryBlock, Scopes.size()-1);
// Jump from the catch into the try is not allowed either.
- for(unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
+ for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
CXXCatchStmt *CS = TS->getHandler(I);
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_cxx_catch,
@@ -215,14 +217,14 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
void JumpScopeChecker::VerifyJumps() {
while (!Jumps.empty()) {
Stmt *Jump = Jumps.pop_back_val();
-
- // With a goto,
+
+ // With a goto,
if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {
CheckJump(GS, GS->getLabel(), GS->getGotoLoc(),
diag::err_goto_into_protected_scope);
continue;
}
-
+
if (SwitchStmt *SS = dyn_cast<SwitchStmt>(Jump)) {
for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase()) {
@@ -234,7 +236,7 @@ void JumpScopeChecker::VerifyJumps() {
}
unsigned DiagnosticScope;
-
+
// We don't know where an indirect goto goes, require that it be at the
// top level of scoping.
if (IndirectGotoStmt *IG = dyn_cast<IndirectGotoStmt>(Jump)) {
@@ -252,12 +254,12 @@ void JumpScopeChecker::VerifyJumps() {
// indirectly jumping to the label.
assert(isa<AddrLabelExpr>(Jump) && "Unknown jump type");
LabelStmt *TheLabel = cast<AddrLabelExpr>(Jump)->getLabel();
-
+
assert(LabelAndGotoScopes.count(TheLabel) &&
"Referenced label didn't get added to scopes?");
unsigned LabelScope = LabelAndGotoScopes[TheLabel];
if (LabelScope == 0) continue; // Addr of label is ok.
-
+
S.Diag(Jump->getLocStart(), diag::err_addr_of_label_in_protected_scope);
DiagnosticScope = LabelScope;
}
@@ -280,10 +282,10 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?");
unsigned ToScope = LabelAndGotoScopes[To];
-
+
// Common case: exactly the same scope, which is fine.
if (FromScope == ToScope) return;
-
+
// The only valid mismatch jump case happens when the jump is more deeply
// nested inside the jump target. Do a quick scan to see if the jump is valid
// because valid code is more common than invalid code.
@@ -292,11 +294,11 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
// If we found the jump target, then we're jumping out of our current scope,
// which is perfectly fine.
if (TestScope == ToScope) return;
-
+
// Otherwise, scan up the hierarchy.
TestScope = Scopes[TestScope].ParentScope;
}
-
+
// If we get here, then we know we have invalid code. Diagnose the bad jump,
// and then emit a note at each VLA being jumped out of.
S.Diag(DiagLoc, JumpDiag);
@@ -316,7 +318,7 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
FromScopes.pop_back();
ToScopes.pop_back();
}
-
+
// Emit diagnostics for whatever is left in ToScopes.
for (unsigned i = 0, e = ToScopes.size(); i != e; ++i)
S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].Diag);
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index e2ee88ac86bcb..d3f26d875cc4f 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -13,13 +13,15 @@
#include "clang/Sema/ParseAST.h"
#include "Sema.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Sema/SemaConsumer.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Stmt.h"
#include "clang/Parse/Parser.h"
-#include "llvm/ADT/OwningPtr.h"
+#include <cstdio>
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -32,7 +34,9 @@ using namespace clang;
///
void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
ASTContext &Ctx, bool PrintStats,
- bool CompleteTranslationUnit) {
+ bool CompleteTranslationUnit,
+ CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *Data),
+ void *CreateCodeCompleterData) {
// Collect global stats on Decls/Stmts (until we have a module streamer).
if (PrintStats) {
Decl::CollectingStats(true);
@@ -42,25 +46,31 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit);
Parser P(PP, S);
PP.EnterMainSourceFile();
-
+
// Initialize the parser.
P.Initialize();
-
+
Consumer->Initialize(Ctx);
-
+
if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumer))
SC->InitializeSema(S);
if (ExternalASTSource *External = Ctx.getExternalSource()) {
- if (ExternalSemaSource *ExternalSema =
+ if (ExternalSemaSource *ExternalSema =
dyn_cast<ExternalSemaSource>(External))
ExternalSema->InitializeSema(S);
External->StartTranslationUnit(Consumer);
}
- Parser::DeclGroupPtrTy ADecl;
+ CodeCompleteConsumer *CodeCompleter = 0;
+ if (CreateCodeCompleter) {
+ CodeCompleter = CreateCodeCompleter(S, CreateCodeCompleterData);
+ S.setCodeCompleteConsumer(CodeCompleter);
+ }
+ Parser::DeclGroupPtrTy ADecl;
+
while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file.
// If we got a null return and something *was* parsed, ignore it. This
// is due to a top-level semicolon, an action override, or a parse error
@@ -68,9 +78,18 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
if (ADecl)
Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
};
-
+
+ // process any TopLevelDecls generated by #pragma weak
+ for (llvm::SmallVector<Decl*,2>::iterator
+ I = S.WeakTopLevelDecls().begin(),
+ E = S.WeakTopLevelDecls().end(); I != E; ++I)
+ Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
+
Consumer->HandleTranslationUnit(Ctx);
+ if (CreateCodeCompleter)
+ delete CodeCompleter;
+
if (PrintStats) {
fprintf(stderr, "\nSTATISTICS:\n");
P.getActions().PrintStats();
@@ -78,7 +97,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
Decl::PrintStats();
Stmt::PrintStats();
Consumer->PrintStats();
-
+
Decl::CollectingStats(false);
Stmt::CollectingStats(false);
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index d1e8e2104d50f..ba05a07f26540 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -13,15 +13,65 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "llvm/ADT/DenseMap.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
using namespace clang;
-/// ConvertQualTypeToStringFn - This function is used to pretty print the
+/// \brief Convert the given type to a string suitable for printing as part of
+/// a diagnostic.
+///
+/// \param Context the context in which the type was allocated
+/// \param Ty the type to print
+static std::string ConvertTypeToDiagnosticString(ASTContext &Context,
+ QualType Ty) {
+ // FIXME: Playing with std::string is really slow.
+ std::string S = Ty.getAsString(Context.PrintingPolicy);
+
+ // If this is a sugared type (like a typedef, typeof, etc), then unwrap one
+ // level of the sugar so that the type is more obvious to the user.
+ QualType DesugaredTy = Ty.getDesugaredType();
+
+ if (Ty != DesugaredTy &&
+ // If the desugared type is a vector type, we don't want to expand it,
+ // it will turn into an attribute mess. People want their "vec4".
+ !isa<VectorType>(DesugaredTy) &&
+
+ // Don't aka just because we saw an elaborated type...
+ (!isa<ElaboratedType>(Ty) ||
+ cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) &&
+
+ // ...or a qualified name type...
+ (!isa<QualifiedNameType>(Ty) ||
+ cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) &&
+
+ // ...or a non-dependent template specialization.
+ (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) &&
+
+ // Don't desugar magic Objective-C types.
+ Ty.getUnqualifiedType() != Context.getObjCIdType() &&
+ Ty.getUnqualifiedType() != Context.getObjCClassType() &&
+ Ty.getUnqualifiedType() != Context.getObjCSelType() &&
+ Ty.getUnqualifiedType() != Context.getObjCProtoType() &&
+
+ // Not va_list.
+ Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) {
+ S = "'"+S+"' (aka '";
+ S += DesugaredTy.getAsString(Context.PrintingPolicy);
+ S += "')";
+ return S;
+ }
+
+ S = "'" + S + "'";
+ return S;
+}
+
+/// ConvertQualTypeToStringFn - This function is used to pretty print the
/// specified QualType as a string in diagnostics.
static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
const char *Modifier, unsigned ModLen,
@@ -29,48 +79,21 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
llvm::SmallVectorImpl<char> &Output,
void *Cookie) {
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
-
+
std::string S;
+ bool NeedQuotes = true;
if (Kind == Diagnostic::ak_qualtype) {
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for QualType argument");
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
-
- // FIXME: Playing with std::string is really slow.
- S = Ty.getAsString(Context.PrintingPolicy);
-
- // If this is a sugared type (like a typedef, typeof, etc), then unwrap one
- // level of the sugar so that the type is more obvious to the user.
- QualType DesugaredTy = Ty->getDesugaredType(true);
- DesugaredTy.setCVRQualifiers(DesugaredTy.getCVRQualifiers() |
- Ty.getCVRQualifiers());
-
- if (Ty != DesugaredTy &&
- // If the desugared type is a vector type, we don't want to expand it,
- // it will turn into an attribute mess. People want their "vec4".
- !isa<VectorType>(DesugaredTy) &&
-
- // Don't desugar magic Objective-C types.
- Ty.getUnqualifiedType() != Context.getObjCIdType() &&
- Ty.getUnqualifiedType() != Context.getObjCSelType() &&
- Ty.getUnqualifiedType() != Context.getObjCProtoType() &&
- Ty.getUnqualifiedType() != Context.getObjCClassType() &&
-
- // Not va_list.
- Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) {
- S = "'"+S+"' (aka '";
- S += DesugaredTy.getAsString(Context.PrintingPolicy);
- S += "')";
- Output.append(S.begin(), S.end());
- return;
- }
-
+ S = ConvertTypeToDiagnosticString(Context, Ty);
+ NeedQuotes = false;
} else if (Kind == Diagnostic::ak_declarationname) {
-
+
DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
S = N.getAsString();
-
+
if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
S = '+' + S;
else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0)
@@ -78,30 +101,73 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
else
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for DeclarationName argument");
- } else {
- assert(Kind == Diagnostic::ak_nameddecl);
+ } else if (Kind == Diagnostic::ak_nameddecl) {
+ bool Qualified;
if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
- S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString();
- else {
+ Qualified = true;
+ else {
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for NamedDecl* argument");
- S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString();
+ Qualified = false;
+ }
+ reinterpret_cast<NamedDecl*>(Val)->getNameForDiagnostic(S,
+ Context.PrintingPolicy,
+ Qualified);
+ } else if (Kind == Diagnostic::ak_nestednamespec) {
+ llvm::raw_string_ostream OS(S);
+ reinterpret_cast<NestedNameSpecifier*> (Val)->print(OS,
+ Context.PrintingPolicy);
+ NeedQuotes = false;
+ } else {
+ assert(Kind == Diagnostic::ak_declcontext);
+ DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
+ NeedQuotes = false;
+ if (!DC) {
+ assert(false && "Should never have a null declaration context");
+ S = "unknown context";
+ } else if (DC->isTranslationUnit()) {
+ // FIXME: Get these strings from some localized place
+ if (Context.getLangOptions().CPlusPlus)
+ S = "the global namespace";
+ else
+ S = "the global scope";
+ } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
+ S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type));
+ NeedQuotes = false;
+ } else {
+ // FIXME: Get these strings from some localized place
+ NamedDecl *ND = cast<NamedDecl>(DC);
+ if (isa<NamespaceDecl>(ND))
+ S += "namespace ";
+ else if (isa<ObjCMethodDecl>(ND))
+ S += "method ";
+ else if (isa<FunctionDecl>(ND))
+ S += "function ";
+
+ S += "'";
+ ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
+ S += "'";
+ NeedQuotes = false;
}
}
+
+ if (NeedQuotes)
+ Output.push_back('\'');
- Output.push_back('\'');
Output.append(S.begin(), S.end());
- Output.push_back('\'');
+
+ if (NeedQuotes)
+ Output.push_back('\'');
}
static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
if (C.getLangOptions().CPlusPlus)
- return CXXRecordDecl::Create(C, TagDecl::TK_struct,
+ return CXXRecordDecl::Create(C, TagDecl::TK_struct,
C.getTranslationUnitDecl(),
SourceLocation(), &C.Idents.get(Name));
- return RecordDecl::Create(C, TagDecl::TK_struct,
+ return RecordDecl::Create(C, TagDecl::TK_struct,
C.getTranslationUnitDecl(),
SourceLocation(), &C.Idents.get(Name));
}
@@ -109,7 +175,7 @@ static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
TUScope = S;
PushDeclContext(S, Context.getTranslationUnitDecl());
-
+
if (PP.getTargetInfo().getPointerWidth(0) >= 64) {
// Install [u]int128_t for 64-bit targets.
PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
@@ -121,16 +187,16 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
&Context.Idents.get("__uint128_t"),
Context.UnsignedInt128Ty), TUScope);
}
-
-
+
+
if (!PP.getLangOptions().ObjC1) return;
-
+
// Built-in ObjC types may already be set by PCHReader (hence isNull checks).
if (Context.getObjCSelType().isNull()) {
// Synthesize "typedef struct objc_selector *SEL;"
RecordDecl *SelTag = CreateStructDecl(Context, "objc_selector");
PushOnScopeChains(SelTag, TUScope);
-
+
QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag));
TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext,
SourceLocation(),
@@ -140,74 +206,72 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
Context.setObjCSelType(Context.getTypeDeclType(SelTypedef));
}
- if (Context.getObjCClassType().isNull()) {
- RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class");
- QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag));
- TypedefDecl *ClassTypedef =
- TypedefDecl::Create(Context, CurContext, SourceLocation(),
- &Context.Idents.get("Class"), ClassT);
- PushOnScopeChains(ClassTag, TUScope);
- PushOnScopeChains(ClassTypedef, TUScope);
- Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
- }
-
// Synthesize "@class Protocol;
if (Context.getObjCProtoType().isNull()) {
ObjCInterfaceDecl *ProtocolDecl =
ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
- &Context.Idents.get("Protocol"),
+ &Context.Idents.get("Protocol"),
SourceLocation(), true);
Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
PushOnScopeChains(ProtocolDecl, TUScope);
}
-
- // Synthesize "typedef struct objc_object { Class isa; } *id;"
+ // Create the built-in typedef for 'id'.
if (Context.getObjCIdType().isNull()) {
- RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object");
-
- QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag));
- PushOnScopeChains(ObjectTag, TUScope);
- TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext,
- SourceLocation(),
- &Context.Idents.get("id"),
- ObjT);
+ TypedefDecl *IdTypedef =
+ TypedefDecl::Create(
+ Context, CurContext, SourceLocation(), &Context.Idents.get("id"),
+ Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy)
+ );
PushOnScopeChains(IdTypedef, TUScope);
Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
+ Context.ObjCIdRedefinitionType = Context.getObjCIdType();
+ }
+ // Create the built-in typedef for 'Class'.
+ if (Context.getObjCClassType().isNull()) {
+ TypedefDecl *ClassTypedef =
+ TypedefDecl::Create(
+ Context, CurContext, SourceLocation(), &Context.Idents.get("Class"),
+ Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy)
+ );
+ PushOnScopeChains(ClassTypedef, TUScope);
+ Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
+ Context.ObjCClassRedefinitionType = Context.getObjCClassType();
}
}
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
bool CompleteTranslationUnit)
: LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
- Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
- ExternalSource(0), CurContext(0), PreDeclaratorDC(0),
- CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
+ Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
+ ExternalSource(0), CodeCompleter(0), CurContext(0),
+ PreDeclaratorDC(0), CurBlock(0), PackContext(0),
+ IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), CurrentInstantiationScope(0) {
-
- StdNamespace = 0;
+
TUScope = 0;
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
-
+
// Tell diagnostics how to render things from the AST library.
PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);
}
-/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
+/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
-void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) {
+void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
+ CastExpr::CastKind Kind, bool isLvalue) {
QualType ExprTy = Context.getCanonicalType(Expr->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
-
+
if (ExprTy == TypeTy)
return;
-
+
if (Expr->getType().getTypePtr()->isPointerType() &&
Ty.getTypePtr()->isPointerType()) {
- QualType ExprBaseType =
+ QualType ExprBaseType =
cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType();
QualType BaseType =
cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType();
@@ -216,12 +280,16 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) {
<< Expr->getSourceRange();
}
}
-
+
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
- ImpCast->setType(Ty);
- ImpCast->setLvalueCast(isLvalue);
- } else
- Expr = new (Context) ImplicitCastExpr(Ty, Expr, isLvalue);
+ if (ImpCast->getCastKind() == Kind) {
+ ImpCast->setType(Ty);
+ ImpCast->setLvalueCast(isLvalue);
+ return;
+ }
+ }
+
+ Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue);
}
void Sema::DeleteExpr(ExprTy *E) {
@@ -241,12 +309,24 @@ void Sema::ActOnEndOfTranslationUnit() {
// keep track of the point of instantiation (C++ [temp.point]). This means
// that name lookup that occurs within the template instantiation will
// always happen at the end of the translation unit, so it will find
- // some names that should not be found. Although this is common behavior
+ // some names that should not be found. Although this is common behavior
// for C++ compilers, it is technically wrong. In the future, we either need
// to be able to filter the results of name lookup or we need to perform
// template instantiations earlier.
PerformPendingImplicitInstantiations();
-
+
+ // Check for #pragma weak identifiers that were never declared
+ // FIXME: This will cause diagnostics to be emitted in a non-determinstic
+ // order! Iterating over a densemap like this is bad.
+ for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator
+ I = WeakUndeclaredIdentifiers.begin(),
+ E = WeakUndeclaredIdentifiers.end(); I != E; ++I) {
+ if (I->second.getUsed()) continue;
+
+ Diag(I->second.getLocation(), diag::warn_weak_identifier_undeclared)
+ << I->first;
+ }
+
if (!CompleteTranslationUnit)
return;
@@ -261,32 +341,31 @@ void Sema::ActOnEndOfTranslationUnit() {
// translation unit contains a file scope declaration of that
// identifier, with the composite type as of the end of the
// translation unit, with an initializer equal to 0.
- for (llvm::DenseMap<DeclarationName, VarDecl *>::iterator
- D = TentativeDefinitions.begin(),
- DEnd = TentativeDefinitions.end();
- D != DEnd; ++D) {
- VarDecl *VD = D->second;
+ for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) {
+ VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]);
- if (VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
+ // If the tentative definition was completed, it will be in the list, but
+ // not the map.
+ if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
continue;
- if (const IncompleteArrayType *ArrayT
+ if (const IncompleteArrayType *ArrayT
= Context.getAsIncompleteArrayType(VD->getType())) {
- if (RequireCompleteType(VD->getLocation(),
+ if (RequireCompleteType(VD->getLocation(),
ArrayT->getElementType(),
- diag::err_tentative_def_incomplete_type_arr))
+ diag::err_tentative_def_incomplete_type_arr)) {
VD->setInvalidDecl();
- else {
- // Set the length of the array to 1 (C99 6.9.2p5).
- Diag(VD->getLocation(), diag::warn_tentative_incomplete_array);
- llvm::APInt One(Context.getTypeSize(Context.getSizeType()),
- true);
- QualType T
- = Context.getConstantArrayType(ArrayT->getElementType(),
- One, ArrayType::Normal, 0);
- VD->setType(T);
+ continue;
}
- } else if (RequireCompleteType(VD->getLocation(), VD->getType(),
+
+ // Set the length of the array to 1 (C99 6.9.2p5).
+ Diag(VD->getLocation(), diag::warn_tentative_incomplete_array);
+ llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true);
+ QualType T
+ = Context.getConstantArrayWithoutExprType(ArrayT->getElementType(),
+ One, ArrayType::Normal, 0);
+ VD->setType(T);
+ } else if (RequireCompleteType(VD->getLocation(), VD->getType(),
diag::err_tentative_def_incomplete_type))
VD->setInvalidDecl();
@@ -302,27 +381,30 @@ void Sema::ActOnEndOfTranslationUnit() {
// Helper functions.
//===----------------------------------------------------------------------===//
+DeclContext *Sema::getFunctionLevelDeclContext() {
+ DeclContext *DC = PreDeclaratorDC ? PreDeclaratorDC : CurContext;
+
+ while (isa<BlockDecl>(DC))
+ DC = DC->getParent();
+
+ return DC;
+}
+
/// getCurFunctionDecl - If inside of a function body, this returns a pointer
/// to the function decl for the function being parsed. If we're currently
/// in a 'block', this returns the containing context.
FunctionDecl *Sema::getCurFunctionDecl() {
- DeclContext *DC = CurContext;
- while (isa<BlockDecl>(DC))
- DC = DC->getParent();
+ DeclContext *DC = getFunctionLevelDeclContext();
return dyn_cast<FunctionDecl>(DC);
}
ObjCMethodDecl *Sema::getCurMethodDecl() {
- DeclContext *DC = CurContext;
- while (isa<BlockDecl>(DC))
- DC = DC->getParent();
+ DeclContext *DC = getFunctionLevelDeclContext();
return dyn_cast<ObjCMethodDecl>(DC);
}
NamedDecl *Sema::getCurFunctionOrMethodDecl() {
- DeclContext *DC = CurContext;
- while (isa<BlockDecl>(DC))
- DC = DC->getParent();
+ DeclContext *DC = getFunctionLevelDeclContext();
if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC))
return cast<NamedDecl>(DC);
return 0;
@@ -331,21 +413,30 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() {
Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
if (!this->Emit())
return;
-
+
// If this is not a note, and we're in a template instantiation
// that is different from the last template instantiation where
// we emitted an error, print a template instantiation
// backtrace.
if (!SemaRef.Diags.isBuiltinNote(DiagID) &&
!SemaRef.ActiveTemplateInstantiations.empty() &&
- SemaRef.ActiveTemplateInstantiations.back()
+ SemaRef.ActiveTemplateInstantiations.back()
!= SemaRef.LastTemplateInstantiationErrorContext) {
SemaRef.PrintInstantiationStack();
- SemaRef.LastTemplateInstantiationErrorContext
+ SemaRef.LastTemplateInstantiationErrorContext
= SemaRef.ActiveTemplateInstantiations.back();
}
}
+Sema::SemaDiagnosticBuilder
+Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
+ SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID()));
+ PD.Emit(Builder);
+
+ return Builder;
+}
+
void Sema::ActOnComment(SourceRange Comment) {
Context.Comments.push_back(Comment);
}
+
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 7af80c0261e4d..80f366302171b 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -18,6 +18,7 @@
#include "IdentifierResolver.h"
#include "CXXFieldCollector.h"
#include "SemaOverload.h"
+#include "SemaTemplate.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Decl.h"
@@ -41,6 +42,7 @@ namespace llvm {
namespace clang {
class ASTContext;
class ASTConsumer;
+ class CodeCompleteConsumer;
class Preprocessor;
class Decl;
class DeclContext;
@@ -50,6 +52,7 @@ namespace clang {
class Stmt;
class Expr;
class InitListExpr;
+ class ParenListExpr;
class DesignatedInitExpr;
class CallExpr;
class DeclRefExpr;
@@ -87,8 +90,7 @@ namespace clang {
class ObjCPropertyDecl;
class ObjCContainerDecl;
class FunctionProtoType;
- class BasePaths;
- struct MemberLookupCriteria;
+ class CXXBasePaths;
class CXXTemporary;
/// BlockSemaInfo - When a block is being parsed, this contains information
@@ -98,35 +100,69 @@ struct BlockSemaInfo {
bool hasPrototype;
bool isVariadic;
bool hasBlockDeclRefExprs;
-
+
BlockDecl *TheDecl;
-
+
/// TheScope - This is the scope for the block itself, which contains
/// arguments etc.
Scope *TheScope;
-
+
/// ReturnType - This will get set to block result type, by looking at
/// return types, if any, in the block body.
QualType ReturnType;
-
+
/// LabelMap - This is a mapping from label identifiers to the LabelStmt for
/// it (which acts like the label decl in some ways). Forward referenced
/// labels have a LabelStmt created for them with a null location & SubStmt.
llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap;
-
+
/// SwitchStack - This is the current set of active switch statements in the
/// block.
llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
-
+
/// SavedFunctionNeedsScopeChecking - This is the value of
/// CurFunctionNeedsScopeChecking at the point when the block started.
bool SavedFunctionNeedsScopeChecking;
-
+
/// PrevBlockInfo - If this is nested inside another block, this points
/// to the outer block.
BlockSemaInfo *PrevBlockInfo;
};
+/// \brief Holds a QualType and a DeclaratorInfo* that came out of a declarator
+/// parsing.
+///
+/// LocInfoType is a "transient" type, only needed for passing to/from Parser
+/// and Sema, when we want to preserve type source info for a parsed type.
+/// It will not participate in the type system semantics in any way.
+class LocInfoType : public Type {
+ enum {
+ // The last number that can fit in Type's TC.
+ // Avoids conflict with an existing Type class.
+ LocInfo = (1 << TypeClassBitSize) - 1
+ };
+
+ DeclaratorInfo *DeclInfo;
+
+ LocInfoType(QualType ty, DeclaratorInfo *DInfo)
+ : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(DInfo) {
+ assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?");
+ }
+ friend class Sema;
+
+public:
+ QualType getType() const { return getCanonicalTypeInternal(); }
+ DeclaratorInfo *getDeclaratorInfo() const { return DeclInfo; }
+
+ virtual void getAsStringInternal(std::string &Str,
+ const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == (TypeClass)LocInfo;
+ }
+ static bool classof(const LocInfoType *) { return true; }
+};
+
/// Sema - This implements semantic analysis and AST building for C.
class Sema : public Action {
Sema(const Sema&); // DO NOT IMPLEMENT
@@ -142,6 +178,9 @@ public:
/// \brief Source of additional semantic information.
ExternalSemaSource *ExternalSource;
+ /// \brief Code-completion consumer.
+ CodeCompleteConsumer *CodeCompleter;
+
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;
@@ -165,13 +204,13 @@ public:
/// Note that this should always be accessed through getLabelMap() in order
/// to handle blocks properly.
llvm::DenseMap<IdentifierInfo*, LabelStmt*> FunctionLabelMap;
-
+
/// FunctionSwitchStack - This is the current set of active switch statements
/// in the top level function. Clients should always use getSwitchStack() to
/// handle the case when they are in a block.
llvm::SmallVector<SwitchStmt*, 8> FunctionSwitchStack;
- /// ExprTemporaries - This is the stack of temporaries that are created by
+ /// ExprTemporaries - This is the stack of temporaries that are created by
/// the current full expression.
llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries;
@@ -180,26 +219,22 @@ public:
/// scopes that need to be checked for goto conditions. If a function does
/// not contain this, then it need not have the jump checker run on it.
bool CurFunctionNeedsScopeChecking;
-
+
/// ExtVectorDecls - This is a list all the extended vector types. This allows
/// us to associate a raw vector type with one of the ext_vector type names.
/// This is only necessary for issuing pretty diagnostics.
llvm::SmallVector<TypedefDecl*, 24> ExtVectorDecls;
- /// ObjCCategoryImpls - Maintain a list of category implementations so
- /// we can check for duplicates and find local method declarations.
- llvm::SmallVector<ObjCCategoryImplDecl*, 8> ObjCCategoryImpls;
-
/// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
llvm::OwningPtr<CXXFieldCollector> FieldCollector;
typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy;
-
- /// PureVirtualClassDiagSet - a set of class declarations which we have
+
+ /// PureVirtualClassDiagSet - a set of class declarations which we have
/// emitted a list of pure virtual functions. Used to prevent emitting the
/// same list more than once.
llvm::OwningPtr<RecordDeclSetTy> PureVirtualClassDiagSet;
-
+
/// \brief A mapping from external names to the most recent
/// locally-scoped external declaration with that name.
///
@@ -234,6 +269,37 @@ public:
/// declaration, and only the most recent tentative declaration for
/// a given variable will be recorded here.
llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions;
+ std::vector<DeclarationName> TentativeDefinitionList;
+
+ /// WeakUndeclaredIdentifiers - Identifiers contained in
+ /// #pragma weak before declared. rare. may alias another
+ /// identifier, declared or undeclared
+ class WeakInfo {
+ IdentifierInfo *alias; // alias (optional)
+ SourceLocation loc; // for diagnostics
+ bool used; // identifier later declared?
+ public:
+ WeakInfo()
+ : alias(0), loc(SourceLocation()), used(false) {}
+ WeakInfo(IdentifierInfo *Alias, SourceLocation Loc)
+ : alias(Alias), loc(Loc), used(false) {}
+ inline IdentifierInfo * getAlias() const { return alias; }
+ inline SourceLocation getLocation() const { return loc; }
+ void setUsed(bool Used=true) { used = Used; }
+ inline bool getUsed() { return used; }
+ bool operator==(WeakInfo RHS) const {
+ return alias == RHS.getAlias() && loc == RHS.getLocation();
+ }
+ bool operator!=(WeakInfo RHS) const { return !(*this == RHS); }
+ };
+ llvm::DenseMap<IdentifierInfo*,WeakInfo> WeakUndeclaredIdentifiers;
+
+ /// WeakTopLevelDecl - Translation-unit scoped declarations generated by
+ /// #pragma weak during processing of other Decls.
+ /// I couldn't figure out a clean way to generate these in-line, so
+ /// we store them here and handle separately -- which is a hack.
+ /// It would be best to refactor this.
+ llvm::SmallVector<Decl*,2> WeakTopLevelDecl;
IdentifierResolver IdResolver;
@@ -242,27 +308,30 @@ public:
/// For example, user-defined classes, built-in "id" type, etc.
Scope *TUScope;
- /// The C++ "std" namespace, where the standard library resides. Cached here
- /// by GetStdNamespace
+ /// \brief The C++ "std" namespace, where the standard library resides.
NamespaceDecl *StdNamespace;
+ /// \brief The C++ "std::bad_alloc" class, which is defined by the C++
+ /// standard library.
+ CXXRecordDecl *StdBadAlloc;
+
/// A flag to remember whether the implicit forms of operator new and delete
/// have been declared.
bool GlobalNewDeleteDeclared;
/// The current expression evaluation context.
ExpressionEvaluationContext ExprEvalContext;
-
- typedef std::vector<std::pair<SourceLocation, Decl *> >
+
+ typedef std::vector<std::pair<SourceLocation, Decl *> >
PotentiallyReferencedDecls;
-
+
/// A stack of declarations, each element of which is a set of declarations
/// that will be marked as referenced if the corresponding potentially
/// potentially evaluated expression is potentially evaluated. Each element
/// in the stack corresponds to a PotentiallyPotentiallyEvaluated expression
/// evaluation context.
std::list<PotentiallyReferencedDecls> PotentiallyReferencedDeclStack;
-
+
/// \brief Whether the code handled by Sema should be considered a
/// complete translation unit or not.
///
@@ -274,6 +343,8 @@ public:
/// unit.
bool CompleteTranslationUnit;
+ llvm::BumpPtrAllocator BumpAlloc;
+
/// \brief The number of SFINAE diagnostics that have been trapped.
unsigned NumSFINAEErrors;
@@ -281,11 +352,11 @@ public:
/// Instance/Factory Method Pools - allows efficient lookup when typechecking
/// messages to "id". We need to maintain a list, since selectors can have
- /// differing signatures across classes. In Cocoa, this happens to be
+ /// differing signatures across classes. In Cocoa, this happens to be
/// extremely uncommon (only 1% of selectors are "overloaded").
MethodPool InstanceMethodPool;
MethodPool FactoryMethodPool;
-
+
MethodPool::iterator ReadMethodPool(Selector Sel, bool isInstance);
/// Private Helper predicate to check for 'self'.
@@ -296,7 +367,7 @@ public:
~Sema() {
if (PackContext) FreePackedContext();
}
-
+
const LangOptions &getLangOptions() const { return LangOpts; }
Diagnostic &getDiagnostics() const { return Diags; }
SourceManager &getSourceManager() const { return SourceMgr; }
@@ -318,7 +389,7 @@ public:
SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
: DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { }
- explicit SemaDiagnosticBuilder(Sema &SemaRef)
+ explicit SemaDiagnosticBuilder(Sema &SemaRef)
: DiagnosticBuilder(DiagnosticBuilder::Suppress), SemaRef(SemaRef) { }
~SemaDiagnosticBuilder();
@@ -331,6 +402,7 @@ public:
// deduction, and that error is one of the SFINAE errors,
// suppress the diagnostic.
++NumSFINAEErrors;
+ Diags.setLastDiagnosticIgnored();
return SemaDiagnosticBuilder(*this);
}
@@ -338,6 +410,9 @@ public:
return SemaDiagnosticBuilder(DB, *this, DiagID);
}
+ /// \brief Emit a partial diagnostic.
+ SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD);
+
virtual void DeleteExpr(ExprTy *E);
virtual void DeleteStmt(StmtTy *S);
@@ -356,13 +431,16 @@ public:
llvm::DenseMap<IdentifierInfo*, LabelStmt*> &getLabelMap() {
return CurBlock ? CurBlock->LabelMap : FunctionLabelMap;
}
-
+
/// getSwitchStack - This is returns the switch stack for the current block or
/// function.
llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() {
return CurBlock ? CurBlock->SwitchStack : FunctionSwitchStack;
}
-
+
+ /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls
+ llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
+
virtual void ActOnComment(SourceRange Comment);
//===--------------------------------------------------------------------===//
@@ -370,34 +448,51 @@ public:
//
QualType adjustParameterType(QualType T);
QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc,
- bool &IsInvalid);
+ bool &IsInvalid, QualType &SourceTy);
void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
- QualType BuildPointerType(QualType T, unsigned Quals,
+ QualType BuildPointerType(QualType T, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
Expr *ArraySize, unsigned Quals,
- SourceLocation Loc, DeclarationName Entity);
- QualType BuildExtVectorType(QualType T, ExprArg ArraySize,
+ SourceRange Brackets, DeclarationName Entity);
+ QualType BuildExtVectorType(QualType T, ExprArg ArraySize,
SourceLocation AttrLoc);
QualType BuildFunctionType(QualType T,
QualType *ParamTypes, unsigned NumParamTypes,
bool Variadic, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
- QualType BuildMemberPointerType(QualType T, QualType Class,
- unsigned Quals, SourceLocation Loc,
+ QualType BuildMemberPointerType(QualType T, QualType Class,
+ unsigned Quals, SourceLocation Loc,
DeclarationName Entity);
QualType BuildBlockPointerType(QualType T, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
- QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0,
- TagDecl **OwnedDecl = 0);
+ QualType GetTypeForDeclarator(Declarator &D, Scope *S,
+ DeclaratorInfo **DInfo = 0,
+ unsigned Skip = 0, TagDecl **OwnedDecl = 0);
+ DeclaratorInfo *GetDeclaratorInfoForDeclarator(Declarator &D, QualType T,
+ unsigned Skip);
+ /// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo.
+ QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo);
DeclarationName GetNameForDeclarator(Declarator &D);
+ static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0);
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
bool CheckDistantExceptionSpec(QualType T);
bool CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc);
+ bool CheckEquivalentExceptionSpec(
+ const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Old, SourceLocation OldLoc,
+ const FunctionProtoType *New, SourceLocation NewLoc);
+ bool CheckExceptionSpecSubset(
+ const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Superset, SourceLocation SuperLoc,
+ const FunctionProtoType *Subset, SourceLocation SubLoc);
+ bool CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Target, SourceLocation TargetLoc,
+ const FunctionProtoType *Source, SourceLocation SourceLoc);
QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
@@ -405,72 +500,87 @@ public:
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
- bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
- SourceRange Range1 = SourceRange(),
- SourceRange Range2 = SourceRange(),
- QualType PrintType = QualType());
+ bool RequireCompleteType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ std::pair<SourceLocation,
+ PartialDiagnostic> Note =
+ std::make_pair(SourceLocation(), PDiag()));
QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T);
QualType BuildTypeofExprType(Expr *E);
QualType BuildDecltypeType(Expr *E);
-
+
//===--------------------------------------------------------------------===//
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
//
/// getDeclName - Return a pretty name for the specified decl if possible, or
- /// an empty string if not. This is used for pretty crash reporting.
+ /// an empty string if not. This is used for pretty crash reporting.
virtual std::string getDeclName(DeclPtrTy D);
-
+
DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr);
- virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec *SS);
+ virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
+ Scope *S, const CXXScopeSpec *SS,
+ bool isClassName = false);
virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S);
+ virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TypeTy *&SuggestedType);
virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
}
-
- DeclPtrTy HandleDeclarator(Scope *S, Declarator &D,
+
+ DeclPtrTy HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
bool IsFunctionDefinition);
void RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl,
Scope *S);
void DiagnoseFunctionSpecifiers(Declarator& D);
NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, Decl* PrevDecl,
- bool &Redeclaration);
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl, bool &Redeclaration);
NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, NamedDecl* PrevDecl,
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl,
+ MultiTemplateParamsArg TemplateParamLists,
bool &Redeclaration);
void CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
bool &Redeclaration);
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, NamedDecl* PrevDecl,
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition,
bool &Redeclaration);
void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
- bool &Redeclaration,
+ bool IsExplicitSpecialization,
+ bool &Redeclaration,
bool &OverloadableAttrRequired);
+ void CheckMain(FunctionDecl *FD);
virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D);
virtual void ActOnParamDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
ExprArg defarg);
- virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
+ virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
SourceLocation ArgLoc);
virtual void ActOnParamDefaultArgumentError(DeclPtrTy param);
-
+ bool SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg,
+ SourceLocation EqualLoc);
+
+
// Contains the locations of the beginning of unparsed default
// argument locations.
llvm::DenseMap<ParmVarDecl *,SourceLocation> UnparsedDefaultArgLocs;
- virtual void AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init);
+ virtual void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init);
void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit);
- void ActOnUninitializedDecl(DeclPtrTy dcl);
+ void ActOnUninitializedDecl(DeclPtrTy dcl, bool TypeContainsUndeducedAuto);
virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc);
virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
DeclPtrTy *Group,
@@ -484,19 +594,19 @@ public:
virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body);
DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body,
bool IsInstantiation);
-
+
/// \brief Diagnose any unused parameters in the given sequence of
/// ParmVarDecl pointers.
template<typename InputIterator>
void DiagnoseUnusedParameters(InputIterator Param, InputIterator ParamEnd) {
for (; Param != ParamEnd; ++Param) {
- if (!(*Param)->isUsed() && (*Param)->getDeclName() &&
+ if (!(*Param)->isUsed() && (*Param)->getDeclName() &&
!(*Param)->template hasAttr<UnusedAttr>())
Diag((*Param)->getLocation(), diag::warn_unused_parameter)
<< (*Param)->getDeclName();
}
}
-
+
void DiagnoseInvalidJumps(Stmt *Body);
virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc, ExprArg expr);
@@ -507,23 +617,32 @@ public:
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS);
-
+
bool InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
RecordDecl *AnonRecord);
- virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
+ virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
RecordDecl *Record);
- bool isAcceptableTagRedeclaration(const TagDecl *Previous,
+ bool isAcceptableTagRedeclaration(const TagDecl *Previous,
TagDecl::TagKind NewTag,
SourceLocation NewTagLoc,
const IdentifierInfo &Name);
- virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
+ virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
- bool &OwnedDecl);
-
+ MultiTemplateParamsArg TemplateParameterLists,
+ bool &OwnedDecl, bool &IsDependent);
+
+ virtual TypeResult ActOnDependentTag(Scope *S,
+ unsigned TagSpec,
+ TagUseKind TUK,
+ const CXXScopeSpec &SS,
+ IdentifierInfo *Name,
+ SourceLocation TagLoc,
+ SourceLocation NameLoc);
+
virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
IdentifierInfo *ClassName,
llvm::SmallVectorImpl<DeclPtrTy> &Decls);
@@ -535,12 +654,22 @@ public:
Declarator &D, Expr *BitfieldWidth,
AccessSpecifier AS);
- FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T,
+ FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T,
+ DeclaratorInfo *DInfo,
RecordDecl *Record, SourceLocation Loc,
bool Mutable, Expr *BitfieldWidth,
+ SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D = 0);
-
+
+ enum CXXSpecialMember {
+ CXXDefaultConstructor = 0,
+ CXXCopyConstructor = 1,
+ CXXCopyAssignment = 2,
+ CXXDestructor = 3
+ };
+ void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
+
virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
DeclPtrTy IntfDecl,
Declarator &D, ExprTy *BitfieldWidth,
@@ -560,7 +689,8 @@ public:
/// ActOnTagFinishDefinition - Invoked once we have finished parsing
/// the definition of a tag (enumeration, class, struct, or union).
- virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl);
+ virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
+ SourceLocation RBraceLoc);
EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum,
EnumConstantDecl *LastEnumConst,
@@ -574,25 +704,27 @@ public:
SourceLocation EqualLoc, ExprTy *Val);
virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, DeclPtrTy EnumDecl,
- DeclPtrTy *Elements, unsigned NumElements);
+ DeclPtrTy *Elements, unsigned NumElements,
+ Scope *S, AttributeList *Attr);
DeclContext *getContainingDC(DeclContext *DC);
/// Set the current declaration context until it gets popped.
void PushDeclContext(Scope *S, DeclContext *DC);
void PopDeclContext();
-
+
/// EnterDeclaratorContext - Used when we must lookup names in the context
/// of a declarator's nested name specifier.
void EnterDeclaratorContext(Scope *S, DeclContext *DC);
void ExitDeclaratorContext(Scope *S);
-
-
+
+ DeclContext *getFunctionLevelDeclContext();
+
/// getCurFunctionDecl - If inside of a function body, this returns a pointer
/// to the function decl for the function being parsed. If we're currently
/// in a 'block', this returns the containing context.
FunctionDecl *getCurFunctionDecl();
-
+
/// getCurMethodDecl - If inside of a method body, this returns a pointer to
/// the method decl for the method being parsed. If we're currently
/// in a 'block', this returns the containing context.
@@ -604,15 +736,35 @@ public:
NamedDecl *getCurFunctionOrMethodDecl();
/// Add this decl to the scope shadowed decl chains.
- void PushOnScopeChains(NamedDecl *D, Scope *S);
+ void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true);
/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
- bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0) {
- return IdResolver.isDeclInScope(D, Ctx, Context, S);
+ bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0);
+
+ /// Finds the scope corresponding to the given decl context, if it
+ /// happens to be an enclosing scope. Otherwise return NULL.
+ Scope *getScopeForDeclContext(Scope *S, DeclContext *DC) {
+ DeclContext *TargetDC = DC->getPrimaryContext();
+ do {
+ if (DeclContext *ScopeDC = (DeclContext*) S->getEntity())
+ if (ScopeDC->getPrimaryContext() == TargetDC)
+ return S;
+ } while ((S = S->getParent()));
+
+ return NULL;
}
+ /// OverloadingResult - Capture the result of performing overload
+ /// resolution.
+ enum OverloadingResult {
+ OR_Success, ///< Overload resolution succeeded.
+ OR_No_Viable_Function, ///< No viable function found.
+ OR_Ambiguous, ///< Ambiguous candidates found.
+ OR_Deleted ///< Overload resoltuion refers to a deleted function.
+ };
+
/// Subroutines of ActOnDeclarator().
TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T);
@@ -623,41 +775,52 @@ public:
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
/// C++ Overloading.
- bool IsOverload(FunctionDecl *New, Decl* OldD,
+ bool IsOverload(FunctionDecl *New, Decl* OldD,
OverloadedFunctionDecl::function_iterator &MatchedDecl);
- ImplicitConversionSequence
+ ImplicitConversionSequence
TryImplicitConversion(Expr* From, QualType ToType,
- bool SuppressUserConversions = false,
- bool AllowExplicit = false,
- bool ForceRValue = false);
- bool IsStandardConversion(Expr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool AllowExplicit,
+ bool ForceRValue,
+ bool InOverloadResolution,
+ bool UserCast = false);
+ bool IsStandardConversion(Expr *From, QualType ToType,
+ bool InOverloadResolution,
StandardConversionSequence& SCS);
bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
bool IsComplexPromotion(QualType FromType, QualType ToType);
bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
+ bool InOverloadResolution,
QualType& ConvertedType, bool &IncompatibleObjC);
bool isObjCPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType, bool &IncompatibleObjC);
- bool CheckPointerConversion(Expr *From, QualType ToType);
+ bool CheckPointerConversion(Expr *From, QualType ToType,
+ CastExpr::CastKind &Kind);
bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
+ bool InOverloadResolution,
QualType &ConvertedType);
- bool CheckMemberPointerConversion(Expr *From, QualType ToType);
+ bool CheckMemberPointerConversion(Expr *From, QualType ToType,
+ CastExpr::CastKind &Kind);
bool IsQualificationConversion(QualType FromType, QualType ToType);
- bool IsUserDefinedConversion(Expr *From, QualType ToType,
+ OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
+ OverloadCandidateSet& Conversions,
bool AllowConversionFunctions,
- bool AllowExplicit, bool ForceRValue);
+ bool AllowExplicit, bool ForceRValue,
+ bool UserCast = false);
+ bool DiagnoseAmbiguousUserDefinedConversion(Expr *From, QualType ToType);
+
- ImplicitConversionSequence::CompareKind
+ ImplicitConversionSequence::CompareKind
CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
const ImplicitConversionSequence& ICS2);
- ImplicitConversionSequence::CompareKind
+ ImplicitConversionSequence::CompareKind
CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
- ImplicitConversionSequence::CompareKind
+ ImplicitConversionSequence::CompareKind
CompareQualificationConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
@@ -665,11 +828,11 @@ public:
CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
- ImplicitConversionSequence
+ ImplicitConversionSequence
TryCopyInitialization(Expr* From, QualType ToType,
- bool SuppressUserConversions = false,
- bool ForceRValue = false);
- bool PerformCopyInitialization(Expr *&From, QualType ToType,
+ bool SuppressUserConversions, bool ForceRValue,
+ bool InOverloadResolution);
+ bool PerformCopyInitialization(Expr *&From, QualType ToType,
const char *Flavor, bool Elidable = false);
ImplicitConversionSequence
@@ -679,24 +842,21 @@ public:
ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
bool PerformContextuallyConvertToBool(Expr *&From);
- /// OverloadingResult - Capture the result of performing overload
- /// resolution.
- enum OverloadingResult {
- OR_Success, ///< Overload resolution succeeded.
- OR_No_Viable_Function, ///< No viable function found.
- OR_Ambiguous, ///< Ambiguous candidates found.
- OR_Deleted ///< Overload resoltuion refers to a deleted function.
- };
+ bool PerformObjectMemberConversion(Expr *&From, NamedDecl *Member);
+
+ // Members have to be NamespaceDecl* or TranslationUnitDecl*.
+ // TODO: make this is a typesafe union.
+ typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet;
typedef llvm::SmallPtrSet<AnyFunctionDecl, 16> FunctionSet;
- typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet;
typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
- void AddOverloadCandidate(FunctionDecl *Function,
+ void AddOverloadCandidate(FunctionDecl *Function,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
- bool ForceRValue = false);
+ bool ForceRValue = false,
+ bool PartialOverloading = false);
void AddFunctionCandidates(const FunctionSet &Functions,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -706,6 +866,14 @@ public:
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
+ void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ Expr *Object, Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions = false,
+ bool ForceRValue = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
@@ -717,6 +885,9 @@ public:
void AddConversionCandidate(CXXConversionDecl *Conversion,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet);
+ void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ Expr *From, QualType ToType,
+ OverloadCandidateSet &CandidateSet);
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
const FunctionProtoType *Proto,
Expr *Object, Expr **Args, unsigned NumArgs,
@@ -731,29 +902,45 @@ public:
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange = SourceRange());
- void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
+ void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool IsAssignmentOperator = false,
unsigned NumContextualBoolArguments = 0);
- void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
- Expr **Args, unsigned NumArgs,
+ void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
void AddArgumentDependentLookupCandidates(DeclarationName Name,
Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet);
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool PartialOverloading = false);
bool isBetterOverloadCandidate(const OverloadCandidate& Cand1,
const OverloadCandidate& Cand2);
OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
SourceLocation Loc,
OverloadCandidateSet::iterator& Best);
void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
- bool OnlyViable);
-
+ bool OnlyViable,
+ const char *Opc=0,
+ SourceLocation Loc=SourceLocation());
+
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain);
void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
+ void AddOverloadedCallCandidates(NamedDecl *Callee,
+ DeclarationName &UnqualifiedName,
+ bool &ArgumentDependentLookup,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet,
+ bool PartialOverloading = false);
+
FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
DeclarationName UnqualifiedName,
bool HasExplicitTemplateArgs,
@@ -761,7 +948,7 @@ public:
unsigned NumExplicitTemplateArgs,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
- SourceLocation *CommaLocs,
+ SourceLocation *CommaLocs,
SourceLocation RParenLoc,
bool &ArgumentDependentLookup);
@@ -777,23 +964,33 @@ public:
ExprResult
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
- SourceLocation LParenLoc, Expr **Args,
+ SourceLocation LParenLoc, Expr **Args,
unsigned NumArgs, SourceLocation *CommaLocs,
SourceLocation RParenLoc);
- ExprResult
+ ExprResult
BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
- SourceLocation *CommaLocs,
+ SourceLocation *CommaLocs,
SourceLocation RParenLoc);
- ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
- SourceLocation MemberLoc,
- IdentifierInfo &Member);
-
- /// Helpers for dealing with function parameters.
+ OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc);
+
+ /// CheckCallReturnType - Checks that a call expression's return type is
+ /// complete. Returns true on failure. The location passed in is the location
+ /// that best represents the call.
+ bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
+ CallExpr *CE, FunctionDecl *FD);
+
+ /// Helpers for dealing with blocks and functions.
+ void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body);
+ void CheckFallThroughForBlock(QualType BlockTy, Stmt *Body);
bool CheckParmsForFunctionDef(FunctionDecl *FD);
void CheckCXXDefaultArguments(FunctionDecl *FD);
void CheckExtraCXXDefaultArguments(Declarator &D);
+ enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
+ AlwaysFallThrough = 2 };
+ ControlFlowKind CheckFallThrough(Stmt *);
Scope *getNonFieldDeclScope(Scope *S);
@@ -804,7 +1001,7 @@ public:
/// overloaded operator names, constructor names, etc.) into zero or
/// more declarations within a particular scope. The major entry
/// points are LookupName, which performs unqualified name lookup,
- /// and LookupQualifiedName, which performs qualified name lookup.
+ /// and LookupQualifiedName, which performs qualified name lookup.
///
/// All name lookup is performed based on some specific criteria,
/// which specify what names will be visible to name lookup and how
@@ -851,7 +1048,7 @@ public:
LookupNamespaceName,
/// Look up an ordinary name that is going to be redeclared as a
/// name with linkage. This lookup ignores any declarations that
- /// are outside of the current scope unless they have linkage. See
+ /// are outside of the current scope unless they have linkage. See
/// C99 6.2.2p4-5 and C++ [basic.link]p6.
LookupRedeclarationWithLinkage,
/// Look up the name of an Objective-C protocol.
@@ -868,66 +1065,16 @@ public:
/// single name lookup, which can return no result (nothing found),
/// a single declaration, a set of overloaded functions, or an
/// ambiguity. Use the getKind() method to determine which of these
- /// results occurred for a given lookup.
+ /// results occurred for a given lookup.
///
/// Any non-ambiguous lookup can be converted into a single
- /// (possibly NULL) @c NamedDecl* via a conversion function or the
- /// getAsDecl() method. This conversion permits the common-case
- /// usage in C and Objective-C where name lookup will always return
- /// a single declaration.
- struct LookupResult {
- /// The kind of entity that is actually stored within the
- /// LookupResult object.
- enum {
- /// First is a single declaration (a NamedDecl*), which may be NULL.
- SingleDecl,
-
- /// First is a single declaration (an OverloadedFunctionDecl*).
- OverloadedDeclSingleDecl,
-
- /// [First, Last) is an iterator range represented as opaque
- /// pointers used to reconstruct IdentifierResolver::iterators.
- OverloadedDeclFromIdResolver,
-
- /// [First, Last) is an iterator range represented as opaque
- /// pointers used to reconstruct DeclContext::lookup_iterators.
- OverloadedDeclFromDeclContext,
-
- /// First is a pointer to a BasePaths structure, which is owned
- /// by the LookupResult. Last is non-zero to indicate that the
- /// ambiguity is caused by two names found in base class
- /// subobjects of different types.
- AmbiguousLookupStoresBasePaths,
-
- /// [First, Last) is an iterator range represented as opaque
- /// pointers used to reconstruct new'ed Decl*[] array containing
- /// found ambiguous decls. LookupResult is owner of this array.
- AmbiguousLookupStoresDecls
- } StoredKind;
-
- /// The first lookup result, whose contents depend on the kind of
- /// lookup result. This may be a NamedDecl* (if StoredKind ==
- /// SingleDecl), OverloadedFunctionDecl* (if StoredKind ==
- /// OverloadedDeclSingleDecl), the opaque pointer from an
- /// IdentifierResolver::iterator (if StoredKind ==
- /// OverloadedDeclFromIdResolver), a DeclContext::lookup_iterator
- /// (if StoredKind == OverloadedDeclFromDeclContext), or a
- /// BasePaths pointer (if StoredKind == AmbiguousLookupStoresBasePaths).
- mutable uintptr_t First;
-
- /// The last lookup result, whose contents depend on the kind of
- /// lookup result. This may be unused (if StoredKind ==
- /// SingleDecl), it may have the same type as First (for
- /// overloaded function declarations), or is may be used as a
- /// Boolean value (if StoredKind == AmbiguousLookupStoresBasePaths).
- mutable uintptr_t Last;
-
- /// Context - The context in which we will build any
- /// OverloadedFunctionDecl nodes needed by the conversion to
- /// Decl*.
- ASTContext *Context;
-
- /// @brief The kind of entity found by name lookup.
+ /// (possibly NULL) @c NamedDecl* via the getAsSingleDecl() method.
+ /// This permits the common-case usage in C and Objective-C where
+ /// name lookup will always return a single declaration. Use of
+ /// this is largely deprecated; callers should handle the possibility
+ /// of multiple declarations.
+ class LookupResult {
+ public:
enum LookupKind {
/// @brief No entity found met the criteria.
NotFound = 0,
@@ -941,6 +1088,13 @@ public:
/// functions into an OverloadedFunctionDecl.
FoundOverloaded,
+ /// @brief Name lookup results in an ambiguity; use
+ /// getAmbiguityKind to figure out what kind of ambiguity
+ /// we have.
+ Ambiguous
+ };
+
+ enum AmbiguityKind {
/// Name lookup results in an ambiguity because multiple
/// entities that meet the lookup criteria were found in
/// subobjects of different types. For example:
@@ -948,7 +1102,7 @@ public:
/// struct A { void f(int); }
/// struct B { void f(double); }
/// struct C : A, B { };
- /// void test(C c) {
+ /// void test(C c) {
/// c.f(0); // error: A::f and B::f come from subobjects of different
/// // types. overload resolution is not performed.
/// }
@@ -982,125 +1136,178 @@ public:
/// }
/// }
/// @endcode
- AmbiguousReference
+ AmbiguousReference,
+
+ /// Name lookup results in an ambiguity because an entity with a
+ /// tag name was hidden by an entity with an ordinary name from
+ /// a different context.
+ /// @code
+ /// namespace A { struct Foo {}; }
+ /// namespace B { void Foo(); }
+ /// namespace C {
+ /// using namespace A;
+ /// using namespace B;
+ /// }
+ /// void test() {
+ /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a
+ /// // different namespace
+ /// }
+ /// @endcode
+ AmbiguousTagHiding
};
- static LookupResult CreateLookupResult(ASTContext &Context, NamedDecl *D);
+ typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy;
+ typedef DeclsTy::const_iterator iterator;
- static LookupResult CreateLookupResult(ASTContext &Context,
- IdentifierResolver::iterator F,
- IdentifierResolver::iterator L);
+ LookupResult()
+ : Kind(NotFound),
+ Paths(0)
+ {}
+ ~LookupResult() {
+ if (Paths) deletePaths(Paths);
+ }
- static LookupResult CreateLookupResult(ASTContext &Context,
- DeclContext::lookup_iterator F,
- DeclContext::lookup_iterator L);
+ bool isAmbiguous() const {
+ return getKind() == Ambiguous;
+ }
- static LookupResult CreateLookupResult(ASTContext &Context, BasePaths *Paths,
- bool DifferentSubobjectTypes) {
- LookupResult Result;
- Result.StoredKind = AmbiguousLookupStoresBasePaths;
- Result.First = reinterpret_cast<uintptr_t>(Paths);
- Result.Last = DifferentSubobjectTypes? 1 : 0;
- Result.Context = &Context;
- return Result;
+ LookupKind getKind() const {
+ sanity();
+ return Kind;
}
- template <typename Iterator>
- static LookupResult CreateLookupResult(ASTContext &Context,
- Iterator B, std::size_t Len) {
- NamedDecl ** Array = new NamedDecl*[Len];
- for (std::size_t Idx = 0; Idx < Len; ++Idx, ++B)
- Array[Idx] = *B;
- LookupResult Result;
- Result.StoredKind = AmbiguousLookupStoresDecls;
- Result.First = reinterpret_cast<uintptr_t>(Array);
- Result.Last = reinterpret_cast<uintptr_t>(Array + Len);
- Result.Context = &Context;
- return Result;
+ AmbiguityKind getAmbiguityKind() const {
+ assert(isAmbiguous());
+ return Ambiguity;
}
- LookupKind getKind() const;
+ iterator begin() const { return Decls.begin(); }
+ iterator end() const { return Decls.end(); }
- /// @brief Determine whether name look found something.
- operator bool() const { return getKind() != NotFound; }
+ /// \brief Return true if no decls were found
+ bool empty() const { return Decls.empty(); }
- /// @brief Determines whether the lookup resulted in an ambiguity.
- bool isAmbiguous() const {
- return StoredKind == AmbiguousLookupStoresBasePaths ||
- StoredKind == AmbiguousLookupStoresDecls;
+ /// \brief Return the base paths structure that's associated with
+ /// these results, or null if none is.
+ CXXBasePaths *getBasePaths() const {
+ return Paths;
}
- /// @brief Allows conversion of a lookup result into a
- /// declaration, with the same behavior as getAsDecl.
- operator NamedDecl*() const { return getAsDecl(); }
+ /// \brief Add a declaration to these results.
+ void addDecl(NamedDecl *D) {
+ Decls.push_back(D->getUnderlyingDecl());
+ Kind = Found;
+ }
- NamedDecl* getAsDecl() const;
+ /// \brief Add all the declarations from another set of lookup
+ /// results.
+ void addAllDecls(const LookupResult &Other) {
+ Decls.append(Other.begin(), Other.end());
+ Kind = Found;
+ }
- BasePaths *getBasePaths() const;
+ /// \brief Hides a set of declarations.
+ template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) {
+ unsigned I = 0, N = Decls.size();
+ while (I < N) {
+ if (Set.count(Decls[I]))
+ Decls[I] = Decls[--N];
+ else
+ I++;
+ }
+ Decls.set_size(N);
+ }
- /// \brief Iterate over the results of name lookup.
+ /// \brief Resolves the kind of the lookup, possibly hiding decls.
///
- /// The @c iterator class provides iteration over the results of a
- /// non-ambiguous name lookup.
- class iterator {
- /// The LookupResult structure we're iterating through.
- LookupResult *Result;
+ /// This should be called in any environment where lookup might
+ /// generate multiple lookup results.
+ void resolveKind();
- /// The current position of this iterator within the sequence of
- /// results. This value will have the same representation as the
- /// @c First field in the LookupResult structure.
- mutable uintptr_t Current;
-
- public:
- typedef NamedDecl * value_type;
- typedef NamedDecl * reference;
- typedef NamedDecl * pointer;
- typedef std::ptrdiff_t difference_type;
- typedef std::forward_iterator_tag iterator_category;
+ /// \brief Fetch this as an unambiguous single declaration
+ /// (possibly an overloaded one).
+ ///
+ /// This is deprecated; users should be written to handle
+ /// ambiguous and overloaded lookups.
+ NamedDecl *getAsSingleDecl(ASTContext &Context) const;
- iterator() : Result(0), Current(0) { }
+ /// \brief Fetch the unique decl found by this lookup. Asserts
+ /// that one was found.
+ ///
+ /// This is intended for users who have examined the result kind
+ /// and are certain that there is only one result.
+ NamedDecl *getFoundDecl() const {
+ assert(getKind() == Found && "getFoundDecl called on non-unique result");
+ return *Decls.begin();
+ }
- iterator(LookupResult *Res, uintptr_t Cur) : Result(Res), Current(Cur) { }
+ /// \brief Asks if the result is a single tag decl.
+ bool isSingleTagDecl() const {
+ return getKind() == Found && isa<TagDecl>(getFoundDecl());
+ }
- reference operator*() const;
+ /// \brief Make these results show that the name was found in
+ /// base classes of different types.
+ ///
+ /// The given paths object is copied and invalidated.
+ void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P);
- pointer operator->() const { return **this; }
+ /// \brief Make these results show that the name was found in
+ /// distinct base classes of the same type.
+ ///
+ /// The given paths object is copied and invalidated.
+ void setAmbiguousBaseSubobjects(CXXBasePaths &P);
+
+ /// \brief Make these results show that the name was found in
+ /// different contexts and a tag decl was hidden by an ordinary
+ /// decl in a different context.
+ void setAmbiguousQualifiedTagHiding() {
+ setAmbiguous(AmbiguousTagHiding);
+ }
- iterator &operator++();
+ /// \brief Clears out any current state.
+ void clear() {
+ Kind = NotFound;
+ Decls.clear();
+ if (Paths) deletePaths(Paths);
+ Paths = NULL;
+ }
- iterator operator++(int) {
- iterator tmp(*this);
- ++(*this);
- return tmp;
- }
+ void print(llvm::raw_ostream &);
- friend inline bool operator==(iterator const& x, iterator const& y) {
- return x.Current == y.Current;
- }
+ private:
+ void setAmbiguous(AmbiguityKind AK) {
+ Kind = Ambiguous;
+ Ambiguity = AK;
+ }
- friend inline bool operator!=(iterator const& x, iterator const& y) {
- return x.Current != y.Current;
- }
- };
- friend class iterator;
+ void addDeclsFromBasePaths(const CXXBasePaths &P);
+
+ // Sanity checks.
+ void sanity() const {
+ assert(Kind != NotFound || Decls.size() == 0);
+ assert(Kind != Found || Decls.size() == 1);
+ assert(Kind == NotFound || Kind == Found ||
+ (Kind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects)
+ || Decls.size() > 1);
+ assert((Paths != NULL) == (Kind == Ambiguous &&
+ (Ambiguity == AmbiguousBaseSubobjectTypes ||
+ Ambiguity == AmbiguousBaseSubobjects)));
+ }
- iterator begin();
- iterator end();
+ static void deletePaths(CXXBasePaths *);
- /// \brief Free the memory associated with this lookup.
- void Destroy();
+ LookupKind Kind;
+ AmbiguityKind Ambiguity; // ill-defined unless ambiguous
+ DeclsTy Decls;
+ CXXBasePaths *Paths;
};
private:
typedef llvm::SmallVector<LookupResult, 3> LookupResultsVecTy;
- std::pair<bool, LookupResult> CppLookupName(Scope *S, DeclarationName Name,
- LookupNameKind NameKind,
- bool RedeclarationOnly);
- ObjCMethodDecl *FindMethodInNestedImplementations(
- const ObjCInterfaceDecl *IFace,
- const Selector &Sel);
-
+ bool CppLookupName(LookupResult &R, Scope *S, DeclarationName Name,
+ LookupNameKind NameKind, bool RedeclarationOnly);
public:
/// Determines whether D is a suitable lookup result according to the
/// lookup criteria.
@@ -1115,62 +1322,75 @@ public:
case Sema::LookupObjCImplementationName:
case Sema::LookupObjCCategoryImplName:
return D->isInIdentifierNamespace(IDNS);
-
+
case Sema::LookupOperatorName:
- return D->isInIdentifierNamespace(IDNS) &&
+ return D->isInIdentifierNamespace(IDNS) &&
!D->getDeclContext()->isRecord();
case Sema::LookupNestedNameSpecifierName:
return isa<TypedefDecl>(D) || D->isInIdentifierNamespace(Decl::IDNS_Tag);
-
+
case Sema::LookupNamespaceName:
return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D);
}
-
- assert(false &&
+
+ assert(false &&
"isAcceptableLookupResult always returns before this point");
return false;
}
- LookupResult LookupName(Scope *S, DeclarationName Name,
- LookupNameKind NameKind,
- bool RedeclarationOnly = false,
- bool AllowBuiltinCreation = false,
- SourceLocation Loc = SourceLocation());
- LookupResult LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
- LookupNameKind NameKind,
- bool RedeclarationOnly = false);
- LookupResult LookupParsedName(Scope *S, const CXXScopeSpec *SS,
- DeclarationName Name,
- LookupNameKind NameKind,
- bool RedeclarationOnly = false,
- bool AllowBuiltinCreation = false,
- SourceLocation Loc = SourceLocation());
+ /// \brief Look up a name, looking for a single declaration. Return
+ /// null if no unambiguous results were found.
+ ///
+ /// It is preferable to use the elaborated form and explicitly handle
+ /// ambiguity and overloaded.
+ NamedDecl *LookupSingleName(Scope *S, DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false) {
+ LookupResult R;
+ LookupName(R, S, Name, NameKind, RedeclarationOnly);
+ return R.getAsSingleDecl(Context);
+ }
+ bool LookupName(LookupResult &R, Scope *S,
+ DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false,
+ bool AllowBuiltinCreation = false,
+ SourceLocation Loc = SourceLocation());
+ bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+ DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false);
+ bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
+ DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false,
+ bool AllowBuiltinCreation = false,
+ SourceLocation Loc = SourceLocation(),
+ bool EnteringContext = false);
ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II);
- ObjCImplementationDecl *LookupObjCImplementation(IdentifierInfo *II);
ObjCCategoryImplDecl *LookupObjCCategoryImpl(IdentifierInfo *II);
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
- QualType T1, QualType T2,
+ QualType T1, QualType T2,
FunctionSet &Functions);
-
+
void ArgumentDependentLookup(DeclarationName Name,
Expr **Args, unsigned NumArgs,
FunctionSet &Functions);
void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
AssociatedNamespaceSet &AssociatedNamespaces,
- AssociatedClassSet &AssociatedClasses,
- bool &GlobalScope);
+ AssociatedClassSet &AssociatedClasses);
bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
- SourceLocation NameLoc,
+ SourceLocation NameLoc,
SourceRange LookupRange = SourceRange());
//@}
-
+
ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
- NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
+ NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
Scope *S, bool ForRedeclaration,
SourceLocation Loc);
NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
@@ -1179,7 +1399,7 @@ public:
// More parsing and symbol table subroutines.
- // Decl attributes - this routine is the top level dispatcher.
+ // Decl attributes - this routine is the top level dispatcher.
void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD);
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList);
@@ -1187,13 +1407,10 @@ public:
bool &IncompleteImpl);
void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
ObjCMethodDecl *IntfMethod);
- bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
- NamespaceDecl *GetStdNamespace();
-
bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl,
ObjCInterfaceDecl *IDecl);
-
+
/// CheckProtocolMethodDefs - This routine checks unimplemented
/// methods declared in protocol, and those referenced by it.
/// \param IDecl - Used for checking for methods which may have been
@@ -1204,24 +1421,24 @@ public:
const llvm::DenseSet<Selector> &InsMap,
const llvm::DenseSet<Selector> &ClsMap,
ObjCInterfaceDecl *IDecl);
-
+
/// CheckImplementationIvars - This routine checks if the instance variables
- /// listed in the implelementation match those listed in the interface.
+ /// listed in the implelementation match those listed in the interface.
void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
ObjCIvarDecl **Fields, unsigned nIvars,
SourceLocation Loc);
-
+
/// ImplMethodsVsClassMethods - This is main routine to warn if any method
/// remains unimplemented in the class or category @implementation.
- void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
- ObjCContainerDecl* IDecl,
+ void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* IDecl,
bool IncompleteImpl = false);
-
+
/// MatchTwoMethodDeclarations - Checks if two methods' type match and returns
/// true, or false, accordingly.
- bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
+ bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
const ObjCMethodDecl *PrevMethod,
- bool matchBasedOnSizeAndAlignment = false);
+ bool matchBasedOnSizeAndAlignment = false);
/// MatchAllMethodDeclarations - Check methods declaraed in interface or
/// or protocol against those declared in their implementations.
@@ -1239,15 +1456,16 @@ public:
/// a selector with a method declaraation for purposes of typechecking
/// messages sent to "id" (where the class of the object is unknown).
void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method);
-
+
/// LookupInstanceMethodInGlobalPool - Returns the method and warns if
/// there are multiple signatures.
- ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R);
+ ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R,
+ bool warn=true);
/// LookupFactoryMethodInGlobalPool - Returns the method and warns if
/// there are multiple signatures.
ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R);
-
+
/// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method);
//===--------------------------------------------------------------------===//
@@ -1266,7 +1484,7 @@ public:
SourceLocation DotDotDotLoc, ExprArg RHSVal,
SourceLocation ColonLoc);
virtual void ActOnCaseStmtBody(StmtTy *CaseStmt, StmtArg SubStmt);
-
+
virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
SourceLocation ColonLoc,
StmtArg SubStmt, Scope *CurScope);
@@ -1274,13 +1492,13 @@ public:
IdentifierInfo *II,
SourceLocation ColonLoc,
StmtArg SubStmt);
- virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
- FullExprArg CondVal, StmtArg ThenVal,
+ virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
+ FullExprArg CondVal, StmtArg ThenVal,
SourceLocation ElseLoc, StmtArg ElseVal);
virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond);
virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
StmtArg Switch, StmtArg Body);
- virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
+ virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
FullExprArg Cond, StmtArg Body);
virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
SourceLocation WhileLoc,
@@ -1309,7 +1527,7 @@ public:
Scope *CurScope);
virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
- FullExprArg RetValExp);
+ ExprArg RetValExp);
OwningStmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc,
Expr *RetValExp);
@@ -1338,13 +1556,14 @@ public:
StmtArg Catch, StmtArg Finally);
virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
- ExprArg Throw,
+ ExprArg Throw,
Scope *CurScope);
virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
ExprArg SynchExpr,
StmtArg SynchBody);
VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
+ DeclaratorInfo *DInfo,
IdentifierInfo *Name,
SourceLocation Loc,
SourceRange Range);
@@ -1358,25 +1577,29 @@ public:
MultiStmtArg Handlers);
void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock);
+ /// DiagnoseUnusedExprResult - If the statement passed in is an expression
+ /// whose result is unused, warn.
+ void DiagnoseUnusedExprResult(const Stmt *S);
+
//===--------------------------------------------------------------------===//
// Expression Parsing Callbacks: SemaExpr.cpp.
bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc);
- bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
+ bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
ObjCMethodDecl *Getter,
SourceLocation Loc);
void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
Expr **Args, unsigned NumArgs);
- virtual ExpressionEvaluationContext
+ virtual ExpressionEvaluationContext
PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext);
-
- virtual void
+
+ virtual void
PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
ExpressionEvaluationContext NewContext);
-
+
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
-
+
// Primary Expressions.
virtual SourceRange getExprRange(ExprTy *E) const;
@@ -1397,8 +1620,8 @@ public:
bool HasTrailingLParen,
const CXXScopeSpec &SS,
bool isAddressOfOperand);
- OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty,
- SourceLocation Loc, bool TypeDependent,
+ OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty,
+ SourceLocation Loc, bool TypeDependent,
bool ValueDependent,
const CXXScopeSpec *SS = 0);
VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
@@ -1415,15 +1638,18 @@ public:
bool isAddressOfOperand = false);
OwningExprResult BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
bool HasTrailingLParen,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec *SS,
bool isAddressOfOperand);
-
+
virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
tok::TokenKind Kind);
virtual OwningExprResult ActOnNumericConstant(const Token &);
virtual OwningExprResult ActOnCharacterConstant(const Token &);
virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
ExprArg Val);
+ virtual OwningExprResult ActOnParenListExpr(SourceLocation L,
+ SourceLocation R,
+ MultiExprArg Val);
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz").
@@ -1432,19 +1658,19 @@ public:
// Binary/Unary Operators. 'Tok' is the token for the operator.
OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc,
- unsigned OpcIn,
+ unsigned OpcIn,
ExprArg InputArg);
virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Op, ExprArg Input);
- OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
+ OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
bool isSizeOf, SourceRange R);
- OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
+ OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
bool isSizeOf, SourceRange R);
virtual OwningExprResult
ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
void *TyOrEx, const SourceRange &ArgRange);
-
+
bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R);
bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc,
const SourceRange &R, bool isSizeof);
@@ -1457,18 +1683,67 @@ public:
SourceLocation LLoc,
ExprArg Idx,
SourceLocation RLoc);
+
+ OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ DeclarationName MemberName,
+ DeclPtrTy ImplDecl,
+ const CXXScopeSpec *SS = 0,
+ NamedDecl *FirstQualifierInScope = 0) {
+ // FIXME: Temporary helper while we migrate existing calls to
+ // BuildMemberReferenceExpr to support explicitly-specified template
+ // arguments.
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
+ MemberName, false, SourceLocation(), 0, 0,
+ SourceLocation(), ImplDecl, SS,
+ FirstQualifierInScope);
+ }
+
+ OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ DeclarationName MemberName,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ SourceLocation RAngleLoc,
+ DeclPtrTy ImplDecl,
+ const CXXScopeSpec *SS,
+ NamedDecl *FirstQualifierInScope = 0);
+
virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation MemberLoc,
IdentifierInfo &Member,
- DeclPtrTy ImplDecl);
+ DeclPtrTy ImplDecl,
+ const CXXScopeSpec *SS = 0);
+ virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl);
bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
FunctionDecl *FDecl,
const FunctionProtoType *Proto,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc);
-
+ void BuildBaseOrMemberInitializers(ASTContext &C,
+ CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers
+ );
+
+ void DeconstructCallFunction(Expr *FnExpr,
+ NamedDecl *&Function,
+ DeclarationName &Name,
+ NestedNameSpecifier *&Qualifier,
+ SourceRange &QualifierRange,
+ bool &ArgumentDependentLookup,
+ bool &HasExplicitTemplateArguments,
+ const TemplateArgument *&ExplicitTemplateArgs,
+ unsigned &NumExplicitTemplateArgs);
+
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
@@ -1478,8 +1753,14 @@ public:
SourceLocation *CommaLocs,
SourceLocation RParenLoc);
- virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
- SourceLocation RParenLoc, ExprArg Op);
+ virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
+ TypeTy *Ty, SourceLocation RParenLoc,
+ ExprArg Op);
+
+ OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME);
+ OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
+ SourceLocation RParenLoc, ExprArg E,
+ QualType Ty);
virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc,
TypeTy *Ty,
@@ -1577,7 +1858,7 @@ public:
SourceLocation IdentLoc,
IdentifierInfo *NamespcName,
AttributeList *AttrList);
-
+
void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir);
virtual DeclPtrTy ActOnNamespaceAliasDef(Scope *CurScope,
@@ -1588,16 +1869,24 @@ public:
SourceLocation IdentLoc,
IdentifierInfo *Ident);
+ NamedDecl *BuildUsingDeclaration(SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ DeclarationName Name,
+ AttributeList *AttrList,
+ bool IsTypeName);
+
virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,
- SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
- SourceLocation IdentLoc,
- IdentifierInfo *TargetName,
- OverloadedOperatorKind Op,
- AttributeList *AttrList,
- bool IsTypeName);
-
- /// AddCXXDirectInitializerToDecl - This action is called immediately after
+ AccessSpecifier AS,
+ SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *TargetName,
+ OverloadedOperatorKind Op,
+ AttributeList *AttrList,
+ bool IsTypeName);
+
+ /// AddCXXDirectInitializerToDecl - This action is called immediately after
/// ActOnDeclarator, when a C++ direct initializer is present.
/// e.g: "int x(1);"
virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
@@ -1608,57 +1897,79 @@ public:
/// InitializeVarWithConstructor - Creates an CXXConstructExpr
/// and sets it as the initializer for the the passed in VarDecl.
- void InitializeVarWithConstructor(VarDecl *VD,
+ bool InitializeVarWithConstructor(VarDecl *VD,
CXXConstructorDecl *Constructor,
- QualType DeclInitType,
- Expr **Exprs, unsigned NumExprs);
-
- /// MarkDestructorReferenced - Prepare for calling destructor on the
- /// constructed decl.
- void MarkDestructorReferenced(SourceLocation Loc, QualType DeclInitType);
-
- /// DefineImplicitDefaultConstructor - Checks for feasibility of
+ QualType DeclInitType,
+ MultiExprArg Exprs);
+
+ /// BuildCXXConstructExpr - Creates a complete call to a constructor,
+ /// including handling of its default argument expressions.
+ OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc,
+ QualType DeclInitType,
+ CXXConstructorDecl *Constructor,
+ MultiExprArg Exprs);
+
+ // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
+ // the constructor can be elidable?
+ OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc,
+ QualType DeclInitType,
+ CXXConstructorDecl *Constructor,
+ bool Elidable,
+ MultiExprArg Exprs);
+
+ OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
+ QualType writtenTy,
+ SourceLocation tyBeginLoc,
+ MultiExprArg Args,
+ SourceLocation rParenLoc);
+
+ OwningExprResult BuildCXXCastArgument(SourceLocation CastLoc,
+ QualType Ty,
+ CastExpr::CastKind Kind,
+ CXXMethodDecl *Method,
+ ExprArg Arg);
+
+ /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
+ /// the default expr if needed.
+ OwningExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc,
+ FunctionDecl *FD,
+ ParmVarDecl *Param);
+
+ /// FinalizeVarWithDestructor - Prepare for calling destructor on the
+ /// constructed variable.
+ void FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType);
+
+ /// DefineImplicitDefaultConstructor - Checks for feasibility of
/// defining this constructor as the default constructor.
void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor);
-
- /// DefineImplicitDestructor - Checks for feasibility of
+
+ /// DefineImplicitDestructor - Checks for feasibility of
/// defining this destructor as the default destructor.
void DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXDestructorDecl *Destructor);
-
- /// DefineImplicitCopyConstructor - Checks for feasibility of
+
+ /// DefineImplicitCopyConstructor - Checks for feasibility of
/// defining this constructor as the copy constructor.
void DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor,
unsigned TypeQuals);
-
+
/// DefineImplicitOverloadedAssign - Checks for feasibility of
/// defining implicit this overloaded assignment operator.
- void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
+ void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
CXXMethodDecl *MethodDecl);
-
+
/// getAssignOperatorMethod - Returns the default copy assignmment operator
/// for the class.
CXXMethodDecl *getAssignOperatorMethod(ParmVarDecl *Decl,
- CXXRecordDecl *ClassDecl);
+ CXXRecordDecl *ClassDecl);
/// MaybeBindToTemporary - If the passed in expression has a record type with
/// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
/// it simply returns the passed in expression.
OwningExprResult MaybeBindToTemporary(Expr *E);
- /// RemoveOutermostTemporaryBinding - Remove and destroy the outermost
- /// CXXBindToTemporaryExpr if necessary. This is used when we want to not
- /// destroy a temporary when a full expression has been evaluated.
- /// For example:
- ///
- /// const T& t = T(10, T());
- ///
- /// Here the outermost T needs to be destroyed when t goes out of scope, but
- /// the innermost T needs to be destroyed when the expr has been evaluated.
- Expr *RemoveOutermostTemporaryBinding(Expr *E);
-
/// InitializationKind - Represents which kind of C++ initialization
/// [dcl.init] a routine is to perform.
enum InitializationKind {
@@ -1669,11 +1980,17 @@ public:
CXXConstructorDecl *
PerformInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg ArgsPtr,
SourceLocation Loc, SourceRange Range,
DeclarationName InitEntity,
- InitializationKind Kind);
+ InitializationKind Kind,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
+ bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
+ MultiExprArg ArgsPtr,
+ SourceLocation Loc,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
+
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
tok::TokenKind Kind,
@@ -1729,7 +2046,7 @@ public:
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
- bool ParenTypeId,
+ bool ParenTypeId,
QualType AllocType,
SourceLocation TypeLoc,
SourceRange TypeRange,
@@ -1737,7 +2054,7 @@ public:
SourceLocation ConstructorLParen,
MultiExprArg ConstructorArgs,
SourceLocation ConstructorRParen);
-
+
bool CheckAllocatedType(QualType AllocType, SourceLocation Loc,
SourceRange R);
bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
@@ -1775,17 +2092,62 @@ public:
TypeTy *Ty,
SourceLocation RParen);
- /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
+ virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S,
+ ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ TypeTy *&ObjectType);
+
+ virtual OwningExprResult
+ ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ IdentifierInfo *ClassName,
+ const CXXScopeSpec &SS,
+ bool HasTrailingLParen);
+
+ virtual OwningExprResult
+ ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ OverloadedOperatorKind OverOpKind,
+ const CXXScopeSpec *SS = 0);
+ virtual OwningExprResult
+ ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ TypeTy *Ty,
+ const CXXScopeSpec *SS = 0);
+
+ virtual OwningExprResult
+ ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ // FIXME: "template" keyword?
+ TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc);
+
+ /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
/// non-empty, will create a new CXXExprWithTemporaries expression.
/// Otherwise, just returs the passed in expression.
Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
bool ShouldDestroyTemporaries);
-
+
virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr);
bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
-
- DeclContext *computeDeclContext(const CXXScopeSpec &SS);
+
+ DeclContext *computeDeclContext(QualType T);
+ DeclContext *computeDeclContext(const CXXScopeSpec &SS,
+ bool EnteringContext = false);
bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS);
bool isUnknownSpecialization(const CXXScopeSpec &SS);
@@ -1795,17 +2157,26 @@ public:
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
SourceLocation CCLoc);
- /// ActOnCXXNestedNameSpecifier - Called during parsing of a
- /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
- /// we want to resolve "bar::". 'SS' is empty or the previously parsed
- /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
- /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
- /// Returns a CXXScopeTy* object representing the C++ scope.
+ bool isAcceptableNestedNameSpecifier(NamedDecl *SD);
+ NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
+
+
+ CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ SourceLocation IdLoc,
+ SourceLocation CCLoc,
+ IdentifierInfo &II,
+ QualType ObjectType,
+ NamedDecl *ScopeLookupResult,
+ bool EnteringContext);
+
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
- IdentifierInfo &II);
+ IdentifierInfo &II,
+ TypeTy *ObjectType,
+ bool EnteringContext);
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
/// nested-name-specifier that involves a template-id, e.g.,
@@ -1827,7 +2198,7 @@ public:
/// looked up in the declarator-id's scope, until the declarator is parsed and
/// ActOnCXXExitDeclaratorScope is called.
/// The 'SS' should be a non-empty valid CXXScopeSpec.
- virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
+ virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
/// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
@@ -1848,26 +2219,28 @@ public:
virtual void ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl);
// ParseObjCStringLiteral - Parse Objective-C string literals.
- virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
+ virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
ExprTy **Strings,
unsigned NumStrings);
-
- Expr *BuildObjCEncodeExpression(SourceLocation AtLoc,
+
+ Expr *BuildObjCEncodeExpression(SourceLocation AtLoc,
QualType EncodedType,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc);
+ CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method);
+
virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc,
SourceLocation EncodeLoc,
SourceLocation LParenLoc,
TypeTy *Ty,
SourceLocation RParenLoc);
-
+
// ParseObjCSelectorExpression - Build selector expression for @selector
virtual ExprResult ParseObjCSelectorExpression(Selector Sel,
SourceLocation AtLoc,
SourceLocation SelLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc);
-
+
// ParseObjCProtocolExpression - Build protocol expression for @protocol
virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName,
SourceLocation AtLoc,
@@ -1897,6 +2270,7 @@ public:
virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
Declarator &D,
+ MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BitfieldWidth,
ExprTy *Init,
bool Deleted = false);
@@ -1912,12 +2286,33 @@ public:
SourceLocation *CommaLocs,
SourceLocation RParenLoc);
+ MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args,
+ unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation RParenLoc);
+
+ MemInitResult BuildBaseInitializer(QualType BaseType, Expr **Args,
+ unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation RParenLoc,
+ CXXRecordDecl *ClassDecl);
+
+ void setBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers,
+ llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
+ llvm::SmallVectorImpl<FieldDecl *>&Members);
+
+ /// computeBaseOrMembersToDestroy - Compute information in current
+ /// destructor decl's AST of bases and non-static data members which will be
+ /// implicitly destroyed. We are storing the destruction in the order that
+ /// they should occur (which is the reverse of construction order).
+ void computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor);
+
void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
- virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
+ virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
MemInitTy **MemInits, unsigned NumMemInits);
-
+
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
@@ -1930,12 +2325,14 @@ public:
virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S,
DeclPtrTy Method);
- virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+ virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
ExprArg AssertExpr,
ExprArg AssertMessageExpr);
-
- virtual bool ActOnFriendDecl(Scope *S, SourceLocation FriendLoc,
- DeclPtrTy Dcl);
+
+ DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
+ MultiTemplateParamsArg TemplateParams);
+ DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
+ MultiTemplateParamsArg TemplateParams);
QualType CheckConstructorDeclarator(Declarator &D, QualType R,
FunctionDecl::StorageClass& SC);
@@ -1954,23 +2351,22 @@ public:
CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
- QualType BaseType,
+ QualType BaseType,
SourceLocation BaseLoc);
- virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl,
+ virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
- TypeTy *basetype, SourceLocation
+ TypeTy *basetype, SourceLocation
BaseLoc);
bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
unsigned NumBases);
- virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
+ virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
unsigned NumBases);
bool IsDerivedFrom(QualType Derived, QualType Base);
- bool IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths);
- bool LookupInBases(CXXRecordDecl *Class, const MemberLookupCriteria& Criteria,
- BasePaths &Paths);
+ bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths);
+
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
@@ -1978,29 +2374,37 @@ public:
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name);
-
- std::string getAmbiguousPathsDisplayString(BasePaths &Paths);
-
- /// CheckReturnTypeCovariance - Checks whether two types are covariant,
- /// according to C++ [class.virtual]p5.
- bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
+
+ std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths);
+
+ /// CheckOverridingFunctionReturnType - Checks whether the return types are
+ /// covariant, according to C++ [class.virtual]p5.
+ bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old);
-
+
+ /// CheckOverridingFunctionExceptionSpec - Checks whether the exception
+ /// spec is a subset of base spec.
+ bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old);
//===--------------------------------------------------------------------===//
// C++ Access Control
//
-
- bool SetMemberAccessSpecifier(NamedDecl *MemberDecl,
+
+ bool SetMemberAccessSpecifier(NamedDecl *MemberDecl,
NamedDecl *PrevMemberDecl,
AccessSpecifier LexicalAS);
-
- bool CheckBaseClassAccess(QualType Derived, QualType Base,
+
+ const CXXBaseSpecifier *FindInaccessibleBase(QualType Derived, QualType Base,
+ CXXBasePaths &Paths,
+ bool NoPrivileges = false);
+
+ bool CheckBaseClassAccess(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
- BasePaths& Paths, SourceLocation AccessLoc,
+ CXXBasePaths& Paths, SourceLocation AccessLoc,
DeclarationName Name);
-
-
+
+
enum AbstractDiagSelID {
AbstractNone = -1,
AbstractReturnType,
@@ -2008,8 +2412,12 @@ public:
AbstractVariableType,
AbstractFieldType
};
-
- bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID,
+
+ bool RequireNonAbstractType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ const CXXRecordDecl *CurrentRD = 0);
+
+ bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID,
AbstractDiagSelID SelID = AbstractNone,
const CXXRecordDecl *CurrentRD = 0);
@@ -2022,19 +2430,23 @@ public:
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
- virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
- TemplateTy &Template,
- const CXXScopeSpec *SS = 0);
+ virtual TemplateNameKind isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ const CXXScopeSpec *SS,
+ TypeTy *ObjectType,
+ bool EnteringContext,
+ TemplateTy &Template);
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl);
- virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
+ virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
SourceLocation EllipsisLoc,
SourceLocation KeyLoc,
IdentifierInfo *ParamName,
SourceLocation ParamNameLoc,
unsigned Depth, unsigned Position);
- virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam,
+ virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam,
SourceLocation EqualLoc,
SourceLocation DefaultLoc,
TypeTy *Default);
@@ -2060,21 +2472,30 @@ public:
virtual TemplateParamsTy *
ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
- SourceLocation TemplateLoc,
+ SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
DeclPtrTy *Params, unsigned NumParams,
SourceLocation RAngleLoc);
bool CheckTemplateParameterList(TemplateParameterList *NewParams,
TemplateParameterList *OldParams);
-
- virtual DeclResult
- ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
- IdentifierInfo *Name, SourceLocation NameLoc,
- AttributeList *Attr,
- MultiTemplateParamsArg TemplateParameterLists,
- AccessSpecifier AS);
-
+ TemplateParameterList *
+ MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
+ const CXXScopeSpec &SS,
+ TemplateParameterList **ParamLists,
+ unsigned NumParamLists,
+ bool &IsExplicitSpecialization);
+
+ DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr,
+ TemplateParameterList *TemplateParams,
+ AccessSpecifier AS);
+
+ void translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
+ llvm::SmallVector<TemplateArgument, 16> &TemplateArgs);
+
QualType CheckTemplateIdType(TemplateName Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@@ -2088,32 +2509,31 @@ public:
ASTTemplateArgsPtr TemplateArgs,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc);
-
+
+ virtual TypeResult ActOnTagTemplateIdType(TypeResult Type,
+ TagUseKind TUK,
+ DeclSpec::TST TagSpec,
+ SourceLocation TagLoc);
+
OwningExprResult BuildTemplateIdExpr(TemplateName Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceLocation RAngleLoc);
-
+
virtual OwningExprResult ActOnTemplateIdExpr(TemplateTy Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc);
-
+
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc,
- const CXXScopeSpec &SS);
-
- bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
- ClassTemplateSpecializationDecl *PrevDecl,
- SourceLocation TemplateNameLoc,
- SourceRange ScopeSpecifierRange,
- bool PartialSpecialization,
- bool ExplicitInstantiation);
+ const CXXScopeSpec &SS,
+ TypeTy *ObjectType);
bool CheckClassTemplatePartialSpecializationArgs(
TemplateParameterList *TemplateParams,
@@ -2121,8 +2541,8 @@ public:
bool &MirrorsPrimaryTemplate);
virtual DeclResult
- ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
- SourceLocation KWLoc,
+ ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
+ SourceLocation KWLoc,
const CXXScopeSpec &SS,
TemplateTy Template,
SourceLocation TemplateNameLoc,
@@ -2133,17 +2553,28 @@ public:
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists);
- virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S,
+ virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D);
-
- virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
+
+ virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D);
-
+
+ bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ SourceLocation RAngleLoc,
+ NamedDecl *&PrevDecl);
+ bool CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl);
+
virtual DeclResult
- ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
- unsigned TagSpec,
+ ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
TemplateTy Template,
@@ -2155,14 +2586,21 @@ public:
AttributeList *Attr);
virtual DeclResult
- ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
- unsigned TagSpec,
+ ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
AttributeList *Attr);
+ virtual DeclResult ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ Declarator &D);
+
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@@ -2172,16 +2610,16 @@ public:
bool PartialTemplateArgs,
TemplateArgumentListBuilder &Converted);
- bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
+ bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
const TemplateArgument &Arg,
TemplateArgumentListBuilder &Converted);
bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg,
SourceLocation ArgLoc);
- bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
+ bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
NamedDecl *&Entity);
bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member);
- bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
+ bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
TemplateArgument &Converted);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
@@ -2191,9 +2629,8 @@ public:
bool IsTemplateTemplateParm = false,
SourceLocation TemplateArgLoc
= SourceLocation());
-
- bool CheckTemplateDeclScope(Scope *S,
- MultiTemplateParamsArg &TemplateParameterLists);
+
+ bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams);
/// \brief Called when the parser has parsed a C++ typename
/// specifier, e.g., "typename T::type".
@@ -2207,7 +2644,7 @@ public:
const IdentifierInfo &II, SourceLocation IdLoc);
/// \brief Called when the parser has parsed a C++ typename
- /// specifier that ends in a template-id, e.g.,
+ /// specifier that ends in a template-id, e.g.,
/// "typename MetaFun::template apply<T1, T2>".
///
/// \param TypenameLoc the location of the 'typename' keyword
@@ -2222,6 +2659,13 @@ public:
const IdentifierInfo &II,
SourceRange Range);
+ QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
+ DeclarationName Name);
+
+ std::string
+ getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgumentList &Args);
+
/// \brief Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
@@ -2256,10 +2700,10 @@ public:
/// produces a type that does not match the original template
/// arguments provided.
TDK_NonDeducedMismatch,
- /// \brief When performing template argument deduction for a function
+ /// \brief When performing template argument deduction for a function
/// template, there were too many call arguments.
TDK_TooManyArguments,
- /// \brief When performing template argument deduction for a class
+ /// \brief When performing template argument deduction for a function
/// template, there were too few call arguments.
TDK_TooFewArguments,
/// \brief The explicitly-specified template arguments were not valid
@@ -2290,7 +2734,7 @@ public:
}
/// \brief Take ownership of the deduced template argument list.
- TemplateArgumentList *take() {
+ TemplateArgumentList *take() {
TemplateArgumentList *Result = Deduced;
Deduced = 0;
return Result;
@@ -2343,7 +2787,22 @@ public:
DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
TemplateDeductionInfo &Info);
-
+
+ TemplateDeductionResult
+ SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<QualType> &ParamTypes,
+ QualType *FunctionType,
+ TemplateDeductionInfo &Info);
+
+ TemplateDeductionResult
+ FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info);
+
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
@@ -2352,15 +2811,50 @@ public:
Expr **Args, unsigned NumArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info);
-
- void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
+
+ TemplateDeductionResult
+ DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ QualType ArgFunctionType,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info);
+
+ TemplateDeductionResult
+ DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ QualType ToType,
+ CXXConversionDecl *&Specialization,
+ TemplateDeductionInfo &Info);
+
+ FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
+ FunctionTemplateDecl *FT2,
+ TemplatePartialOrderingContext TPOC);
+ FunctionDecl *getMostSpecialized(FunctionDecl **Specializations,
+ unsigned NumSpecializations,
+ TemplatePartialOrderingContext TPOC,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag,
+ unsigned *Index = 0);
+
+ ClassTemplatePartialSpecializationDecl *
+ getMoreSpecializedPartialSpecialization(
+ ClassTemplatePartialSpecializationDecl *PS1,
+ ClassTemplatePartialSpecializationDecl *PS2);
+
+ void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used);
+ void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
llvm::SmallVectorImpl<bool> &Deduced);
-
+
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
//
- const TemplateArgumentList &getTemplateInstantiationArgs(NamedDecl *D);
+ MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D);
/// \brief A template instantiation that is currently in progress.
struct ActiveTemplateInstantiation {
@@ -2377,10 +2871,15 @@ public:
/// FIXME: Use a TemplateArgumentList
DefaultTemplateArgumentInstantiation,
- /// We are substituting explicit template arguments provided for
+ /// We are instantiating a default argument for a function.
+ /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs
+ /// provides the template arguments as specified.
+ DefaultFunctionArgumentInstantiation,
+
+ /// We are substituting explicit template arguments provided for
/// a function template. The entity is a FunctionTemplateDecl.
ExplicitTemplateArgumentSubstitution,
-
+
/// We are substituting template argument determined as part of
/// template argument deduction for either a class template
/// partial specialization or a function template. The
@@ -2407,6 +2906,9 @@ public:
/// template instantiation.
SourceRange InstantiationRange;
+ ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Entity(0),
+ TemplateArgs(0), NumTemplateArgs(0) {}
+
friend bool operator==(const ActiveTemplateInstantiation &X,
const ActiveTemplateInstantiation &Y) {
if (X.Kind != Y.Kind)
@@ -2422,7 +2924,9 @@ public:
case DefaultTemplateArgumentInstantiation:
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
+ case DefaultFunctionArgumentInstantiation:
return X.TemplateArgs == Y.TemplateArgs;
+
}
return true;
@@ -2440,7 +2944,7 @@ public:
/// requires another template instantiation, additional
/// instantiations are pushed onto the stack up to a
/// user-configurable limit LangOptions::InstantiationDepth.
- llvm::SmallVector<ActiveTemplateInstantiation, 16>
+ llvm::SmallVector<ActiveTemplateInstantiation, 16>
ActiveTemplateInstantiations;
/// \brief The last template from which a template instantiation
@@ -2486,7 +2990,7 @@ public:
unsigned NumTemplateArgs,
ActiveTemplateInstantiation::InstantiationKind Kind,
SourceRange InstantiationRange = SourceRange());
-
+
/// \brief Note that we are instantiating as part of template
/// argument deduction for a class template partial
/// specialization.
@@ -2496,6 +3000,12 @@ public:
unsigned NumTemplateArgs,
SourceRange InstantiationRange = SourceRange());
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ParmVarDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange = SourceRange());
+
/// \brief Note that we have finished instantiating this template.
void Clear();
@@ -2514,7 +3024,7 @@ public:
InstantiatingTemplate(const InstantiatingTemplate&); // not implemented
- InstantiatingTemplate&
+ InstantiatingTemplate&
operator=(const InstantiatingTemplate&); // not implemented
};
@@ -2541,8 +3051,8 @@ public:
~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; }
/// \brief Determine whether any SFINAE errors have been trapped.
- bool hasErrorOccurred() const {
- return SemaRef.NumSFINAEErrors > PrevSFINAEErrors;
+ bool hasErrorOccurred() const {
+ return SemaRef.NumSFINAEErrors > PrevSFINAEErrors;
}
};
@@ -2584,7 +3094,7 @@ public:
public:
LocalInstantiationScope(Sema &SemaRef)
- : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) {
+ : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) {
SemaRef.CurrentInstantiationScope = this;
}
@@ -2619,85 +3129,89 @@ public:
/// \brief An entity for which implicit template instantiation is required.
///
- /// The source location associated with the declaration is the first place in
+ /// The source location associated with the declaration is the first place in
/// the source code where the declaration was "used". It is not necessarily
- /// the point of instantiation (which will be either before or after the
+ /// the point of instantiation (which will be either before or after the
/// namespace-scope declaration that triggered this implicit instantiation),
/// However, it is the location that diagnostics should generally refer to,
/// because users will need to know what code triggered the instantiation.
typedef std::pair<ValueDecl *, SourceLocation> PendingImplicitInstantiation;
-
+
/// \brief The queue of implicit template instantiations that are required
/// but have not yet been performed.
std::deque<PendingImplicitInstantiation> PendingImplicitInstantiations;
void PerformPendingImplicitInstantiations();
-
- QualType InstantiateType(QualType T, const TemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity);
-
- OwningExprResult InstantiateExpr(Expr *E,
- const TemplateArgumentList &TemplateArgs);
- OwningStmtResult InstantiateStmt(Stmt *S,
- const TemplateArgumentList &TemplateArgs);
- OwningStmtResult InstantiateCompoundStmt(CompoundStmt *S,
- const TemplateArgumentList &TemplateArgs,
- bool isStmtExpr);
+ QualType SubstType(QualType T,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation Loc, DeclarationName Entity);
- Decl *InstantiateDecl(Decl *D, DeclContext *Owner,
- const TemplateArgumentList &TemplateArgs);
+ OwningExprResult SubstExpr(Expr *E,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
- bool
- InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
- CXXRecordDecl *Pattern,
- const TemplateArgumentList &TemplateArgs);
+ OwningStmtResult SubstStmt(Stmt *S,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+
+ Decl *SubstDecl(Decl *D, DeclContext *Owner,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+
+ bool
+ SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
+ CXXRecordDecl *Pattern,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
bool
InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
- const TemplateArgumentList &TemplateArgs,
- bool ExplicitInstantiation);
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK,
+ bool Complain = true);
- bool
+ bool
InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec,
- bool ExplicitInstantiation);
+ TemplateSpecializationKind TSK,
+ bool Complain = true);
void InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
- const TemplateArgumentList &TemplateArgs);
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK);
void InstantiateClassTemplateSpecializationMembers(
SourceLocation PointOfInstantiation,
- ClassTemplateSpecializationDecl *ClassTemplateSpec);
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ TemplateSpecializationKind TSK);
NestedNameSpecifier *
- InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
- SourceRange Range,
- const TemplateArgumentList &TemplateArgs);
+ SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
TemplateName
- InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
- const TemplateArgumentList &TemplateArgs);
- TemplateArgument Instantiate(TemplateArgument Arg,
- const TemplateArgumentList &TemplateArgs);
+ SubstTemplateName(TemplateName Name, SourceLocation Loc,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+ TemplateArgument Subst(TemplateArgument Arg,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive = false);
- void InstantiateVariableDefinition(VarDecl *Var);
+ void InstantiateStaticDataMemberDefinition(
+ SourceLocation PointOfInstantiation,
+ VarDecl *Var,
+ bool Recursive = false);
+
+ void InstantiateMemInitializers(CXXConstructorDecl *New,
+ const CXXConstructorDecl *Tmpl,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+
+ NamedDecl *FindInstantiatedDecl(NamedDecl *D,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+ DeclContext *FindInstantiatedContext(DeclContext *DC,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
- NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D);
-
- // Simple function for cloning expressions.
- template<typename T>
- OwningExprResult Clone(T *E) {
- assert(!E->isValueDependent() && !E->isTypeDependent() &&
- "expression is value or type dependent!");
- return Owned(E->Clone(Context));
- }
-
// Objective-C declarations.
virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
@@ -2708,7 +3222,7 @@ public:
unsigned NumProtoRefs,
SourceLocation EndProtoLoc,
AttributeList *AttrList);
-
+
virtual DeclPtrTy ActOnCompatiblityAlias(
SourceLocation AtCompatibilityAliasLoc,
IdentifierInfo *AliasName, SourceLocation AliasLocation,
@@ -2718,14 +3232,14 @@ public:
IdentifierInfo *PName,
SourceLocation &PLoc, SourceLocation PrevLoc,
const ObjCList<ObjCProtocolDecl> &PList);
-
+
virtual DeclPtrTy ActOnStartProtocolInterface(
SourceLocation AtProtoInterfaceLoc,
IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
const DeclPtrTy *ProtoRefNames, unsigned NumProtoRefs,
SourceLocation EndProtoLoc,
AttributeList *AttrList);
-
+
virtual DeclPtrTy ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLoc,
@@ -2734,78 +3248,82 @@ public:
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
SourceLocation EndProtoLoc);
-
+
virtual DeclPtrTy ActOnStartClassImplementation(
SourceLocation AtClassImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
- IdentifierInfo *SuperClassname,
+ IdentifierInfo *SuperClassname,
SourceLocation SuperClassLoc);
-
+
virtual DeclPtrTy ActOnStartCategoryImplementation(
SourceLocation AtCatImplLoc,
- IdentifierInfo *ClassName,
+ IdentifierInfo *ClassName,
SourceLocation ClassLoc,
IdentifierInfo *CatName,
SourceLocation CatLoc);
-
+
virtual DeclPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
IdentifierInfo **IdentList,
unsigned NumElts);
-
+
virtual DeclPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
const IdentifierLocPair *IdentList,
unsigned NumElts,
AttributeList *attrList);
-
+
virtual void FindProtocolDeclaration(bool WarnOnDeclarations,
const IdentifierLocPair *ProtocolId,
unsigned NumProtocols,
llvm::SmallVectorImpl<DeclPtrTy> &Protocols);
-
- /// Ensure attributes are consistent with type.
+
+ /// Ensure attributes are consistent with type.
/// \param [in, out] Attributes The attributes to check; they will
/// be modified to be consistent with \arg PropertyTy.
- void CheckObjCPropertyAttributes(QualType PropertyTy,
+ void CheckObjCPropertyAttributes(QualType PropertyTy,
SourceLocation Loc,
unsigned &Attributes);
void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC);
- void DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
+ void DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
ObjCPropertyDecl *SuperProperty,
const IdentifierInfo *Name);
void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl);
-
+
+ void CompareMethodParamsInBaseAndSuper(Decl *IDecl,
+ ObjCMethodDecl *MethodDecl,
+ bool IsInstance);
+
void MergeProtocolPropertiesIntoClass(Decl *CDecl,
DeclPtrTy MergeProtocols);
-
- void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
+
+ void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
ObjCInterfaceDecl *ID);
-
+
void MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
ObjCProtocolDecl *PDecl);
-
+
virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
DeclPtrTy *allMethods = 0, unsigned allNum = 0,
DeclPtrTy *allProperties = 0, unsigned pNum = 0,
DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
-
+
virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc,
FieldDeclarator &FD, ObjCDeclSpec &ODS,
Selector GetterSel, Selector SetterSel,
DeclPtrTy ClassCategory,
bool *OverridingProperty,
tok::ObjCKeywordKind MethodImplKind);
-
- virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc,
+
+ virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc,
SourceLocation PropertyLoc,
bool ImplKind,DeclPtrTy ClassImplDecl,
IdentifierInfo *PropertyId,
IdentifierInfo *PropertyIvar);
-
+
virtual DeclPtrTy ActOnMethodDeclaration(
SourceLocation BeginLoc, // location of the + or -.
SourceLocation EndLoc, // location of the ; or {.
- tok::TokenKind MethodType,
- DeclPtrTy ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType,
+ tok::TokenKind MethodType,
+ DeclPtrTy ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType,
Selector Sel,
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
@@ -2818,24 +3336,24 @@ public:
// Will search "local" class/category implementations for a method decl.
// Will also search in class's root looking for instance method.
// Returns 0 if no method is found.
- ObjCMethodDecl *LookupPrivateClassMethod(Selector Sel,
+ ObjCMethodDecl *LookupPrivateClassMethod(Selector Sel,
ObjCInterfaceDecl *CDecl);
ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel,
ObjCInterfaceDecl *ClassDecl);
-
+
virtual OwningExprResult ActOnClassPropertyRefExpr(
IdentifierInfo &receiverName,
IdentifierInfo &propertyName,
SourceLocation &receiverNameLoc,
SourceLocation &propertyNameLoc);
-
+
// ActOnClassMessage - used for both unary and keyword messages.
// ArgExprs is optional - if it is present, the number of expressions
// is obtained from NumArgs.
virtual ExprResult ActOnClassMessage(
Scope *S,
- IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac,
- SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac,
+ IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac,
+ SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac,
ExprTy **ArgExprs, unsigned NumArgs);
// ActOnInstanceMessage - used for both unary and keyword messages.
@@ -2843,23 +3361,27 @@ public:
// is obtained from NumArgs.
virtual ExprResult ActOnInstanceMessage(
ExprTy *receiver, Selector Sel,
- SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac,
+ SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac,
ExprTy **ArgExprs, unsigned NumArgs);
-
+
/// ActOnPragmaPack - Called on well formed #pragma pack(...).
virtual void ActOnPragmaPack(PragmaPackKind Kind,
IdentifierInfo *Name,
ExprTy *Alignment,
- SourceLocation PragmaLoc,
+ SourceLocation PragmaLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc);
-
+
/// ActOnPragmaUnused - Called on well-formed '#pragma unused'.
- virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
- SourceLocation PragmaLoc,
+ virtual void ActOnPragmaUnused(const Token *Identifiers,
+ unsigned NumIdentifiers, Scope *curScope,
+ SourceLocation PragmaLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc);
+ NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II);
+ void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W);
+
/// ActOnPragmaWeakID - Called on well formed #pragma weak ident.
virtual void ActOnPragmaWeakID(IdentifierInfo* WeakName,
SourceLocation PragmaLoc,
@@ -2875,25 +3397,27 @@ public:
/// getPragmaPackAlignment() - Return the current alignment as specified by
/// the current #pragma pack directive, or 0 if none is currently active.
unsigned getPragmaPackAlignment() const;
-
+
/// FreePackedContext - Deallocate and null out PackContext.
void FreePackedContext();
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
/// cast. If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
- void ImpCastExprToType(Expr *&Expr, QualType Type, bool isLvalue = false);
+ void ImpCastExprToType(Expr *&Expr, QualType Type,
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown,
+ bool isLvalue = false);
// UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts
// functions and arrays to their respective pointers (C99 6.3.2.1).
- Expr *UsualUnaryConversions(Expr *&expr);
+ Expr *UsualUnaryConversions(Expr *&expr);
// DefaultFunctionArrayConversion - converts functions and arrays
- // to their respective pointers (C99 6.3.2.1).
+ // to their respective pointers (C99 6.3.2.1).
void DefaultFunctionArrayConversion(Expr *&expr);
-
+
// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
- // do not have a prototype. Integer promotions are performed on each
+ // do not have a prototype. Integer promotions are performed on each
// argument, and arguments that have type float are promoted to double.
void DefaultArgumentPromotion(Expr *&Expr);
@@ -2901,26 +3425,21 @@ public:
enum VariadicCallType {
VariadicFunction,
VariadicBlock,
- VariadicMethod
+ VariadicMethod,
+ VariadicConstructor
};
-
+
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
// will warn if the resulting type is not a POD type.
bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT);
-
+
// UsualArithmeticConversions - performs the UsualUnaryConversions on it's
// operands and then handles various conversions that are common to binary
// operators (C99 6.3.1.8). If both operands aren't arithmetic, this
- // routine returns the first non-arithmetic type found. The client is
+ // routine returns the first non-arithmetic type found. The client is
// responsible for emitting appropriate error diagnostics.
QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr,
bool isCompAssign = false);
-
- /// UsualArithmeticConversionsType - handles the various conversions
- /// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9)
- /// and returns the result type of that conversion.
- QualType UsualArithmeticConversionsType(QualType lhs, QualType rhs);
-
/// AssignConvertType - All of the 'assignment' semantic checks return this
/// enum to indicate whether the assignment was allowed. These checks are
@@ -2930,15 +3449,15 @@ public:
enum AssignConvertType {
/// Compatible - the types are compatible according to the standard.
Compatible,
-
+
/// PointerToInt - The assignment converts a pointer to an int, which we
/// accept as an extension.
PointerToInt,
-
+
/// IntToPointer - The assignment converts an int to a pointer, which we
/// accept as an extension.
IntToPointer,
-
+
/// FunctionVoidPointer - The assignment is between a function pointer and
/// void*, which the standard doesn't allow, but we accept as an extension.
FunctionVoidPointer,
@@ -2960,25 +3479,25 @@ public:
/// IncompatibleVectors - The assignment is between two vector types that
/// have the same size, which we accept as an extension.
IncompatibleVectors,
-
- /// IntToBlockPointer - The assignment converts an int to a block
+
+ /// IntToBlockPointer - The assignment converts an int to a block
/// pointer. We disallow this.
IntToBlockPointer,
- /// IncompatibleBlockPointer - The assignment is between two block
+ /// IncompatibleBlockPointer - The assignment is between two block
/// pointers types that are not compatible.
IncompatibleBlockPointer,
-
+
/// IncompatibleObjCQualifiedId - The assignment is between a qualified
/// id type and something else (that is incompatible with it). For example,
/// "id <XXX>" = "Foo *", where "Foo *" doesn't implement the XXX protocol.
IncompatibleObjCQualifiedId,
-
+
/// Incompatible - We reject this conversion outright, it is invalid to
/// represent it in the AST.
Incompatible
};
-
+
/// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the
/// assignment conversion type specified by ConvTy. This returns true if the
/// conversion was invalid or false if the conversion was accepted.
@@ -2986,39 +3505,46 @@ public:
SourceLocation Loc,
QualType DstType, QualType SrcType,
Expr *SrcExpr, const char *Flavor);
-
- /// CheckAssignmentConstraints - Perform type checking for assignment,
- /// argument passing, variable initialization, and function return values.
+
+ /// CheckAssignmentConstraints - Perform type checking for assignment,
+ /// argument passing, variable initialization, and function return values.
/// This routine is only used by the following two methods. C99 6.5.16.
AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs);
-
- // CheckSingleAssignmentConstraints - Currently used by
- // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking,
+
+ // CheckSingleAssignmentConstraints - Currently used by
+ // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking,
// this routine performs the default function/array converions.
- AssignConvertType CheckSingleAssignmentConstraints(QualType lhs,
+ AssignConvertType CheckSingleAssignmentConstraints(QualType lhs,
Expr *&rExpr);
// \brief If the lhs type is a transparent union, check whether we
// can initialize the transparent union with the given expression.
- AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs,
+ AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs,
Expr *&rExpr);
-
+
// Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
- AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
+ AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
QualType rhsType);
-
+
// Helper function for CheckAssignmentConstraints involving two
// block pointer types.
- AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType,
+ AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType,
QualType rhsType);
bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
- bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType);
+
+ bool PerformImplicitConversion(Expr *&From, QualType ToType,
const char *Flavor,
bool AllowExplicit = false,
bool Elidable = false);
- bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ const char *Flavor,
+ bool AllowExplicit,
+ bool Elidable,
+ ImplicitConversionSequence& ICS);
+ bool PerformImplicitConversion(Expr *&From, QualType ToType,
const ImplicitConversionSequence& ICS,
const char *Flavor);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
@@ -3065,7 +3591,7 @@ public:
inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx,
SourceLocation l, bool isRel);
-
+
/// type checking unary operators (subroutines of ActOnUnaryOp).
/// C99 6.5.3.1, 6.5.3.2, 6.5.3.4
QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc,
@@ -3073,19 +3599,20 @@ public:
QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc);
QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc);
QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal);
-
+
/// type checking primary expressions.
QualType CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
- IdentifierInfo &Comp, SourceLocation CmpLoc);
-
+ const IdentifierInfo *Comp,
+ SourceLocation CmpLoc);
+
/// type checking declaration initializers (C99 6.7.8)
-
+
bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType,
SourceLocation InitLoc,DeclarationName InitEntity,
bool DirectInit);
bool CheckInitList(InitListExpr *&InitList, QualType &DeclType);
bool CheckForConstantInitializer(Expr *e, QualType t);
-
+
bool CheckValueInitialization(QualType Type, SourceLocation Loc);
// type checking C++ declaration initializers (C++ [dcl.init]).
@@ -3115,48 +3642,70 @@ public:
bool& DerivedToBase);
bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType,
- ImplicitConversionSequence *ICS = 0,
- bool SuppressUserConversions = false,
- bool AllowExplicit = false,
- bool ForceRValue = false);
-
- /// CheckCastTypes - Check type constraints for casting between types.
- bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);
-
- // CheckVectorCast - check type constraints for vectors.
+ SourceLocation DeclLoc,
+ bool SuppressUserConversions,
+ bool AllowExplicit,
+ bool ForceRValue,
+ ImplicitConversionSequence *ICS = 0);
+
+ /// CheckCastTypes - Check type constraints for casting between types under
+ /// C semantics, or forward to CXXCheckCStyleCast in C++.
+ bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *& ConversionDecl,
+ bool FunctionalStyle = false);
+
+ // CheckVectorCast - check type constraints for vectors.
// Since vectors are an extension, there are no C standard reference for this.
// We allow casting between vectors and integer datatypes of the same size.
// returns true if the cast is invalid
bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
-
- // CheckExtVectorCast - check type constraints for extended vectors.
+
+ // CheckExtVectorCast - check type constraints for extended vectors.
// Since vectors are an extension, there are no C standard reference for this.
// We allow casting between vectors and integer datatypes of the same size,
// or vectors and the element type of that vector.
// returns true if the cast is invalid
bool CheckExtVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
-
- /// CheckMessageArgumentTypes - Check types in an Obj-C message send.
+
+ /// CXXCheckCStyleCast - Check constraints of a C-style or function-style
+ /// cast under C++ semantics.
+ bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
+ CastExpr::CastKind &Kind, bool FunctionalStyle,
+ CXXMethodDecl *&ConversionDecl);
+
+ /// CheckMessageArgumentTypes - Check types in an Obj-C message send.
/// \param Method - May be null.
/// \param [out] ReturnType - The return type of the send.
/// \return true iff there were any incompatible types.
bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Selector Sel,
ObjCMethodDecl *Method, bool isClassMessage,
SourceLocation lbrac, SourceLocation rbrac,
- QualType &ReturnType);
+ QualType &ReturnType);
+
+ /// CheckBooleanCondition - Diagnose problems involving the use of
+ /// the given expression as a boolean condition (e.g. in an if
+ /// statement). Also performs the standard function and array
+ /// decays, possibly changing the input variable.
+ ///
+ /// \param Loc - A location associated with the condition, e.g. the
+ /// 'if' keyword.
+ /// \return true iff there were any errors
+ bool CheckBooleanCondition(Expr *&CondExpr, SourceLocation Loc);
+
+ /// DiagnoseAssignmentAsCondition - Given that an expression is
+ /// being used as a boolean condition, warn if it's an assignment.
+ void DiagnoseAssignmentAsCondition(Expr *E);
/// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid.
bool CheckCXXBooleanCondition(Expr *&CondExpr);
-
+
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
/// the specified width and sign. If an overflow occurs, detect it and emit
/// the specified diagnostic.
- void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal,
+ void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal,
unsigned NewWidth, bool NewSign,
SourceLocation Loc, unsigned DiagID);
-
- bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
- bool ForCompare);
/// Checks that the Objective-C declaration is declared in the global scope.
/// Emits an error and marks the declaration as invalid if it's not declared
@@ -3171,23 +3720,67 @@ public:
bool VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result = 0);
/// VerifyBitField - verifies that a bit field expression is an ICE and has
- /// the correct width, and that the field type is valid.
+ /// the correct width, and that the field type is valid.
/// Returns false on success.
- bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
- QualType FieldTy, const Expr *BitWidth);
+ /// Can optionally return whether the bit-field is of width 0
+ bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
+ QualType FieldTy, const Expr *BitWidth,
+ bool *ZeroWidth = 0);
+
+ /// adjustFunctionParamType - Converts the type of a function parameter to a
+ // type that can be passed as an argument type to
+ /// ASTContext::getFunctionType.
+ ///
+ /// C++ [dcl.fct]p3: "...Any cv-qualifier modifying a parameter type is
+ /// deleted. Such cv-qualifiers affect only the definition of the parameter
+ /// within the body of the function; they do not affect the function type.
+ QualType adjustFunctionParamType(QualType T) const {
+ if (!Context.getLangOptions().CPlusPlus)
+ return T;
+ return
+ T->isDependentType() ? T.getUnqualifiedType()
+ : T.getDesugaredType().getUnqualifiedType();
+
+ }
+ /// \name Code completion
+ //@{
+ void setCodeCompleteConsumer(CodeCompleteConsumer *CCC);
+ virtual void CodeCompleteOrdinaryName(Scope *S);
+ virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
+ SourceLocation OpLoc,
+ bool IsArrow);
+ virtual void CodeCompleteTag(Scope *S, unsigned TagSpec);
+ virtual void CodeCompleteCase(Scope *S);
+ virtual void CodeCompleteCall(Scope *S, ExprTy *Fn,
+ ExprTy **Args, unsigned NumArgs);
+ virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+ bool EnteringContext);
+ virtual void CodeCompleteUsing(Scope *S);
+ virtual void CodeCompleteUsingDirective(Scope *S);
+ virtual void CodeCompleteNamespaceDecl(Scope *S);
+ virtual void CodeCompleteNamespaceAliasDecl(Scope *S);
+ virtual void CodeCompleteOperatorName(Scope *S);
+
+ virtual void CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS);
+ //@}
+
//===--------------------------------------------------------------------===//
// Extra semantic analysis beyond the C type system
private:
- Action::OwningExprResult CheckFunctionCall(FunctionDecl *FDecl,
- CallExpr *TheCall);
-
- Action::OwningExprResult CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
+ bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
+ bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
+
SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
unsigned ByteNo) const;
+ bool CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall);
bool CheckObjCString(Expr *Arg);
+
+ Action::OwningExprResult CheckBuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall);
bool SemaBuiltinVAStart(CallExpr *TheCall);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
+ bool SemaBuiltinUnaryFP(CallExpr *TheCall);
bool SemaBuiltinStackAddress(CallExpr *TheCall);
public:
@@ -3195,19 +3788,20 @@ public:
Action::OwningExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
private:
- bool SemaBuiltinPrefetch(CallExpr *TheCall);
+ bool SemaBuiltinPrefetch(CallExpr *TheCall);
bool SemaBuiltinObjectSize(CallExpr *TheCall);
bool SemaBuiltinLongjmp(CallExpr *TheCall);
bool SemaBuiltinAtomicOverloaded(CallExpr *TheCall);
+ bool SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall);
bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg);
void CheckPrintfString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
const CallExpr *TheCall, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg);
- void CheckNonNullArguments(const NonNullAttr *NonNull,
+ void CheckNonNullArguments(const NonNullAttr *NonNull,
const CallExpr *TheCall);
- void CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
+ void CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg);
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
@@ -3221,12 +3815,12 @@ template <typename T>
class ExprOwningPtr : public Action::ExprArg {
public:
ExprOwningPtr(Sema *S, T *expr) : Action::ExprArg(*S, expr) {}
-
+
void reset(T* p) { Action::ExprArg::operator=(p); }
T* get() const { return static_cast<T*>(Action::ExprArg::get()); }
T* take() { return static_cast<T*>(Action::ExprArg::take()); }
T* release() { return take(); }
-
+
T& operator*() const { return *get(); }
T* operator->() const { return get(); }
};
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index bae69ac6dc74a..21f83a560d7c4 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -11,15 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "SemaInherit.h"
#include "Sema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclCXX.h"
using namespace clang;
/// SetMemberAccessSpecifier - Set the access specifier of a member.
/// Returns true on error (when the previous member decl access specifier
/// is different from the new member decl access specifier).
-bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
+bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
NamedDecl *PrevMemberDecl,
AccessSpecifier LexicalAS) {
if (!PrevMemberDecl) {
@@ -27,52 +28,49 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
MemberDecl->setAccess(LexicalAS);
return false;
}
-
+
// C++ [class.access.spec]p3: When a member is redeclared its access
// specifier must be same as its initial declaration.
if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
- Diag(MemberDecl->getLocation(),
- diag::err_class_redeclared_with_different_access)
+ Diag(MemberDecl->getLocation(),
+ diag::err_class_redeclared_with_different_access)
<< MemberDecl << LexicalAS;
Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
<< PrevMemberDecl << PrevMemberDecl->getAccess();
return true;
}
-
+
MemberDecl->setAccess(PrevMemberDecl->getAccess());
return false;
}
-/// CheckBaseClassAccess - Check that a derived class can access its base class
-/// and report an error if it can't. [class.access.base]
-bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
- BasePaths& Paths, SourceLocation AccessLoc,
- DeclarationName Name) {
+/// Find a class on the derivation path between Derived and Base that is
+/// inaccessible. If @p NoPrivileges is true, special access rights (members
+/// and friends) are not considered.
+const CXXBaseSpecifier *Sema::FindInaccessibleBase(
+ QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) {
Base = Context.getCanonicalType(Base).getUnqualifiedType();
- assert(!Paths.isAmbiguous(Base) &&
+ assert(!Paths.isAmbiguous(Base) &&
"Can't check base class access if set of paths is ambiguous");
assert(Paths.isRecordingPaths() &&
"Can't check base class access without recorded paths");
-
- if (!getLangOptions().AccessControl)
- return false;
-
- const CXXBaseSpecifier *InacessibleBase = 0;
- const CXXRecordDecl* CurrentClassDecl = 0;
+
+ const CXXBaseSpecifier *InaccessibleBase = 0;
+
+ const CXXRecordDecl *CurrentClassDecl = 0;
if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl()))
CurrentClassDecl = MD->getParent();
- for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
+ for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
Path != PathsEnd; ++Path) {
-
+
bool FoundInaccessibleBase = false;
-
- for (BasePath::const_iterator Element = Path->begin(),
+
+ for (CXXBasePath::const_iterator Element = Path->begin(),
ElementEnd = Path->end(); Element != ElementEnd; ++Element) {
const CXXBaseSpecifier *Base = Element->Base;
-
+
switch (Base->getAccessSpecifier()) {
default:
assert(0 && "invalid access specifier");
@@ -81,44 +79,59 @@ bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
break;
case AS_private:
// FIXME: Check if the current function/class is a friend.
- if (CurrentClassDecl != Element->Class)
+ if (NoPrivileges || CurrentClassDecl != Element->Class)
FoundInaccessibleBase = true;
break;
- case AS_protected:
+ case AS_protected:
// FIXME: Implement
break;
}
-
+
if (FoundInaccessibleBase) {
- InacessibleBase = Base;
+ InaccessibleBase = Base;
break;
}
}
-
+
if (!FoundInaccessibleBase) {
// We found a path to the base, our work here is done.
- InacessibleBase = 0;
- break;
+ return 0;
}
}
- if (InacessibleBase) {
- Diag(AccessLoc, InaccessibleBaseID)
+ assert(InaccessibleBase && "no path found, but no inaccessible base");
+ return InaccessibleBase;
+}
+
+/// CheckBaseClassAccess - Check that a derived class can access its base class
+/// and report an error if it can't. [class.access.base]
+bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
+ unsigned InaccessibleBaseID,
+ CXXBasePaths &Paths, SourceLocation AccessLoc,
+ DeclarationName Name) {
+
+ if (!getLangOptions().AccessControl)
+ return false;
+ const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase(
+ Derived, Base, Paths);
+
+ if (InaccessibleBase) {
+ Diag(AccessLoc, InaccessibleBaseID)
<< Derived << Base << Name;
- AccessSpecifier AS = InacessibleBase->getAccessSpecifierAsWritten();
-
+ AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten();
+
// If there's no written access specifier, then the inheritance specifier
// is implicitly private.
if (AS == AS_none)
- Diag(InacessibleBase->getSourceRange().getBegin(),
+ Diag(InaccessibleBase->getSourceRange().getBegin(),
diag::note_inheritance_implicitly_private_here);
else
- Diag(InacessibleBase->getSourceRange().getBegin(),
+ Diag(InaccessibleBase->getSourceRange().getBegin(),
diag::note_inheritance_specifier_here) << AS;
return true;
}
-
+
return false;
}
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 1bf8444c42b74..0a5335a2be05e 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -32,8 +32,8 @@ namespace {
/// Stack - Entries in the #pragma pack stack, consisting of saved
/// alignments and optional names.
stack_ty Stack;
-
- public:
+
+ public:
PragmaPackStack() : Alignment(0) {}
void setAlignment(unsigned A) { Alignment = A; }
@@ -56,14 +56,14 @@ namespace {
bool PragmaPackStack::pop(IdentifierInfo *Name) {
if (Stack.empty())
return false;
-
+
// If name is empty just pop top.
if (!Name) {
Alignment = Stack.back().first;
Stack.pop_back();
return true;
- }
-
+ }
+
// Otherwise, find the named record.
for (unsigned i = Stack.size(); i != 0; ) {
--i;
@@ -74,7 +74,7 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) {
return true;
}
}
-
+
return false;
}
@@ -93,8 +93,8 @@ unsigned Sema::getPragmaPackAlignment() const {
return 0;
}
-void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
- ExprTy *alignment, SourceLocation PragmaLoc,
+void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
+ ExprTy *alignment, SourceLocation PragmaLoc,
SourceLocation LParenLoc, SourceLocation RParenLoc) {
Expr *Alignment = static_cast<Expr *>(alignment);
@@ -102,7 +102,7 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
unsigned AlignmentVal = 0;
if (Alignment) {
llvm::APSInt Val;
-
+
// pack(0) is like pack(), which just works out since that is what
// we use 0 for in PackAttr.
if (!Alignment->isIntegerConstantExpr(Val, Context) ||
@@ -115,12 +115,12 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
AlignmentVal = (unsigned) Val.getZExtValue();
}
-
+
if (PackContext == 0)
PackContext = new PragmaPackStack();
-
+
PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
-
+
switch (Kind) {
case Action::PPK_Default: // pack([n])
Context->setAlignment(AlignmentVal);
@@ -140,15 +140,15 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
Context->push(Name);
// Set the new alignment if specified.
if (Alignment)
- Context->setAlignment(AlignmentVal);
+ Context->setAlignment(AlignmentVal);
break;
case Action::PPK_Pop: // pack(pop [, id] [, n])
// MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack:
// "#pragma pack(pop, identifier, n) is undefined"
if (Alignment && Name)
- Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment);
-
+ Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment);
+
// Do the pop.
if (!Context->pop(Name)) {
// If a name was specified then failure indicates the name
@@ -170,42 +170,34 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
}
}
-void Sema::ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
+void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers,
+ Scope *curScope,
SourceLocation PragmaLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
-
- // Verify that all of the expressions are valid before
- // modifying the attributes of any referenced decl.
- Expr *ErrorExpr = 0;
-
- for (unsigned i = 0; i < NumExprs; ++i) {
- Expr *Ex = (Expr*) Exprs[i];
- if (!isa<DeclRefExpr>(Ex)) {
- ErrorExpr = Ex;
- break;
- }
- Decl *d = cast<DeclRefExpr>(Ex)->getDecl();;
+ for (unsigned i = 0; i < NumIdentifiers; ++i) {
+ const Token &Tok = Identifiers[i];
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ LookupResult Lookup;
+ LookupParsedName(Lookup, curScope, NULL, Name,LookupOrdinaryName,
+ false, true, Tok.getLocation());
+ // FIXME: Handle Lookup.isAmbiguous?
- if (!isa<VarDecl>(d) || !cast<VarDecl>(d)->hasLocalStorage()) {
- ErrorExpr = Ex;
- break;
+ NamedDecl *ND = Lookup.getAsSingleDecl(Context);
+
+ if (!ND) {
+ Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
+ << Name << SourceRange(Tok.getLocation());
+ continue;
}
- }
-
- // Delete the expressions if we encountered any error.
- if (ErrorExpr) {
- Diag(ErrorExpr->getLocStart(), diag::warn_pragma_unused_expected_localvar);
- for (unsigned i = 0; i < NumExprs; ++i)
- ((Expr*) Exprs[i])->Destroy(Context);
- return;
- }
-
- // Otherwise, add the 'unused' attribute to each referenced declaration.
- for (unsigned i = 0; i < NumExprs; ++i) {
- DeclRefExpr *DR = (DeclRefExpr*) Exprs[i];
- DR->getDecl()->addAttr(::new (Context) UnusedAttr());
- DR->Destroy(Context);
+
+ if (!isa<VarDecl>(ND) || !cast<VarDecl>(ND)->hasLocalStorage()) {
+ Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar)
+ << Name << SourceRange(Tok.getLocation());
+ continue;
+ }
+
+ ND->addAttr(::new (Context) UnusedAttr());
}
}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
new file mode 100644
index 0000000000000..69d1f92a08323
--- /dev/null
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -0,0 +1,1128 @@
+//===--- SemaNamedCast.cpp - Semantic Analysis for Named Casts ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for C++ named casts.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/Basic/PartialDiagnostic.h"
+#include "llvm/ADT/SmallVector.h"
+#include <set>
+using namespace clang;
+
+enum TryCastResult {
+ TC_NotApplicable, ///< The cast method is not applicable.
+ TC_Success, ///< The cast method is appropriate and successful.
+ TC_Failed ///< The cast method is appropriate, but failed. A
+ ///< diagnostic has been emitted.
+};
+
+enum CastType {
+ CT_Const, ///< const_cast
+ CT_Static, ///< static_cast
+ CT_Reinterpret, ///< reinterpret_cast
+ CT_Dynamic, ///< dynamic_cast
+ CT_CStyle, ///< (Type)expr
+ CT_Functional ///< Type(expr)
+};
+
+static void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ const SourceRange &DestRange);
+static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ const SourceRange &DestRange,
+ CastExpr::CastKind &Kind);
+static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl);
+static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ const SourceRange &DestRange,
+ CastExpr::CastKind &Kind);
+
+static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
+
+// The Try functions attempt a specific way of casting. If they succeed, they
+// return TC_Success. If their way of casting is not appropriate for the given
+// arguments, they return TC_NotApplicable and *may* set diag to a diagnostic
+// to emit if no other way succeeds. If their way of casting is appropriate but
+// fails, they return TC_Failed and *must* set diag; they can set it to 0 if
+// they emit a specialized diagnostic.
+// All diagnostics returned by these functions must expect the same three
+// arguments:
+// %0: Cast Type (a value from the CastType enumeration)
+// %1: Source Type
+// %2: Destination Type
+static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, unsigned &msg);
+static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg);
+static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg);
+static TryCastResult TryStaticDowncast(Sema &Self, QualType SrcType,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ QualType OrigSrcType,
+ QualType OrigDestType, unsigned &msg);
+static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType,
+ QualType DestType,bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg);
+static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl);
+static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl);
+static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ bool CStyle, unsigned &msg);
+static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind);
+
+/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
+Action::OwningExprResult
+Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc, TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc, ExprArg E,
+ SourceLocation RParenLoc) {
+ Expr *Ex = E.takeAs<Expr>();
+ // FIXME: Preserve type source info.
+ QualType DestType = GetTypeFromParser(Ty);
+ SourceRange OpRange(OpLoc, RParenLoc);
+ SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc);
+
+ // If the type is dependent, we won't do the semantic analysis now.
+ // FIXME: should we check this in a more fine-grained manner?
+ bool TypeDependent = DestType->isDependentType() || Ex->isTypeDependent();
+
+ switch (Kind) {
+ default: assert(0 && "Unknown C++ cast!");
+
+ case tok::kw_const_cast:
+ if (!TypeDependent)
+ CheckConstCast(*this, Ex, DestType, OpRange, DestRange);
+ return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(),
+ Ex, DestType, OpLoc));
+
+ case tok::kw_dynamic_cast: {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (!TypeDependent)
+ CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind);
+ return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
+ Kind, Ex, DestType, OpLoc));
+ }
+ case tok::kw_reinterpret_cast: {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (!TypeDependent)
+ CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind);
+ return Owned(new (Context) CXXReinterpretCastExpr(
+ DestType.getNonReferenceType(),
+ Kind, Ex, DestType, OpLoc));
+ }
+ case tok::kw_static_cast: {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (!TypeDependent) {
+ CXXMethodDecl *Method = 0;
+
+ CheckStaticCast(*this, Ex, DestType, OpRange, Kind, Method);
+
+ if (Method) {
+ OwningExprResult CastArg
+ = BuildCXXCastArgument(OpLoc, DestType.getNonReferenceType(),
+ Kind, Method, Owned(Ex));
+ if (CastArg.isInvalid())
+ return ExprError();
+
+ Ex = CastArg.takeAs<Expr>();
+ }
+ }
+
+ return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
+ Kind, Ex, DestType, OpLoc));
+ }
+ }
+
+ return ExprError();
+}
+
+/// CastsAwayConstness - Check if the pointer conversion from SrcType to
+/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by
+/// the cast checkers. Both arguments must denote pointer (possibly to member)
+/// types.
+bool
+CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
+ // Casting away constness is defined in C++ 5.2.11p8 with reference to
+ // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
+ // the rules are non-trivial. So first we construct Tcv *...cv* as described
+ // in C++ 5.2.11p8.
+ assert((SrcType->isPointerType() || SrcType->isMemberPointerType()) &&
+ "Source type is not pointer or pointer to member.");
+ assert((DestType->isPointerType() || DestType->isMemberPointerType()) &&
+ "Destination type is not pointer or pointer to member.");
+
+ QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType;
+ llvm::SmallVector<Qualifiers, 8> cv1, cv2;
+
+ // Find the qualifications.
+ while (Self.UnwrapSimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
+ cv1.push_back(UnwrappedSrcType.getQualifiers());
+ cv2.push_back(UnwrappedDestType.getQualifiers());
+ }
+ assert(cv1.size() > 0 && "Must have at least one pointer level.");
+
+ // Construct void pointers with those qualifiers (in reverse order of
+ // unwrapping, of course).
+ QualType SrcConstruct = Self.Context.VoidTy;
+ QualType DestConstruct = Self.Context.VoidTy;
+ ASTContext &Context = Self.Context;
+ for (llvm::SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(),
+ i2 = cv2.rbegin();
+ i1 != cv1.rend(); ++i1, ++i2) {
+ SrcConstruct
+ = Context.getPointerType(Context.getQualifiedType(SrcConstruct, *i1));
+ DestConstruct
+ = Context.getPointerType(Context.getQualifiedType(DestConstruct, *i2));
+ }
+
+ // Test if they're compatible.
+ return SrcConstruct != DestConstruct &&
+ !Self.IsQualificationConversion(SrcConstruct, DestConstruct);
+}
+
+/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
+/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime-
+/// checked downcasts in class hierarchies.
+static void
+CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ const SourceRange &DestRange, CastExpr::CastKind &Kind) {
+ QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
+ DestType = Self.Context.getCanonicalType(DestType);
+
+ // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type,
+ // or "pointer to cv void".
+
+ QualType DestPointee;
+ const PointerType *DestPointer = DestType->getAs<PointerType>();
+ const ReferenceType *DestReference = DestType->getAs<ReferenceType>();
+ if (DestPointer) {
+ DestPointee = DestPointer->getPointeeType();
+ } else if (DestReference) {
+ DestPointee = DestReference->getPointeeType();
+ } else {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr)
+ << OrigDestType << DestRange;
+ return;
+ }
+
+ const RecordType *DestRecord = DestPointee->getAs<RecordType>();
+ if (DestPointee->isVoidType()) {
+ assert(DestPointer && "Reference to void is not possible");
+ } else if (DestRecord) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
+ PDiag(diag::err_bad_dynamic_cast_incomplete)
+ << DestRange))
+ return;
+ } else {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
+ << DestPointee.getUnqualifiedType() << DestRange;
+ return;
+ }
+
+ // C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to
+ // complete class type, [...]. If T is an lvalue reference type, v shall be
+ // an lvalue of a complete class type, [...]. If T is an rvalue reference
+ // type, v shall be an expression having a complete effective class type,
+ // [...]
+
+ QualType SrcType = Self.Context.getCanonicalType(OrigSrcType);
+ QualType SrcPointee;
+ if (DestPointer) {
+ if (const PointerType *SrcPointer = SrcType->getAs<PointerType>()) {
+ SrcPointee = SrcPointer->getPointeeType();
+ } else {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr)
+ << OrigSrcType << SrcExpr->getSourceRange();
+ return;
+ }
+ } else if (DestReference->isLValueReferenceType()) {
+ if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
+ << CT_Dynamic << OrigSrcType << OrigDestType << OpRange;
+ }
+ SrcPointee = SrcType;
+ } else {
+ SrcPointee = SrcType;
+ }
+
+ const RecordType *SrcRecord = SrcPointee->getAs<RecordType>();
+ if (SrcRecord) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
+ PDiag(diag::err_bad_dynamic_cast_incomplete)
+ << SrcExpr->getSourceRange()))
+ return;
+ } else {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
+ << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
+ return;
+ }
+
+ assert((DestPointer || DestReference) &&
+ "Bad destination non-ptr/ref slipped through.");
+ assert((DestRecord || DestPointee->isVoidType()) &&
+ "Bad destination pointee slipped through.");
+ assert(SrcRecord && "Bad source pointee slipped through.");
+
+ // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness.
+ if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
+ << CT_Dynamic << OrigSrcType << OrigDestType << OpRange;
+ return;
+ }
+
+ // C++ 5.2.7p3: If the type of v is the same as the required result type,
+ // [except for cv].
+ if (DestRecord == SrcRecord) {
+ return;
+ }
+
+ // C++ 5.2.7p5
+ // Upcasts are resolved statically.
+ if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) {
+ Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
+ OpRange.getBegin(), OpRange);
+ Kind = CastExpr::CK_DerivedToBase;
+ // Diagnostic already emitted on error.
+ return;
+ }
+
+ // C++ 5.2.7p6: Otherwise, v shall be [polymorphic].
+ const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context);
+ assert(SrcDecl && "Definition missing");
+ if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
+ << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
+ }
+
+ // Done. Everything else is run-time checks.
+ Kind = CastExpr::CK_Dynamic;
+}
+
+/// CheckConstCast - Check that a const_cast\<DestType\>(SrcExpr) is valid.
+/// Refer to C++ 5.2.11 for details. const_cast is typically used in code
+/// like this:
+/// const char *str = "literal";
+/// legacy_function(const_cast\<char*\>(str));
+void
+CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange, const SourceRange &DestRange) {
+ if (!DestType->isLValueReferenceType())
+ Self.DefaultFunctionArrayConversion(SrcExpr);
+
+ unsigned msg = diag::err_bad_cxx_cast_generic;
+ if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success
+ && msg != 0)
+ Self.Diag(OpRange.getBegin(), msg) << CT_Const
+ << SrcExpr->getType() << DestType << OpRange;
+}
+
+/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
+/// valid.
+/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code
+/// like this:
+/// char *bytes = reinterpret_cast\<char*\>(int_ptr);
+void
+CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange, const SourceRange &DestRange,
+ CastExpr::CastKind &Kind) {
+ if (!DestType->isLValueReferenceType())
+ Self.DefaultFunctionArrayConversion(SrcExpr);
+
+ unsigned msg = diag::err_bad_cxx_cast_generic;
+ if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
+ msg, Kind)
+ != TC_Success && msg != 0)
+ Self.Diag(OpRange.getBegin(), msg) << CT_Reinterpret
+ << SrcExpr->getType() << DestType << OpRange;
+}
+
+
+/// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid.
+/// Refer to C++ 5.2.9 for details. Static casts are mostly used for making
+/// implicit conversions explicit and getting rid of data loss warnings.
+void
+CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange, CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl) {
+ // This test is outside everything else because it's the only case where
+ // a non-lvalue-reference target type does not lead to decay.
+ // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
+ if (DestType->isVoidType()) {
+ return;
+ }
+
+ if (!DestType->isLValueReferenceType())
+ Self.DefaultFunctionArrayConversion(SrcExpr);
+
+ unsigned msg = diag::err_bad_cxx_cast_generic;
+ if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false,OpRange, msg,
+ Kind, ConversionDecl)
+ != TC_Success && msg != 0)
+ Self.Diag(OpRange.getBegin(), msg) << CT_Static
+ << SrcExpr->getType() << DestType << OpRange;
+}
+
+/// TryStaticCast - Check if a static cast can be performed, and do so if
+/// possible. If @p CStyle, ignore access restrictions on hierarchy casting
+/// and casting away constness.
+static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange, unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl) {
+ // The order the tests is not entirely arbitrary. There is one conversion
+ // that can be handled in two different ways. Given:
+ // struct A {};
+ // struct B : public A {
+ // B(); B(const A&);
+ // };
+ // const A &a = B();
+ // the cast static_cast<const B&>(a) could be seen as either a static
+ // reference downcast, or an explicit invocation of the user-defined
+ // conversion using B's conversion constructor.
+ // DR 427 specifies that the downcast is to be applied here.
+
+ // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
+ // Done outside this function.
+
+ TryCastResult tcr;
+
+ // C++ 5.2.9p5, reference downcast.
+ // See the function for details.
+ // DR 427 specifies that this is to be applied before paragraph 2.
+ tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle,OpRange,msg);
+ if (tcr != TC_NotApplicable)
+ return tcr;
+
+ // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
+ // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
+ tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, msg);
+ if (tcr != TC_NotApplicable)
+ return tcr;
+
+ // C++ 5.2.9p2: An expression e can be explicitly converted to a type T
+ // [...] if the declaration "T t(e);" is well-formed, [...].
+ tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg,
+ Kind, ConversionDecl);
+ if (tcr != TC_NotApplicable)
+ return tcr;
+
+ // C++ 5.2.9p6: May apply the reverse of any standard conversion, except
+ // lvalue-to-rvalue, array-to-pointer, function-to-pointer, and boolean
+ // conversions, subject to further restrictions.
+ // Also, C++ 5.2.9p1 forbids casting away constness, which makes reversal
+ // of qualification conversions impossible.
+ // In the CStyle case, the earlier attempt to const_cast should have taken
+ // care of reverse qualification conversions.
+
+ QualType OrigSrcType = SrcExpr->getType();
+
+ QualType SrcType = Self.Context.getCanonicalType(SrcExpr->getType());
+
+ // Reverse integral promotion/conversion. All such conversions are themselves
+ // again integral promotions or conversions and are thus already handled by
+ // p2 (TryDirectInitialization above).
+ // (Note: any data loss warnings should be suppressed.)
+ // The exception is the reverse of enum->integer, i.e. integer->enum (and
+ // enum->enum). See also C++ 5.2.9p7.
+ // The same goes for reverse floating point promotion/conversion and
+ // floating-integral conversions. Again, only floating->enum is relevant.
+ if (DestType->isEnumeralType()) {
+ if (SrcType->isComplexType() || SrcType->isVectorType()) {
+ // Fall through - these cannot be converted.
+ } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType())
+ return TC_Success;
+ }
+
+ // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
+ // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance.
+ tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg);
+ if (tcr != TC_NotApplicable)
+ return tcr;
+
+ // Reverse member pointer conversion. C++ 4.11 specifies member pointer
+ // conversion. C++ 5.2.9p9 has additional information.
+ // DR54's access restrictions apply here also.
+ tcr = TryStaticMemberPointerUpcast(Self, SrcType, DestType, CStyle,
+ OpRange, msg);
+ if (tcr != TC_NotApplicable)
+ return tcr;
+
+ // Reverse pointer conversion to void*. C++ 4.10.p2 specifies conversion to
+ // void*. C++ 5.2.9p10 specifies additional restrictions, which really is
+ // just the usual constness stuff.
+ if (const PointerType *SrcPointer = SrcType->getAs<PointerType>()) {
+ QualType SrcPointee = SrcPointer->getPointeeType();
+ if (SrcPointee->isVoidType()) {
+ if (const PointerType *DestPointer = DestType->getAs<PointerType>()) {
+ QualType DestPointee = DestPointer->getPointeeType();
+ if (DestPointee->isIncompleteOrObjectType()) {
+ // This is definitely the intended conversion, but it might fail due
+ // to a const violation.
+ if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
+ msg = diag::err_bad_cxx_cast_const_away;
+ return TC_Failed;
+ }
+ return TC_Success;
+ }
+ }
+ }
+ }
+
+ // We tried everything. Everything! Nothing works! :-(
+ return TC_NotApplicable;
+}
+
+/// Tests whether a conversion according to N2844 is valid.
+TryCastResult
+TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ unsigned &msg) {
+ // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
+ // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
+ const RValueReferenceType *R = DestType->getAs<RValueReferenceType>();
+ if (!R)
+ return TC_NotApplicable;
+
+ if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid)
+ return TC_NotApplicable;
+
+ // Because we try the reference downcast before this function, from now on
+ // this is the only cast possibility, so we issue an error if we fail now.
+ // FIXME: Should allow casting away constness if CStyle.
+ bool DerivedToBase;
+ if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(),
+ DerivedToBase) <
+ Sema::Ref_Compatible_With_Added_Qualification) {
+ msg = diag::err_bad_lvalue_to_rvalue_cast;
+ return TC_Failed;
+ }
+
+ // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation
+ // than nothing.
+ return TC_Success;
+}
+
+/// Tests whether a conversion according to C++ 5.2.9p5 is valid.
+TryCastResult
+TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ bool CStyle, const SourceRange &OpRange,
+ unsigned &msg) {
+ // C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be
+ // cast to type "reference to cv2 D", where D is a class derived from B,
+ // if a valid standard conversion from "pointer to D" to "pointer to B"
+ // exists, cv2 >= cv1, and B is not a virtual base class of D.
+ // In addition, DR54 clarifies that the base must be accessible in the
+ // current context. Although the wording of DR54 only applies to the pointer
+ // variant of this rule, the intent is clearly for it to apply to the this
+ // conversion as well.
+
+ const ReferenceType *DestReference = DestType->getAs<ReferenceType>();
+ if (!DestReference) {
+ return TC_NotApplicable;
+ }
+ bool RValueRef = DestReference->isRValueReferenceType();
+ if (!RValueRef && SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ // We know the left side is an lvalue reference, so we can suggest a reason.
+ msg = diag::err_bad_cxx_cast_rvalue;
+ return TC_NotApplicable;
+ }
+
+ QualType DestPointee = DestReference->getPointeeType();
+
+ return TryStaticDowncast(Self, SrcExpr->getType(), DestPointee, CStyle,
+ OpRange, SrcExpr->getType(), DestType, msg);
+}
+
+/// Tests whether a conversion according to C++ 5.2.9p8 is valid.
+TryCastResult
+TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
+ bool CStyle, const SourceRange &OpRange,
+ unsigned &msg) {
+ // C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class
+ // type, can be converted to an rvalue of type "pointer to cv2 D", where D
+ // is a class derived from B, if a valid standard conversion from "pointer
+ // to D" to "pointer to B" exists, cv2 >= cv1, and B is not a virtual base
+ // class of D.
+ // In addition, DR54 clarifies that the base must be accessible in the
+ // current context.
+
+ const PointerType *DestPointer = DestType->getAs<PointerType>();
+ if (!DestPointer) {
+ return TC_NotApplicable;
+ }
+
+ const PointerType *SrcPointer = SrcType->getAs<PointerType>();
+ if (!SrcPointer) {
+ msg = diag::err_bad_static_cast_pointer_nonpointer;
+ return TC_NotApplicable;
+ }
+
+ return TryStaticDowncast(Self, SrcPointer->getPointeeType(),
+ DestPointer->getPointeeType(), CStyle,
+ OpRange, SrcType, DestType, msg);
+}
+
+/// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and
+/// TryStaticPointerDowncast. Tests whether a static downcast from SrcType to
+/// DestType, both of which must be canonical, is possible and allowed.
+TryCastResult
+TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType,
+ bool CStyle, const SourceRange &OpRange, QualType OrigSrcType,
+ QualType OrigDestType, unsigned &msg) {
+ // Downcast can only happen in class hierarchies, so we need classes.
+ if (!DestType->isRecordType() || !SrcType->isRecordType()) {
+ return TC_NotApplicable;
+ }
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle,
+ /*DetectVirtual=*/true);
+ if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) {
+ return TC_NotApplicable;
+ }
+
+ // Target type does derive from source type. Now we're serious. If an error
+ // appears now, it's not ignored.
+ // This may not be entirely in line with the standard. Take for example:
+ // struct A {};
+ // struct B : virtual A {
+ // B(A&);
+ // };
+ //
+ // void f()
+ // {
+ // (void)static_cast<const B&>(*((A*)0));
+ // }
+ // As far as the standard is concerned, p5 does not apply (A is virtual), so
+ // p2 should be used instead - "const B& t(*((A*)0));" is perfectly valid.
+ // However, both GCC and Comeau reject this example, and accepting it would
+ // mean more complex code if we're to preserve the nice error message.
+ // FIXME: Being 100% compliant here would be nice to have.
+
+ // Must preserve cv, as always, unless we're in C-style mode.
+ if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) {
+ msg = diag::err_bad_cxx_cast_const_away;
+ return TC_Failed;
+ }
+
+ if (Paths.isAmbiguous(SrcType.getUnqualifiedType())) {
+ // This code is analoguous to that in CheckDerivedToBaseConversion, except
+ // that it builds the paths in reverse order.
+ // To sum up: record all paths to the base and build a nice string from
+ // them. Use it to spice up the error message.
+ if (!Paths.isRecordingPaths()) {
+ Paths.clear();
+ Paths.setRecordingPaths(true);
+ Self.IsDerivedFrom(DestType, SrcType, Paths);
+ }
+ std::string PathDisplayStr;
+ std::set<unsigned> DisplayedPaths;
+ for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
+ PI != PE; ++PI) {
+ if (DisplayedPaths.insert(PI->back().SubobjectNumber).second) {
+ // We haven't displayed a path to this particular base
+ // class subobject yet.
+ PathDisplayStr += "\n ";
+ for (CXXBasePath::const_reverse_iterator EI = PI->rbegin(),
+ EE = PI->rend();
+ EI != EE; ++EI)
+ PathDisplayStr += EI->Base->getType().getAsString() + " -> ";
+ PathDisplayStr += DestType.getAsString();
+ }
+ }
+
+ Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast)
+ << SrcType.getUnqualifiedType() << DestType.getUnqualifiedType()
+ << PathDisplayStr << OpRange;
+ msg = 0;
+ return TC_Failed;
+ }
+
+ if (Paths.getDetectedVirtual() != 0) {
+ QualType VirtualBase(Paths.getDetectedVirtual(), 0);
+ Self.Diag(OpRange.getBegin(), diag::err_static_downcast_via_virtual)
+ << OrigSrcType << OrigDestType << VirtualBase << OpRange;
+ msg = 0;
+ return TC_Failed;
+ }
+
+ if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
+ diag::err_downcast_from_inaccessible_base, Paths,
+ OpRange.getBegin(), DeclarationName())) {
+ msg = 0;
+ return TC_Failed;
+ }
+
+ return TC_Success;
+}
+
+/// TryStaticMemberPointerUpcast - Tests whether a conversion according to
+/// C++ 5.2.9p9 is valid:
+///
+/// An rvalue of type "pointer to member of D of type cv1 T" can be
+/// converted to an rvalue of type "pointer to member of B of type cv2 T",
+/// where B is a base class of D [...].
+///
+TryCastResult
+TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
+ bool CStyle, const SourceRange &OpRange,
+ unsigned &msg) {
+ const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>();
+ if (!DestMemPtr)
+ return TC_NotApplicable;
+ const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>();
+ if (!SrcMemPtr) {
+ msg = diag::err_bad_static_cast_member_pointer_nonmp;
+ return TC_NotApplicable;
+ }
+
+ // T == T, modulo cv
+ if (Self.Context.getCanonicalType(
+ SrcMemPtr->getPointeeType().getUnqualifiedType()) !=
+ Self.Context.getCanonicalType(DestMemPtr->getPointeeType().
+ getUnqualifiedType()))
+ return TC_NotApplicable;
+
+ // B base of D
+ QualType SrcClass(SrcMemPtr->getClass(), 0);
+ QualType DestClass(DestMemPtr->getClass(), 0);
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle,
+ /*DetectVirtual=*/true);
+ if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) {
+ return TC_NotApplicable;
+ }
+
+ // B is a base of D. But is it an allowed base? If not, it's a hard error.
+ if (Paths.isAmbiguous(DestClass)) {
+ Paths.clear();
+ Paths.setRecordingPaths(true);
+ bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths);
+ assert(StillOkay);
+ StillOkay = StillOkay;
+ std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths);
+ Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv)
+ << 1 << SrcClass << DestClass << PathDisplayStr << OpRange;
+ msg = 0;
+ return TC_Failed;
+ }
+
+ if (const RecordType *VBase = Paths.getDetectedVirtual()) {
+ Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual)
+ << SrcClass << DestClass << QualType(VBase, 0) << OpRange;
+ msg = 0;
+ return TC_Failed;
+ }
+
+ if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
+ diag::err_downcast_from_inaccessible_base, Paths,
+ OpRange.getBegin(), DeclarationName())) {
+ msg = 0;
+ return TC_Failed;
+ }
+
+ return TC_Success;
+}
+
+/// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2
+/// is valid:
+///
+/// An expression e can be explicitly converted to a type T using a
+/// @c static_cast if the declaration "T t(e);" is well-formed [...].
+TryCastResult
+TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ bool CStyle, const SourceRange &OpRange, unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXMethodDecl *&ConversionDecl) {
+ if (DestType->isRecordType()) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
+ diag::err_bad_dynamic_cast_incomplete)) {
+ msg = 0;
+ return TC_Failed;
+ }
+ }
+
+ if (DestType->isReferenceType()) {
+ // At this point of CheckStaticCast, if the destination is a reference,
+ // this has to work. There is no other way that works.
+ // On the other hand, if we're checking a C-style cast, we've still got
+ // the reinterpret_cast way. In that case, we pass an ICS so we don't
+ // get error messages.
+ ImplicitConversionSequence ICS;
+ bool failed = Self.CheckReferenceInit(SrcExpr, DestType,
+ OpRange.getBegin(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ CStyle ? &ICS : 0);
+ if (!failed)
+ return TC_Success;
+ if (CStyle)
+ return TC_NotApplicable;
+ // If we didn't pass the ICS, we already got an error message.
+ msg = 0;
+ return TC_Failed;
+ }
+
+ // FIXME: To get a proper error from invalid conversions here, we need to
+ // reimplement more of this.
+ // FIXME: This does not actually perform the conversion, and thus does not
+ // check for ambiguity or access.
+ ImplicitConversionSequence ICS =
+ Self.TryImplicitConversion(SrcExpr, DestType,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/true,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false,
+ /*one of user provided casts*/true);
+
+ if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
+ return TC_NotApplicable;
+
+ if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) {
+ ConversionDecl = cast<CXXMethodDecl>(ICS.UserDefined.ConversionFunction);
+ if (isa<CXXConstructorDecl>(ConversionDecl))
+ Kind = CastExpr::CK_ConstructorConversion;
+ else if (isa<CXXConversionDecl>(ConversionDecl))
+ Kind = CastExpr::CK_UserDefinedConversion;
+ } else if (ICS.ConversionKind ==
+ ImplicitConversionSequence::StandardConversion) {
+ // FIXME: Set the cast kind depending on which types of conversions we have.
+ }
+
+ return TC_Success;
+}
+
+/// TryConstCast - See if a const_cast from source to destination is allowed,
+/// and perform it if it is.
+static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ bool CStyle, unsigned &msg) {
+ DestType = Self.Context.getCanonicalType(DestType);
+ QualType SrcType = SrcExpr->getType();
+ if (const LValueReferenceType *DestTypeTmp =
+ DestType->getAs<LValueReferenceType>()) {
+ if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ // Cannot const_cast non-lvalue to lvalue reference type. But if this
+ // is C-style, static_cast might find a way, so we simply suggest a
+ // message and tell the parent to keep searching.
+ msg = diag::err_bad_cxx_cast_rvalue;
+ return TC_NotApplicable;
+ }
+
+ // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2
+ // [...] if a pointer to T1 can be [cast] to the type pointer to T2.
+ DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
+ SrcType = Self.Context.getPointerType(SrcType);
+ }
+
+ // C++ 5.2.11p5: For a const_cast involving pointers to data members [...]
+ // the rules for const_cast are the same as those used for pointers.
+
+ if (!DestType->isPointerType() && !DestType->isMemberPointerType()) {
+ // Cannot cast to non-pointer, non-reference type. Note that, if DestType
+ // was a reference type, we converted it to a pointer above.
+ // The status of rvalue references isn't entirely clear, but it looks like
+ // conversion to them is simply invalid.
+ // C++ 5.2.11p3: For two pointer types [...]
+ if (!CStyle)
+ msg = diag::err_bad_const_cast_dest;
+ return TC_NotApplicable;
+ }
+ if (DestType->isFunctionPointerType() ||
+ DestType->isMemberFunctionPointerType()) {
+ // Cannot cast direct function pointers.
+ // C++ 5.2.11p2: [...] where T is any object type or the void type [...]
+ // T is the ultimate pointee of source and target type.
+ if (!CStyle)
+ msg = diag::err_bad_const_cast_dest;
+ return TC_NotApplicable;
+ }
+ SrcType = Self.Context.getCanonicalType(SrcType);
+
+ // Unwrap the pointers. Ignore qualifiers. Terminate early if the types are
+ // completely equal.
+ // FIXME: const_cast should probably not be able to convert between pointers
+ // to different address spaces.
+ // C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers
+ // in multi-level pointers may change, but the level count must be the same,
+ // as must be the final pointee type.
+ while (SrcType != DestType &&
+ Self.UnwrapSimilarPointerTypes(SrcType, DestType)) {
+ SrcType = SrcType.getUnqualifiedType();
+ DestType = DestType.getUnqualifiedType();
+ }
+
+ // Since we're dealing in canonical types, the remainder must be the same.
+ if (SrcType != DestType)
+ return TC_NotApplicable;
+
+ return TC_Success;
+}
+
+static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind) {
+ QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
+
+ DestType = Self.Context.getCanonicalType(DestType);
+ QualType SrcType = SrcExpr->getType();
+ if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
+ bool LValue = DestTypeTmp->isLValueReferenceType();
+ if (LValue && SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ // Cannot cast non-lvalue to reference type. See the similar comment in
+ // const_cast.
+ msg = diag::err_bad_cxx_cast_rvalue;
+ return TC_NotApplicable;
+ }
+
+ // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the
+ // same effect as the conversion *reinterpret_cast<T*>(&x) with the
+ // built-in & and * operators.
+ // This code does this transformation for the checked types.
+ DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
+ SrcType = Self.Context.getPointerType(SrcType);
+ }
+
+ // Canonicalize source for comparison.
+ SrcType = Self.Context.getCanonicalType(SrcType);
+
+ const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(),
+ *SrcMemPtr = SrcType->getAs<MemberPointerType>();
+ if (DestMemPtr && SrcMemPtr) {
+ // C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1"
+ // can be explicitly converted to an rvalue of type "pointer to member
+ // of Y of type T2" if T1 and T2 are both function types or both object
+ // types.
+ if (DestMemPtr->getPointeeType()->isFunctionType() !=
+ SrcMemPtr->getPointeeType()->isFunctionType())
+ return TC_NotApplicable;
+
+ // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away
+ // constness.
+ // A reinterpret_cast followed by a const_cast can, though, so in C-style,
+ // we accept it.
+ if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
+ msg = diag::err_bad_cxx_cast_const_away;
+ return TC_Failed;
+ }
+
+ // A valid member pointer cast.
+ return TC_Success;
+ }
+
+ // See below for the enumeral issue.
+ if (SrcType->isNullPtrType() && DestType->isIntegralType() &&
+ !DestType->isEnumeralType()) {
+ // C++0x 5.2.10p4: A pointer can be explicitly converted to any integral
+ // type large enough to hold it. A value of std::nullptr_t can be
+ // converted to an integral type; the conversion has the same meaning
+ // and validity as a conversion of (void*)0 to the integral type.
+ if (Self.Context.getTypeSize(SrcType) >
+ Self.Context.getTypeSize(DestType)) {
+ msg = diag::err_bad_reinterpret_cast_small_int;
+ return TC_Failed;
+ }
+ Kind = CastExpr::CK_PointerToIntegral;
+ return TC_Success;
+ }
+
+ bool destIsVector = DestType->isVectorType();
+ bool srcIsVector = SrcType->isVectorType();
+ if (srcIsVector || destIsVector) {
+ bool srcIsScalar = SrcType->isIntegralType() && !SrcType->isEnumeralType();
+ bool destIsScalar =
+ DestType->isIntegralType() && !DestType->isEnumeralType();
+
+ // Check if this is a cast between a vector and something else.
+ if (!(srcIsScalar && destIsVector) && !(srcIsVector && destIsScalar) &&
+ !(srcIsVector && destIsVector))
+ return TC_NotApplicable;
+
+ // If both types have the same size, we can successfully cast.
+ if (Self.Context.getTypeSize(SrcType) == Self.Context.getTypeSize(DestType))
+ return TC_Success;
+
+ if (destIsScalar)
+ msg = diag::err_bad_cxx_cast_vector_to_scalar_different_size;
+ else if (srcIsScalar)
+ msg = diag::err_bad_cxx_cast_scalar_to_vector_different_size;
+ else
+ msg = diag::err_bad_cxx_cast_vector_to_vector_different_size;
+
+ return TC_Failed;
+ }
+
+ bool destIsPtr = DestType->isPointerType();
+ bool srcIsPtr = SrcType->isPointerType();
+ if (!destIsPtr && !srcIsPtr) {
+ // Except for std::nullptr_t->integer and lvalue->reference, which are
+ // handled above, at least one of the two arguments must be a pointer.
+ return TC_NotApplicable;
+ }
+
+ if (SrcType == DestType) {
+ // C++ 5.2.10p2 has a note that mentions that, subject to all other
+ // restrictions, a cast to the same type is allowed. The intent is not
+ // entirely clear here, since all other paragraphs explicitly forbid casts
+ // to the same type. However, the behavior of compilers is pretty consistent
+ // on this point: allow same-type conversion if the involved types are
+ // pointers, disallow otherwise.
+ return TC_Success;
+ }
+
+ // Note: Clang treats enumeration types as integral types. If this is ever
+ // changed for C++, the additional check here will be redundant.
+ if (DestType->isIntegralType() && !DestType->isEnumeralType()) {
+ assert(srcIsPtr && "One type must be a pointer");
+ // C++ 5.2.10p4: A pointer can be explicitly converted to any integral
+ // type large enough to hold it.
+ if (Self.Context.getTypeSize(SrcType) >
+ Self.Context.getTypeSize(DestType)) {
+ msg = diag::err_bad_reinterpret_cast_small_int;
+ return TC_Failed;
+ }
+ Kind = CastExpr::CK_PointerToIntegral;
+ return TC_Success;
+ }
+
+ if (SrcType->isIntegralType() || SrcType->isEnumeralType()) {
+ assert(destIsPtr && "One type must be a pointer");
+ // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly
+ // converted to a pointer.
+ Kind = CastExpr::CK_IntegralToPointer;
+ return TC_Success;
+ }
+
+ if (!destIsPtr || !srcIsPtr) {
+ // With the valid non-pointer conversions out of the way, we can be even
+ // more stringent.
+ return TC_NotApplicable;
+ }
+
+ // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
+ // The C-style cast operator can.
+ if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
+ msg = diag::err_bad_cxx_cast_const_away;
+ return TC_Failed;
+ }
+
+ // Not casting away constness, so the only remaining check is for compatible
+ // pointer categories.
+
+ if (SrcType->isFunctionPointerType()) {
+ if (DestType->isFunctionPointerType()) {
+ // C++ 5.2.10p6: A pointer to a function can be explicitly converted to
+ // a pointer to a function of a different type.
+ return TC_Success;
+ }
+
+ // C++0x 5.2.10p8: Converting a pointer to a function into a pointer to
+ // an object type or vice versa is conditionally-supported.
+ // Compilers support it in C++03 too, though, because it's necessary for
+ // casting the return value of dlsym() and GetProcAddress().
+ // FIXME: Conditionally-supported behavior should be configurable in the
+ // TargetInfo or similar.
+ if (!Self.getLangOptions().CPlusPlus0x)
+ Self.Diag(OpRange.getBegin(), diag::ext_cast_fn_obj) << OpRange;
+ return TC_Success;
+ }
+
+ if (DestType->isFunctionPointerType()) {
+ // See above.
+ if (!Self.getLangOptions().CPlusPlus0x)
+ Self.Diag(OpRange.getBegin(), diag::ext_cast_fn_obj) << OpRange;
+ return TC_Success;
+ }
+
+ // C++ 5.2.10p7: A pointer to an object can be explicitly converted to
+ // a pointer to an object of different type.
+ // Void pointers are not specified, but supported by every compiler out there.
+ // So we finish by allowing everything that remains - it's got to be two
+ // object pointers.
+ Kind = CastExpr::CK_BitCast;
+ return TC_Success;
+}
+
+bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
+ CastExpr::CastKind &Kind, bool FunctionalStyle,
+ CXXMethodDecl *&ConversionDecl) {
+ // This test is outside everything else because it's the only case where
+ // a non-lvalue-reference target type does not lead to decay.
+ // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
+ if (CastTy->isVoidType())
+ return false;
+
+ // If the type is dependent, we won't do any other semantic analysis now.
+ if (CastTy->isDependentType() || CastExpr->isTypeDependent())
+ return false;
+
+ if (!CastTy->isLValueReferenceType())
+ DefaultFunctionArrayConversion(CastExpr);
+
+ // C++ [expr.cast]p5: The conversions performed by
+ // - a const_cast,
+ // - a static_cast,
+ // - a static_cast followed by a const_cast,
+ // - a reinterpret_cast, or
+ // - a reinterpret_cast followed by a const_cast,
+ // can be performed using the cast notation of explicit type conversion.
+ // [...] If a conversion can be interpreted in more than one of the ways
+ // listed above, the interpretation that appears first in the list is used,
+ // even if a cast resulting from that interpretation is ill-formed.
+ // In plain language, this means trying a const_cast ...
+ unsigned msg = diag::err_bad_cxx_cast_generic;
+ TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true,
+ msg);
+ if (tcr == TC_NotApplicable) {
+ // ... or if that is not possible, a static_cast, ignoring const, ...
+ tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
+ Kind, ConversionDecl);
+ if (tcr == TC_NotApplicable) {
+ // ... and finally a reinterpret_cast, ignoring const.
+ tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
+ Kind);
+ }
+ }
+
+ if (tcr != TC_Success && msg != 0)
+ Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle)
+ << CastExpr->getType() << CastTy << R;
+
+ return tcr != TC_Success;
+}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index a14bcd5287cd5..10c138c7558f5 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -14,26 +14,89 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
+/// \brief Compute the DeclContext that is associated with the given type.
+///
+/// \param T the type for which we are attempting to find a DeclContext.
+///
+/// \returns the declaration context represented by the type T,
+/// or NULL if the declaration context cannot be computed (e.g., because it is
+/// dependent and not the current instantiation).
+DeclContext *Sema::computeDeclContext(QualType T) {
+ if (const TagType *Tag = T->getAs<TagType>())
+ return Tag->getDecl();
+
+ return 0;
+}
+
/// \brief Compute the DeclContext that is associated with the given
/// scope specifier.
-DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) {
+///
+/// \param SS the C++ scope specifier as it appears in the source
+///
+/// \param EnteringContext when true, we will be entering the context of
+/// this scope specifier, so we can retrieve the declaration context of a
+/// class template or class template partial specialization even if it is
+/// not the current instantiation.
+///
+/// \returns the declaration context represented by the scope specifier @p SS,
+/// or NULL if the declaration context cannot be computed (e.g., because it is
+/// dependent and not the current instantiation).
+DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
+ bool EnteringContext) {
if (!SS.isSet() || SS.isInvalid())
return 0;
- NestedNameSpecifier *NNS
+ NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
if (NNS->isDependent()) {
// If this nested-name-specifier refers to the current
// instantiation, return its DeclContext.
if (CXXRecordDecl *Record = getCurrentInstantiationOf(NNS))
return Record;
- else
- return 0;
+
+ if (EnteringContext) {
+ if (const TemplateSpecializationType *SpecType
+ = dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) {
+ // We are entering the context of the nested name specifier, so try to
+ // match the nested name specifier to either a primary class template
+ // or a class template partial specialization.
+ if (ClassTemplateDecl *ClassTemplate
+ = dyn_cast_or_null<ClassTemplateDecl>(
+ SpecType->getTemplateName().getAsTemplateDecl())) {
+ QualType ContextType
+ = Context.getCanonicalType(QualType(SpecType, 0));
+
+ // If the type of the nested name specifier is the same as the
+ // injected class name of the named class template, we're entering
+ // into that class template definition.
+ QualType Injected = ClassTemplate->getInjectedClassNameType(Context);
+ if (Context.hasSameType(Injected, ContextType))
+ return ClassTemplate->getTemplatedDecl();
+
+ // If the type of the nested name specifier is the same as the
+ // type of one of the class template's class template partial
+ // specializations, we're entering into the definition of that
+ // class template partial specialization.
+ if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = ClassTemplate->findPartialSpecialization(ContextType))
+ return PartialSpec;
+ }
+ } else if (const RecordType *RecordT
+ = dyn_cast_or_null<RecordType>(NNS->getAsType())) {
+ // The nested name specifier refers to a member of a class template.
+ return RecordT->getDecl();
+ }
+ }
+
+ return 0;
}
switch (NNS->getKind()) {
@@ -46,7 +109,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) {
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
- const TagType *Tag = NNS->getAsType()->getAsTagType();
+ const TagType *Tag = NNS->getAsType()->getAs<TagType>();
assert(Tag && "Non-tag type in nested-name-specifier");
return Tag->getDecl();
} break;
@@ -63,7 +126,7 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return false;
- NestedNameSpecifier *NNS
+ NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
return NNS->isDependent();
}
@@ -75,7 +138,7 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
if (!isDependentScopeSpecifier(SS))
return false;
- NestedNameSpecifier *NNS
+ NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
return getCurrentInstantiationOf(NNS) == 0;
}
@@ -89,6 +152,9 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
assert(getLangOptions().CPlusPlus && "Only callable in C++");
assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed");
+ if (!NNS->getAsType())
+ return 0;
+
QualType T = QualType(NNS->getAsType(), 0);
// If the nested name specifier does not refer to a type, then it
// does not refer to the current instantiation.
@@ -108,7 +174,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
if (!Record)
continue;
- // If this record type is not dependent,
+ // If this record type is not dependent,
if (!Record->isDependentType())
return 0;
@@ -126,27 +192,29 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
// enclosed in <>,
// -- in the definition of a nested class of a class template,
// the name of the nested class referenced as a member of
- // the current instantiation, or
+ // the current instantiation, or
// -- in the definition of a partial specialization, the name
// of the class template followed by the template argument
// list of the partial specialization enclosed in <>. If
// the nth template parameter is a parameter pack, the nth
// template argument is a pack expansion (14.6.3) whose
- // pattern is the name of the parameter pack. (FIXME)
+ // pattern is the name of the parameter pack.
+ // (FIXME: parameter packs)
//
// All of these options come down to having the
// nested-name-specifier type that is equivalent to the
// injected-class-name of one of the types that is currently in
// our context.
- if (Context.getTypeDeclType(Record) == T)
+ if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T)
return Record;
-
+
if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) {
- QualType InjectedClassName
+ QualType InjectedClassName
= Template->getInjectedClassNameType(Context);
if (T == Context.getCanonicalType(InjectedClassName))
return Template->getTemplatedDecl();
}
+ // FIXME: check for class template partial specializations
}
return 0;
@@ -164,20 +232,20 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return false;
-
- DeclContext *DC = computeDeclContext(SS);
+
+ DeclContext *DC = computeDeclContext(SS, true);
if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
// If we're currently defining this type, then lookup into the
// type is okay: don't complain that it isn't complete yet.
- const TagType *TagT = Context.getTypeDeclType(Tag)->getAsTagType();
+ const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>();
if (TagT->isBeingDefined())
return false;
// The type must be complete.
return RequireCompleteType(SS.getRange().getBegin(),
Context.getTypeDeclType(Tag),
- diag::err_incomplete_nested_name_spec,
- SS.getRange());
+ PDiag(diag::err_incomplete_nested_name_spec)
+ << SS.getRange());
}
return false;
@@ -190,72 +258,222 @@ Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
return NestedNameSpecifier::GlobalSpecifier(Context);
}
-/// ActOnCXXNestedNameSpecifier - Called during parsing of a
-/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
-/// we want to resolve "bar::". 'SS' is empty or the previously parsed
-/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
-/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
-/// Returns a CXXScopeTy* object representing the C++ scope.
-Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+/// \brief Determines whether the given declaration is an valid acceptable
+/// result for name lookup of a nested-name-specifier.
+bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) {
+ if (!SD)
+ return false;
+
+ // Namespace and namespace aliases are fine.
+ if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD))
+ return true;
+
+ if (!isa<TypeDecl>(SD))
+ return false;
+
+ // Determine whether we have a class (or, in C++0x, an enum) or
+ // a typedef thereof. If so, build the nested-name-specifier.
+ QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
+ if (T->isDependentType())
+ return true;
+ else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (TD->getUnderlyingType()->isRecordType() ||
+ (Context.getLangOptions().CPlusPlus0x &&
+ TD->getUnderlyingType()->isEnumeralType()))
+ return true;
+ } else if (isa<RecordDecl>(SD) ||
+ (Context.getLangOptions().CPlusPlus0x && isa<EnumDecl>(SD)))
+ return true;
+
+ return false;
+}
+
+/// \brief If the given nested-name-specifier begins with a bare identifier
+/// (e.g., Base::), perform name lookup for that identifier as a
+/// nested-name-specifier within the given scope, and return the result of that
+/// name lookup.
+NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
+ if (!S || !NNS)
+ return 0;
+
+ while (NNS->getPrefix())
+ NNS = NNS->getPrefix();
+
+ if (NNS->getKind() != NestedNameSpecifier::Identifier)
+ return 0;
+
+ LookupResult Found;
+ LookupName(Found, S, NNS->getAsIdentifier(), LookupNestedNameSpecifierName);
+ assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
+
+ NamedDecl *Result = Found.getAsSingleDecl(Context);
+ if (isAcceptableNestedNameSpecifier(Result))
+ return Result;
+
+ return 0;
+}
+
+/// \brief Build a new nested-name-specifier for "identifier::", as described
+/// by ActOnCXXNestedNameSpecifier.
+///
+/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
+/// that it contains an extra parameter \p ScopeLookupResult, which provides
+/// the result of name lookup within the scope of the nested-name-specifier
+/// that was computed at template definitino time.
+Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
- IdentifierInfo &II) {
- NestedNameSpecifier *Prefix
+ IdentifierInfo &II,
+ QualType ObjectType,
+ NamedDecl *ScopeLookupResult,
+ bool EnteringContext) {
+ NestedNameSpecifier *Prefix
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- // If the prefix already refers to an unknown specialization, there
- // is no name lookup to perform. Just build the resulting
- // nested-name-specifier.
- if (Prefix && isUnknownSpecialization(SS))
+ // Determine where to perform name lookup
+ DeclContext *LookupCtx = 0;
+ bool isDependent = false;
+ if (!ObjectType.isNull()) {
+ // This nested-name-specifier occurs in a member access expression, e.g.,
+ // x->B::f, and we are looking into the type of the object.
+ assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
+ LookupCtx = computeDeclContext(ObjectType);
+ isDependent = ObjectType->isDependentType();
+ } else if (SS.isSet()) {
+ // This nested-name-specifier occurs after another nested-name-specifier,
+ // so long into the context associated with the prior nested-name-specifier.
+ LookupCtx = computeDeclContext(SS, EnteringContext);
+ isDependent = isDependentScopeSpecifier(SS);
+ }
+
+ LookupResult Found;
+ bool ObjectTypeSearchedInScope = false;
+ if (LookupCtx) {
+ // Perform "qualified" name lookup into the declaration context we
+ // computed, which is either the type of the base of a member access
+ // expression or the declaration context associated with a prior
+ // nested-name-specifier.
+
+ // The declaration context must be complete.
+ if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
+ return 0;
+
+ LookupQualifiedName(Found, LookupCtx, &II, LookupNestedNameSpecifierName,
+ false);
+
+ if (!ObjectType.isNull() && Found.getKind() == LookupResult::NotFound) {
+ // C++ [basic.lookup.classref]p4:
+ // If the id-expression in a class member access is a qualified-id of
+ // the form
+ //
+ // class-name-or-namespace-name::...
+ //
+ // the class-name-or-namespace-name following the . or -> operator is
+ // looked up both in the context of the entire postfix-expression and in
+ // the scope of the class of the object expression. If the name is found
+ // only in the scope of the class of the object expression, the name
+ // shall refer to a class-name. If the name is found only in the
+ // context of the entire postfix-expression, the name shall refer to a
+ // class-name or namespace-name. [...]
+ //
+ // Qualified name lookup into a class will not find a namespace-name,
+ // so we do not need to diagnoste that case specifically. However,
+ // this qualified name lookup may find nothing. In that case, perform
+ // unqualified name lookup in the given scope (if available) or
+ // reconstruct the result from when name lookup was performed at template
+ // definition time.
+ if (S)
+ LookupName(Found, S, &II, LookupNestedNameSpecifierName);
+ else if (ScopeLookupResult)
+ Found.addDecl(ScopeLookupResult);
+
+ ObjectTypeSearchedInScope = true;
+ }
+ } else if (isDependent) {
+ // We were not able to compute the declaration context for a dependent
+ // base object type or prior nested-name-specifier, so this
+ // nested-name-specifier refers to an unknown specialization. Just build
+ // a dependent nested-name-specifier.
+ if (!Prefix)
+ return NestedNameSpecifier::Create(Context, &II);
+
return NestedNameSpecifier::Create(Context, Prefix, &II);
+ } else {
+ // Perform unqualified name lookup in the current scope.
+ LookupName(Found, S, &II, LookupNestedNameSpecifierName);
+ }
- NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName);
+ // FIXME: Deal with ambiguities cleanly.
+ NamedDecl *SD = Found.getAsSingleDecl(Context);
+ if (isAcceptableNestedNameSpecifier(SD)) {
+ if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) {
+ // C++ [basic.lookup.classref]p4:
+ // [...] If the name is found in both contexts, the
+ // class-name-or-namespace-name shall refer to the same entity.
+ //
+ // We already found the name in the scope of the object. Now, look
+ // into the current scope (the scope of the postfix-expression) to
+ // see if we can find the same name there. As above, if there is no
+ // scope, reconstruct the result from the template instantiation itself.
+ NamedDecl *OuterDecl;
+ if (S) {
+ LookupResult FoundOuter;
+ LookupName(FoundOuter, S, &II, LookupNestedNameSpecifierName);
+ // FIXME: Handle ambiguities!
+ OuterDecl = FoundOuter.getAsSingleDecl(Context);
+ } else
+ OuterDecl = ScopeLookupResult;
+
+ if (isAcceptableNestedNameSpecifier(OuterDecl) &&
+ OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() &&
+ (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) ||
+ !Context.hasSameType(
+ Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
+ Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
+ Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
+ << &II;
+ Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
+ << ObjectType;
+ Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);
+
+ // Fall through so that we'll pick the name we found in the object type,
+ // since that's probably what the user wanted anyway.
+ }
+ }
- if (SD) {
if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD))
return NestedNameSpecifier::Create(Context, Prefix, Namespace);
- if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) {
- // Determine whether we have a class (or, in C++0x, an enum) or
- // a typedef thereof. If so, build the nested-name-specifier.
- QualType T = Context.getTypeDeclType(Type);
- bool AcceptableType = false;
- if (T->isDependentType())
- AcceptableType = true;
- else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
- if (TD->getUnderlyingType()->isRecordType() ||
- (getLangOptions().CPlusPlus0x &&
- TD->getUnderlyingType()->isEnumeralType()))
- AcceptableType = true;
- } else if (isa<RecordDecl>(Type) ||
- (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type)))
- AcceptableType = true;
-
- if (AcceptableType)
- return NestedNameSpecifier::Create(Context, Prefix, false,
- T.getTypePtr());
- }
-
+ // FIXME: It would be nice to maintain the namespace alias name, then
+ // see through that alias when resolving the nested-name-specifier down to
+ // a declaration context.
if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD))
return NestedNameSpecifier::Create(Context, Prefix,
+
Alias->getNamespace());
- // Fall through to produce an error: we found something that isn't
- // a class or a namespace.
+ QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
+ return NestedNameSpecifier::Create(Context, Prefix, false,
+ T.getTypePtr());
}
// If we didn't find anything during our lookup, try again with
// ordinary name lookup, which can help us produce better error
// messages.
- if (!SD)
- SD = LookupParsedName(S, &SS, &II, LookupOrdinaryName);
+ if (!SD) {
+ Found.clear();
+ LookupName(Found, S, &II, LookupOrdinaryName);
+ SD = Found.getAsSingleDecl(Context);
+ }
+
unsigned DiagID;
if (SD)
DiagID = diag::err_expected_class_or_namespace;
- else if (SS.isSet())
- DiagID = diag::err_typecheck_no_member;
- else
+ else if (SS.isSet()) {
+ Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange();
+ return 0;
+ } else
DiagID = diag::err_undeclared_var_use;
if (SS.isSet())
@@ -266,14 +484,32 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
return 0;
}
+/// ActOnCXXNestedNameSpecifier - Called during parsing of a
+/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
+/// we want to resolve "bar::". 'SS' is empty or the previously parsed
+/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
+/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
+/// Returns a CXXScopeTy* object representing the C++ scope.
+Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ SourceLocation IdLoc,
+ SourceLocation CCLoc,
+ IdentifierInfo &II,
+ TypeTy *ObjectTypePtr,
+ bool EnteringContext) {
+ return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II,
+ QualType::getFromOpaquePtr(ObjectTypePtr),
+ /*ScopeLookupResult=*/0, EnteringContext);
+}
+
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
TypeTy *Ty,
SourceRange TypeRange,
SourceLocation CCLoc) {
- NestedNameSpecifier *Prefix
+ NestedNameSpecifier *Prefix
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- QualType T = QualType::getFromOpaquePtr(Ty);
+ QualType T = GetTypeFromParser(Ty);
return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false,
T.getTypePtr());
}
@@ -284,9 +520,18 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
/// looked up in the declarator-id's scope, until the declarator is parsed and
/// ActOnCXXExitDeclaratorScope is called.
/// The 'SS' should be a non-empty valid CXXScopeSpec.
-void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
- EnterDeclaratorContext(S, computeDeclContext(SS));
+ if (DeclContext *DC = computeDeclContext(SS, true)) {
+ // Before we enter a declarator's context, we need to make sure that
+ // it is a complete declaration context.
+ if (!DC->isDependentContext() && RequireCompleteDeclContext(SS))
+ return true;
+
+ EnterDeclaratorContext(S, DC);
+ }
+
+ return false;
}
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
@@ -296,6 +541,8 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
/// defining scope.
void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
- assert(S->getEntity() == computeDeclContext(SS) && "Context imbalance!");
- ExitDeclaratorContext(S);
+ if (SS.isInvalid())
+ return;
+ if (computeDeclContext(SS, true))
+ ExitDeclaratorContext(S);
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 4eed01872246c..92bf83f0830d0 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements extra semantic analysis beyond what is enforced
+// This file implements extra semantic analysis beyond what is enforced
// by the C type system.
//
//===----------------------------------------------------------------------===//
@@ -32,14 +32,14 @@ using namespace clang;
SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
unsigned ByteNo) const {
assert(!SL->isWide() && "This doesn't work for wide strings yet");
-
+
// Loop over all of the tokens in this string until we find the one that
// contains the byte we're looking for.
unsigned TokNo = 0;
while (1) {
assert(TokNo < SL->getNumConcatenated() && "Invalid byte number!");
SourceLocation StrTokLoc = SL->getStrTokenLoc(TokNo);
-
+
// Get the spelling of the string so that we can get the data that makes up
// the string literal, not the identifier for the macro it is potentially
// expanded through.
@@ -51,65 +51,71 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
std::pair<const char *,const char *> Buffer =
SourceMgr.getBufferData(LocInfo.first);
const char *StrData = Buffer.first+LocInfo.second;
-
+
// Create a langops struct and enable trigraphs. This is sufficient for
// relexing tokens.
LangOptions LangOpts;
LangOpts.Trigraphs = true;
-
+
// Create a lexer starting at the beginning of this token.
Lexer TheLexer(StrTokSpellingLoc, LangOpts, Buffer.first, StrData,
Buffer.second);
Token TheTok;
TheLexer.LexFromRawLexer(TheTok);
-
+
// Use the StringLiteralParser to compute the length of the string in bytes.
StringLiteralParser SLP(&TheTok, 1, PP);
unsigned TokNumBytes = SLP.GetStringLength();
-
+
// If the byte is in this token, return the location of the byte.
if (ByteNo < TokNumBytes ||
(ByteNo == TokNumBytes && TokNo == SL->getNumConcatenated())) {
- unsigned Offset =
+ unsigned Offset =
StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP);
-
+
// Now that we know the offset of the token in the spelling, use the
// preprocessor to get the offset in the original source.
return PP.AdvanceToTokenCharacter(StrTokLoc, Offset);
}
-
+
// Move to the next string token.
++TokNo;
ByteNo -= TokNumBytes;
}
}
+/// CheckablePrintfAttr - does a function call have a "printf" attribute
+/// and arguments that merit checking?
+bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) {
+ if (Format->getType() == "printf") return true;
+ if (Format->getType() == "printf0") {
+ // printf0 allows null "format" string; if so don't check format/args
+ unsigned format_idx = Format->getFormatIdx() - 1;
+ if (format_idx < TheCall->getNumArgs()) {
+ Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts();
+ if (!Format->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
+ return true;
+ }
+ }
+ return false;
+}
-/// CheckFunctionCall - Check a direct function call for various correctness
-/// and safety properties not strictly enforced by the C type system.
Action::OwningExprResult
-Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
+Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
OwningExprResult TheCallResult(Owned(TheCall));
- // Get the IdentifierInfo* for the called function.
- IdentifierInfo *FnInfo = FDecl->getIdentifier();
-
- // None of the checks below are needed for functions that don't have
- // simple names (e.g., C++ conversion functions).
- if (!FnInfo)
- return move(TheCallResult);
- switch (FDecl->getBuiltinID(Context)) {
+ switch (BuiltinID) {
case Builtin::BI__builtin___CFStringMakeConstantString:
assert(TheCall->getNumArgs() == 1 &&
"Wrong # arguments to builtin CFStringMakeConstantString");
if (CheckObjCString(TheCall->getArg(0)))
return ExprError();
- return move(TheCallResult);
+ break;
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
if (SemaBuiltinVAStart(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
case Builtin::BI__builtin_isgreater:
case Builtin::BI__builtin_isgreaterequal:
case Builtin::BI__builtin_isless:
@@ -118,12 +124,24 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
case Builtin::BI__builtin_isunordered:
if (SemaBuiltinUnorderedCompare(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
+ case Builtin::BI__builtin_isfinite:
+ case Builtin::BI__builtin_isinf:
+ case Builtin::BI__builtin_isinf_sign:
+ case Builtin::BI__builtin_isnan:
+ case Builtin::BI__builtin_isnormal:
+ if (SemaBuiltinUnaryFP(TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_return_address:
case Builtin::BI__builtin_frame_address:
if (SemaBuiltinStackAddress(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
+ case Builtin::BI__builtin_eh_return_data_regno:
+ if (SemaBuiltinEHReturnDataRegNo(TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_shufflevector:
return SemaBuiltinShuffleVector(TheCall);
// TheCall will be freed by the smart pointer here, but that's fine, since
@@ -131,15 +149,15 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
case Builtin::BI__builtin_prefetch:
if (SemaBuiltinPrefetch(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
case Builtin::BI__builtin_object_size:
if (SemaBuiltinObjectSize(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
case Builtin::BI__builtin_longjmp:
if (SemaBuiltinLongjmp(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
case Builtin::BI__sync_fetch_and_add:
case Builtin::BI__sync_fetch_and_sub:
case Builtin::BI__sync_fetch_and_or:
@@ -158,61 +176,76 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
case Builtin::BI__sync_lock_release:
if (SemaBuiltinAtomicOverloaded(TheCall))
return ExprError();
- return move(TheCallResult);
+ break;
}
+ return move(TheCallResult);
+}
+
+/// CheckFunctionCall - Check a direct function call for various correctness
+/// and safety properties not strictly enforced by the C type system.
+bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
+ // Get the IdentifierInfo* for the called function.
+ IdentifierInfo *FnInfo = FDecl->getIdentifier();
+
+ // None of the checks below are needed for functions that don't have
+ // simple names (e.g., C++ conversion functions).
+ if (!FnInfo)
+ return false;
+
// FIXME: This mechanism should be abstracted to be less fragile and
// more efficient. For example, just map function ids to custom
// handlers.
// Printf checking.
if (const FormatAttr *Format = FDecl->getAttr<FormatAttr>()) {
- if (Format->getType() == "printf") {
+ if (CheckablePrintfAttr(Format, TheCall)) {
bool HasVAListArg = Format->getFirstArg() == 0;
if (!HasVAListArg) {
- if (const FunctionProtoType *Proto
- = FDecl->getType()->getAsFunctionProtoType())
+ if (const FunctionProtoType *Proto
+ = FDecl->getType()->getAs<FunctionProtoType>())
HasVAListArg = !Proto->isVariadic();
}
CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
HasVAListArg ? 0 : Format->getFirstArg() - 1);
}
}
- for (const Attr *attr = FDecl->getAttrs();
- attr; attr = attr->getNext()) {
- if (const NonNullAttr *NonNull = dyn_cast<NonNullAttr>(attr))
- CheckNonNullArguments(NonNull, TheCall);
- }
- return move(TheCallResult);
-}
+ for (const NonNullAttr *NonNull = FDecl->getAttr<NonNullAttr>(); NonNull;
+ NonNull = NonNull->getNext<NonNullAttr>())
+ CheckNonNullArguments(NonNull, TheCall);
-Action::OwningExprResult
-Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
+ return false;
+}
- OwningExprResult TheCallResult(Owned(TheCall));
+bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
// Printf checking.
const FormatAttr *Format = NDecl->getAttr<FormatAttr>();
if (!Format)
- return move(TheCallResult);
+ return false;
+
const VarDecl *V = dyn_cast<VarDecl>(NDecl);
if (!V)
- return move(TheCallResult);
+ return false;
+
QualType Ty = V->getType();
if (!Ty->isBlockPointerType())
- return move(TheCallResult);
- if (Format->getType() == "printf") {
- bool HasVAListArg = Format->getFirstArg() == 0;
- if (!HasVAListArg) {
- const FunctionType *FT =
- Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType();
- if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
- HasVAListArg = !Proto->isVariadic();
- }
- CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
- HasVAListArg ? 0 : Format->getFirstArg() - 1);
+ return false;
+
+ if (!CheckablePrintfAttr(Format, TheCall))
+ return false;
+
+ bool HasVAListArg = Format->getFirstArg() == 0;
+ if (!HasVAListArg) {
+ const FunctionType *FT =
+ Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
+ if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
+ HasVAListArg = !Proto->isVariadic();
}
- return move(TheCallResult);
+ CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
+ HasVAListArg ? 0 : Format->getFirstArg() - 1);
+
+ return false;
}
/// SemaBuiltinAtomicOverloaded - We have a call to a function like
@@ -231,7 +264,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
if (TheCall->getNumArgs() < 1)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 << TheCall->getCallee()->getSourceRange();
-
+
// Inspect the first argument of the atomic builtin. This should always be
// a pointer type, whose element is an integral scalar or pointer type.
// Because it is a pointer type, we don't have to worry about any implicit
@@ -240,9 +273,9 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
if (!FirstArg->getType()->isPointerType())
return Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
<< FirstArg->getType() << FirstArg->getSourceRange();
-
- QualType ValType = FirstArg->getType()->getAsPointerType()->getPointeeType();
- if (!ValType->isIntegerType() && !ValType->isPointerType() &&
+
+ QualType ValType = FirstArg->getType()->getAs<PointerType>()->getPointeeType();
+ if (!ValType->isIntegerType() && !ValType->isPointerType() &&
!ValType->isBlockPointerType())
return Diag(DRE->getLocStart(),
diag::err_atomic_builtin_must_be_pointer_intptr)
@@ -254,7 +287,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
#define BUILTIN_ROW(x) \
{ Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \
Builtin::BI##x##_8, Builtin::BI##x##_16 }
-
+
static const unsigned BuiltinIndices[][5] = {
BUILTIN_ROW(__sync_fetch_and_add),
BUILTIN_ROW(__sync_fetch_and_sub),
@@ -262,21 +295,21 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
BUILTIN_ROW(__sync_fetch_and_and),
BUILTIN_ROW(__sync_fetch_and_xor),
BUILTIN_ROW(__sync_fetch_and_nand),
-
+
BUILTIN_ROW(__sync_add_and_fetch),
BUILTIN_ROW(__sync_sub_and_fetch),
BUILTIN_ROW(__sync_and_and_fetch),
BUILTIN_ROW(__sync_or_and_fetch),
BUILTIN_ROW(__sync_xor_and_fetch),
BUILTIN_ROW(__sync_nand_and_fetch),
-
+
BUILTIN_ROW(__sync_val_compare_and_swap),
BUILTIN_ROW(__sync_bool_compare_and_swap),
BUILTIN_ROW(__sync_lock_test_and_set),
BUILTIN_ROW(__sync_lock_release)
};
-#undef BUILTIN_ROW
-
+#undef BUILTIN_ROW
+
// Determine the index of the size.
unsigned SizeIndex;
switch (Context.getTypeSize(ValType)/8) {
@@ -289,12 +322,12 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
return Diag(DRE->getLocStart(), diag::err_atomic_builtin_pointer_size)
<< FirstArg->getType() << FirstArg->getSourceRange();
}
-
+
// Each of these builtins has one pointer argument, followed by some number of
// values (0, 1 or 2) followed by a potentially empty varags list of stuff
// that we ignore. Find out which row of BuiltinIndices to read from as well
// as the number of fixed args.
- unsigned BuiltinID = FDecl->getBuiltinID(Context);
+ unsigned BuiltinID = FDecl->getBuiltinID();
unsigned BuiltinIndex, NumFixed = 1;
switch (BuiltinID) {
default: assert(0 && "Unknown overloaded atomic builtin!");
@@ -304,14 +337,14 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
case Builtin::BI__sync_fetch_and_and: BuiltinIndex = 3; break;
case Builtin::BI__sync_fetch_and_xor: BuiltinIndex = 4; break;
case Builtin::BI__sync_fetch_and_nand:BuiltinIndex = 5; break;
-
+
case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 6; break;
case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 7; break;
case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 8; break;
case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 9; break;
case Builtin::BI__sync_xor_and_fetch: BuiltinIndex =10; break;
case Builtin::BI__sync_nand_and_fetch:BuiltinIndex =11; break;
-
+
case Builtin::BI__sync_val_compare_and_swap:
BuiltinIndex = 12;
NumFixed = 2;
@@ -326,36 +359,37 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
NumFixed = 0;
break;
}
-
+
// Now that we know how many fixed arguments we expect, first check that we
// have at least that many.
if (TheCall->getNumArgs() < 1+NumFixed)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 << TheCall->getCallee()->getSourceRange();
-
-
+
+
// Get the decl for the concrete builtin from this, we can tell what the
// concrete integer type we should convert to is.
unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
const char *NewBuiltinName = Context.BuiltinInfo.GetName(NewBuiltinID);
IdentifierInfo *NewBuiltinII = PP.getIdentifierInfo(NewBuiltinName);
- FunctionDecl *NewBuiltinDecl =
+ FunctionDecl *NewBuiltinDecl =
cast<FunctionDecl>(LazilyCreateBuiltin(NewBuiltinII, NewBuiltinID,
TUScope, false, DRE->getLocStart()));
const FunctionProtoType *BuiltinFT =
- NewBuiltinDecl->getType()->getAsFunctionProtoType();
- ValType = BuiltinFT->getArgType(0)->getAsPointerType()->getPointeeType();
-
+ NewBuiltinDecl->getType()->getAs<FunctionProtoType>();
+ ValType = BuiltinFT->getArgType(0)->getAs<PointerType>()->getPointeeType();
+
// If the first type needs to be converted (e.g. void** -> int*), do it now.
if (BuiltinFT->getArgType(0) != FirstArg->getType()) {
- ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), false);
+ ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), CastExpr::CK_Unknown,
+ /*isLvalue=*/false);
TheCall->setArg(0, FirstArg);
}
-
+
// Next, walk the valid ones promoting to the right type.
for (unsigned i = 0; i != NumFixed; ++i) {
Expr *Arg = TheCall->getArg(i+1);
-
+
// If the argument is an implicit cast, then there was a promotion due to
// "...", just remove it now.
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
@@ -364,32 +398,35 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
ICE->Destroy(Context);
TheCall->setArg(i+1, Arg);
}
-
+
// GCC does an implicit conversion to the pointer or integer ValType. This
// can fail in some cases (1i -> int**), check for this error case now.
- if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg))
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ CXXMethodDecl *ConversionDecl = 0;
+ if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind,
+ ConversionDecl))
return true;
-
+
// Okay, we have something that *can* be converted to the right type. Check
// to see if there is a potentially weird extension going on here. This can
// happen when you do an atomic operation on something like an char* and
// pass in 42. The 42 gets converted to char. This is even more strange
// for things like 45.123 -> char, etc.
- // FIXME: Do this check.
- ImpCastExprToType(Arg, ValType, false);
+ // FIXME: Do this check.
+ ImpCastExprToType(Arg, ValType, Kind, /*isLvalue=*/false);
TheCall->setArg(i+1, Arg);
}
-
+
// Switch the DeclRefExpr to refer to the new decl.
DRE->setDecl(NewBuiltinDecl);
DRE->setType(NewBuiltinDecl->getType());
-
+
// Set the callee in the CallExpr.
// FIXME: This leaks the original parens and implicit casts.
Expr *PromotedCall = DRE;
UsualUnaryConversions(PromotedCall);
TheCall->setCallee(PromotedCall);
-
+
// Change the result type of the call to match the result type of the decl.
TheCall->setType(NewBuiltinDecl->getResultType());
@@ -400,7 +437,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
/// CheckObjCString - Checks that the argument to the builtin
/// CFString constructor is correct
/// FIXME: GCC currently emits the following warning:
-/// "warning: input conversion stopped due to an input byte that does not
+/// "warning: input conversion stopped due to an input byte that does not
/// belong to the input codeset UTF-8"
/// Note: It might also make sense to do the UTF-16 conversion here (would
/// simplify the backend).
@@ -413,10 +450,10 @@ bool Sema::CheckObjCString(Expr *Arg) {
<< Arg->getSourceRange();
return true;
}
-
+
const char *Data = Literal->getStrData();
unsigned Length = Literal->getByteLength();
-
+
for (unsigned i = 0; i < Length; ++i) {
if (!Data[i]) {
Diag(getLocationOfStringLiteralByte(Literal, i),
@@ -425,7 +462,7 @@ bool Sema::CheckObjCString(Expr *Arg) {
break;
}
}
-
+
return false;
}
@@ -437,7 +474,7 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/ << Fn->getSourceRange()
- << SourceRange(TheCall->getArg(2)->getLocStart(),
+ << SourceRange(TheCall->getArg(2)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
return true;
}
@@ -460,17 +497,17 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
} else {
isVariadic = getCurMethodDecl()->isVariadic();
}
-
+
if (!isVariadic) {
Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
return true;
}
-
+
// Verify that the second argument to the builtin is the last argument of the
// current function or method.
bool SecondArgIsLastNamedArgument = false;
const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts();
-
+
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
// FIXME: This isn't correct for methods (results in bogus warning).
@@ -485,9 +522,9 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
SecondArgIsLastNamedArgument = PV == LastArg;
}
}
-
+
if (!SecondArgIsLastNamedArgument)
- Diag(TheCall->getArg(1)->getLocStart(),
+ Diag(TheCall->getArg(1)->getLocStart(),
diag::warn_second_parameter_of_va_start_not_last_named_argument);
return false;
}
@@ -499,12 +536,12 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 /*function call*/;
if (TheCall->getNumArgs() > 2)
- return Diag(TheCall->getArg(2)->getLocStart(),
+ return Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/
<< SourceRange(TheCall->getArg(2)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
-
+
Expr *OrigArg0 = TheCall->getArg(0);
Expr *OrigArg1 = TheCall->getArg(1);
@@ -517,18 +554,45 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
// foo(...)".
TheCall->setArg(0, OrigArg0);
TheCall->setArg(1, OrigArg1);
-
+
if (OrigArg0->isTypeDependent() || OrigArg1->isTypeDependent())
return false;
// If the common type isn't a real floating type, then the arguments were
// invalid for this operation.
if (!Res->isRealFloatingType())
- return Diag(OrigArg0->getLocStart(),
+ return Diag(OrigArg0->getLocStart(),
diag::err_typecheck_call_invalid_ordered_compare)
<< OrigArg0->getType() << OrigArg1->getType()
<< SourceRange(OrigArg0->getLocStart(), OrigArg1->getLocEnd());
-
+
+ return false;
+}
+
+/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isnan and
+/// friends. This is declared to take (...), so we have to check everything.
+bool Sema::SemaBuiltinUnaryFP(CallExpr *TheCall) {
+ if (TheCall->getNumArgs() < 1)
+ return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 /*function call*/;
+ if (TheCall->getNumArgs() > 1)
+ return Diag(TheCall->getArg(1)->getLocStart(),
+ diag::err_typecheck_call_too_many_args)
+ << 0 /*function call*/
+ << SourceRange(TheCall->getArg(1)->getLocStart(),
+ (*(TheCall->arg_end()-1))->getLocEnd());
+
+ Expr *OrigArg = TheCall->getArg(0);
+
+ if (OrigArg->isTypeDependent())
+ return false;
+
+ // This operation requires a floating-point number
+ if (!OrigArg->getType()->isRealFloatingType())
+ return Diag(OrigArg->getLocStart(),
+ diag::err_typecheck_call_invalid_unary_fp)
+ << OrigArg->getType() << OrigArg->getSourceRange();
+
return false;
}
@@ -540,7 +604,7 @@ bool Sema::SemaBuiltinStackAddress(CallExpr *TheCall) {
!TheCall->getArg(0)->isValueDependent() &&
!TheCall->getArg(0)->isIntegerConstantExpr(Context, &Loc))
return Diag(Loc, diag::err_stack_const_level) << TheCall->getSourceRange();
-
+
return false;
}
@@ -557,23 +621,23 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
!TheCall->getArg(1)->isTypeDependent()) {
QualType FAType = TheCall->getArg(0)->getType();
QualType SAType = TheCall->getArg(1)->getType();
-
+
if (!FAType->isVectorType() || !SAType->isVectorType()) {
Diag(TheCall->getLocStart(), diag::err_shufflevector_non_vector)
- << SourceRange(TheCall->getArg(0)->getLocStart(),
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
TheCall->getArg(1)->getLocEnd());
return ExprError();
}
-
+
if (Context.getCanonicalType(FAType).getUnqualifiedType() !=
Context.getCanonicalType(SAType).getUnqualifiedType()) {
Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector)
- << SourceRange(TheCall->getArg(0)->getLocStart(),
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
TheCall->getArg(1)->getLocEnd());
return ExprError();
}
- numElements = FAType->getAsVectorType()->getNumElements();
+ numElements = FAType->getAs<VectorType>()->getNumElements();
if (TheCall->getNumArgs() != numElements+2) {
if (TheCall->getNumArgs() < numElements+2)
return ExprError(Diag(TheCall->getLocEnd(),
@@ -609,8 +673,8 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
TheCall->setArg(i, 0);
}
- return Owned(new (Context) ShuffleVectorExpr(exprs.begin(), exprs.size(),
- exprs[0]->getType(),
+ return Owned(new (Context) ShuffleVectorExpr(Context, exprs.begin(),
+ exprs.size(), exprs[0]->getType(),
TheCall->getCallee()->getLocStart(),
TheCall->getRParenLoc()));
}
@@ -634,11 +698,11 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
QualType RWType = Arg->getType();
- const BuiltinType *BT = RWType->getAsBuiltinType();
+ const BuiltinType *BT = RWType->getAs<BuiltinType>();
llvm::APSInt Result;
if (!BT || BT->getKind() != BuiltinType::Int)
return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument)
- << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ << Arg->getSourceRange();
if (Arg->isValueDependent())
continue;
@@ -646,24 +710,36 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
if (!Arg->isIntegerConstantExpr(Result, Context))
return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument)
<< SourceRange(Arg->getLocStart(), Arg->getLocEnd());
-
+
// FIXME: gcc issues a warning and rewrites these to 0. These
// seems especially odd for the third argument since the default
// is 3.
if (i == 1) {
if (Result.getSExtValue() < 0 || Result.getSExtValue() > 1)
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << "0" << "1" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ << "0" << "1" << Arg->getSourceRange();
} else {
if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3)
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ << "0" << "3" << Arg->getSourceRange();
}
}
return false;
}
+/// SemaBuiltinEHReturnDataRegNo - Handle __builtin_eh_return_data_regno, the
+/// operand must be an integer constant.
+bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) {
+ llvm::APSInt Result;
+ if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context))
+ return Diag(TheCall->getLocStart(), diag::err_expr_not_ice)
+ << TheCall->getArg(0)->getSourceRange();
+
+ return false;
+}
+
+
/// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr,
/// int type). This simply type checks that type is one of the defined
/// constants (0-3).
@@ -672,8 +748,8 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
if (Arg->isTypeDependent())
return false;
- QualType ArgType = Arg->getType();
- const BuiltinType *BT = ArgType->getAsBuiltinType();
+ QualType ArgType = Arg->getType();
+ const BuiltinType *BT = ArgType->getAs<BuiltinType>();
llvm::APSInt Result(32);
if (!BT || BT->getKind() != BuiltinType::Int)
return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument)
@@ -737,10 +813,10 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
format_idx, firstDataArg);
}
-
+
case Stmt::DeclRefExprClass: {
const DeclRefExpr *DR = cast<DeclRefExpr>(E);
-
+
// As an exception, do not flag errors for variables binding to
// const string literals.
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
@@ -749,19 +825,18 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
if (const ArrayType *AT = Context.getAsArrayType(T)) {
isConstant = AT->getElementType().isConstant(Context);
- }
- else if (const PointerType *PT = T->getAsPointerType()) {
- isConstant = T.isConstant(Context) &&
+ } else if (const PointerType *PT = T->getAs<PointerType>()) {
+ isConstant = T.isConstant(Context) &&
PT->getPointeeType().isConstant(Context);
}
-
+
if (isConstant) {
const VarDecl *Def = 0;
if (const Expr *Init = VD->getDefinition(Def))
return SemaCheckStringLiteral(Init, TheCall,
HasVAListArg, format_idx, firstDataArg);
}
-
+
// For vprintf* functions (i.e., HasVAListArg==true), we add a
// special check to see if the format string is a function parameter
// of the function calling the printf function. If the function
@@ -784,66 +859,67 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
if (isa<ParmVarDecl>(VD))
return true;
}
-
+
return false;
}
case Stmt::CallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
- if (const ImplicitCastExpr *ICE
+ if (const ImplicitCastExpr *ICE
= dyn_cast<ImplicitCastExpr>(CE->getCallee())) {
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
if (const FormatArgAttr *FA = FD->getAttr<FormatArgAttr>()) {
unsigned ArgIndex = FA->getFormatIdx();
const Expr *Arg = CE->getArg(ArgIndex - 1);
-
- return SemaCheckStringLiteral(Arg, TheCall, HasVAListArg,
+
+ return SemaCheckStringLiteral(Arg, TheCall, HasVAListArg,
format_idx, firstDataArg);
}
}
}
}
-
+
return false;
}
case Stmt::ObjCStringLiteralClass:
case Stmt::StringLiteralClass: {
const StringLiteral *StrE = NULL;
-
+
if (const ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E))
StrE = ObjCFExpr->getString();
else
StrE = cast<StringLiteral>(E);
-
+
if (StrE) {
- CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx,
+ CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx,
firstDataArg);
return true;
}
-
+
return false;
}
-
+
default:
return false;
}
}
void
-Sema::CheckNonNullArguments(const NonNullAttr *NonNull, const CallExpr *TheCall)
-{
+Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
+ const CallExpr *TheCall) {
for (NonNullAttr::iterator i = NonNull->begin(), e = NonNull->end();
i != e; ++i) {
const Expr *ArgExpr = TheCall->getArg(*i);
- if (ArgExpr->isNullPointerConstant(Context))
+ if (ArgExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNotNull))
Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg)
<< ArgExpr->getSourceRange();
}
}
/// CheckPrintfArguments - Check calls to printf (and similar functions) for
-/// correct use of format strings.
+/// correct use of format strings.
///
/// HasVAListArg - A predicate indicating whether the printf-like
/// function is passed an explicit va_arg argument (e.g., vprintf)
@@ -892,30 +968,30 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, const CallExpr *TheCall)
///
/// For now, we ONLY do (1), (3), (5), (6), (7), and (8).
void
-Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
+Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg) {
const Expr *Fn = TheCall->getCallee();
- // CHECK: printf-like function is called with no format string.
+ // CHECK: printf-like function is called with no format string.
if (format_idx >= TheCall->getNumArgs()) {
Diag(TheCall->getRParenLoc(), diag::warn_printf_missing_format_string)
<< Fn->getSourceRange();
return;
}
-
+
const Expr *OrigFormatExpr = TheCall->getArg(format_idx)->IgnoreParenCasts();
-
+
// CHECK: format string is not a string literal.
- //
+ //
// Dynamically generated format strings are difficult to
// automatically vet at compile time. Requiring that format strings
// are string literals: (1) permits the checking of format strings by
// the compiler and thereby (2) can practically remove the source of
// many format string exploits.
- // Format string can be either ObjC string (e.g. @"%d") or
+ // Format string can be either ObjC string (e.g. @"%d") or
// C string (e.g. "%d")
- // ObjC string uses the same format specifiers as C string, so we can use
+ // ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
if (SemaCheckStringLiteral(OrigFormatExpr, TheCall, HasVAListArg, format_idx,
firstDataArg))
@@ -924,11 +1000,11 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
if (TheCall->getNumArgs() == format_idx+1)
- Diag(TheCall->getArg(format_idx)->getLocStart(),
+ Diag(TheCall->getArg(format_idx)->getLocStart(),
diag::warn_printf_nonliteral_noargs)
<< OrigFormatExpr->getSourceRange();
else
- Diag(TheCall->getArg(format_idx)->getLocStart(),
+ Diag(TheCall->getArg(format_idx)->getLocStart(),
diag::warn_printf_nonliteral)
<< OrigFormatExpr->getSourceRange();
}
@@ -954,7 +1030,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
// CHECK: empty format string?
unsigned StrLen = FExpr->getByteLength();
-
+
if (StrLen == 0) {
Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string)
<< OrigFormatExpr->getSourceRange();
@@ -967,7 +1043,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
state_OrdChr,
state_Conversion
} CurrentState = state_OrdChr;
-
+
// numConversions - The number of conversions seen so far. This is
// incremented as we traverse the format string.
unsigned numConversions = 0;
@@ -980,17 +1056,17 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
// Inspect the format string.
unsigned StrIdx = 0;
-
+
// LastConversionIdx - Index within the format string where we last saw
// a '%' character that starts a new format conversion.
unsigned LastConversionIdx = 0;
-
+
for (; StrIdx < StrLen; ++StrIdx) {
-
+
// Is the number of detected conversion conversions greater than
// the number of matching data arguments? If so, stop.
if (!HasVAListArg && numConversions > numDataArgs) break;
-
+
// Handle "\0"
if (Str[StrIdx] == '\0') {
// The string returned by getStrData() is not null-terminated,
@@ -1000,7 +1076,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
<< OrigFormatExpr->getSourceRange();
return;
}
-
+
// Ordinary characters (not processing a format conversion).
if (CurrentState == state_OrdChr) {
if (Str[StrIdx] == '%') {
@@ -1012,10 +1088,10 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
// Seen '%'. Now processing a format conversion.
switch (Str[StrIdx]) {
- // Handle dynamic precision or width specifier.
+ // Handle dynamic precision or width specifier.
case '*': {
++numConversions;
-
+
if (!HasVAListArg) {
if (numConversions > numDataArgs) {
SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx);
@@ -1026,39 +1102,39 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
else
Diag(Loc, diag::warn_printf_asterisk_width_missing_arg)
<< OrigFormatExpr->getSourceRange();
-
+
// Don't do any more checking. We'll just emit spurious errors.
return;
}
-
+
// Perform type checking on width/precision specifier.
const Expr *E = TheCall->getArg(format_idx+numConversions);
- if (const BuiltinType *BT = E->getType()->getAsBuiltinType())
+ if (const BuiltinType *BT = E->getType()->getAs<BuiltinType>())
if (BT->getKind() == BuiltinType::Int)
break;
-
+
SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx);
-
+
if (Str[StrIdx-1] == '.')
Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type)
<< E->getType() << E->getSourceRange();
else
Diag(Loc, diag::warn_printf_asterisk_width_wrong_type)
<< E->getType() << E->getSourceRange();
-
- break;
+
+ break;
}
}
-
+
// Characters which can terminate a format conversion
// (e.g. "%d"). Characters that specify length modifiers or
// other flags are handled by the default case below.
//
- // FIXME: additional checks will go into the following cases.
+ // FIXME: additional checks will go into the following cases.
case 'i':
case 'd':
- case 'o':
- case 'u':
+ case 'o':
+ case 'u':
case 'x':
case 'X':
case 'D':
@@ -1076,7 +1152,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
case 'C':
case 'S':
case 's':
- case 'p':
+ case 'p':
++numConversions;
CurrentState = state_OrdChr;
break;
@@ -1092,21 +1168,21 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
CurrentState = state_OrdChr;
SourceLocation Loc = getLocationOfStringLiteralByte(FExpr,
LastConversionIdx);
-
+
Diag(Loc, diag::warn_printf_write_back)<<OrigFormatExpr->getSourceRange();
break;
}
-
+
// Handle "%@"
case '@':
// %@ is allowed in ObjC format strings only.
- if(ObjCFExpr != NULL)
- CurrentState = state_OrdChr;
+ if (ObjCFExpr != NULL)
+ CurrentState = state_OrdChr;
else {
// Issue a warning: invalid format conversion.
- SourceLocation Loc =
+ SourceLocation Loc =
getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
+
Diag(Loc, diag::warn_printf_invalid_conversion)
<< std::string(Str+LastConversionIdx,
Str+std::min(LastConversionIdx+2, StrLen))
@@ -1114,7 +1190,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
}
++numConversions;
break;
-
+
// Handle "%%"
case '%':
// Sanity check: Was the first "%" character the previous one?
@@ -1122,23 +1198,23 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
// conversion, and that the current "%" character is the start
// of a new conversion.
if (StrIdx - LastConversionIdx == 1)
- CurrentState = state_OrdChr;
+ CurrentState = state_OrdChr;
else {
// Issue a warning: invalid format conversion.
SourceLocation Loc =
getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
+
Diag(Loc, diag::warn_printf_invalid_conversion)
<< std::string(Str+LastConversionIdx, Str+StrIdx)
<< OrigFormatExpr->getSourceRange();
-
+
// This conversion is broken. Advance to the next format
// conversion.
LastConversionIdx = StrIdx;
++numConversions;
}
break;
-
+
default:
// This case catches all other characters: flags, widths, etc.
// We should eventually process those as well.
@@ -1150,21 +1226,21 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
// Issue a warning: invalid format conversion.
SourceLocation Loc =
getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
+
Diag(Loc, diag::warn_printf_invalid_conversion)
<< std::string(Str+LastConversionIdx,
Str+std::min(LastConversionIdx+2, StrLen))
<< OrigFormatExpr->getSourceRange();
return;
}
-
+
if (!HasVAListArg) {
// CHECK: Does the number of format conversions exceed the number
// of data arguments?
if (numConversions > numDataArgs) {
SourceLocation Loc =
getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
+
Diag(Loc, diag::warn_printf_insufficient_data_args)
<< OrigFormatExpr->getSourceRange();
}
@@ -1187,25 +1263,22 @@ static DeclRefExpr* EvalAddr(Expr* E);
void
Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc) {
-
+
// Perform checking for returned stack addresses.
if (lhsType->isPointerType() || lhsType->isBlockPointerType()) {
if (DeclRefExpr *DR = EvalAddr(RetValExp))
Diag(DR->getLocStart(), diag::warn_ret_stack_addr)
<< DR->getDecl()->getDeclName() << RetValExp->getSourceRange();
-
+
// Skip over implicit cast expressions when checking for block expressions.
- if (ImplicitCastExpr *IcExpr =
- dyn_cast_or_null<ImplicitCastExpr>(RetValExp))
- RetValExp = IcExpr->getSubExpr();
+ RetValExp = RetValExp->IgnoreParenCasts();
if (BlockExpr *C = dyn_cast_or_null<BlockExpr>(RetValExp))
if (C->hasBlockDeclRefExprs())
Diag(C->getLocStart(), diag::err_ret_local_block)
<< C->getSourceRange();
- }
- // Perform checking for stack values returned by reference.
- else if (lhsType->isReferenceType()) {
+ } else if (lhsType->isReferenceType()) {
+ // Perform checking for stack values returned by reference.
// Check for a reference to the stack
if (DeclRefExpr *DR = EvalVal(RetValExp))
Diag(DR->getLocStart(), diag::warn_ret_stack_ref)
@@ -1223,7 +1296,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
///
/// EvalAddr processes expressions that are pointers that are used as
/// references (and not L-values). EvalVal handles all other values.
-/// At the base case of the recursion is a check for a DeclRefExpr* in
+/// At the base case of the recursion is a check for a DeclRefExpr* in
/// the refers to a stack variable.
///
/// This implementation handles:
@@ -1236,11 +1309,11 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
/// * taking the address of an array element where the array is on the stack
static DeclRefExpr* EvalAddr(Expr *E) {
// We should only be called for evaluating pointer expressions.
- assert((E->getType()->isPointerType() ||
+ assert((E->getType()->isAnyPointerType() ||
E->getType()->isBlockPointerType() ||
E->getType()->isObjCQualifiedIdType()) &&
"EvalAddr only works on pointers");
-
+
// Our "symbolic interpreter" is just a dispatch off the currently
// viewed AST node. We then recursively traverse the AST by calling
// EvalAddr and EvalVal appropriately.
@@ -1253,28 +1326,28 @@ static DeclRefExpr* EvalAddr(Expr *E) {
// The only unary operator that make sense to handle here
// is AddrOf. All others don't make sense as pointers.
UnaryOperator *U = cast<UnaryOperator>(E);
-
+
if (U->getOpcode() == UnaryOperator::AddrOf)
return EvalVal(U->getSubExpr());
else
return NULL;
}
-
+
case Stmt::BinaryOperatorClass: {
// Handle pointer arithmetic. All other binary operators are not valid
// in this context.
BinaryOperator *B = cast<BinaryOperator>(E);
BinaryOperator::Opcode op = B->getOpcode();
-
+
if (op != BinaryOperator::Add && op != BinaryOperator::Sub)
return NULL;
-
+
Expr *Base = B->getLHS();
// Determine which argument is the real pointer base. It could be
// the RHS argument instead of the LHS.
if (!Base->getType()->isPointerType()) Base = B->getRHS();
-
+
assert (Base->getType()->isPointerType());
return EvalAddr(Base);
}
@@ -1283,7 +1356,7 @@ static DeclRefExpr* EvalAddr(Expr *E) {
// valid DeclRefExpr*s. If one of them is valid, we return it.
case Stmt::ConditionalOperatorClass: {
ConditionalOperator *C = cast<ConditionalOperator>(E);
-
+
// Handle the GNU extension for missing LHS.
if (Expr *lhsExpr = C->getLHS())
if (DeclRefExpr* LHS = EvalAddr(lhsExpr))
@@ -1291,7 +1364,7 @@ static DeclRefExpr* EvalAddr(Expr *E) {
return EvalAddr(C->getRHS());
}
-
+
// For casts, we need to handle conversions from arrays to
// pointer values, and pointer-to-pointer conversions.
case Stmt::ImplicitCastExprClass:
@@ -1299,7 +1372,7 @@ static DeclRefExpr* EvalAddr(Expr *E) {
case Stmt::CXXFunctionalCastExprClass: {
Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
QualType T = SubExpr->getType();
-
+
if (SubExpr->getType()->isPointerType() ||
SubExpr->getType()->isBlockPointerType() ||
SubExpr->getType()->isObjCQualifiedIdType())
@@ -1309,7 +1382,7 @@ static DeclRefExpr* EvalAddr(Expr *E) {
else
return 0;
}
-
+
// C++ casts. For dynamic casts, static casts, and const casts, we
// are always converting from a pointer-to-pointer, so we just blow
// through the cast. In the case the dynamic cast doesn't fail (and
@@ -1317,9 +1390,9 @@ static DeclRefExpr* EvalAddr(Expr *E) {
// where we return the address of a stack variable. For Reinterpre
// FIXME: The comment about is wrong; we're not always converting
// from pointer to pointer. I'm guessing that this code should also
- // handle references to objects.
- case Stmt::CXXStaticCastExprClass:
- case Stmt::CXXDynamicCastExprClass:
+ // handle references to objects.
+ case Stmt::CXXStaticCastExprClass:
+ case Stmt::CXXDynamicCastExprClass:
case Stmt::CXXConstCastExprClass:
case Stmt::CXXReinterpretCastExprClass: {
Expr *S = cast<CXXNamedCastExpr>(E)->getSubExpr();
@@ -1328,62 +1401,62 @@ static DeclRefExpr* EvalAddr(Expr *E) {
else
return NULL;
}
-
+
// Everything else: we simply don't reason about them.
default:
return NULL;
}
}
-
+
/// EvalVal - This function is complements EvalAddr in the mutual recursion.
/// See the comments for EvalAddr for more details.
static DeclRefExpr* EvalVal(Expr *E) {
-
+
// We should only be called for evaluating non-pointer expressions, or
// expressions with a pointer type that are not used as references but instead
// are l-values (e.g., DeclRefExpr with a pointer type).
-
+
// Our "symbolic interpreter" is just a dispatch off the currently
// viewed AST node. We then recursively traverse the AST by calling
// EvalAddr and EvalVal appropriately.
switch (E->getStmtClass()) {
- case Stmt::DeclRefExprClass:
+ case Stmt::DeclRefExprClass:
case Stmt::QualifiedDeclRefExprClass: {
// DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking
// at code that refers to a variable's name. We check if it has local
// storage within the function, and if so, return the expression.
DeclRefExpr *DR = cast<DeclRefExpr>(E);
-
+
if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
- if(V->hasLocalStorage() && !V->getType()->isReferenceType()) return DR;
-
+ if (V->hasLocalStorage() && !V->getType()->isReferenceType()) return DR;
+
return NULL;
}
-
+
case Stmt::ParenExprClass:
// Ignore parentheses.
return EvalVal(cast<ParenExpr>(E)->getSubExpr());
-
+
case Stmt::UnaryOperatorClass: {
// The only unary operator that make sense to handle here
// is Deref. All others don't resolve to a "name." This includes
// handling all sorts of rvalues passed to a unary operator.
UnaryOperator *U = cast<UnaryOperator>(E);
-
+
if (U->getOpcode() == UnaryOperator::Deref)
return EvalAddr(U->getSubExpr());
return NULL;
}
-
+
case Stmt::ArraySubscriptExprClass: {
// Array subscripts are potential references to data on the stack. We
// retrieve the DeclRefExpr* for the array variable if it indeed
// has local storage.
return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase());
}
-
+
case Stmt::ConditionalOperatorClass: {
// For conditional operators we need to see if either the LHS or RHS are
// non-NULL DeclRefExpr's. If one is non-NULL, we return it.
@@ -1396,18 +1469,18 @@ static DeclRefExpr* EvalVal(Expr *E) {
return EvalVal(C->getRHS());
}
-
+
// Accesses to members are potential references to data on the stack.
case Stmt::MemberExprClass: {
MemberExpr *M = cast<MemberExpr>(E);
-
+
// Check for indirect access. We only want direct field accesses.
if (!M->isArrow())
return EvalVal(M->getBase());
else
return NULL;
}
-
+
// Everything else: we simply don't reason about them.
default:
return NULL;
@@ -1421,7 +1494,7 @@ static DeclRefExpr* EvalVal(Expr *E) {
/// to do what the programmer intended.
void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) {
bool EmitWarning = true;
-
+
Expr* LeftExprSansParen = lex->IgnoreParens();
Expr* RightExprSansParen = rex->IgnoreParens();
@@ -1431,8 +1504,8 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) {
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RightExprSansParen))
if (DRL->getDecl() == DRR->getDecl())
EmitWarning = false;
-
-
+
+
// Special case: check for comparisons against literals that can be exactly
// represented by APFloat. In such cases, do not emit a warning. This
// is a heuristic: often comparison against such literals are used to
@@ -1442,25 +1515,24 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) {
if (FloatingLiteral* FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) {
if (FLL->isExact())
EmitWarning = false;
- }
- else
+ } else
if (FloatingLiteral* FLR = dyn_cast<FloatingLiteral>(RightExprSansParen)){
if (FLR->isExact())
EmitWarning = false;
}
}
-
+
// Check for comparisons with builtin types.
if (EmitWarning)
if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen))
if (CL->isBuiltinCall(Context))
EmitWarning = false;
-
+
if (EmitWarning)
if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
if (CR->isBuiltinCall(Context))
EmitWarning = false;
-
+
// Emit the diagnostic.
if (EmitWarning)
Diag(loc, diag::warn_floatingpoint_eq)
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
new file mode 100644
index 0000000000000..3981b8d22fa35
--- /dev/null
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -0,0 +1,1432 @@
+//===---------------- SemaCodeComplete.cpp - Code Completion ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the code-completion semantic actions.
+//
+//===----------------------------------------------------------------------===//
+#include "Sema.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringExtras.h"
+#include <list>
+#include <map>
+#include <vector>
+
+using namespace clang;
+
+/// \brief Set the code-completion consumer for semantic analysis.
+void Sema::setCodeCompleteConsumer(CodeCompleteConsumer *CCC) {
+ assert(((CodeCompleter != 0) != (CCC != 0)) &&
+ "Already set or cleared a code-completion consumer?");
+ CodeCompleter = CCC;
+}
+
+namespace {
+ /// \brief A container of code-completion results.
+ class ResultBuilder {
+ public:
+ /// \brief The type of a name-lookup filter, which can be provided to the
+ /// name-lookup routines to specify which declarations should be included in
+ /// the result set (when it returns true) and which declarations should be
+ /// filtered out (returns false).
+ typedef bool (ResultBuilder::*LookupFilter)(NamedDecl *) const;
+
+ typedef CodeCompleteConsumer::Result Result;
+
+ private:
+ /// \brief The actual results we have found.
+ std::vector<Result> Results;
+
+ /// \brief A record of all of the declarations we have found and placed
+ /// into the result set, used to ensure that no declaration ever gets into
+ /// the result set twice.
+ llvm::SmallPtrSet<Decl*, 16> AllDeclsFound;
+
+ /// \brief A mapping from declaration names to the declarations that have
+ /// this name within a particular scope and their index within the list of
+ /// results.
+ typedef std::multimap<DeclarationName,
+ std::pair<NamedDecl *, unsigned> > ShadowMap;
+
+ /// \brief The semantic analysis object for which results are being
+ /// produced.
+ Sema &SemaRef;
+
+ /// \brief If non-NULL, a filter function used to remove any code-completion
+ /// results that are not desirable.
+ LookupFilter Filter;
+
+ /// \brief A list of shadow maps, which is used to model name hiding at
+ /// different levels of, e.g., the inheritance hierarchy.
+ std::list<ShadowMap> ShadowMaps;
+
+ public:
+ explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0)
+ : SemaRef(SemaRef), Filter(Filter) { }
+
+ /// \brief Set the filter used for code-completion results.
+ void setFilter(LookupFilter Filter) {
+ this->Filter = Filter;
+ }
+
+ typedef std::vector<Result>::iterator iterator;
+ iterator begin() { return Results.begin(); }
+ iterator end() { return Results.end(); }
+
+ Result *data() { return Results.empty()? 0 : &Results.front(); }
+ unsigned size() const { return Results.size(); }
+ bool empty() const { return Results.empty(); }
+
+ /// \brief Add a new result to this result set (if it isn't already in one
+ /// of the shadow maps), or replace an existing result (for, e.g., a
+ /// redeclaration).
+ ///
+ /// \param R the result to add (if it is unique).
+ ///
+ /// \param R the context in which this result will be named.
+ void MaybeAddResult(Result R, DeclContext *CurContext = 0);
+
+ /// \brief Enter into a new scope.
+ void EnterNewScope();
+
+ /// \brief Exit from the current scope.
+ void ExitScope();
+
+ /// \name Name lookup predicates
+ ///
+ /// These predicates can be passed to the name lookup functions to filter the
+ /// results of name lookup. All of the predicates have the same type, so that
+ ///
+ //@{
+ bool IsOrdinaryName(NamedDecl *ND) const;
+ bool IsNestedNameSpecifier(NamedDecl *ND) const;
+ bool IsEnum(NamedDecl *ND) const;
+ bool IsClassOrStruct(NamedDecl *ND) const;
+ bool IsUnion(NamedDecl *ND) const;
+ bool IsNamespace(NamedDecl *ND) const;
+ bool IsNamespaceOrAlias(NamedDecl *ND) const;
+ bool IsType(NamedDecl *ND) const;
+ bool IsMember(NamedDecl *ND) const;
+ //@}
+ };
+}
+
+/// \brief Determines whether the given hidden result could be found with
+/// some extra work, e.g., by qualifying the name.
+///
+/// \param Hidden the declaration that is hidden by the currenly \p Visible
+/// declaration.
+///
+/// \param Visible the declaration with the same name that is already visible.
+///
+/// \returns true if the hidden result can be found by some mechanism,
+/// false otherwise.
+static bool canHiddenResultBeFound(const LangOptions &LangOpts,
+ NamedDecl *Hidden, NamedDecl *Visible) {
+ // In C, there is no way to refer to a hidden name.
+ if (!LangOpts.CPlusPlus)
+ return false;
+
+ DeclContext *HiddenCtx = Hidden->getDeclContext()->getLookupContext();
+
+ // There is no way to qualify a name declared in a function or method.
+ if (HiddenCtx->isFunctionOrMethod())
+ return false;
+
+ return HiddenCtx != Visible->getDeclContext()->getLookupContext();
+}
+
+/// \brief Compute the qualification required to get from the current context
+/// (\p CurContext) to the target context (\p TargetContext).
+///
+/// \param Context the AST context in which the qualification will be used.
+///
+/// \param CurContext the context where an entity is being named, which is
+/// typically based on the current scope.
+///
+/// \param TargetContext the context in which the named entity actually
+/// resides.
+///
+/// \returns a nested name specifier that refers into the target context, or
+/// NULL if no qualification is needed.
+static NestedNameSpecifier *
+getRequiredQualification(ASTContext &Context,
+ DeclContext *CurContext,
+ DeclContext *TargetContext) {
+ llvm::SmallVector<DeclContext *, 4> TargetParents;
+
+ for (DeclContext *CommonAncestor = TargetContext;
+ CommonAncestor && !CommonAncestor->Encloses(CurContext);
+ CommonAncestor = CommonAncestor->getLookupParent()) {
+ if (CommonAncestor->isTransparentContext() ||
+ CommonAncestor->isFunctionOrMethod())
+ continue;
+
+ TargetParents.push_back(CommonAncestor);
+ }
+
+ NestedNameSpecifier *Result = 0;
+ while (!TargetParents.empty()) {
+ DeclContext *Parent = TargetParents.back();
+ TargetParents.pop_back();
+
+ if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Parent))
+ Result = NestedNameSpecifier::Create(Context, Result, Namespace);
+ else if (TagDecl *TD = dyn_cast<TagDecl>(Parent))
+ Result = NestedNameSpecifier::Create(Context, Result,
+ false,
+ Context.getTypeDeclType(TD).getTypePtr());
+ else
+ assert(Parent->isTranslationUnit());
+ }
+
+ return Result;
+}
+
+void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
+ assert(!ShadowMaps.empty() && "Must enter into a results scope");
+
+ if (R.Kind != Result::RK_Declaration) {
+ // For non-declaration results, just add the result.
+ Results.push_back(R);
+ return;
+ }
+
+ // Skip unnamed entities.
+ if (!R.Declaration->getDeclName())
+ return;
+
+ // Look through using declarations.
+ if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration))
+ MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier),
+ CurContext);
+
+ // Handle each declaration in an overload set separately.
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(R.Declaration)) {
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F)
+ MaybeAddResult(Result(*F, R.Rank, R.Qualifier), CurContext);
+
+ return;
+ }
+
+ Decl *CanonDecl = R.Declaration->getCanonicalDecl();
+ unsigned IDNS = CanonDecl->getIdentifierNamespace();
+
+ // Friend declarations and declarations introduced due to friends are never
+ // added as results.
+ if (isa<FriendDecl>(CanonDecl) ||
+ (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
+ return;
+
+ if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) {
+ // __va_list_tag is a freak of nature. Find it and skip it.
+ if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list"))
+ return;
+
+ // Filter out names reserved for the implementation (C99 7.1.3,
+ // C++ [lib.global.names]). Users don't need to see those.
+ if (Id->getLength() >= 2) {
+ const char *Name = Id->getName();
+ if (Name[0] == '_' &&
+ (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')))
+ return;
+ }
+ }
+
+ // C++ constructors are never found by name lookup.
+ if (isa<CXXConstructorDecl>(CanonDecl))
+ return;
+
+ // Filter out any unwanted results.
+ if (Filter && !(this->*Filter)(R.Declaration))
+ return;
+
+ ShadowMap &SMap = ShadowMaps.back();
+ ShadowMap::iterator I, IEnd;
+ for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName());
+ I != IEnd; ++I) {
+ NamedDecl *ND = I->second.first;
+ unsigned Index = I->second.second;
+ if (ND->getCanonicalDecl() == CanonDecl) {
+ // This is a redeclaration. Always pick the newer declaration.
+ I->second.first = R.Declaration;
+ Results[Index].Declaration = R.Declaration;
+
+ // Pick the best rank of the two.
+ Results[Index].Rank = std::min(Results[Index].Rank, R.Rank);
+
+ // We're done.
+ return;
+ }
+ }
+
+ // This is a new declaration in this scope. However, check whether this
+ // declaration name is hidden by a similarly-named declaration in an outer
+ // scope.
+ std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end();
+ --SMEnd;
+ for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) {
+ for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName());
+ I != IEnd; ++I) {
+ // A tag declaration does not hide a non-tag declaration.
+ if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
+ Decl::IDNS_ObjCProtocol)))
+ continue;
+
+ // Protocols are in distinct namespaces from everything else.
+ if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
+ || (IDNS & Decl::IDNS_ObjCProtocol)) &&
+ I->second.first->getIdentifierNamespace() != IDNS)
+ continue;
+
+ // The newly-added result is hidden by an entry in the shadow map.
+ if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration,
+ I->second.first)) {
+ // Note that this result was hidden.
+ R.Hidden = true;
+ R.QualifierIsInformative = false;
+
+ if (!R.Qualifier)
+ R.Qualifier = getRequiredQualification(SemaRef.Context,
+ CurContext,
+ R.Declaration->getDeclContext());
+ } else {
+ // This result was hidden and cannot be found; don't bother adding
+ // it.
+ return;
+ }
+
+ break;
+ }
+ }
+
+ // Make sure that any given declaration only shows up in the result set once.
+ if (!AllDeclsFound.insert(CanonDecl))
+ return;
+
+ // If the filter is for nested-name-specifiers, then this result starts a
+ // nested-name-specifier.
+ if ((Filter == &ResultBuilder::IsNestedNameSpecifier) ||
+ (Filter == &ResultBuilder::IsMember &&
+ isa<CXXRecordDecl>(R.Declaration) &&
+ cast<CXXRecordDecl>(R.Declaration)->isInjectedClassName()))
+ R.StartsNestedNameSpecifier = true;
+
+ // If this result is supposed to have an informative qualifier, add one.
+ if (R.QualifierIsInformative && !R.Qualifier &&
+ !R.StartsNestedNameSpecifier) {
+ DeclContext *Ctx = R.Declaration->getDeclContext();
+ if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
+ else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
+ SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
+ else
+ R.QualifierIsInformative = false;
+ }
+
+ // Insert this result into the set of results and into the current shadow
+ // map.
+ SMap.insert(std::make_pair(R.Declaration->getDeclName(),
+ std::make_pair(R.Declaration, Results.size())));
+ Results.push_back(R);
+}
+
+/// \brief Enter into a new scope.
+void ResultBuilder::EnterNewScope() {
+ ShadowMaps.push_back(ShadowMap());
+}
+
+/// \brief Exit from the current scope.
+void ResultBuilder::ExitScope() {
+ ShadowMaps.pop_back();
+}
+
+/// \brief Determines whether this given declaration will be found by
+/// ordinary name lookup.
+bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ if (SemaRef.getLangOptions().CPlusPlus)
+ IDNS |= Decl::IDNS_Tag;
+
+ return ND->getIdentifierNamespace() & IDNS;
+}
+
+/// \brief Determines whether the given declaration is suitable as the
+/// start of a C++ nested-name-specifier, e.g., a class or namespace.
+bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const {
+ // Allow us to find class templates, too.
+ if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ ND = ClassTemplate->getTemplatedDecl();
+
+ return SemaRef.isAcceptableNestedNameSpecifier(ND);
+}
+
+/// \brief Determines whether the given declaration is an enumeration.
+bool ResultBuilder::IsEnum(NamedDecl *ND) const {
+ return isa<EnumDecl>(ND);
+}
+
+/// \brief Determines whether the given declaration is a class or struct.
+bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const {
+ // Allow us to find class templates, too.
+ if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ ND = ClassTemplate->getTemplatedDecl();
+
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
+ return RD->getTagKind() == TagDecl::TK_class ||
+ RD->getTagKind() == TagDecl::TK_struct;
+
+ return false;
+}
+
+/// \brief Determines whether the given declaration is a union.
+bool ResultBuilder::IsUnion(NamedDecl *ND) const {
+ // Allow us to find class templates, too.
+ if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ ND = ClassTemplate->getTemplatedDecl();
+
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
+ return RD->getTagKind() == TagDecl::TK_union;
+
+ return false;
+}
+
+/// \brief Determines whether the given declaration is a namespace.
+bool ResultBuilder::IsNamespace(NamedDecl *ND) const {
+ return isa<NamespaceDecl>(ND);
+}
+
+/// \brief Determines whether the given declaration is a namespace or
+/// namespace alias.
+bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const {
+ return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
+}
+
+/// \brief Brief determines whether the given declaration is a namespace or
+/// namespace alias.
+bool ResultBuilder::IsType(NamedDecl *ND) const {
+ return isa<TypeDecl>(ND);
+}
+
+/// \brief Since every declaration found within a class is a member that we
+/// care about, always returns true. This predicate exists mostly to
+/// communicate to the result builder that we are performing a lookup for
+/// member access.
+bool ResultBuilder::IsMember(NamedDecl *ND) const {
+ return true;
+}
+
+// Find the next outer declaration context corresponding to this scope.
+static DeclContext *findOuterContext(Scope *S) {
+ for (S = S->getParent(); S; S = S->getParent())
+ if (S->getEntity())
+ return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
+
+ return 0;
+}
+
+/// \brief Collect the results of searching for members within the given
+/// declaration context.
+///
+/// \param Ctx the declaration context from which we will gather results.
+///
+/// \param Rank the rank given to results in this declaration context.
+///
+/// \param Visited the set of declaration contexts that have already been
+/// visited. Declaration contexts will only be visited once.
+///
+/// \param Results the result set that will be extended with any results
+/// found within this declaration context (and, for a C++ class, its bases).
+///
+/// \param InBaseClass whether we are in a base class.
+///
+/// \returns the next higher rank value, after considering all of the
+/// names within this declaration context.
+static unsigned CollectMemberLookupResults(DeclContext *Ctx,
+ unsigned Rank,
+ DeclContext *CurContext,
+ llvm::SmallPtrSet<DeclContext *, 16> &Visited,
+ ResultBuilder &Results,
+ bool InBaseClass = false) {
+ // Make sure we don't visit the same context twice.
+ if (!Visited.insert(Ctx->getPrimaryContext()))
+ return Rank;
+
+ // Enumerate all of the results in this context.
+ typedef CodeCompleteConsumer::Result Result;
+ Results.EnterNewScope();
+ for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
+ CurCtx = CurCtx->getNextContext()) {
+ for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
+ DEnd = CurCtx->decls_end();
+ D != DEnd; ++D) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
+ Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext);
+ }
+ }
+
+ // Traverse the contexts of inherited classes.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+ for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
+ BEnd = Record->bases_end();
+ B != BEnd; ++B) {
+ QualType BaseType = B->getType();
+
+ // Don't look into dependent bases, because name lookup can't look
+ // there anyway.
+ if (BaseType->isDependentType())
+ continue;
+
+ const RecordType *Record = BaseType->getAs<RecordType>();
+ if (!Record)
+ continue;
+
+ // FIXME: It would be nice to be able to determine whether referencing
+ // a particular member would be ambiguous. For example, given
+ //
+ // struct A { int member; };
+ // struct B { int member; };
+ // struct C : A, B { };
+ //
+ // void f(C *c) { c->### }
+ // accessing 'member' would result in an ambiguity. However, code
+ // completion could be smart enough to qualify the member with the
+ // base class, e.g.,
+ //
+ // c->B::member
+ //
+ // or
+ //
+ // c->A::member
+
+ // Collect results from this base class (and its bases).
+ CollectMemberLookupResults(Record->getDecl(), Rank, CurContext, Visited,
+ Results, /*InBaseClass=*/true);
+ }
+ }
+
+ // FIXME: Look into base classes in Objective-C!
+
+ Results.ExitScope();
+ return Rank + 1;
+}
+
+/// \brief Collect the results of searching for members within the given
+/// declaration context.
+///
+/// \param Ctx the declaration context from which we will gather results.
+///
+/// \param InitialRank the initial rank given to results in this declaration
+/// context. Larger rank values will be used for, e.g., members found in
+/// base classes.
+///
+/// \param Results the result set that will be extended with any results
+/// found within this declaration context (and, for a C++ class, its bases).
+///
+/// \returns the next higher rank value, after considering all of the
+/// names within this declaration context.
+static unsigned CollectMemberLookupResults(DeclContext *Ctx,
+ unsigned InitialRank,
+ DeclContext *CurContext,
+ ResultBuilder &Results) {
+ llvm::SmallPtrSet<DeclContext *, 16> Visited;
+ return CollectMemberLookupResults(Ctx, InitialRank, CurContext, Visited,
+ Results);
+}
+
+/// \brief Collect the results of searching for declarations within the given
+/// scope and its parent scopes.
+///
+/// \param S the scope in which we will start looking for declarations.
+///
+/// \param InitialRank the initial rank given to results in this scope.
+/// Larger rank values will be used for results found in parent scopes.
+///
+/// \param CurContext the context from which lookup results will be found.
+///
+/// \param Results the builder object that will receive each result.
+static unsigned CollectLookupResults(Scope *S,
+ TranslationUnitDecl *TranslationUnit,
+ unsigned InitialRank,
+ DeclContext *CurContext,
+ ResultBuilder &Results) {
+ if (!S)
+ return InitialRank;
+
+ // FIXME: Using directives!
+
+ unsigned NextRank = InitialRank;
+ Results.EnterNewScope();
+ if (S->getEntity() &&
+ !((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
+ // Look into this scope's declaration context, along with any of its
+ // parent lookup contexts (e.g., enclosing classes), up to the point
+ // where we hit the context stored in the next outer scope.
+ DeclContext *Ctx = (DeclContext *)S->getEntity();
+ DeclContext *OuterCtx = findOuterContext(S);
+
+ for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
+ Ctx = Ctx->getLookupParent()) {
+ if (Ctx->isFunctionOrMethod())
+ continue;
+
+ NextRank = CollectMemberLookupResults(Ctx, NextRank + 1, CurContext,
+ Results);
+ }
+ } else if (!S->getParent()) {
+ // Look into the translation unit scope. We walk through the translation
+ // unit's declaration context, because the Scope itself won't have all of
+ // the declarations if we loaded a precompiled header.
+ // FIXME: We would like the translation unit's Scope object to point to the
+ // translation unit, so we don't need this special "if" branch. However,
+ // doing so would force the normal C++ name-lookup code to look into the
+ // translation unit decl when the IdentifierInfo chains would suffice.
+ // Once we fix that problem (which is part of a more general "don't look
+ // in DeclContexts unless we have to" optimization), we can eliminate the
+ // TranslationUnit parameter entirely.
+ NextRank = CollectMemberLookupResults(TranslationUnit, NextRank + 1,
+ CurContext, Results);
+ } else {
+ // Walk through the declarations in this Scope.
+ for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get())))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, NextRank),
+ CurContext);
+ }
+
+ NextRank = NextRank + 1;
+ }
+
+ // Lookup names in the parent scope.
+ NextRank = CollectLookupResults(S->getParent(), TranslationUnit, NextRank,
+ CurContext, Results);
+ Results.ExitScope();
+
+ return NextRank;
+}
+
+/// \brief Add type specifiers for the current language as keyword results.
+static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ Results.MaybeAddResult(Result("short", Rank));
+ Results.MaybeAddResult(Result("long", Rank));
+ Results.MaybeAddResult(Result("signed", Rank));
+ Results.MaybeAddResult(Result("unsigned", Rank));
+ Results.MaybeAddResult(Result("void", Rank));
+ Results.MaybeAddResult(Result("char", Rank));
+ Results.MaybeAddResult(Result("int", Rank));
+ Results.MaybeAddResult(Result("float", Rank));
+ Results.MaybeAddResult(Result("double", Rank));
+ Results.MaybeAddResult(Result("enum", Rank));
+ Results.MaybeAddResult(Result("struct", Rank));
+ Results.MaybeAddResult(Result("union", Rank));
+
+ if (LangOpts.C99) {
+ // C99-specific
+ Results.MaybeAddResult(Result("_Complex", Rank));
+ Results.MaybeAddResult(Result("_Imaginary", Rank));
+ Results.MaybeAddResult(Result("_Bool", Rank));
+ }
+
+ if (LangOpts.CPlusPlus) {
+ // C++-specific
+ Results.MaybeAddResult(Result("bool", Rank));
+ Results.MaybeAddResult(Result("class", Rank));
+ Results.MaybeAddResult(Result("typename", Rank));
+ Results.MaybeAddResult(Result("wchar_t", Rank));
+
+ if (LangOpts.CPlusPlus0x) {
+ Results.MaybeAddResult(Result("char16_t", Rank));
+ Results.MaybeAddResult(Result("char32_t", Rank));
+ Results.MaybeAddResult(Result("decltype", Rank));
+ }
+ }
+
+ // GNU extensions
+ if (LangOpts.GNUMode) {
+ // FIXME: Enable when we actually support decimal floating point.
+ // Results.MaybeAddResult(Result("_Decimal32", Rank));
+ // Results.MaybeAddResult(Result("_Decimal64", Rank));
+ // Results.MaybeAddResult(Result("_Decimal128", Rank));
+ Results.MaybeAddResult(Result("typeof", Rank));
+ }
+}
+
+/// \brief Add function parameter chunks to the given code completion string.
+static void AddFunctionParameterChunks(ASTContext &Context,
+ FunctionDecl *Function,
+ CodeCompletionString *Result) {
+ CodeCompletionString *CCStr = Result;
+
+ for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) {
+ ParmVarDecl *Param = Function->getParamDecl(P);
+
+ if (Param->hasDefaultArg()) {
+ // When we see an optional default argument, put that argument and
+ // the remaining default arguments into a new, optional string.
+ CodeCompletionString *Opt = new CodeCompletionString;
+ CCStr->AddOptionalChunk(std::auto_ptr<CodeCompletionString>(Opt));
+ CCStr = Opt;
+ }
+
+ if (P != 0)
+ CCStr->AddTextChunk(", ");
+
+ // Format the placeholder string.
+ std::string PlaceholderStr;
+ if (Param->getIdentifier())
+ PlaceholderStr = Param->getIdentifier()->getName();
+
+ Param->getType().getAsStringInternal(PlaceholderStr,
+ Context.PrintingPolicy);
+
+ // Add the placeholder string.
+ CCStr->AddPlaceholderChunk(PlaceholderStr.c_str());
+ }
+
+ if (const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>())
+ if (Proto->isVariadic())
+ CCStr->AddPlaceholderChunk(", ...");
+}
+
+/// \brief Add template parameter chunks to the given code completion string.
+static void AddTemplateParameterChunks(ASTContext &Context,
+ TemplateDecl *Template,
+ CodeCompletionString *Result,
+ unsigned MaxParameters = 0) {
+ CodeCompletionString *CCStr = Result;
+ bool FirstParameter = true;
+
+ TemplateParameterList *Params = Template->getTemplateParameters();
+ TemplateParameterList::iterator PEnd = Params->end();
+ if (MaxParameters)
+ PEnd = Params->begin() + MaxParameters;
+ for (TemplateParameterList::iterator P = Params->begin(); P != PEnd; ++P) {
+ bool HasDefaultArg = false;
+ std::string PlaceholderStr;
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
+ if (TTP->wasDeclaredWithTypename())
+ PlaceholderStr = "typename";
+ else
+ PlaceholderStr = "class";
+
+ if (TTP->getIdentifier()) {
+ PlaceholderStr += ' ';
+ PlaceholderStr += TTP->getIdentifier()->getName();
+ }
+
+ HasDefaultArg = TTP->hasDefaultArgument();
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ if (NTTP->getIdentifier())
+ PlaceholderStr = NTTP->getIdentifier()->getName();
+ NTTP->getType().getAsStringInternal(PlaceholderStr,
+ Context.PrintingPolicy);
+ HasDefaultArg = NTTP->hasDefaultArgument();
+ } else {
+ assert(isa<TemplateTemplateParmDecl>(*P));
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
+
+ // Since putting the template argument list into the placeholder would
+ // be very, very long, we just use an abbreviation.
+ PlaceholderStr = "template<...> class";
+ if (TTP->getIdentifier()) {
+ PlaceholderStr += ' ';
+ PlaceholderStr += TTP->getIdentifier()->getName();
+ }
+
+ HasDefaultArg = TTP->hasDefaultArgument();
+ }
+
+ if (HasDefaultArg) {
+ // When we see an optional default argument, put that argument and
+ // the remaining default arguments into a new, optional string.
+ CodeCompletionString *Opt = new CodeCompletionString;
+ CCStr->AddOptionalChunk(std::auto_ptr<CodeCompletionString>(Opt));
+ CCStr = Opt;
+ }
+
+ if (FirstParameter)
+ FirstParameter = false;
+ else
+ CCStr->AddTextChunk(", ");
+
+ // Add the placeholder string.
+ CCStr->AddPlaceholderChunk(PlaceholderStr.c_str());
+ }
+}
+
+/// \brief Add a qualifier to the given code-completion string, if the
+/// provided nested-name-specifier is non-NULL.
+void AddQualifierToCompletionString(CodeCompletionString *Result,
+ NestedNameSpecifier *Qualifier,
+ bool QualifierIsInformative,
+ ASTContext &Context) {
+ if (!Qualifier)
+ return;
+
+ std::string PrintedNNS;
+ {
+ llvm::raw_string_ostream OS(PrintedNNS);
+ Qualifier->print(OS, Context.PrintingPolicy);
+ }
+ if (QualifierIsInformative)
+ Result->AddInformativeChunk(PrintedNNS.c_str());
+ else
+ Result->AddTextChunk(PrintedNNS.c_str());
+}
+
+/// \brief If possible, create a new code completion string for the given
+/// result.
+///
+/// \returns Either a new, heap-allocated code completion string describing
+/// how to use this result, or NULL to indicate that the string or name of the
+/// result is all that is needed.
+CodeCompletionString *
+CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
+ if (Kind != RK_Declaration)
+ return 0;
+
+ NamedDecl *ND = Declaration;
+
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
+ CodeCompletionString *Result = new CodeCompletionString;
+ AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
+ S.Context);
+ Result->AddTextChunk(Function->getNameAsString().c_str());
+ Result->AddTextChunk("(");
+ AddFunctionParameterChunks(S.Context, Function, Result);
+ Result->AddTextChunk(")");
+ return Result;
+ }
+
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
+ CodeCompletionString *Result = new CodeCompletionString;
+ AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
+ S.Context);
+ FunctionDecl *Function = FunTmpl->getTemplatedDecl();
+ Result->AddTextChunk(Function->getNameAsString().c_str());
+
+ // Figure out which template parameters are deduced (or have default
+ // arguments).
+ llvm::SmallVector<bool, 16> Deduced;
+ S.MarkDeducedTemplateParameters(FunTmpl, Deduced);
+ unsigned LastDeducibleArgument;
+ for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0;
+ --LastDeducibleArgument) {
+ if (!Deduced[LastDeducibleArgument - 1]) {
+ // C++0x: Figure out if the template argument has a default. If so,
+ // the user doesn't need to type this argument.
+ // FIXME: We need to abstract template parameters better!
+ bool HasDefaultArg = false;
+ NamedDecl *Param = FunTmpl->getTemplateParameters()->getParam(
+ LastDeducibleArgument - 1);
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ HasDefaultArg = TTP->hasDefaultArgument();
+ else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param))
+ HasDefaultArg = NTTP->hasDefaultArgument();
+ else {
+ assert(isa<TemplateTemplateParmDecl>(Param));
+ HasDefaultArg
+ = cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument();
+ }
+
+ if (!HasDefaultArg)
+ break;
+ }
+ }
+
+ if (LastDeducibleArgument) {
+ // Some of the function template arguments cannot be deduced from a
+ // function call, so we introduce an explicit template argument list
+ // containing all of the arguments up to the first deducible argument.
+ Result->AddTextChunk("<");
+ AddTemplateParameterChunks(S.Context, FunTmpl, Result,
+ LastDeducibleArgument);
+ Result->AddTextChunk(">");
+ }
+
+ // Add the function parameters
+ Result->AddTextChunk("(");
+ AddFunctionParameterChunks(S.Context, Function, Result);
+ Result->AddTextChunk(")");
+ return Result;
+ }
+
+ if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
+ CodeCompletionString *Result = new CodeCompletionString;
+ AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
+ S.Context);
+ Result->AddTextChunk(Template->getNameAsString().c_str());
+ Result->AddTextChunk("<");
+ AddTemplateParameterChunks(S.Context, Template, Result);
+ Result->AddTextChunk(">");
+ return Result;
+ }
+
+ if (Qualifier || StartsNestedNameSpecifier) {
+ CodeCompletionString *Result = new CodeCompletionString;
+ AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
+ S.Context);
+ Result->AddTextChunk(ND->getNameAsString().c_str());
+ if (StartsNestedNameSpecifier)
+ Result->AddTextChunk("::");
+ return Result;
+ }
+
+ return 0;
+}
+
+CodeCompletionString *
+CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
+ unsigned CurrentArg,
+ Sema &S) const {
+ CodeCompletionString *Result = new CodeCompletionString;
+ FunctionDecl *FDecl = getFunction();
+ const FunctionProtoType *Proto
+ = dyn_cast<FunctionProtoType>(getFunctionType());
+ if (!FDecl && !Proto) {
+ // Function without a prototype. Just give the return type and a
+ // highlighted ellipsis.
+ const FunctionType *FT = getFunctionType();
+ Result->AddTextChunk(
+ FT->getResultType().getAsString(S.Context.PrintingPolicy).c_str());
+ Result->AddTextChunk("(");
+ Result->AddPlaceholderChunk("...");
+ Result->AddTextChunk("(");
+ return Result;
+ }
+
+ if (FDecl)
+ Result->AddTextChunk(FDecl->getNameAsString().c_str());
+ else
+ Result->AddTextChunk(
+ Proto->getResultType().getAsString(S.Context.PrintingPolicy).c_str());
+
+ Result->AddTextChunk("(");
+ unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs();
+ for (unsigned I = 0; I != NumParams; ++I) {
+ if (I)
+ Result->AddTextChunk(", ");
+
+ std::string ArgString;
+ QualType ArgType;
+
+ if (FDecl) {
+ ArgString = FDecl->getParamDecl(I)->getNameAsString();
+ ArgType = FDecl->getParamDecl(I)->getOriginalType();
+ } else {
+ ArgType = Proto->getArgType(I);
+ }
+
+ ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy);
+
+ if (I == CurrentArg)
+ Result->AddPlaceholderChunk(ArgString.c_str());
+ else
+ Result->AddTextChunk(ArgString.c_str());
+ }
+
+ if (Proto && Proto->isVariadic()) {
+ Result->AddTextChunk(", ");
+ if (CurrentArg < NumParams)
+ Result->AddTextChunk("...");
+ else
+ Result->AddPlaceholderChunk("...");
+ }
+ Result->AddTextChunk(")");
+
+ return Result;
+}
+
+namespace {
+ struct SortCodeCompleteResult {
+ typedef CodeCompleteConsumer::Result Result;
+
+ bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const {
+ if (X.getNameKind() != Y.getNameKind())
+ return X.getNameKind() < Y.getNameKind();
+
+ return llvm::LowercaseString(X.getAsString())
+ < llvm::LowercaseString(Y.getAsString());
+ }
+
+ bool operator()(const Result &X, const Result &Y) const {
+ // Sort first by rank.
+ if (X.Rank < Y.Rank)
+ return true;
+ else if (X.Rank > Y.Rank)
+ return false;
+
+ // Result kinds are ordered by decreasing importance.
+ if (X.Kind < Y.Kind)
+ return true;
+ else if (X.Kind > Y.Kind)
+ return false;
+
+ // Non-hidden names precede hidden names.
+ if (X.Hidden != Y.Hidden)
+ return !X.Hidden;
+
+ // Non-nested-name-specifiers precede nested-name-specifiers.
+ if (X.StartsNestedNameSpecifier != Y.StartsNestedNameSpecifier)
+ return !X.StartsNestedNameSpecifier;
+
+ // Ordering depends on the kind of result.
+ switch (X.Kind) {
+ case Result::RK_Declaration:
+ // Order based on the declaration names.
+ return isEarlierDeclarationName(X.Declaration->getDeclName(),
+ Y.Declaration->getDeclName());
+
+ case Result::RK_Keyword:
+ return strcmp(X.Keyword, Y.Keyword) < 0;
+ }
+
+ // Silence GCC warning.
+ return false;
+ }
+ };
+}
+
+static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter,
+ CodeCompleteConsumer::Result *Results,
+ unsigned NumResults) {
+ // Sort the results by rank/kind/etc.
+ std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult());
+
+ if (CodeCompleter)
+ CodeCompleter->ProcessCodeCompleteResults(Results, NumResults);
+}
+
+void Sema::CodeCompleteOrdinaryName(Scope *S) {
+ ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName);
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext,
+ Results);
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
+ SourceLocation OpLoc,
+ bool IsArrow) {
+ if (!BaseE || !CodeCompleter)
+ return;
+
+ typedef CodeCompleteConsumer::Result Result;
+
+ Expr *Base = static_cast<Expr *>(BaseE);
+ QualType BaseType = Base->getType();
+
+ if (IsArrow) {
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+ BaseType = Ptr->getPointeeType();
+ else if (BaseType->isObjCObjectPointerType())
+ /*Do nothing*/ ;
+ else
+ return;
+ }
+
+ ResultBuilder Results(*this, &ResultBuilder::IsMember);
+ unsigned NextRank = 0;
+
+ if (const RecordType *Record = BaseType->getAs<RecordType>()) {
+ NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank,
+ Record->getDecl(), Results);
+
+ if (getLangOptions().CPlusPlus) {
+ if (!Results.empty()) {
+ // The "template" keyword can follow "->" or "." in the grammar.
+ // However, we only want to suggest the template keyword if something
+ // is dependent.
+ bool IsDependent = BaseType->isDependentType();
+ if (!IsDependent) {
+ for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent())
+ if (DeclContext *Ctx = (DeclContext *)DepScope->getEntity()) {
+ IsDependent = Ctx->isDependentContext();
+ break;
+ }
+ }
+
+ if (IsDependent)
+ Results.MaybeAddResult(Result("template", NextRank++));
+ }
+
+ // We could have the start of a nested-name-specifier. Add those
+ // results as well.
+ Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank,
+ CurContext, Results);
+ }
+
+ // Hand off the results found for code completion.
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+
+ // We're done!
+ return;
+ }
+}
+
+void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
+ if (!CodeCompleter)
+ return;
+
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder::LookupFilter Filter = 0;
+ switch ((DeclSpec::TST)TagSpec) {
+ case DeclSpec::TST_enum:
+ Filter = &ResultBuilder::IsEnum;
+ break;
+
+ case DeclSpec::TST_union:
+ Filter = &ResultBuilder::IsUnion;
+ break;
+
+ case DeclSpec::TST_struct:
+ case DeclSpec::TST_class:
+ Filter = &ResultBuilder::IsClassOrStruct;
+ break;
+
+ default:
+ assert(false && "Unknown type specifier kind in CodeCompleteTag");
+ return;
+ }
+
+ ResultBuilder Results(*this, Filter);
+ unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
+ 0, CurContext, Results);
+
+ if (getLangOptions().CPlusPlus) {
+ // We could have the start of a nested-name-specifier. Add those
+ // results as well.
+ Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank,
+ CurContext, Results);
+ }
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteCase(Scope *S) {
+ if (getSwitchStack().empty() || !CodeCompleter)
+ return;
+
+ SwitchStmt *Switch = getSwitchStack().back();
+ if (!Switch->getCond()->getType()->isEnumeralType())
+ return;
+
+ // Code-complete the cases of a switch statement over an enumeration type
+ // by providing the list of
+ EnumDecl *Enum = Switch->getCond()->getType()->getAs<EnumType>()->getDecl();
+
+ // Determine which enumerators we have already seen in the switch statement.
+ // FIXME: Ideally, we would also be able to look *past* the code-completion
+ // token, in case we are code-completing in the middle of the switch and not
+ // at the end. However, we aren't able to do so at the moment.
+ llvm::SmallPtrSet<EnumConstantDecl *, 8> EnumeratorsSeen;
+ NestedNameSpecifier *Qualifier = 0;
+ for (SwitchCase *SC = Switch->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ CaseStmt *Case = dyn_cast<CaseStmt>(SC);
+ if (!Case)
+ continue;
+
+ Expr *CaseVal = Case->getLHS()->IgnoreParenCasts();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CaseVal))
+ if (EnumConstantDecl *Enumerator
+ = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+ // We look into the AST of the case statement to determine which
+ // enumerator was named. Alternatively, we could compute the value of
+ // the integral constant expression, then compare it against the
+ // values of each enumerator. However, value-based approach would not
+ // work as well with C++ templates where enumerators declared within a
+ // template are type- and value-dependent.
+ EnumeratorsSeen.insert(Enumerator);
+
+ // If this is a qualified-id, keep track of the nested-name-specifier
+ // so that we can reproduce it as part of code completion, e.g.,
+ //
+ // switch (TagD.getKind()) {
+ // case TagDecl::TK_enum:
+ // break;
+ // case XXX
+ //
+ // At the XXX, our completions are TagDecl::TK_union,
+ // TagDecl::TK_struct, and TagDecl::TK_class, rather than TK_union,
+ // TK_struct, and TK_class.
+ if (QualifiedDeclRefExpr *QDRE = dyn_cast<QualifiedDeclRefExpr>(DRE))
+ Qualifier = QDRE->getQualifier();
+ }
+ }
+
+ if (getLangOptions().CPlusPlus && !Qualifier && EnumeratorsSeen.empty()) {
+ // If there are no prior enumerators in C++, check whether we have to
+ // qualify the names of the enumerators that we suggest, because they
+ // may not be visible in this scope.
+ Qualifier = getRequiredQualification(Context, CurContext,
+ Enum->getDeclContext());
+
+ // FIXME: Scoped enums need to start with "EnumDecl" as the context!
+ }
+
+ // Add any enumerators that have not yet been mentioned.
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ for (EnumDecl::enumerator_iterator E = Enum->enumerator_begin(),
+ EEnd = Enum->enumerator_end();
+ E != EEnd; ++E) {
+ if (EnumeratorsSeen.count(*E))
+ continue;
+
+ Results.MaybeAddResult(CodeCompleteConsumer::Result(*E, 0, Qualifier));
+ }
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+namespace {
+ struct IsBetterOverloadCandidate {
+ Sema &S;
+
+ public:
+ explicit IsBetterOverloadCandidate(Sema &S) : S(S) { }
+
+ bool
+ operator()(const OverloadCandidate &X, const OverloadCandidate &Y) const {
+ return S.isBetterOverloadCandidate(X, Y);
+ }
+ };
+}
+
+void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
+ ExprTy **ArgsIn, unsigned NumArgs) {
+ if (!CodeCompleter)
+ return;
+
+ Expr *Fn = (Expr *)FnIn;
+ Expr **Args = (Expr **)ArgsIn;
+
+ // Ignore type-dependent call expressions entirely.
+ if (Fn->isTypeDependent() ||
+ Expr::hasAnyTypeDependentArguments(Args, NumArgs))
+ return;
+
+ NamedDecl *Function;
+ DeclarationName UnqualifiedName;
+ NestedNameSpecifier *Qualifier;
+ SourceRange QualifierRange;
+ bool ArgumentDependentLookup;
+ bool HasExplicitTemplateArgs;
+ const TemplateArgument *ExplicitTemplateArgs;
+ unsigned NumExplicitTemplateArgs;
+
+ DeconstructCallFunction(Fn,
+ Function, UnqualifiedName, Qualifier, QualifierRange,
+ ArgumentDependentLookup, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs, NumExplicitTemplateArgs);
+
+
+ // FIXME: What if we're calling something that isn't a function declaration?
+ // FIXME: What if we're calling a pseudo-destructor?
+ // FIXME: What if we're calling a member function?
+
+ // Build an overload candidate set based on the functions we find.
+ OverloadCandidateSet CandidateSet;
+ AddOverloadedCallCandidates(Function, UnqualifiedName,
+ ArgumentDependentLookup, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ Args, NumArgs,
+ CandidateSet,
+ /*PartialOverloading=*/true);
+
+ // Sort the overload candidate set by placing the best overloads first.
+ std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
+ IsBetterOverloadCandidate(*this));
+
+ // Add the remaining viable overload candidates as code-completion reslults.
+ typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate;
+ llvm::SmallVector<ResultCandidate, 8> Results;
+
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+ CandEnd = CandidateSet.end();
+ Cand != CandEnd; ++Cand) {
+ if (Cand->Viable)
+ Results.push_back(ResultCandidate(Cand->Function));
+ }
+ CodeCompleter->ProcessOverloadCandidates(NumArgs, Results.data(),
+ Results.size());
+}
+
+void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+ bool EnteringContext) {
+ if (!SS.getScopeRep() || !CodeCompleter)
+ return;
+
+ DeclContext *Ctx = computeDeclContext(SS, EnteringContext);
+ if (!Ctx)
+ return;
+
+ ResultBuilder Results(*this);
+ unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results);
+
+ // The "template" keyword can follow "::" in the grammar, but only
+ // put it into the grammar if the nested-name-specifier is dependent.
+ NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
+ if (!Results.empty() && NNS->isDependent())
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank));
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteUsing(Scope *S) {
+ if (!CodeCompleter)
+ return;
+
+ ResultBuilder Results(*this, &ResultBuilder::IsNestedNameSpecifier);
+ Results.EnterNewScope();
+
+ // If we aren't in class scope, we could see the "namespace" keyword.
+ if (!S->isClassScope())
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("namespace", 0));
+
+ // After "using", we can see anything that would start a
+ // nested-name-specifier.
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), 0,
+ CurContext, Results);
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteUsingDirective(Scope *S) {
+ if (!CodeCompleter)
+ return;
+
+ // After "using namespace", we expect to see a namespace name or namespace
+ // alias.
+ ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
+ Results.EnterNewScope();
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext,
+ Results);
+ Results.ExitScope();
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteNamespaceDecl(Scope *S) {
+ if (!CodeCompleter)
+ return;
+
+ ResultBuilder Results(*this, &ResultBuilder::IsNamespace);
+ DeclContext *Ctx = (DeclContext *)S->getEntity();
+ if (!S->getParent())
+ Ctx = Context.getTranslationUnitDecl();
+
+ if (Ctx && Ctx->isFileContext()) {
+ // We only want to see those namespaces that have already been defined
+ // within this scope, because its likely that the user is creating an
+ // extended namespace declaration. Keep track of the most recent
+ // definition of each namespace.
+ std::map<NamespaceDecl *, NamespaceDecl *> OrigToLatest;
+ for (DeclContext::specific_decl_iterator<NamespaceDecl>
+ NS(Ctx->decls_begin()), NSEnd(Ctx->decls_end());
+ NS != NSEnd; ++NS)
+ OrigToLatest[NS->getOriginalNamespace()] = *NS;
+
+ // Add the most recent definition (or extended definition) of each
+ // namespace to the list of results.
+ Results.EnterNewScope();
+ for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator
+ NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end();
+ NS != NSEnd; ++NS)
+ Results.MaybeAddResult(CodeCompleteConsumer::Result(NS->second, 0),
+ CurContext);
+ Results.ExitScope();
+ }
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
+ if (!CodeCompleter)
+ return;
+
+ // After "namespace", we expect to see a namespace or alias.
+ ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext,
+ Results);
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteOperatorName(Scope *S) {
+ if (!CodeCompleter)
+ return;
+
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this, &ResultBuilder::IsType);
+ Results.EnterNewScope();
+
+ // Add the names of overloadable operators.
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ if (std::strcmp(Spelling, "?")) \
+ Results.MaybeAddResult(Result(Spelling, 0));
+#include "clang/Basic/OperatorKinds.def"
+
+ // Add any type names visible from the current scope
+ unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
+ 0, CurContext, Results);
+
+ // Add any type specifiers
+ AddTypeSpecifierResults(getLangOptions(), 0, Results);
+
+ // Add any nested-name-specifiers
+ Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank + 1,
+ CurContext, Results);
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) {
+ if (!CodeCompleter)
+ return;
+ unsigned Attributes = ODS.getPropertyAttributes();
+
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_readonly))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("readonly", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_assign))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("assign", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_readwrite))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("readwrite", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_retain))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("retain", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_copy))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("copy", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_nonatomic))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("nonatomic", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_setter))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("setter", 0));
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_getter))
+ Results.MaybeAddResult(CodeCompleteConsumer::Result("getter", 0));
+ Results.ExitScope();
+ HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 1fd569729a373..606b33f5f74b6 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -12,28 +12,34 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "SemaInherit.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/Parse/DeclSpec.h"
-#include "clang/Basic/TargetInfo.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's)
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "llvm/ADT/SmallSet.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
+#include <cstring>
#include <functional>
+#include <queue>
using namespace clang;
/// getDeclName - Return a pretty name for the specified decl if possible, or
-/// an empty string if not. This is used for pretty crash reporting.
+/// an empty string if not. This is used for pretty crash reporting.
std::string Sema::getDeclName(DeclPtrTy d) {
Decl *D = d.getAs<Decl>();
if (NamedDecl *DN = dyn_cast_or_null<NamedDecl>(D))
@@ -57,7 +63,8 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) {
/// If name lookup results in an ambiguity, this routine will complain
/// and then return NULL.
Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec *SS) {
+ Scope *S, const CXXScopeSpec *SS,
+ bool isClassName) {
// C++ [temp.res]p3:
// A qualified-id that refers to a type and in which the
// nested-name-specifier depends on a template-parameter (14.6.2)
@@ -67,11 +74,20 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
//
// We therefore do not perform any name lookup if the result would
// refer to a member of an unknown specialization.
- if (SS && isUnknownSpecialization(*SS))
- return 0;
+ if (SS && isUnknownSpecialization(*SS)) {
+ if (!isClassName)
+ return 0;
+
+ // We know from the grammar that this name refers to a type, so build a
+ // TypenameType node to describe the type.
+ // FIXME: Record somewhere that this TypenameType node has no "typename"
+ // keyword associated with it.
+ return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
+ II, SS->getRange()).getAsOpaquePtr();
+ }
- LookupResult Result
- = LookupParsedName(S, SS, &II, LookupOrdinaryName, false, false);
+ LookupResult Result;
+ LookupParsedName(Result, S, SS, &II, LookupOrdinaryName, false, false);
NamedDecl *IIDecl = 0;
switch (Result.getKind()) {
@@ -79,15 +95,21 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::FoundOverloaded:
return 0;
- case LookupResult::AmbiguousBaseSubobjectTypes:
- case LookupResult::AmbiguousBaseSubobjects:
- case LookupResult::AmbiguousReference: {
+ case LookupResult::Ambiguous: {
+ // Recover from type-hiding ambiguities by hiding the type. We'll
+ // do the lookup again when looking for an object, and we can
+ // diagnose the error then. If we don't do this, then the error
+ // about hiding the type will be immediately followed by an error
+ // that only makes sense if the identifier was treated like a type.
+ if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding)
+ return 0;
+
// Look to see if we have a type anywhere in the list of results.
for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end();
Res != ResEnd; ++Res) {
if (isa<TypeDecl>(*Res) || isa<ObjCInterfaceDecl>(*Res)) {
- if (!IIDecl ||
- (*Res)->getLocation().getRawEncoding() <
+ if (!IIDecl ||
+ (*Res)->getLocation().getRawEncoding() <
IIDecl->getLocation().getRawEncoding())
IIDecl = *Res;
}
@@ -100,7 +122,6 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// perform this lookup again (e.g., as an object name), which
// will produce the ambiguity, or will complain that it expected
// a type name.
- Result.Destroy();
return 0;
}
@@ -113,17 +134,17 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
}
case LookupResult::Found:
- IIDecl = Result.getAsDecl();
+ IIDecl = Result.getFoundDecl();
break;
}
if (IIDecl) {
QualType T;
-
+
if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
// Check whether we can use this type
(void)DiagnoseUseOfDecl(IIDecl, NameLoc);
-
+
if (getLangOptions().CPlusPlus) {
// C++ [temp.local]p2:
// Within the scope of a class template specialization or
@@ -143,7 +164,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
} else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
// Check whether we can use this interface.
(void)DiagnoseUseOfDecl(IIDecl, NameLoc);
-
+
T = Context.getObjCInterfaceType(IDecl);
} else
return 0;
@@ -164,9 +185,10 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
/// where the user forgot to specify the tag.
DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
// Do a tag name lookup in this scope.
- LookupResult R = LookupName(S, &II, LookupTagName, false, false);
+ LookupResult R;
+ LookupName(R, S, &II, LookupTagName, false, false);
if (R.getKind() == LookupResult::Found)
- if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsDecl())) {
+ if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsSingleDecl(Context))) {
switch (TD->getTagKind()) {
case TagDecl::TK_struct: return DeclSpec::TST_struct;
case TagDecl::TK_union: return DeclSpec::TST_union;
@@ -174,24 +196,60 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
case TagDecl::TK_enum: return DeclSpec::TST_enum;
}
}
-
+
return DeclSpec::TST_unspecified;
}
+bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TypeTy *&SuggestedType) {
+ // We don't have anything to suggest (yet).
+ SuggestedType = 0;
+
+ // FIXME: Should we move the logic that tries to recover from a missing tag
+ // (struct, union, enum) from Parser::ParseImplicitInt here, instead?
+
+ if (!SS)
+ Diag(IILoc, diag::err_unknown_typename) << &II;
+ else if (DeclContext *DC = computeDeclContext(*SS, false))
+ Diag(IILoc, diag::err_typename_nested_not_found)
+ << &II << DC << SS->getRange();
+ else if (isDependentScopeSpecifier(*SS)) {
+ Diag(SS->getRange().getBegin(), diag::err_typename_missing)
+ << (NestedNameSpecifier *)SS->getScopeRep() << II.getName()
+ << SourceRange(SS->getRange().getBegin(), IILoc)
+ << CodeModificationHint::CreateInsertion(SS->getRange().getBegin(),
+ "typename ");
+ SuggestedType = ActOnTypenameType(SourceLocation(), *SS, II, IILoc).get();
+ } else {
+ assert(SS && SS->isInvalid() &&
+ "Invalid scope specifier has already been diagnosed");
+ }
+
+ return true;
+}
-
+// Determines the context to return to after temporarily entering a
+// context. This depends in an unnecessarily complicated way on the
+// exact ordering of callbacks from the parser.
DeclContext *Sema::getContainingDC(DeclContext *DC) {
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
- // A C++ out-of-line method will return to the file declaration context.
- if (MD->isOutOfLine())
- return MD->getLexicalDeclContext();
-
- // A C++ inline method is parsed *after* the topmost class it was declared
- // in is fully parsed (it's "complete").
- // The parsing of a C++ inline method happens at the declaration context of
- // the topmost (non-nested) class it is lexically declared in.
- assert(isa<CXXRecordDecl>(MD->getParent()) && "C++ method not in Record.");
- DC = MD->getParent();
+
+ // Functions defined inline within classes aren't parsed until we've
+ // finished parsing the top-level class, so the top-level class is
+ // the context we'll need to return to.
+ if (isa<FunctionDecl>(DC)) {
+ DC = DC->getLexicalParent();
+
+ // A function not defined within a class will always return to its
+ // lexical context.
+ if (!isa<CXXRecordDecl>(DC))
+ return DC;
+
+ // A C++ inline method/friend is parsed *after* the topmost class
+ // it was declared in is fully parsed ("complete"); the topmost
+ // class is the context we need to return to.
while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getLexicalParent()))
DC = RD;
@@ -260,103 +318,84 @@ static bool AllowOverloadingOfFunction(Decl *PrevDecl, ASTContext &Context) {
}
/// Add this decl to the scope shadowed decl chains.
-void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
+void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
// Move up the scope chain until we find the nearest enclosing
// non-transparent context. The declaration will be introduced into this
// scope.
- while (S->getEntity() &&
+ while (S->getEntity() &&
((DeclContext *)S->getEntity())->isTransparentContext())
S = S->getParent();
- S->AddDecl(DeclPtrTy::make(D));
-
// Add scoped declarations into their context, so that they can be
// found later. Declarations without a context won't be inserted
// into any context.
- CurContext->addDecl(D);
-
- // C++ [basic.scope]p4:
- // -- exactly one declaration shall declare a class name or
- // enumeration name that is not a typedef name and the other
- // declarations shall all refer to the same object or
- // enumerator, or all refer to functions and function templates;
- // in this case the class name or enumeration name is hidden.
- if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
- // We are pushing the name of a tag (enum or class).
- if (CurContext->getLookupContext()
- == TD->getDeclContext()->getLookupContext()) {
- // We're pushing the tag into the current context, which might
- // require some reshuffling in the identifier resolver.
- IdentifierResolver::iterator
- I = IdResolver.begin(TD->getDeclName()),
- IEnd = IdResolver.end();
- if (I != IEnd && isDeclInScope(*I, CurContext, S)) {
- NamedDecl *PrevDecl = *I;
- for (; I != IEnd && isDeclInScope(*I, CurContext, S);
- PrevDecl = *I, ++I) {
- if (TD->declarationReplaces(*I)) {
- // This is a redeclaration. Remove it from the chain and
- // break out, so that we'll add in the shadowed
- // declaration.
- S->RemoveDecl(DeclPtrTy::make(*I));
- if (PrevDecl == *I) {
- IdResolver.RemoveDecl(*I);
- IdResolver.AddDecl(TD);
- return;
- } else {
- IdResolver.RemoveDecl(*I);
- break;
- }
- }
- }
+ if (AddToContext)
+ CurContext->addDecl(D);
- // There is already a declaration with the same name in the same
- // scope, which is not a tag declaration. It must be found
- // before we find the new declaration, so insert the new
- // declaration at the end of the chain.
- IdResolver.AddShadowedDecl(TD, PrevDecl);
-
- return;
- }
- }
- } else if ((isa<FunctionDecl>(D) &&
- AllowOverloadingOfFunction(D, Context)) ||
- isa<FunctionTemplateDecl>(D)) {
- // We are pushing the name of a function or function template,
- // which might be an overloaded name.
- IdentifierResolver::iterator Redecl
- = std::find_if(IdResolver.begin(D->getDeclName()),
- IdResolver.end(),
- std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
- D));
- if (Redecl != IdResolver.end() &&
- S->isDeclScope(DeclPtrTy::make(*Redecl))) {
- // There is already a declaration of a function on our
- // IdResolver chain. Replace it with this declaration.
- S->RemoveDecl(DeclPtrTy::make(*Redecl));
- IdResolver.RemoveDecl(*Redecl);
- }
- } else if (isa<ObjCInterfaceDecl>(D)) {
- // We're pushing an Objective-C interface into the current
- // context. If there is already an alias declaration, remove it first.
- for (IdentifierResolver::iterator
- I = IdResolver.begin(D->getDeclName()), IEnd = IdResolver.end();
- I != IEnd; ++I) {
- if (isa<ObjCCompatibleAliasDecl>(*I)) {
- S->RemoveDecl(DeclPtrTy::make(*I));
- IdResolver.RemoveDecl(*I);
- break;
- }
+ // Out-of-line function and variable definitions should not be pushed into
+ // scope.
+ if ((isa<FunctionTemplateDecl>(D) &&
+ cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->isOutOfLine()) ||
+ (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isOutOfLine()) ||
+ (isa<VarDecl>(D) && cast<VarDecl>(D)->isOutOfLine()))
+ return;
+
+ // If this replaces anything in the current scope,
+ IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()),
+ IEnd = IdResolver.end();
+ for (; I != IEnd; ++I) {
+ if (S->isDeclScope(DeclPtrTy::make(*I)) && D->declarationReplaces(*I)) {
+ S->RemoveDecl(DeclPtrTy::make(*I));
+ IdResolver.RemoveDecl(*I);
+
+ // Should only need to replace one decl.
+ break;
}
}
+ S->AddDecl(DeclPtrTy::make(D));
IdResolver.AddDecl(D);
}
+bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) {
+ if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
+ // Look inside the overload set to determine if any of the declarations
+ // are in scope. (Possibly) build a new overload set containing only
+ // those declarations that are in scope.
+ OverloadedFunctionDecl *NewOvl = 0;
+ bool FoundInScope = false;
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ NamedDecl *FD = F->get();
+ if (!isDeclInScope(FD, Ctx, S)) {
+ if (!NewOvl && F != Ovl->function_begin()) {
+ NewOvl = OverloadedFunctionDecl::Create(Context,
+ F->get()->getDeclContext(),
+ F->get()->getDeclName());
+ D = NewOvl;
+ for (OverloadedFunctionDecl::function_iterator
+ First = Ovl->function_begin();
+ First != F; ++First)
+ NewOvl->addOverload(*First);
+ }
+ } else {
+ FoundInScope = true;
+ if (NewOvl)
+ NewOvl->addOverload(*F);
+ }
+ }
+
+ return FoundInScope;
+ }
+
+ return IdResolver.isDeclInScope(D, Ctx, Context, S);
+}
+
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
- "Scope shouldn't contain decls!");
+ "Scope shouldn't contain decls!");
for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
I != E; ++I) {
@@ -368,6 +407,12 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (!D->getDeclName()) continue;
+ // Diagnose unused variables in this scope.
+ if (!D->isUsed() && !D->hasAttr<UnusedAttr>() && isa<VarDecl>(D) &&
+ !isa<ParmVarDecl>(D) && !isa<ImplicitParamDecl>(D) &&
+ D->getDeclContext()->isFunctionOrMethod())
+ Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName();
+
// Remove this name from our lexical scope.
IdResolver.RemoveDecl(D);
}
@@ -378,8 +423,8 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
// The third "scope" argument is 0 since we aren't enabling lazy built-in
// creation from this context.
- NamedDecl *IDecl = LookupName(TUScope, Id, LookupOrdinaryName);
-
+ NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName);
+
return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
}
@@ -392,7 +437,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
/// struct S6 {
/// enum { BAR } e;
/// };
-///
+///
/// void test_S6() {
/// struct S6 a;
/// a.e = BAR;
@@ -408,7 +453,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
/// contain non-field names.
Scope *Sema::getNonFieldDeclScope(Scope *S) {
while (((S->getFlags() & Scope::DeclScope) == 0) ||
- (S->getEntity() &&
+ (S->getEntity() &&
((DeclContext *)S->getEntity())->isTransparentContext()) ||
(S->isClassScope() && !getLangOptions().CPlusPlus))
S = S->getParent();
@@ -418,9 +463,9 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) {
void Sema::InitBuiltinVaListType() {
if (!Context.getBuiltinVaListType().isNull())
return;
-
+
IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list");
- NamedDecl *VaDecl = LookupName(TUScope, VaIdent, LookupOrdinaryName);
+ NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, LookupOrdinaryName);
TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl);
Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef));
}
@@ -438,17 +483,23 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
InitBuiltinVaListType();
ASTContext::GetBuiltinTypeError Error;
- QualType R = Context.GetBuiltinType(BID, Error);
+ QualType R = Context.GetBuiltinType(BID, Error);
switch (Error) {
case ASTContext::GE_None:
// Okay
break;
- case ASTContext::GE_Missing_FILE:
+ case ASTContext::GE_Missing_stdio:
if (ForRedeclaration)
Diag(Loc, diag::err_implicit_decl_requires_stdio)
<< Context.BuiltinInfo.GetName(BID);
return 0;
+
+ case ASTContext::GE_Missing_setjmp:
+ if (ForRedeclaration)
+ Diag(Loc, diag::err_implicit_decl_requires_setjmp)
+ << Context.BuiltinInfo.GetName(BID);
+ return 0;
}
if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
@@ -465,7 +516,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
FunctionDecl *New = FunctionDecl::Create(Context,
Context.getTranslationUnitDecl(),
- Loc, II, R,
+ Loc, II, R, /*DInfo=*/0,
FunctionDecl::Extern, false,
/*hasPrototype=*/true);
New->setImplicit();
@@ -476,12 +527,13 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
llvm::SmallVector<ParmVarDecl*, 16> Params;
for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i)
Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0,
- FT->getArgType(i), VarDecl::None, 0));
+ FT->getArgType(i), /*DInfo=*/0,
+ VarDecl::None, 0));
New->setParams(Context, Params.data(), Params.size());
}
-
- AddKnownFunctionAttributes(New);
-
+
+ AddKnownFunctionAttributes(New);
+
// TUScope is the translation-unit scope to insert this function into.
// FIXME: This is hideous. We need to teach PushOnScopeChains to
// relate Scopes to DeclContexts, and probably eliminate CurContext
@@ -493,18 +545,6 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
return New;
}
-/// GetStdNamespace - This method gets the C++ "std" namespace. This is where
-/// everything from the standard library is defined.
-NamespaceDecl *Sema::GetStdNamespace() {
- if (!StdNamespace) {
- IdentifierInfo *StdIdent = &PP.getIdentifierTable().get("std");
- DeclContext *Global = Context.getTranslationUnitDecl();
- Decl *Std = LookupQualifiedName(Global, StdIdent, LookupNamespaceName);
- StdNamespace = dyn_cast_or_null<NamespaceDecl>(Std);
- }
- return StdNamespace;
-}
-
/// MergeTypeDefDecl - We just parsed a typedef 'New' which has the
/// same name and scope as a previous declaration 'Old'. Figure out
/// how to resolve this situation, merging decls or emitting
@@ -515,25 +555,26 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
// don't bother doing any merging checks.
if (New->isInvalidDecl() || OldD->isInvalidDecl())
return New->setInvalidDecl();
-
- bool objc_types = false;
-
+
// Allow multiple definitions for ObjC built-in typedefs.
// FIXME: Verify the underlying types are equivalent!
if (getLangOptions().ObjC1) {
const IdentifierInfo *TypeID = New->getIdentifier();
switch (TypeID->getLength()) {
default: break;
- case 2:
+ case 2:
if (!TypeID->isStr("id"))
break;
- Context.setObjCIdType(Context.getTypeDeclType(New));
- objc_types = true;
- break;
+ Context.ObjCIdRedefinitionType = New->getUnderlyingType();
+ // Install the built-in type for 'id', ignoring the current definition.
+ New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
+ return;
case 5:
if (!TypeID->isStr("Class"))
break;
- Context.setObjCClassType(Context.getTypeDeclType(New));
+ Context.ObjCClassRedefinitionType = New->getUnderlyingType();
+ // Install the built-in type for 'Class', ignoring the current definition.
+ New->setTypeForDecl(Context.getObjCClassType().getTypePtr());
return;
case 3:
if (!TypeID->isStr("SEL"))
@@ -551,14 +592,14 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
// Verify the old decl was also a type.
TypeDecl *Old = dyn_cast<TypeDecl>(OldD);
if (!Old) {
- Diag(New->getLocation(), diag::err_redefinition_different_kind)
+ Diag(New->getLocation(), diag::err_redefinition_different_kind)
<< New->getDeclName();
if (OldD->getLocation().isValid())
Diag(OldD->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
- // Determine the "old" type we'll use for checking and diagnostics.
+ // Determine the "old" type we'll use for checking and diagnostics.
QualType OldType;
if (TypedefDecl *OldTypedef = dyn_cast<TypedefDecl>(Old))
OldType = OldTypedef->getUnderlyingType();
@@ -568,8 +609,8 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
// If the typedef types are not identical, reject them in all languages and
// with any extensions enabled.
- if (OldType != New->getUnderlyingType() &&
- Context.getCanonicalType(OldType) !=
+ if (OldType != New->getUnderlyingType() &&
+ Context.getCanonicalType(OldType) !=
Context.getCanonicalType(New->getUnderlyingType())) {
Diag(New->getLocation(), diag::err_redefinition_different_typedef)
<< New->getUnderlyingType() << OldType;
@@ -577,8 +618,8 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
-
- if (objc_types || getLangOptions().Microsoft)
+
+ if (getLangOptions().Microsoft)
return;
// C++ [dcl.typedef]p2:
@@ -602,7 +643,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
(Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
Context.getSourceManager().isInSystemHeader(New->getLocation())))
return;
-
+
Diag(New->getLocation(), diag::warn_redefinition_of_typedef)
<< New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
@@ -611,7 +652,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
/// DeclhasAttr - returns true if decl Declaration already has the target
/// attribute.
-static bool
+static bool
DeclHasAttr(const Decl *decl, const Attr *target) {
for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext())
if (attr->getKind() == target->getKind())
@@ -651,15 +692,15 @@ struct GNUCompatibleParamWarning {
///
/// Returns true if there was an error, false otherwise.
bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
- assert(!isa<OverloadedFunctionDecl>(OldD) &&
+ assert(!isa<OverloadedFunctionDecl>(OldD) &&
"Cannot merge with an overloaded function declaration");
// Verify the old decl was also a function.
FunctionDecl *Old = 0;
- if (FunctionTemplateDecl *OldFunctionTemplate
+ if (FunctionTemplateDecl *OldFunctionTemplate
= dyn_cast<FunctionTemplateDecl>(OldD))
Old = OldFunctionTemplate->getTemplatedDecl();
- else
+ else
Old = dyn_cast<FunctionDecl>(OldD);
if (!Old) {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
@@ -675,12 +716,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
PrevDiag = diag::note_previous_definition;
else if (Old->isImplicit())
PrevDiag = diag::note_previous_implicit_declaration;
- else
+ else
PrevDiag = diag::note_previous_declaration;
-
+
QualType OldQType = Context.getCanonicalType(Old->getType());
QualType NewQType = Context.getCanonicalType(New->getType());
-
+
if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) &&
New->getStorageClass() == FunctionDecl::Static &&
Old->getStorageClass() != FunctionDecl::Static) {
@@ -693,11 +734,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
if (getLangOptions().CPlusPlus) {
// (C++98 13.1p2):
// Certain function declarations cannot be overloaded:
- // -- Function declarations that differ only in the return type
+ // -- Function declarations that differ only in the return type
// cannot be overloaded.
- QualType OldReturnType
+ QualType OldReturnType
= cast<FunctionType>(OldQType.getTypePtr())->getResultType();
- QualType NewReturnType
+ QualType NewReturnType
= cast<FunctionType>(NewQType.getTypePtr())->getResultType();
if (OldReturnType != NewReturnType) {
Diag(New->getLocation(), diag::err_ovl_diff_return_type);
@@ -707,11 +748,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
- if (OldMethod && NewMethod &&
- OldMethod->getLexicalDeclContext() ==
- NewMethod->getLexicalDeclContext()) {
- // -- Member function declarations with the same name and the
- // same parameter types cannot be overloaded if any of them
+ if (OldMethod && NewMethod && !NewMethod->getFriendObjectKind() &&
+ NewMethod->getLexicalDeclContext()->isRecord()) {
+ // -- Member function declarations with the same name and the
+ // same parameter types cannot be overloaded if any of them
// is a static member function declaration.
if (OldMethod->isStatic() || NewMethod->isStatic()) {
Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member);
@@ -732,7 +772,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
NewDiag = diag::err_conv_function_redeclared;
else
NewDiag = diag::err_member_redeclared;
-
+
Diag(New->getLocation(), NewDiag);
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
}
@@ -750,8 +790,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// duplicate function decls like "void f(int); void f(enum X);" properly.
if (!getLangOptions().CPlusPlus &&
Context.typesAreCompatible(OldQType, NewQType)) {
- const FunctionType *OldFuncType = OldQType->getAsFunctionType();
- const FunctionType *NewFuncType = NewQType->getAsFunctionType();
+ const FunctionType *OldFuncType = OldQType->getAs<FunctionType>();
+ const FunctionType *NewFuncType = NewQType->getAs<FunctionType>();
const FunctionProtoType *OldProto = 0;
if (isa<FunctionNoProtoType>(NewFuncType) &&
(OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
@@ -769,20 +809,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// Synthesize a parameter for each argument type.
llvm::SmallVector<ParmVarDecl*, 16> Params;
- for (FunctionProtoType::arg_type_iterator
- ParamType = OldProto->arg_type_begin(),
+ for (FunctionProtoType::arg_type_iterator
+ ParamType = OldProto->arg_type_begin(),
ParamEnd = OldProto->arg_type_end();
ParamType != ParamEnd; ++ParamType) {
ParmVarDecl *Param = ParmVarDecl::Create(Context, New,
SourceLocation(), 0,
- *ParamType, VarDecl::None,
- 0);
+ *ParamType, /*DInfo=*/0,
+ VarDecl::None, 0);
Param->setImplicit();
Params.push_back(Param);
}
New->setParams(Context, Params.data(), Params.size());
- }
+ }
return MergeCompatibleFunctionDecls(New, Old);
}
@@ -800,29 +840,29 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// C99 6.9.1p8.
if (!getLangOptions().CPlusPlus &&
Old->hasPrototype() && !New->hasPrototype() &&
- New->getType()->getAsFunctionProtoType() &&
+ New->getType()->getAs<FunctionProtoType>() &&
Old->getNumParams() == New->getNumParams()) {
llvm::SmallVector<QualType, 16> ArgTypes;
llvm::SmallVector<GNUCompatibleParamWarning, 16> Warnings;
- const FunctionProtoType *OldProto
- = Old->getType()->getAsFunctionProtoType();
- const FunctionProtoType *NewProto
- = New->getType()->getAsFunctionProtoType();
-
+ const FunctionProtoType *OldProto
+ = Old->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *NewProto
+ = New->getType()->getAs<FunctionProtoType>();
+
// Determine whether this is the GNU C extension.
QualType MergedReturn = Context.mergeTypes(OldProto->getResultType(),
NewProto->getResultType());
bool LooseCompatible = !MergedReturn.isNull();
- for (unsigned Idx = 0, End = Old->getNumParams();
+ for (unsigned Idx = 0, End = Old->getNumParams();
LooseCompatible && Idx != End; ++Idx) {
ParmVarDecl *OldParm = Old->getParamDecl(Idx);
ParmVarDecl *NewParm = New->getParamDecl(Idx);
- if (Context.typesAreCompatible(OldParm->getType(),
+ if (Context.typesAreCompatible(OldParm->getType(),
NewProto->getArgType(Idx))) {
ArgTypes.push_back(NewParm->getType());
} else if (Context.typesAreCompatible(OldParm->getType(),
NewParm->getType())) {
- GNUCompatibleParamWarning Warn
+ GNUCompatibleParamWarning Warn
= { OldParm, NewParm, NewProto->getArgType(Idx) };
Warnings.push_back(Warn);
ArgTypes.push_back(NewParm->getType());
@@ -836,7 +876,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
diag::ext_param_promoted_not_compatible_with_prototype)
<< Warnings[Warn].PromotedType
<< Warnings[Warn].OldParm->getType();
- Diag(Warnings[Warn].OldParm->getLocation(),
+ Diag(Warnings[Warn].OldParm->getLocation(),
diag::note_previous_declaration);
}
@@ -851,7 +891,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// A function that has already been declared has been redeclared or defined
// with a different type- show appropriate diagnostic
- if (unsigned BuiltinID = Old->getBuiltinID(Context)) {
+ if (unsigned BuiltinID = Old->getBuiltinID()) {
// The user has declared a builtin function with an incompatible
// signature.
if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) {
@@ -876,7 +916,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
}
/// \brief Completes the merge of two function declarations that are
-/// known to be compatible.
+/// known to be compatible.
///
/// This routine handles the merging of attributes and other
/// properties of function declarations form the old declaration to
@@ -889,25 +929,10 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
MergeAttributes(New, Old, Context);
// Merge the storage class.
- if (Old->getStorageClass() != FunctionDecl::Extern)
+ if (Old->getStorageClass() != FunctionDecl::Extern &&
+ Old->getStorageClass() != FunctionDecl::None)
New->setStorageClass(Old->getStorageClass());
- // Merge "inline"
- if (Old->isInline())
- New->setInline(true);
-
- // If this function declaration by itself qualifies as a C99 inline
- // definition (C99 6.7.4p6), but the previous definition did not,
- // then the function is not a C99 inline definition.
- if (New->isC99InlineDefinition() && !Old->isC99InlineDefinition())
- New->setC99InlineDefinition(false);
- else if (Old->isC99InlineDefinition() && !New->isC99InlineDefinition()) {
- // Mark all preceding definitions as not being C99 inline definitions.
- for (const FunctionDecl *Prev = Old; Prev;
- Prev = Prev->getPreviousDeclaration())
- const_cast<FunctionDecl *>(Prev)->setC99InlineDefinition(false);
- }
-
// Merge "pure" flag.
if (Old->isPure())
New->setPure();
@@ -915,7 +940,7 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
// Merge the "deleted" flag.
if (Old->isDeleted())
New->setDeleted();
-
+
if (getLangOptions().CPlusPlus)
return MergeCXXFunctionDecl(New, Old);
@@ -926,16 +951,16 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
/// and scope as a previous declaration 'Old'. Figure out how to resolve this
/// situation, merging decls or emitting diagnostics as appropriate.
///
-/// Tentative definition rules (C99 6.9.2p2) are checked by
-/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
+/// Tentative definition rules (C99 6.9.2p2) are checked by
+/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
/// definitions here, since the initializer hasn't been attached.
-///
+///
void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
// If either decl is invalid, make sure the new one is marked invalid and
// don't do any other checking.
if (New->isInvalidDecl() || OldD->isInvalidDecl())
return New->setInvalidDecl();
-
+
// Verify the old decl was also a variable.
VarDecl *Old = dyn_cast<VarDecl>(OldD);
if (!Old) {
@@ -952,11 +977,24 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
if (getLangOptions().CPlusPlus) {
if (Context.hasSameType(New->getType(), Old->getType()))
MergedT = New->getType();
+ // C++ [basic.types]p7:
+ // [...] The declared type of an array object might be an array of
+ // unknown size and therefore be incomplete at one point in a
+ // translation unit and complete later on; [...]
+ else if (Old->getType()->isIncompleteArrayType() &&
+ New->getType()->isArrayType()) {
+ CanQual<ArrayType> OldArray
+ = Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
+ CanQual<ArrayType> NewArray
+ = Context.getCanonicalType(New->getType())->getAs<ArrayType>();
+ if (OldArray->getElementType() == NewArray->getElementType())
+ MergedT = New->getType();
+ }
} else {
MergedT = Context.mergeTypes(New->getType(), Old->getType());
}
if (MergedT.isNull()) {
- Diag(New->getLocation(), diag::err_redefinition_different_type)
+ Diag(New->getLocation(), diag::err_redefinition_different_type)
<< New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -970,7 +1008,7 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
- // C99 6.2.2p4:
+ // C99 6.2.2p4:
// For an identifier declared with the storage-class specifier
// extern in a scope in which a prior declaration of that
// identifier is visible,23) if the prior declaration specifies
@@ -989,7 +1027,7 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
}
// Variables with external linkage are analyzed in FinalizeDeclaratorGroup.
-
+
// FIXME: The test for external storage here seems wrong? We still
// need to check for mismatches.
if (!New->hasExternalStorage() && !New->isFileVarDecl() &&
@@ -1013,6 +1051,214 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
New->setPreviousDeclaration(Old);
}
+/// CheckFallThrough - Check that we don't fall off the end of a
+/// Statement that should return a value.
+///
+/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
+/// MaybeFallThrough iff we might or might not fall off the end and
+/// NeverFallThrough iff we never fall off the end of the statement. We assume
+/// that functions not marked noreturn will return.
+Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
+ llvm::OwningPtr<CFG> cfg (CFG::buildCFG(Root, &Context));
+
+ // FIXME: They should never return 0, fix that, delete this code.
+ if (cfg == 0)
+ return NeverFallThrough;
+ // The CFG leaves in dead things, and we don't want to dead code paths to
+ // confuse us, so we mark all live things first.
+ std::queue<CFGBlock*> workq;
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ // Prep work queue
+ workq.push(&cfg->getEntry());
+ // Solve
+ while (!workq.empty()) {
+ CFGBlock *item = workq.front();
+ workq.pop();
+ live.set(item->getBlockID());
+ for (CFGBlock::succ_iterator I=item->succ_begin(),
+ E=item->succ_end();
+ I != E;
+ ++I) {
+ if ((*I) && !live[(*I)->getBlockID()]) {
+ live.set((*I)->getBlockID());
+ workq.push(*I);
+ }
+ }
+ }
+
+ // Now we know what is live, we check the live precessors of the exit block
+ // and look for fall through paths, being careful to ignore normal returns,
+ // and exceptional paths.
+ bool HasLiveReturn = false;
+ bool HasFakeEdge = false;
+ bool HasPlainEdge = false;
+ for (CFGBlock::succ_iterator I=cfg->getExit().pred_begin(),
+ E = cfg->getExit().pred_end();
+ I != E;
+ ++I) {
+ CFGBlock& B = **I;
+ if (!live[B.getBlockID()])
+ continue;
+ if (B.size() == 0) {
+ // A labeled empty statement, or the entry block...
+ HasPlainEdge = true;
+ continue;
+ }
+ Stmt *S = B[B.size()-1];
+ if (isa<ReturnStmt>(S)) {
+ HasLiveReturn = true;
+ continue;
+ }
+ if (isa<ObjCAtThrowStmt>(S)) {
+ HasFakeEdge = true;
+ continue;
+ }
+ if (isa<CXXThrowExpr>(S)) {
+ HasFakeEdge = true;
+ continue;
+ }
+ bool NoReturnEdge = false;
+ if (CallExpr *C = dyn_cast<CallExpr>(S)) {
+ Expr *CEE = C->getCallee()->IgnoreParenCasts();
+ if (CEE->getType().getNoReturnAttr()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
+ if (FD->hasAttr<NoReturnAttr>()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ }
+ }
+ }
+ }
+ // FIXME: Add noreturn message sends.
+ if (NoReturnEdge == false)
+ HasPlainEdge = true;
+ }
+ if (!HasPlainEdge)
+ return NeverFallThrough;
+ if (HasFakeEdge || HasLiveReturn)
+ return MaybeFallThrough;
+ // This says AlwaysFallThrough for calls to functions that are not marked
+ // noreturn, that don't return. If people would like this warning to be more
+ // accurate, such functions should be marked as noreturn.
+ return AlwaysFallThrough;
+}
+
+/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
+/// function that should return a value. Check that we don't fall off the end
+/// of a noreturn function. We assume that functions and blocks not marked
+/// noreturn will return.
+void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
+ // FIXME: Would be nice if we had a better way to control cascading errors,
+ // but for now, avoid them. The problem is that when Parse sees:
+ // int foo() { return a; }
+ // The return is eaten and the Sema code sees just:
+ // int foo() { }
+ // which this code would then warn about.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+ bool ReturnsVoid = false;
+ bool HasNoReturn = false;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // If the result type of the function is a dependent type, we don't know
+ // whether it will be void or not, so don't
+ if (FD->getResultType()->isDependentType())
+ return;
+ if (FD->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (FD->hasAttr<NoReturnAttr>())
+ HasNoReturn = true;
+ } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (MD->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (MD->hasAttr<NoReturnAttr>())
+ HasNoReturn = true;
+ }
+
+ // Short circuit for compilation speed.
+ if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
+ == Diagnostic::Ignored || ReturnsVoid)
+ && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
+ == Diagnostic::Ignored || !HasNoReturn)
+ && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+ == Diagnostic::Ignored || !ReturnsVoid))
+ return;
+ // FIXME: Function try block
+ if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
+ switch (CheckFallThrough(Body)) {
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function);
+ break;
+ case NeverFallThrough:
+ if (ReturnsVoid)
+ Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function);
+ break;
+ }
+ }
+}
+
+/// CheckFallThroughForBlock - Check that we don't fall off the end of a block
+/// that should return a value. Check that we don't fall off the end of a
+/// noreturn block. We assume that functions and blocks not marked noreturn
+/// will return.
+void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) {
+ // FIXME: Would be nice if we had a better way to control cascading errors,
+ // but for now, avoid them. The problem is that when Parse sees:
+ // int foo() { return a; }
+ // The return is eaten and the Sema code sees just:
+ // int foo() { }
+ // which this code would then warn about.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+ bool ReturnsVoid = false;
+ bool HasNoReturn = false;
+ if (const FunctionType *FT = BlockTy->getPointeeType()->getAs<FunctionType>()) {
+ if (FT->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (FT->getNoReturnAttr())
+ HasNoReturn = true;
+ }
+
+ // Short circuit for compilation speed.
+ if (ReturnsVoid
+ && !HasNoReturn
+ && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+ == Diagnostic::Ignored || !ReturnsVoid))
+ return;
+ // FIXME: Funtion try block
+ if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
+ switch (CheckFallThrough(Body)) {
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
+ break;
+ case NeverFallThrough:
+ if (ReturnsVoid)
+ Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block);
+ break;
+ }
+ }
+}
+
/// CheckParmsForFunctionDef - Check that the parameters of the given
/// function are appropriate for the definition of a function. This
/// takes care of any checks that cannot be performed on the
@@ -1034,10 +1280,10 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
Param->setInvalidDecl();
HasInvalidParm = true;
}
-
+
// C99 6.9.1p5: If the declarator includes a parameter type list, the
// declaration of each parameter shall include an identifier.
- if (Param->getIdentifier() == 0 &&
+ if (Param->getIdentifier() == 0 &&
!Param->isImplicit() &&
!getLangOptions().CPlusPlus)
Diag(Param->getLocation(), diag::err_parameter_name_omitted);
@@ -1056,17 +1302,31 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
// FIXME: Warn on useless const/volatile
// FIXME: Warn on useless static/extern/typedef/private_extern/mutable
// FIXME: Warn on useless attributes
+ Decl *TagD = 0;
TagDecl *Tag = 0;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
DS.getTypeSpecType() == DeclSpec::TST_struct ||
DS.getTypeSpecType() == DeclSpec::TST_union ||
DS.getTypeSpecType() == DeclSpec::TST_enum) {
- if (!DS.getTypeRep()) // We probably had an error
+ TagD = static_cast<Decl *>(DS.getTypeRep());
+
+ if (!TagD) // We probably had an error
return DeclPtrTy();
- Tag = dyn_cast<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
+ // Note that the above type specs guarantee that the
+ // type rep is a Decl, whereas in many of the others
+ // it's a Type.
+ Tag = dyn_cast<TagDecl>(TagD);
}
+ if (DS.isFriendSpecified()) {
+ // If we're dealing with a class template decl, assume that the
+ // template routines are handling it.
+ if (TagD && isa<ClassTemplateDecl>(TagD))
+ return DeclPtrTy();
+ return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
+ }
+
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
if (!Record->getDeclName() && Record->isDefinition() &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
@@ -1084,8 +1344,8 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
if (Record->getDeclName() && getLangOptions().Microsoft)
return DeclPtrTy::make(Tag);
}
-
- if (!DS.isMissingDeclaratorOk() &&
+
+ if (!DS.isMissingDeclaratorOk() &&
DS.getTypeSpecType() != DeclSpec::TST_error) {
// Warn about typedefs of enums without names, since this is an
// extension in both Microsoft an GNU.
@@ -1100,7 +1360,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
<< DS.getSourceRange();
return DeclPtrTy();
}
-
+
return DeclPtrTy::make(Tag);
}
@@ -1127,14 +1387,16 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
FEnd = AnonRecord->field_end();
F != FEnd; ++F) {
if ((*F)->getDeclName()) {
- NamedDecl *PrevDecl = LookupQualifiedName(Owner, (*F)->getDeclName(),
- LookupOrdinaryName, true);
+ LookupResult R;
+ LookupQualifiedName(R, Owner, (*F)->getDeclName(),
+ LookupOrdinaryName, true);
+ NamedDecl *PrevDecl = R.getAsSingleDecl(Context);
if (PrevDecl && !isa<TagDecl>(PrevDecl)) {
// C++ [class.union]p2:
// The names of the members of an anonymous union shall be
// distinct from the names of any other entity in the
// scope in which the anonymous union is declared.
- unsigned diagKind
+ unsigned diagKind
= AnonRecord->isUnion()? diag::err_anonymous_union_member_redecl
: diag::err_anonymous_struct_member_redecl;
Diag((*F)->getLocation(), diagKind)
@@ -1152,10 +1414,10 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
IdResolver.AddDecl(*F);
}
} else if (const RecordType *InnerRecordType
- = (*F)->getType()->getAsRecordType()) {
+ = (*F)->getType()->getAs<RecordType>()) {
RecordDecl *InnerRecord = InnerRecordType->getDecl();
if (InnerRecord->isAnonymousStructOrUnion())
- Invalid = Invalid ||
+ Invalid = Invalid ||
InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord);
}
}
@@ -1166,7 +1428,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
/// ActOnAnonymousStructOrUnion - Handle the declaration of an
/// anonymous structure or union. Anonymous unions are a C++ feature
/// (C++ [class.union]) and a GNU C extension; anonymous structures
-/// are a GNU C and GNU C++ extension.
+/// are a GNU C and GNU C++ extension.
Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
RecordDecl *Record) {
DeclContext *Owner = Record->getDeclContext();
@@ -1176,40 +1438,42 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Diag(Record->getLocation(), diag::ext_anonymous_union);
else if (!Record->isUnion())
Diag(Record->getLocation(), diag::ext_anonymous_struct);
-
+
// C and C++ require different kinds of checks for anonymous
// structs/unions.
bool Invalid = false;
if (getLangOptions().CPlusPlus) {
const char* PrevSpec = 0;
+ unsigned DiagID;
// C++ [class.union]p3:
// Anonymous unions declared in a named namespace or in the
// global namespace shall be declared static.
if (DS.getStorageClassSpec() != DeclSpec::SCS_static &&
(isa<TranslationUnitDecl>(Owner) ||
- (isa<NamespaceDecl>(Owner) &&
+ (isa<NamespaceDecl>(Owner) &&
cast<NamespaceDecl>(Owner)->getDeclName()))) {
Diag(Record->getLocation(), diag::err_anonymous_union_not_static);
Invalid = true;
// Recover by adding 'static'.
- DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), PrevSpec);
- }
+ DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(),
+ PrevSpec, DiagID);
+ }
// C++ [class.union]p3:
// A storage class is not allowed in a declaration of an
// anonymous union in a class scope.
else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
isa<RecordDecl>(Owner)) {
- Diag(DS.getStorageClassSpecLoc(),
+ Diag(DS.getStorageClassSpecLoc(),
diag::err_anonymous_union_with_storage_spec);
Invalid = true;
// Recover by removing the storage specifier.
DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(),
- PrevSpec);
+ PrevSpec, DiagID);
}
- // C++ [class.union]p2:
+ // C++ [class.union]p2:
// The member-specification of an anonymous union shall only
// define non-static data members. [Note: nested types and
// functions cannot be declared within an anonymous union. ]
@@ -1255,7 +1519,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
}
}
- }
+ }
if (!Record->isUnion() && !Owner->isRecord()) {
Diag(Record->getLocation(), diag::err_anonymous_struct_not_member)
@@ -1263,12 +1527,14 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
}
- // Create a declaration for this anonymous struct/union.
+ // Create a declaration for this anonymous struct/union.
NamedDecl *Anon = 0;
if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) {
Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(),
- /*IdentifierInfo=*/0,
+ /*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
+ // FIXME: Type source info.
+ /*DInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
Anon->setAccess(AS_public);
if (getLangOptions().CPlusPlus)
@@ -1293,9 +1559,11 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
}
Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
- /*IdentifierInfo=*/0,
+ /*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
- SC, DS.getSourceRange().getBegin());
+ // FIXME: Type source info.
+ /*DInfo=*/0,
+ SC);
}
Anon->setImplicit();
@@ -1315,7 +1583,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// members of this anonymous struct/union type, because otherwise
// the members could be injected twice: once by DeclContext when it
// builds its lookup table, and once by
- // InjectAnonymousStructOrUnionMembers.
+ // InjectAnonymousStructOrUnionMembers.
Record->setAnonymousStructOrUnion(true);
if (Invalid)
@@ -1338,28 +1606,39 @@ DeclarationName Sema::GetNameForDeclarator(Declarator &D) {
return DeclarationName(D.getIdentifier());
case Declarator::DK_Constructor: {
- QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
- Ty = Context.getCanonicalType(Ty);
- return Context.DeclarationNames.getCXXConstructorName(Ty);
+ QualType Ty = GetTypeFromParser(D.getDeclaratorIdType());
+ return Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(Ty));
}
case Declarator::DK_Destructor: {
- QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
- Ty = Context.getCanonicalType(Ty);
- return Context.DeclarationNames.getCXXDestructorName(Ty);
+ QualType Ty = GetTypeFromParser(D.getDeclaratorIdType());
+ return Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(Ty));
}
case Declarator::DK_Conversion: {
// FIXME: We'd like to keep the non-canonical type for diagnostics!
- QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
- Ty = Context.getCanonicalType(Ty);
- return Context.DeclarationNames.getCXXConversionFunctionName(Ty);
+ QualType Ty = GetTypeFromParser(D.getDeclaratorIdType());
+ return Context.DeclarationNames.getCXXConversionFunctionName(
+ Context.getCanonicalType(Ty));
}
case Declarator::DK_Operator:
assert(D.getIdentifier() == 0 && "operator names have no identifier");
return Context.DeclarationNames.getCXXOperatorName(
D.getOverloadedOperator());
+
+ case Declarator::DK_TemplateId: {
+ TemplateName Name
+ = TemplateName::getFromVoidPointer(D.getTemplateId()->Template);
+ if (TemplateDecl *Template = Name.getAsTemplateDecl())
+ return Template->getDeclName();
+ if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl())
+ return Ovl->getDeclName();
+
+ return DeclarationName();
+ }
}
assert(false && "Unknown name kind");
@@ -1389,8 +1668,8 @@ static bool isNearlyMatchingFunction(ASTContext &Context,
return true;
}
-Sema::DeclPtrTy
-Sema::HandleDeclarator(Scope *S, Declarator &D,
+Sema::DeclPtrTy
+Sema::HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition) {
DeclarationName Name = GetNameForDeclarator(D);
@@ -1404,18 +1683,44 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
<< D.getDeclSpec().getSourceRange() << D.getSourceRange();
return DeclPtrTy();
}
-
+
// The scope passed in may not be a decl scope. Zip up the scope tree until
// we find one that is.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
-
+
+ // If this is an out-of-line definition of a member of a class template
+ // or class template partial specialization, we may need to rebuild the
+ // type specifier in the declarator. See RebuildTypeInCurrentInstantiation()
+ // for more information.
+ // FIXME: cope with decltype(expr) and typeof(expr) once the rebuilder can
+ // handle expressions properly.
+ DeclSpec &DS = const_cast<DeclSpec&>(D.getDeclSpec());
+ if (D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid() &&
+ isDependentScopeSpecifier(D.getCXXScopeSpec()) &&
+ (DS.getTypeSpecType() == DeclSpec::TST_typename ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeofType ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeofExpr ||
+ DS.getTypeSpecType() == DeclSpec::TST_decltype)) {
+ if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) {
+ // FIXME: Preserve type source info.
+ QualType T = GetTypeFromParser(DS.getTypeRep());
+ EnterDeclaratorContext(S, DC);
+ T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name);
+ ExitDeclaratorContext(S);
+ if (T.isNull())
+ return DeclPtrTy();
+ DS.UpdateTypeRep(T.getAsOpaquePtr());
+ }
+ }
+
DeclContext *DC;
NamedDecl *PrevDecl;
NamedDecl *New;
- QualType R = GetTypeForDeclarator(D, S);
+ DeclaratorInfo *DInfo = 0;
+ QualType R = GetTypeForDeclarator(D, S, &DInfo);
// See if this is a redefinition of a variable in the same scope.
if (D.getCXXScopeSpec().isInvalid()) {
@@ -1431,20 +1736,43 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
/* Do nothing*/;
else if (R->isFunctionType()) {
- if (CurContext->isFunctionOrMethod())
+ if (CurContext->isFunctionOrMethod() ||
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)
NameKind = LookupRedeclarationWithLinkage;
} else if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern)
NameKind = LookupRedeclarationWithLinkage;
+ else if (CurContext->getLookupContext()->isTranslationUnit() &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)
+ NameKind = LookupRedeclarationWithLinkage;
DC = CurContext;
- PrevDecl = LookupName(S, Name, NameKind, true,
- D.getDeclSpec().getStorageClassSpec() !=
- DeclSpec::SCS_static,
- D.getIdentifierLoc());
+ LookupResult R;
+ LookupName(R, S, Name, NameKind, true,
+ NameKind == LookupRedeclarationWithLinkage,
+ D.getIdentifierLoc());
+ PrevDecl = R.getAsSingleDecl(Context);
} else { // Something like "int foo::x;"
- DC = computeDeclContext(D.getCXXScopeSpec());
- // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ?
- PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
+ DC = computeDeclContext(D.getCXXScopeSpec(), true);
+
+ if (!DC) {
+ // If we could not compute the declaration context, it's because the
+ // declaration context is dependent but does not refer to a class,
+ // class template, or class template partial specialization. Complain
+ // and return early, to avoid the coming semantic disaster.
+ Diag(D.getIdentifierLoc(),
+ diag::err_template_qualified_declarator_no_match)
+ << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
+ << D.getCXXScopeSpec().getRange();
+ return DeclPtrTy();
+ }
+
+ if (!DC->isDependentContext() &&
+ RequireCompleteDeclContext(D.getCXXScopeSpec()))
+ return DeclPtrTy();
+
+ LookupResult Res;
+ LookupQualifiedName(Res, DC, Name, LookupOrdinaryName, true);
+ PrevDecl = Res.getAsSingleDecl(Context);
// C++ 7.3.1.2p2:
// Members (including explicit specializations of templates) of a named
@@ -1467,11 +1795,11 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
//
// In this case, PrevDecl will point to the overload set
// containing the two f's declared in X, but neither of them
- // matches.
+ // matches.
// First check whether we named the global scope.
if (isa<TranslationUnitDecl>(DC)) {
- Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope)
+ Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope)
<< Name << D.getCXXScopeSpec().getRange();
} else if (!CurContext->Encloses(DC)) {
// The qualifying scope doesn't enclose the original declaration.
@@ -1480,7 +1808,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
SourceRange R = D.getCXXScopeSpec().getRange();
if (isa<FunctionDecl>(CurContext))
Diag(L, diag::err_invalid_declarator_in_function) << Name << R;
- else
+ else
Diag(L, diag::err_invalid_declarator_scope)
<< Name << cast<NamedDecl>(DC) << R;
D.setInvalidType();
@@ -1489,10 +1817,10 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
- if (!D.isInvalidType())
+ if (!D.isInvalidType())
if (DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl))
D.setInvalidType();
-
+
// Just pretend that we didn't see the previous declaration.
PrevDecl = 0;
}
@@ -1511,24 +1839,28 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
Diag(D.getIdentifierLoc(), diag::err_template_typedef);
return DeclPtrTy();
}
-
- New = ActOnTypedefDeclarator(S, D, DC, R, PrevDecl, Redeclaration);
+
+ New = ActOnTypedefDeclarator(S, D, DC, R, DInfo, PrevDecl, Redeclaration);
} else if (R->isFunctionType()) {
- New = ActOnFunctionDeclarator(S, D, DC, R, PrevDecl,
+ New = ActOnFunctionDeclarator(S, D, DC, R, DInfo, PrevDecl,
move(TemplateParamLists),
IsFunctionDefinition, Redeclaration);
} else {
- New = ActOnVariableDeclarator(S, D, DC, R, PrevDecl, Redeclaration);
+ New = ActOnVariableDeclarator(S, D, DC, R, DInfo, PrevDecl,
+ move(TemplateParamLists),
+ Redeclaration);
}
if (New == 0)
return DeclPtrTy();
-
- // If this has an identifier and is not an invalid redeclaration,
- // add it to the scope stack.
- if (Name && !(Redeclaration && New->isInvalidDecl()))
+
+ // If this has an identifier and is not an invalid redeclaration or
+ // function template specialization, add it to the scope stack.
+ if (Name && !(Redeclaration && New->isInvalidDecl()) &&
+ !(isa<FunctionDecl>(New) &&
+ cast<FunctionDecl>(New)->isFunctionTemplateSpecialization()))
PushOnScopeChains(New, S);
-
+
return DeclPtrTy::make(New);
}
@@ -1544,14 +1876,16 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
// constant expression folding, like struct {char x[(int)(char*)2];}
SizeIsNegative = false;
- if (const PointerType* PTy = dyn_cast<PointerType>(T)) {
+ QualifierCollector Qs;
+ const Type *Ty = Qs.strip(T);
+
+ if (const PointerType* PTy = dyn_cast<PointerType>(Ty)) {
QualType Pointee = PTy->getPointeeType();
QualType FixedType =
TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative);
if (FixedType.isNull()) return FixedType;
FixedType = Context.getPointerType(FixedType);
- FixedType.setCVRQualifiers(T.getCVRQualifiers());
- return FixedType;
+ return Qs.apply(FixedType);
}
const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T);
@@ -1560,7 +1894,7 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
// FIXME: We should probably handle this case
if (VLATy->getElementType()->isVariablyModifiedType())
return QualType();
-
+
Expr::EvalResult EvalResult;
if (!VLATy->getSizeExpr() ||
!VLATy->getSizeExpr()->Evaluate(EvalResult, Context) ||
@@ -1568,9 +1902,18 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
return QualType();
llvm::APSInt &Res = EvalResult.Val.getInt();
- if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned()))
- return Context.getConstantArrayType(VLATy->getElementType(),
- Res, ArrayType::Normal, 0);
+ if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) {
+ Expr* ArySizeExpr = VLATy->getSizeExpr();
+ // FIXME: here we could "steal" (how?) ArySizeExpr from the VLA,
+ // so as to transfer ownership to the ConstantArrayWithExpr.
+ // Alternatively, we could "clone" it (how?).
+ // Since we don't know how to do things above, we just use the
+ // very same Expr*.
+ return Context.getConstantArrayWithExprType(VLATy->getElementType(),
+ Res, ArySizeExpr,
+ ArrayType::Normal, 0,
+ VLATy->getBracketsRange());
+ }
SizeIsNegative = true;
return QualType();
@@ -1578,7 +1921,7 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
/// \brief Register the given locally-scoped external C declaration so
/// that it can be found later for redeclarations
-void
+void
Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl,
Scope *S) {
assert(ND->getLexicalDeclContext()->isFunctionOrMethod() &&
@@ -1609,21 +1952,22 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) {
// FIXME: We should probably indicate the identifier in question to avoid
// confusion for constructs like "inline int a(), b;"
if (D.getDeclSpec().isInlineSpecified())
- Diag(D.getDeclSpec().getInlineSpecLoc(),
+ Diag(D.getDeclSpec().getInlineSpecLoc(),
diag::err_inline_non_function);
if (D.getDeclSpec().isVirtualSpecified())
- Diag(D.getDeclSpec().getVirtualSpecLoc(),
+ Diag(D.getDeclSpec().getVirtualSpecLoc(),
diag::err_virtual_non_function);
if (D.getDeclSpec().isExplicitSpecified())
- Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_non_function);
}
NamedDecl*
Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, Decl* PrevDecl, bool &Redeclaration) {
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl, bool &Redeclaration) {
// Typedef declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator)
@@ -1645,7 +1989,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TypedefDecl *NewTD = ParseTypedefDecl(S, D, R);
if (!NewTD) return 0;
-
+
if (D.isInvalidType())
NewTD->setInvalidDecl();
@@ -1663,7 +2007,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType T = NewTD->getUnderlyingType();
if (T->isVariablyModifiedType()) {
CurFunctionNeedsScopeChecking = true;
-
+
if (S->getFnParent() == 0) {
bool SizeIsNegative;
QualType FixedTy =
@@ -1682,6 +2026,19 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
}
+
+ // If this is the C FILE type, notify the AST context.
+ if (IdentifierInfo *II = NewTD->getIdentifier())
+ if (!NewTD->isInvalidDecl() &&
+ NewTD->getDeclContext()->getLookupContext()->isTranslationUnit()) {
+ if (II->isStr("FILE"))
+ Context.setFILEDecl(NewTD);
+ else if (II->isStr("jmp_buf"))
+ Context.setjmp_bufDecl(NewTD);
+ else if (II->isStr("sigjmp_buf"))
+ Context.setsigjmp_bufDecl(NewTD);
+ }
+
return NewTD;
}
@@ -1697,13 +2054,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
///
/// \param PrevDecl the previous declaration found by name
/// lookup
-///
+///
/// \param DC the context in which the new declaration is being
/// declared.
///
/// \returns true if PrevDecl is an out-of-scope previous declaration
/// for a new delcaration with the same name.
-static bool
+static bool
isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
ASTContext &Context) {
if (!PrevDecl)
@@ -1737,10 +2094,10 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
OuterContext = OuterContext->getParent();
while (!PrevOuterContext->isFileContext())
PrevOuterContext = PrevOuterContext->getParent();
-
+
// The previous declaration is in a different namespace, so it
// isn't the same function.
- if (OuterContext->getPrimaryContext() !=
+ if (OuterContext->getPrimaryContext() !=
PrevOuterContext->getPrimaryContext())
return false;
}
@@ -1752,7 +2109,9 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
NamedDecl*
Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R,NamedDecl* PrevDecl,
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl,
+ MultiTemplateParamsArg TemplateParamLists,
bool &Redeclaration) {
DeclarationName Name = GetNameForDeclarator(D);
@@ -1792,7 +2151,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// C99 6.9p2: The storage-class specifiers auto and register shall not
// appear in the declaration specifiers in an external declaration.
if (SC == VarDecl::Auto || SC == VarDecl::Register) {
-
+
// If this is a register variable with an asm label specified, then this
// is a GNU extension.
if (SC == VarDecl::Register && D.getAsmLabel())
@@ -1805,7 +2164,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (DC->isRecord() && !CurContext->isRecord()) {
// This is an out-of-line definition of a static data member.
if (SC == VarDecl::Static) {
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
<< CodeModificationHint::CreateRemoval(
SourceRange(D.getDeclSpec().getStorageClassSpecLoc()));
@@ -1815,22 +2174,48 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (SC == VarDecl::Static) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
if (RD->isLocalClass())
- Diag(D.getIdentifierLoc(),
+ Diag(D.getIdentifierLoc(),
diag::err_static_data_member_not_allowed_in_local_class)
<< Name << RD->getDeclName();
}
}
-
-
- // The variable can not
- NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
- II, R, SC,
- // FIXME: Move to DeclGroup...
- D.getDeclSpec().getSourceRange().getBegin());
+
+ // Match up the template parameter lists with the scope specifier, then
+ // determine whether we have a template or a template specialization.
+ bool isExplicitSpecialization = false;
+ if (TemplateParameterList *TemplateParams
+ = MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getSourceRange().getBegin(),
+ D.getCXXScopeSpec(),
+ (TemplateParameterList**)TemplateParamLists.get(),
+ TemplateParamLists.size(),
+ isExplicitSpecialization)) {
+ if (TemplateParams->size() > 0) {
+ // There is no such thing as a variable template.
+ Diag(D.getIdentifierLoc(), diag::err_template_variable)
+ << II
+ << SourceRange(TemplateParams->getTemplateLoc(),
+ TemplateParams->getRAngleLoc());
+ return 0;
+ } else {
+ // There is an extraneous 'template<>' for this variable. Complain
+ // about it, but allow the declaration of the variable.
+ Diag(TemplateParams->getTemplateLoc(),
+ diag::err_template_variable_noparams)
+ << II
+ << SourceRange(TemplateParams->getTemplateLoc(),
+ TemplateParams->getRAngleLoc());
+
+ isExplicitSpecialization = true;
+ }
+ }
+
+ NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
+ II, R, DInfo, SC);
if (D.isInvalidType())
NewVD->setInvalidDecl();
-
+
if (D.getDeclSpec().isThreadSpecified()) {
if (NewVD->hasLocalStorage())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global);
@@ -1850,7 +2235,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
- StringLiteral *SE = cast<StringLiteral>(E);
+ StringLiteral *SE = cast<StringLiteral>(E);
NewVD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(),
SE->getByteLength())));
}
@@ -1861,8 +2246,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) &&
!(NewVD->hasLinkage() &&
isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
- PrevDecl = 0;
-
+ PrevDecl = 0;
+
// Merge the decl with the existing one if appropriate.
if (PrevDecl) {
if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) {
@@ -1875,16 +2260,31 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
} else if (D.getCXXScopeSpec().isSet()) {
// No previous declaration in the qualifying scope.
- Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member)
- << Name << D.getCXXScopeSpec().getRange();
+ Diag(D.getIdentifierLoc(), diag::err_no_member)
+ << Name << computeDeclContext(D.getCXXScopeSpec(), true)
+ << D.getCXXScopeSpec().getRange();
NewVD->setInvalidDecl();
}
CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration);
+ // This is an explicit specialization of a static data member. Check it.
+ if (isExplicitSpecialization && !NewVD->isInvalidDecl() &&
+ CheckMemberSpecialization(NewVD, PrevDecl))
+ NewVD->setInvalidDecl();
+
+ // attributes declared post-definition are currently ignored
+ if (PrevDecl) {
+ const VarDecl *Def = 0, *PrevVD = dyn_cast<VarDecl>(PrevDecl);
+ if (PrevVD->getDefinition(Def) && D.hasAttributes()) {
+ Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition);
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ }
+ }
+
// If this is a locally-scoped extern C variable, update the map of
// such variables.
- if (CurContext->isFunctionOrMethod() && NewVD->isExternC(Context) &&
+ if (CurContext->isFunctionOrMethod() && NewVD->isExternC() &&
!NewVD->isInvalidDecl())
RegisterLocallyScopedExternCDecl(NewVD, PrevDecl, S);
@@ -1906,17 +2306,17 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
// If the decl is already known invalid, don't check it.
if (NewVD->isInvalidDecl())
return;
-
+
QualType T = NewVD->getType();
if (T->isObjCInterfaceType()) {
Diag(NewVD->getLocation(), diag::err_statically_allocated_object);
return NewVD->setInvalidDecl();
}
-
+
// The variable can not have an abstract class type.
if (RequireNonAbstractType(NewVD->getLocation(), T,
- diag::err_abstract_type_in_decl,
+ diag::err_abstract_type_in_decl,
AbstractVariableType))
return NewVD->setInvalidDecl();
@@ -1934,21 +2334,22 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
bool isVM = T->isVariablyModifiedType();
- if (isVM || NewVD->hasAttr<CleanupAttr>())
+ if (isVM || NewVD->hasAttr<CleanupAttr>() ||
+ NewVD->hasAttr<BlocksAttr>())
CurFunctionNeedsScopeChecking = true;
-
+
if ((isVM && NewVD->hasLinkage()) ||
(T->isVariableArrayType() && NewVD->hasGlobalStorage())) {
bool SizeIsNegative;
QualType FixedTy =
TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative);
-
+
if (FixedTy.isNull() && T->isVariableArrayType()) {
const VariableArrayType *VAT = Context.getAsVariableArrayType(T);
- // FIXME: This won't give the correct result for
- // int a[10][n];
+ // FIXME: This won't give the correct result for
+ // int a[10][n];
SourceRange SizeRange = VAT->getSizeExpr()->getSourceRange();
-
+
if (NewVD->isFileVarDecl())
Diag(NewVD->getLocation(), diag::err_vla_decl_in_file_scope)
<< SizeRange;
@@ -1959,8 +2360,8 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage)
<< SizeRange;
return NewVD->setInvalidDecl();
- }
-
+ }
+
if (FixedTy.isNull()) {
if (NewVD->isFileVarDecl())
Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope);
@@ -1968,12 +2369,12 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage);
return NewVD->setInvalidDecl();
}
-
+
Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size);
NewVD->setType(FixedTy);
}
- if (!PrevDecl && NewVD->isExternC(Context)) {
+ if (!PrevDecl && NewVD->isExternC()) {
// Since we did not find anything by this name and we're declaring
// an extern "C" variable, look for a non-visible extern "C"
// declaration with the same name.
@@ -1993,7 +2394,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
Diag(NewVD->getLocation(), diag::err_block_on_nonlocal);
return NewVD->setInvalidDecl();
}
-
+
if (isVM && NewVD->hasAttr<BlocksAttr>()) {
Diag(NewVD->getLocation(), diag::err_block_on_vm);
return NewVD->setInvalidDecl();
@@ -2005,9 +2406,43 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
}
}
-NamedDecl*
+static bool isUsingDecl(Decl *D) {
+ return isa<UsingDecl>(D) || isa<UnresolvedUsingDecl>(D);
+}
+
+/// \brief Data used with FindOverriddenMethod
+struct FindOverriddenMethodData {
+ Sema *S;
+ CXXMethodDecl *Method;
+};
+
+/// \brief Member lookup function that determines whether a given C++
+/// method overrides a method in a base class, to be used with
+/// CXXRecordDecl::lookupInBases().
+static bool FindOverriddenMethod(CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *UserData) {
+ RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+
+ FindOverriddenMethodData *Data
+ = reinterpret_cast<FindOverriddenMethodData*>(UserData);
+ for (Path.Decls = BaseRecord->lookup(Data->Method->getDeclName());
+ Path.Decls.first != Path.Decls.second;
+ ++Path.Decls.first) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*Path.Decls.first)) {
+ OverloadedFunctionDecl::function_iterator MatchedDecl;
+ if (MD->isVirtual() && !Data->S->IsOverload(Data->Method, MD, MatchedDecl))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+NamedDecl*
Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
- QualType R, NamedDecl* PrevDecl,
+ QualType R, DeclaratorInfo *DInfo,
+ NamedDecl* PrevDecl,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition, bool &Redeclaration) {
assert(R.getTypePtr()->isFunctionType());
@@ -2019,7 +2454,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
case DeclSpec::SCS_auto:
case DeclSpec::SCS_register:
case DeclSpec::SCS_mutable:
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_typecheck_sclass_func);
D.setInvalidType();
break;
@@ -2032,11 +2467,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// block scope shall have no explicit storage-class specifier
// other than extern
// See also (C++ [dcl.stc]p4).
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_block_func);
SC = FunctionDecl::None;
} else
- SC = FunctionDecl::Static;
+ SC = FunctionDecl::Static;
break;
}
case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
@@ -2045,35 +2480,43 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ bool isFriend = D.getDeclSpec().isFriendSpecified();
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
- // the class has been completely parsed.
+ // the class has been completely parsed.
if (!DC->isRecord() &&
- RequireNonAbstractType(D.getIdentifierLoc(),
- R->getAsFunctionType()->getResultType(),
- diag::err_abstract_type_in_decl,
+ RequireNonAbstractType(D.getIdentifierLoc(),
+ R->getAs<FunctionType>()->getResultType(),
+ diag::err_abstract_type_in_decl,
AbstractReturnType))
D.setInvalidType();
-
+
// Do not allow returning a objc interface by-value.
- if (R->getAsFunctionType()->getResultType()->isObjCInterfaceType()) {
+ if (R->getAs<FunctionType>()->getResultType()->isObjCInterfaceType()) {
Diag(D.getIdentifierLoc(),
diag::err_object_cannot_be_passed_returned_by_value) << 0
- << R->getAsFunctionType()->getResultType();
+ << R->getAs<FunctionType>()->getResultType();
D.setInvalidType();
}
- // Check that we can declare a template here.
- if (TemplateParamLists.size() &&
- CheckTemplateDeclScope(S, TemplateParamLists))
- return 0;
-
bool isVirtualOkay = false;
FunctionDecl *NewFD;
+
+ if (isFriend) {
+ // DC is the namespace in which the function is being declared.
+ assert((DC->isFileContext() || PrevDecl) && "previously-undeclared "
+ "friend function being created in a non-namespace context");
+
+ // C++ [class.friend]p5
+ // A function can be defined in a friend declaration of a
+ // class . . . . Such a function is implicitly inline.
+ isInline |= IsFunctionDefinition;
+ }
+
if (D.getKind() == Declarator::DK_Constructor) {
// This is a C++ constructor declaration.
assert(DC->isRecord() &&
@@ -2082,19 +2525,19 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
R = CheckConstructorDeclarator(D, R, SC);
// Create the new declaration
- NewFD = CXXConstructorDecl::Create(Context,
+ NewFD = CXXConstructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
- D.getIdentifierLoc(), Name, R,
+ D.getIdentifierLoc(), Name, R, DInfo,
isExplicit, isInline,
/*isImplicitlyDeclared=*/false);
} else if (D.getKind() == Declarator::DK_Destructor) {
// This is a C++ destructor declaration.
if (DC->isRecord()) {
R = CheckDestructorDeclarator(D, SC);
-
+
NewFD = CXXDestructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
- D.getIdentifierLoc(), Name, R,
+ D.getIdentifierLoc(), Name, R,
isInline,
/*isImplicitlyDeclared=*/false);
@@ -2105,10 +2548,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Create a FunctionDecl to satisfy the function definition parsing
// code path.
NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
- Name, R, SC, isInline,
- /*hasPrototype=*/true,
- // FIXME: Move to DeclGroup...
- D.getDeclSpec().getSourceRange().getBegin());
+ Name, R, DInfo, SC, isInline,
+ /*hasPrototype=*/true);
D.setInvalidType();
}
} else if (D.getKind() == Declarator::DK_Conversion) {
@@ -2117,29 +2558,29 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
diag::err_conv_function_not_member);
return 0;
}
-
+
CheckConversionDeclarator(D, R, SC);
NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
- D.getIdentifierLoc(), Name, R,
+ D.getIdentifierLoc(), Name, R, DInfo,
isInline, isExplicit);
-
+
isVirtualOkay = true;
} else if (DC->isRecord()) {
// If the of the function is the same as the name of the record, then this
- // must be an invalid constructor that has a return type.
- // (The parser checks for a return type and makes the declarator a
+ // must be an invalid constructor that has a return type.
+ // (The parser checks for a return type and makes the declarator a
// constructor if it has no return type).
- // must have an invalid constructor that has a return type
+ // must have an invalid constructor that has a return type
if (Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){
Diag(D.getIdentifierLoc(), diag::err_constructor_return_type)
<< SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
<< SourceRange(D.getIdentifierLoc());
return 0;
}
-
+
// This is a C++ method declaration.
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
- D.getIdentifierLoc(), Name, R,
+ D.getIdentifierLoc(), Name, R, DInfo,
(SC == FunctionDecl::Static), isInline);
isVirtualOkay = (SC != FunctionDecl::Static);
@@ -2150,44 +2591,56 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// - there is a prototype in the declarator, or
// - the type R of the function is some kind of typedef or other reference
// to a type name (which eventually refers to a function type).
- bool HasPrototype =
+ bool HasPrototype =
getLangOptions().CPlusPlus ||
(D.getNumTypeObjects() && D.getTypeObject(0).Fun.hasPrototype) ||
(!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType());
-
+
NewFD = FunctionDecl::Create(Context, DC,
D.getIdentifierLoc(),
- Name, R, SC, isInline, HasPrototype,
- // FIXME: Move to DeclGroup...
- D.getDeclSpec().getSourceRange().getBegin());
+ Name, R, DInfo, SC, isInline, HasPrototype);
}
if (D.isInvalidType())
NewFD->setInvalidDecl();
-
+
// Set the lexical context. If the declarator has a C++
- // scope specifier, the lexical context will be different
- // from the semantic context.
+ // scope specifier, or is the object of a friend declaration, the
+ // lexical context will be different from the semantic context.
NewFD->setLexicalDeclContext(CurContext);
- // If there is a template parameter list, then we are dealing with a
- // template declaration or specialization.
+ // Match up the template parameter lists with the scope specifier, then
+ // determine whether we have a template or a template specialization.
FunctionTemplateDecl *FunctionTemplate = 0;
- if (TemplateParamLists.size()) {
- // FIXME: member templates!
- TemplateParameterList *TemplateParams
- = static_cast<TemplateParameterList *>(*TemplateParamLists.release());
-
+ bool isExplicitSpecialization = false;
+ bool isFunctionTemplateSpecialization = false;
+ if (TemplateParameterList *TemplateParams
+ = MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getSourceRange().getBegin(),
+ D.getCXXScopeSpec(),
+ (TemplateParameterList**)TemplateParamLists.get(),
+ TemplateParamLists.size(),
+ isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// This is a function template
- FunctionTemplate = FunctionTemplateDecl::Create(Context, CurContext,
+
+ // Check that we can declare a template here.
+ if (CheckTemplateDeclScope(S, TemplateParams))
+ return 0;
+
+ FunctionTemplate = FunctionTemplateDecl::Create(Context, DC,
NewFD->getLocation(),
Name, TemplateParams,
NewFD);
+ FunctionTemplate->setLexicalDeclContext(CurContext);
NewFD->setDescribedFunctionTemplate(FunctionTemplate);
} else {
- // FIXME: Handle function template specializations
+ // This is a function template specialization.
+ isFunctionTemplateSpecialization = true;
}
+
+ // FIXME: Free this memory properly.
+ TemplateParamLists.release();
}
// C++ [dcl.fct.spec]p5:
@@ -2197,7 +2650,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
//
if (isVirtual && !NewFD->isInvalidDecl()) {
if (!isVirtualOkay) {
- Diag(D.getDeclSpec().getVirtualSpecLoc(),
+ Diag(D.getDeclSpec().getVirtualSpecLoc(),
diag::err_virtual_non_function);
} else if (!CurContext->isRecord()) {
// 'virtual' was specified outside of the class.
@@ -2210,28 +2663,47 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC);
CurClass->setAggregate(false);
CurClass->setPOD(false);
+ CurClass->setEmpty(false);
CurClass->setPolymorphic(true);
CurClass->setHasTrivialConstructor(false);
+ CurClass->setHasTrivialCopyConstructor(false);
+ CurClass->setHasTrivialCopyAssignment(false);
+ }
+ }
+
+ if (isFriend) {
+ if (FunctionTemplate) {
+ FunctionTemplate->setObjectOfFriendDecl(
+ /* PreviouslyDeclared= */ PrevDecl != NULL);
+ FunctionTemplate->setAccess(AS_public);
}
+ else
+ NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ PrevDecl != NULL);
+
+ NewFD->setAccess(AS_public);
}
+
if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD)) {
// Look for virtual methods in base classes that this method might override.
-
- BasePaths Paths;
- if (LookupInBases(cast<CXXRecordDecl>(DC),
- MemberLookupCriteria(NewMD), Paths)) {
- for (BasePaths::decl_iterator I = Paths.found_decls_begin(),
+ CXXBasePaths Paths;
+ FindOverriddenMethodData Data;
+ Data.Method = NewMD;
+ Data.S = this;
+ if (cast<CXXRecordDecl>(DC)->lookupInBases(&FindOverriddenMethod, &Data,
+ Paths)) {
+ for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(),
E = Paths.found_decls_end(); I != E; ++I) {
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
- if (!CheckOverridingFunctionReturnType(NewMD, OldMD))
+ if (!CheckOverridingFunctionReturnType(NewMD, OldMD) &&
+ !CheckOverridingFunctionExceptionSpec(NewMD, OldMD))
NewMD->addOverriddenMethod(OldMD);
}
}
}
}
-
- if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) &&
+
+ if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) &&
!CurContext->isRecord()) {
// C++ [class.static]p1:
// A data or function member of a class may be declared static
@@ -2240,7 +2712,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Complain about the 'static' specifier if it's on an out-of-line
// member function definition.
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
<< CodeModificationHint::CreateRemoval(
SourceRange(D.getDeclSpec().getStorageClassSpecLoc()));
@@ -2249,7 +2721,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
- StringLiteral *SE = cast<StringLiteral>(E);
+ StringLiteral *SE = cast<StringLiteral>(E);
NewFD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(),
SE->getByteLength())));
}
@@ -2278,11 +2750,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(Param->getLocation(), diag::err_param_typedef_of_void);
// FIXME: Leaks decl?
} else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
- for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
- Params.push_back(FTI.ArgInfo[i].Param.getAs<ParmVarDecl>());
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+ ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
+ assert(Param->getDeclContext() != NewFD && "Was set before ?");
+ Param->setDeclContext(NewFD);
+ Params.push_back(Param);
+ }
}
-
- } else if (const FunctionProtoType *FT = R->getAsFunctionProtoType()) {
+
+ } else if (const FunctionProtoType *FT = R->getAs<FunctionProtoType>()) {
// When we're declaring a function with a typedef, typeof, etc as in the
// following example, we'll need to synthesize (unnamed)
// parameters for use in the declaration.
@@ -2291,13 +2767,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// typedef void fn(int);
// fn f;
// @endcode
-
+
// Synthesize a parameter for each argument type.
for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(),
AE = FT->arg_type_end(); AI != AE; ++AI) {
ParmVarDecl *Param = ParmVarDecl::Create(Context, DC,
SourceLocation(), 0,
- *AI, VarDecl::None, 0);
+ *AI, /*DInfo=*/0,
+ VarDecl::None, 0);
Param->setImplicit();
Params.push_back(Param);
}
@@ -2307,7 +2784,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
// Finally, we know we have the right number of parameters, install them.
NewFD->setParams(Context, Params.data(), Params.size());
-
+
// If name lookup finds a previous declaration that is not in the
// same scope as the new declaration, this may still be an
// acceptable redeclaration.
@@ -2316,27 +2793,80 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
PrevDecl = 0;
+ // If the declarator is a template-id, translate the parser's template
+ // argument list into our AST format.
+ bool HasExplicitTemplateArgs = false;
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ SourceLocation LAngleLoc, RAngleLoc;
+ if (D.getKind() == Declarator::DK_TemplateId) {
+ TemplateIdAnnotation *TemplateId = D.getTemplateId();
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
+ translateTemplateArguments(TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateArgs);
+ TemplateArgsPtr.release();
+
+ HasExplicitTemplateArgs = true;
+ LAngleLoc = TemplateId->LAngleLoc;
+ RAngleLoc = TemplateId->RAngleLoc;
+
+ if (FunctionTemplate) {
+ // FIXME: Diagnose function template with explicit template
+ // arguments.
+ HasExplicitTemplateArgs = false;
+ } else if (!isFunctionTemplateSpecialization &&
+ !D.getDeclSpec().isFriendSpecified()) {
+ // We have encountered something that the user meant to be a
+ // specialization (because it has explicitly-specified template
+ // arguments) but that was not introduced with a "template<>" (or had
+ // too few of them).
+ Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
+ << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
+ << CodeModificationHint::CreateInsertion(
+ D.getDeclSpec().getSourceRange().getBegin(),
+ "template<> ");
+ isFunctionTemplateSpecialization = true;
+ }
+ }
+
+ if (isFunctionTemplateSpecialization) {
+ if (CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs,
+ LAngleLoc, TemplateArgs.data(),
+ TemplateArgs.size(), RAngleLoc,
+ PrevDecl))
+ NewFD->setInvalidDecl();
+ } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
+ CheckMemberSpecialization(NewFD, PrevDecl))
+ NewFD->setInvalidDecl();
+
// Perform semantic checking on the function declaration.
bool OverloadableAttrRequired = false; // FIXME: HACK!
- CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
- /*FIXME:*/OverloadableAttrRequired);
+ CheckFunctionDeclaration(NewFD, PrevDecl, isExplicitSpecialization,
+ Redeclaration, /*FIXME:*/OverloadableAttrRequired);
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
- if (!IsFunctionDefinition) {
+ // Note that this is not the case for explicit specializations of
+ // function templates or member functions of class templates, per
+ // C++ [temp.expl.spec]p2.
+ if (!IsFunctionDefinition && !isFriend &&
+ !isFunctionTemplateSpecialization && !isExplicitSpecialization) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
- } else if (!Redeclaration && (!PrevDecl || !isa<UsingDecl>(PrevDecl))) {
+ } else if (!Redeclaration && (!PrevDecl || !isUsingDecl(PrevDecl))) {
// The user tried to provide an out-of-line definition for a
// function that is a member of a class or namespace, but there
- // was no such member function declared (C++ [class.mfct]p2,
+ // was no such member function declared (C++ [class.mfct]p2,
// C++ [namespace.memdef]p2). For example:
- //
+ //
// class X {
// void f() const;
- // };
+ // };
//
// void X::f() { } // ill-formed
//
@@ -2344,12 +2874,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// matches (e.g., those that differ only in cv-qualifiers and
// whether the parameter types are references).
Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
- << cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange();
+ << Name << DC << D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
-
- LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName,
- true);
- assert(!Prev.isAmbiguous() &&
+
+ LookupResult Prev;
+ LookupQualifiedName(Prev, DC, Name, LookupOrdinaryName, true);
+ assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
Func != FuncEnd; ++Func) {
@@ -2357,7 +2887,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD))
Diag((*Func)->getLocation(), diag::note_member_def_close_match);
}
-
+
PrevDecl = 0;
}
}
@@ -2367,6 +2897,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// FIXME: This needs to happen before we merge declarations. Then,
// let attribute merging cope with attribute conflicts.
ProcessDeclAttributes(S, NewFD, D);
+
+ // attributes declared post-definition are currently ignored
+ if (Redeclaration && PrevDecl) {
+ const FunctionDecl *Def, *PrevFD = dyn_cast<FunctionDecl>(PrevDecl);
+ if (PrevFD && PrevFD->getBody(Def) && D.hasAttributes()) {
+ Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition);
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ }
+ }
+
AddKnownFunctionAttributes(NewFD);
if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
@@ -2375,14 +2915,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
<< Redeclaration << NewFD;
if (PrevDecl)
- Diag(PrevDecl->getLocation(),
+ Diag(PrevDecl->getLocation(),
diag::note_attribute_overloadable_prev_overload);
NewFD->addAttr(::new (Context) OverloadableAttr());
}
// If this is a locally-scoped extern C function, update the
// map of such names.
- if (CurContext->isFunctionOrMethod() && NewFD->isExternC(Context)
+ if (CurContext->isFunctionOrMethod() && NewFD->isExternC()
&& !NewFD->isInvalidDecl())
RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S);
@@ -2391,10 +2931,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (FunctionTemplate && NewFD->isInvalidDecl())
FunctionTemplate->setInvalidDecl();
-
+
if (FunctionTemplate)
return FunctionTemplate;
-
+
return NewFD;
}
@@ -2408,8 +2948,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
/// that have been instantiated via C++ template instantiation (called
/// via InstantiateDecl).
///
+/// \param IsExplicitSpecialiation whether this new function declaration is
+/// an explicit specialization of the previous declaration.
+///
/// This sets NewFD->isInvalidDecl() to true if there was an error.
void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
+ bool IsExplicitSpecialization,
bool &Redeclaration,
bool &OverloadableAttrRequired) {
// If NewFD is already known erroneous, don't do any of this checking.
@@ -2423,51 +2967,11 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
return NewFD->setInvalidDecl();
}
- // Semantic checking for this function declaration (in isolation).
- if (getLangOptions().CPlusPlus) {
- // C++-specific checks.
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
- CheckConstructor(Constructor);
- } else if (isa<CXXDestructorDecl>(NewFD)) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
- Record->setUserDeclaredDestructor(true);
- // C++ [class]p4: A POD-struct is an aggregate class that has [...] no
- // user-defined destructor.
- Record->setPOD(false);
-
- // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly-
- // declared destructor.
- Record->setHasTrivialDestructor(false);
- } else if (CXXConversionDecl *Conversion
- = dyn_cast<CXXConversionDecl>(NewFD))
- ActOnConversionDeclarator(Conversion);
-
- // Extra checking for C++ overloaded operators (C++ [over.oper]).
- if (NewFD->isOverloadedOperator() &&
- CheckOverloadedOperatorDeclaration(NewFD))
- return NewFD->setInvalidDecl();
- }
-
- // C99 6.7.4p6:
- // [... ] For a function with external linkage, the following
- // restrictions apply: [...] If all of the file scope declarations
- // for a function in a translation unit include the inline
- // function specifier without extern, then the definition in that
- // translation unit is an inline definition. An inline definition
- // does not provide an external definition for the function, and
- // does not forbid an external definition in another translation
- // unit.
- //
- // Here we determine whether this function, in isolation, would be a
- // C99 inline definition. MergeCompatibleFunctionDecls looks at
- // previous declarations.
- if (NewFD->isInline() && getLangOptions().C99 &&
- NewFD->getStorageClass() == FunctionDecl::None &&
- NewFD->getDeclContext()->getLookupContext()->isTranslationUnit())
- NewFD->setC99InlineDefinition(true);
+ if (NewFD->isMain())
+ CheckMain(NewFD);
// Check for a previous declaration of this name.
- if (!PrevDecl && NewFD->isExternC(Context)) {
+ if (!PrevDecl && NewFD->isExternC()) {
// Since we did not find anything by this name and we're declaring
// an extern "C" function, look for a non-visible extern "C"
// declaration with the same name.
@@ -2492,24 +2996,23 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
// Functions marked "overloadable" must have a prototype (that
// we can't get through declaration merging).
- if (!NewFD->getType()->getAsFunctionProtoType()) {
+ if (!NewFD->getType()->getAs<FunctionProtoType>()) {
Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype)
<< NewFD;
Redeclaration = true;
// Turn this into a variadic function with no parameters.
QualType R = Context.getFunctionType(
- NewFD->getType()->getAsFunctionType()->getResultType(),
+ NewFD->getType()->getAs<FunctionType>()->getResultType(),
0, 0, true, 0);
NewFD->setType(R);
return NewFD->setInvalidDecl();
}
}
- if (PrevDecl &&
- (!AllowOverloadingOfFunction(PrevDecl, Context) ||
- !IsOverload(NewFD, PrevDecl, MatchedDecl)) &&
- !isa<UsingDecl>(PrevDecl)) {
+ if (PrevDecl &&
+ (!AllowOverloadingOfFunction(PrevDecl, Context) ||
+ !IsOverload(NewFD, PrevDecl, MatchedDecl)) && !isUsingDecl(PrevDecl)) {
Redeclaration = true;
Decl *OldDecl = PrevDecl;
@@ -2519,23 +3022,160 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
OldDecl = *MatchedDecl;
// NewFD and OldDecl represent declarations that need to be
- // merged.
+ // merged.
if (MergeFunctionDecl(NewFD, OldDecl))
return NewFD->setInvalidDecl();
if (FunctionTemplateDecl *OldTemplateDecl
- = dyn_cast<FunctionTemplateDecl>(OldDecl))
- NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
- else
+ = dyn_cast<FunctionTemplateDecl>(OldDecl)) {
+ NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
+ FunctionTemplateDecl *NewTemplateDecl
+ = NewFD->getDescribedFunctionTemplate();
+ assert(NewTemplateDecl && "Template/non-template mismatch");
+ if (CXXMethodDecl *Method
+ = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
+ Method->setAccess(OldTemplateDecl->getAccess());
+ NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
+ }
+
+ // If this is an explicit specialization of a member that is a function
+ // template, mark it as a member specialization.
+ if (IsExplicitSpecialization &&
+ NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
+ NewTemplateDecl->setMemberSpecialization();
+ assert(OldTemplateDecl->isMemberSpecialization());
+ }
+ } else {
+ if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
+ NewFD->setAccess(OldDecl->getAccess());
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
+ }
}
}
- // In C++, check default arguments now that we have merged decls. Unless
- // the lexical context is the class, because in this case this is done
- // during delayed parsing anyway.
- if (getLangOptions().CPlusPlus && !CurContext->isRecord())
- CheckCXXDefaultArguments(NewFD);
+ // Semantic checking for this function declaration (in isolation).
+ if (getLangOptions().CPlusPlus) {
+ // C++-specific checks.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
+ CheckConstructor(Constructor);
+ } else if (isa<CXXDestructorDecl>(NewFD)) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
+ QualType ClassType = Context.getTypeDeclType(Record);
+ if (!ClassType->isDependentType()) {
+ DeclarationName Name
+ = Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(ClassType));
+ if (NewFD->getDeclName() != Name) {
+ Diag(NewFD->getLocation(), diag::err_destructor_name);
+ return NewFD->setInvalidDecl();
+ }
+ }
+ Record->setUserDeclaredDestructor(true);
+ // C++ [class]p4: A POD-struct is an aggregate class that has [...] no
+ // user-defined destructor.
+ Record->setPOD(false);
+
+ // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly-
+ // declared destructor.
+ // FIXME: C++0x: don't do this for "= default" destructors
+ Record->setHasTrivialDestructor(false);
+ } else if (CXXConversionDecl *Conversion
+ = dyn_cast<CXXConversionDecl>(NewFD))
+ ActOnConversionDeclarator(Conversion);
+
+ // Extra checking for C++ overloaded operators (C++ [over.oper]).
+ if (NewFD->isOverloadedOperator() &&
+ CheckOverloadedOperatorDeclaration(NewFD))
+ return NewFD->setInvalidDecl();
+
+ // In C++, check default arguments now that we have merged decls. Unless
+ // the lexical context is the class, because in this case this is done
+ // during delayed parsing anyway.
+ if (!CurContext->isRecord())
+ CheckCXXDefaultArguments(NewFD);
+ }
+}
+
+void Sema::CheckMain(FunctionDecl* FD) {
+ // C++ [basic.start.main]p3: A program that declares main to be inline
+ // or static is ill-formed.
+ // C99 6.7.4p4: In a hosted environment, the inline function specifier
+ // shall not appear in a declaration of main.
+ // static main is not an error under C99, but we should warn about it.
+ bool isInline = FD->isInline();
+ bool isStatic = FD->getStorageClass() == FunctionDecl::Static;
+ if (isInline || isStatic) {
+ unsigned diagID = diag::warn_unusual_main_decl;
+ if (isInline || getLangOptions().CPlusPlus)
+ diagID = diag::err_unusual_main_decl;
+
+ int which = isStatic + (isInline << 1) - 1;
+ Diag(FD->getLocation(), diagID) << which;
+ }
+
+ QualType T = FD->getType();
+ assert(T->isFunctionType() && "function decl is not of function type");
+ const FunctionType* FT = T->getAs<FunctionType>();
+
+ if (!Context.hasSameUnqualifiedType(FT->getResultType(), Context.IntTy)) {
+ // TODO: add a replacement fixit to turn the return type into 'int'.
+ Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint);
+ FD->setInvalidDecl(true);
+ }
+
+ // Treat protoless main() as nullary.
+ if (isa<FunctionNoProtoType>(FT)) return;
+
+ const FunctionProtoType* FTP = cast<const FunctionProtoType>(FT);
+ unsigned nparams = FTP->getNumArgs();
+ assert(FD->getNumParams() == nparams);
+
+ if (nparams > 3) {
+ Diag(FD->getLocation(), diag::err_main_surplus_args) << nparams;
+ FD->setInvalidDecl(true);
+ nparams = 3;
+ }
+
+ // FIXME: a lot of the following diagnostics would be improved
+ // if we had some location information about types.
+
+ QualType CharPP =
+ Context.getPointerType(Context.getPointerType(Context.CharTy));
+ QualType Expected[] = { Context.IntTy, CharPP, CharPP };
+
+ for (unsigned i = 0; i < nparams; ++i) {
+ QualType AT = FTP->getArgType(i);
+
+ bool mismatch = true;
+
+ if (Context.hasSameUnqualifiedType(AT, Expected[i]))
+ mismatch = false;
+ else if (Expected[i] == CharPP) {
+ // As an extension, the following forms are okay:
+ // char const **
+ // char const * const *
+ // char * const *
+
+ QualifierCollector qs;
+ const PointerType* PT;
+ if ((PT = qs.strip(AT)->getAs<PointerType>()) &&
+ (PT = qs.strip(PT->getPointeeType())->getAs<PointerType>()) &&
+ (QualType(qs.strip(PT->getPointeeType()), 0) == Context.CharTy)) {
+ qs.removeConst();
+ mismatch = !qs.empty();
+ }
+ }
+
+ if (mismatch) {
+ Diag(FD->getLocation(), diag::err_main_arg_wrong) << i << Expected[i];
+ // TODO: suggest replacing given type with expected type
+ FD->setInvalidDecl(true);
+ }
+ }
+
+ if (nparams == 1 && !FD->isInvalidDecl()) {
+ Diag(FD->getLocation(), diag::warn_main_one_arg);
+ }
}
bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
@@ -2554,8 +3194,8 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
return true;
}
-void Sema::AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init) {
- AddInitializerToDecl(dcl, init.release(), /*DirectInit=*/false);
+void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init) {
+ AddInitializerToDecl(dcl, move(init), /*DirectInit=*/false);
}
/// AddInitializerToDecl - Adds the initializer Init to the
@@ -2567,7 +3207,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
// the initializer.
if (RealDecl == 0)
return;
-
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
// With declarators parsed the way they are, the parser cannot
// distinguish between a normal initializer and a pure-specifier.
@@ -2616,7 +3256,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
const VarDecl *Def = 0;
if (VDecl->getDefinition(Def)) {
- Diag(VDecl->getLocation(), diag::err_redefinition)
+ Diag(VDecl->getLocation(), diag::err_redefinition)
<< VDecl->getDeclName();
Diag(Def->getLocation(), diag::note_previous_definition);
VDecl->setInvalidDecl();
@@ -2639,7 +3279,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
VDecl->getDeclName(), DirectInit))
VDecl->setInvalidDecl();
-
+
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
// Don't check invalid declarations to avoid emitting useless diagnostics.
if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) {
@@ -2647,7 +3287,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
CheckForConstantInitializer(Init, DclT);
}
}
- } else if (VDecl->isStaticDataMember() &&
+ } else if (VDecl->isStaticDataMember() &&
VDecl->getLexicalDeclContext()->isRecord()) {
// This is an in-class initialization for a static data member, e.g.,
//
@@ -2663,7 +3303,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
// if it declares a static member (9.4) of const integral or
// const enumeration type, see 9.4.2.
QualType T = VDecl->getType();
- if (!T->isDependentType() &&
+ if (!T->isDependentType() &&
(!Context.getCanonicalType(T).isConstQualified() ||
!T->isIntegralType())) {
Diag(VDecl->getLocation(), diag::err_member_initialization)
@@ -2678,7 +3318,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
if (!Init->isTypeDependent() &&
!Init->getType()->isIntegralType()) {
// We have a non-dependent, non-integral or enumeration type.
- Diag(Init->getSourceRange().getBegin(),
+ Diag(Init->getSourceRange().getBegin(),
diag::err_in_class_initializer_non_integral_type)
<< Init->getType() << Init->getSourceRange();
VDecl->setInvalidDecl();
@@ -2701,7 +3341,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
VDecl->getDeclName(), DirectInit))
VDecl->setInvalidDecl();
-
+
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
// Don't check invalid declarations to avoid emitting useless diagnostics.
if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) {
@@ -2710,14 +3350,16 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
}
}
// If the type changed, it means we had an incomplete type that was
- // completed by the initializer. For example:
+ // completed by the initializer. For example:
// int ary[] = { 1, 3, 5 };
// "ary" transitions from a VariableArrayType to a ConstantArrayType.
if (!VDecl->isInvalidDecl() && (DclT != SavT)) {
VDecl->setType(DclT);
Init->setType(DclT);
}
-
+
+ Init = MaybeCreateCXXExprWithTemporaries(Init,
+ /*ShouldDestroyTemporaries=*/true);
// Attach the initializer to the decl.
VDecl->setInit(Context, Init);
@@ -2725,17 +3367,15 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
// remove it from the set of tentative definitions.
if (VDecl->getPreviousDeclaration() &&
VDecl->getPreviousDeclaration()->isTentativeDefinition(Context)) {
- llvm::DenseMap<DeclarationName, VarDecl *>::iterator Pos
- = TentativeDefinitions.find(VDecl->getDeclName());
- assert(Pos != TentativeDefinitions.end() &&
- "Unrecorded tentative definition?");
- TentativeDefinitions.erase(Pos);
+ bool Deleted = TentativeDefinitions.erase(VDecl->getDeclName());
+ assert(Deleted && "Unrecorded tentative definition?"); Deleted=Deleted;
}
return;
}
-void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
+void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
+ bool TypeContainsUndeducedAuto) {
Decl *RealDecl = dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it. Just ignore it.
@@ -2746,8 +3386,20 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
QualType Type = Var->getType();
// Record tentative definitions.
- if (Var->isTentativeDefinition(Context))
- TentativeDefinitions[Var->getDeclName()] = Var;
+ if (Var->isTentativeDefinition(Context)) {
+ std::pair<llvm::DenseMap<DeclarationName, VarDecl *>::iterator, bool>
+ InsertPair =
+ TentativeDefinitions.insert(std::make_pair(Var->getDeclName(), Var));
+
+ // Keep the latest definition in the map. If we see 'int i; int i;' we
+ // want the second one in the map.
+ InsertPair.first->second = Var;
+
+ // However, for the list, we don't care about the order, just make sure
+ // that there are no dupes for a given declaration name.
+ if (InsertPair.second)
+ TentativeDefinitionList.push_back(Var->getDeclName());
+ }
// C++ [dcl.init.ref]p3:
// The initializer can be omitted for a reference only in a
@@ -2763,46 +3415,72 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
return;
}
+ // C++0x [dcl.spec.auto]p3
+ if (TypeContainsUndeducedAuto) {
+ Diag(Var->getLocation(), diag::err_auto_var_requires_init)
+ << Var->getDeclName() << Type;
+ Var->setInvalidDecl();
+ return;
+ }
+
+ // C++ [temp.expl.spec]p15:
+ // An explicit specialization of a static data member of a template is a
+ // definition if the declaration includes an initializer; otherwise, it
+ // is a declaration.
+ if (Var->isStaticDataMember() &&
+ Var->getInstantiatedFromStaticDataMember() &&
+ Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
+
// C++ [dcl.init]p9:
- //
// If no initializer is specified for an object, and the object
// is of (possibly cv-qualified) non-POD class type (or array
// thereof), the object shall be default-initialized; if the
// object is of const-qualified type, the underlying class type
// shall have a user-declared default constructor.
+ //
+ // FIXME: Diagnose the "user-declared default constructor" bit.
if (getLangOptions().CPlusPlus) {
QualType InitType = Type;
if (const ArrayType *Array = Context.getAsArrayType(Type))
InitType = Array->getElementType();
- if ((!Var->hasExternalStorage() && !Var->isExternC(Context)) &&
+ if ((!Var->hasExternalStorage() && !Var->isExternC()) &&
InitType->isRecordType() && !InitType->isDependentType()) {
- CXXRecordDecl *RD =
- cast<CXXRecordDecl>(InitType->getAsRecordType()->getDecl());
- CXXConstructorDecl *Constructor = 0;
- if (!RequireCompleteType(Var->getLocation(), InitType,
- diag::err_invalid_incomplete_type_use))
- Constructor
- = PerformInitializationByConstructor(InitType, 0, 0,
+ if (!RequireCompleteType(Var->getLocation(), InitType,
+ diag::err_invalid_incomplete_type_use)) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(InitType,
+ MultiExprArg(*this, 0, 0),
Var->getLocation(),
SourceRange(Var->getLocation(),
Var->getLocation()),
Var->getDeclName(),
- IK_Default);
- if (!Constructor)
+ IK_Default,
+ ConstructorArgs);
+
+ // FIXME: Location info for the variable initialization?
+ if (!Constructor)
+ Var->setInvalidDecl();
+ else {
+ // FIXME: Cope with initialization of arrays
+ if (!Constructor->isTrivial() &&
+ InitializeVarWithConstructor(Var, Constructor, InitType,
+ move_arg(ConstructorArgs)))
+ Var->setInvalidDecl();
+
+ FinalizeVarWithDestructor(Var, InitType);
+ }
+ } else {
Var->setInvalidDecl();
- else {
- if (!RD->hasTrivialConstructor())
- InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0);
- // FIXME. Must do all that is needed to destroy the object
- // on scope exit. For now, just mark the destructor as used.
- MarkDestructorReferenced(Var->getLocation(), InitType);
}
}
}
#if 0
// FIXME: Temporarily disabled because we are not properly parsing
- // linkage specifications on declarations, e.g.,
+ // linkage specifications on declarations, e.g.,
//
// extern "C" const CGPoint CGPointerZero;
//
@@ -2844,7 +3522,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
for (unsigned i = 0; i != NumDecls; ++i)
if (Decl *D = Group[i].getAs<Decl>())
Decls.push_back(D);
-
+
// Perform semantic analysis that depends on having fully processed both
// the declarator and initializer.
for (unsigned i = 0, e = Decls.size(); i != e; ++i) {
@@ -2852,38 +3530,40 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (!IDecl)
continue;
QualType T = IDecl->getType();
-
+
// Block scope. C99 6.7p7: If an identifier for an object is declared with
// no linkage (C99 6.2.2p6), the type for the object shall be complete...
if (IDecl->isBlockVarDecl() && !IDecl->hasExternalStorage()) {
if (!IDecl->isInvalidDecl() &&
- RequireCompleteType(IDecl->getLocation(), T,
+ RequireCompleteType(IDecl->getLocation(), T,
diag::err_typecheck_decl_incomplete_type))
IDecl->setInvalidDecl();
}
- // File scope. C99 6.9.2p2: A declaration of an identifier for and
+ // File scope. C99 6.9.2p2: A declaration of an identifier for an
// object that has file scope without an initializer, and without a
// storage-class specifier or with the storage-class specifier "static",
// constitutes a tentative definition. Note: A tentative definition with
// external linkage is valid (C99 6.2.2p5).
- if (IDecl->isTentativeDefinition(Context)) {
- QualType CheckType = T;
- unsigned DiagID = diag::err_typecheck_decl_incomplete_type;
-
- const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(T);
- if (ArrayT) {
- CheckType = ArrayT->getElementType();
- DiagID = diag::err_illegal_decl_array_incomplete_type;
- }
-
- if (IDecl->isInvalidDecl()) {
- // Do nothing with invalid declarations
- } else if ((ArrayT || IDecl->getStorageClass() == VarDecl::Static) &&
- RequireCompleteType(IDecl->getLocation(), CheckType, DiagID)) {
+ if (IDecl->isTentativeDefinition(Context) && !IDecl->isInvalidDecl()) {
+ if (const IncompleteArrayType *ArrayT
+ = Context.getAsIncompleteArrayType(T)) {
+ if (RequireCompleteType(IDecl->getLocation(),
+ ArrayT->getElementType(),
+ diag::err_illegal_decl_array_incomplete_type))
+ IDecl->setInvalidDecl();
+ } else if (IDecl->getStorageClass() == VarDecl::Static) {
// C99 6.9.2p3: If the declaration of an identifier for an object is
- // a tentative definition and has internal linkage (C99 6.2.2p3), the
+ // a tentative definition and has internal linkage (C99 6.2.2p3), the
// declared type shall not be an incomplete type.
- IDecl->setInvalidDecl();
+ // NOTE: code such as the following
+ // static struct s;
+ // struct s { int a; };
+ // is accepted by gcc. Hence here we issue a warning instead of
+ // an error and we do not invalidate the static declaration.
+ // NOTE: to avoid multiple warnings, only check the first declaration.
+ if (IDecl->getPreviousDeclaration() == 0)
+ RequireCompleteType(IDecl->getLocation(), T,
+ diag::ext_typecheck_decl_incomplete_type);
}
}
}
@@ -2894,7 +3574,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
/// to introduce parameters into function prototype scope.
-Sema::DeclPtrTy
+Sema::DeclPtrTy
Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
@@ -2917,10 +3597,12 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// parameter (C++ only).
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
-
+
+ DeclaratorInfo *DInfo = 0;
TagDecl *OwnedDecl = 0;
- QualType parmDeclType = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedDecl);
-
+ QualType parmDeclType = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0,
+ &OwnedDecl);
+
if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) {
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
@@ -2933,7 +3615,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// among each other. Here they can only shadow globals, which is ok.
IdentifierInfo *II = D.getIdentifier();
if (II) {
- if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) {
+ if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) {
if (PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
@@ -2951,26 +3633,26 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Parameters can not be abstract class types.
// For record types, this is done by the AbstractClassUsageDiagnoser once
- // the class has been completely parsed.
- if (!CurContext->isRecord() &&
- RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType,
+ // the class has been completely parsed.
+ if (!CurContext->isRecord() &&
+ RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType,
diag::err_abstract_type_in_decl,
AbstractParamType))
D.setInvalidType(true);
QualType T = adjustParameterType(parmDeclType);
-
+
ParmVarDecl *New;
if (T == parmDeclType) // parameter type did not need adjustment
- New = ParmVarDecl::Create(Context, CurContext,
+ New = ParmVarDecl::Create(Context, CurContext,
D.getIdentifierLoc(), II,
- parmDeclType, StorageClass,
+ parmDeclType, DInfo, StorageClass,
0);
else // keep track of both the adjusted and unadjusted types
- New = OriginalParmVarDecl::Create(Context, CurContext,
- D.getIdentifierLoc(), II, T,
+ New = OriginalParmVarDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), II, T, DInfo,
parmDeclType, StorageClass, 0);
-
+
if (D.isInvalidType())
New->setInvalidDecl();
@@ -2981,14 +3663,25 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
New->setInvalidDecl();
}
-
+
// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
<< D.getCXXScopeSpec().getRange();
New->setInvalidDecl();
}
-
+
+ // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
+ // duration shall not be qualified by an address-space qualifier."
+ // Since all parameters have automatic store duration, they can not have
+ // an address space.
+ if (T.getAddressSpace() != 0) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_arg_with_address_space);
+ New->setInvalidDecl();
+ }
+
+
// Add the parameter declaration into this scope.
S->AddDecl(DeclPtrTy::make(New));
if (II)
@@ -3025,14 +3718,15 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
// type.
DeclSpec DS;
const char* PrevSpec; // unused
- DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
- PrevSpec);
+ unsigned DiagID; // unused
+ DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
+ PrevSpec, DiagID);
Declarator ParamD(DS, Declarator::KNRTypeListContext);
ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc);
FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD);
}
}
- }
+ }
}
Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
@@ -3043,12 +3737,12 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
if (FTI.hasPrototype) {
- // FIXME: Diagnose arguments without names in C.
+ // FIXME: Diagnose arguments without names in C.
}
-
+
Scope *ParentScope = FnBodyScope->getParent();
- DeclPtrTy DP = HandleDeclarator(ParentScope, D,
+ DeclPtrTy DP = HandleDeclarator(ParentScope, D,
MultiTemplateParamsArg(*this),
/*IsFunctionDefinition=*/true);
return ActOnStartOfFunctionDef(FnBodyScope, DP);
@@ -3057,10 +3751,16 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
if (!D)
return D;
- FunctionDecl *FD = cast<FunctionDecl>(D.getAs<Decl>());
+ FunctionDecl *FD = 0;
+
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(D.getAs<Decl>()))
+ FD = FunTmpl->getTemplatedDecl();
+ else
+ FD = cast<FunctionDecl>(D.getAs<Decl>());
CurFunctionNeedsScopeChecking = false;
-
+
// See if this is a redefinition.
const FunctionDecl *Definition;
if (FD->getBody(Definition)) {
@@ -3069,7 +3769,7 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
}
// Builtin functions cannot be defined.
- if (unsigned BuiltinID = FD->getBuiltinID(Context)) {
+ if (unsigned BuiltinID = FD->getBuiltinID()) {
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) {
Diag(FD->getLocation(), diag::err_builtin_definition) << FD;
FD->setInvalidDecl();
@@ -3126,7 +3826,7 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
// Checking attributes of current function definition
// dllimport attribute.
- if (FD->getAttr<DLLImportAttr>() &&
+ if (FD->getAttr<DLLImportAttr>() &&
(!FD->getAttr<DLLExportAttr>())) {
// dllimport attribute cannot be applied to definition.
if (!(FD->getAttr<DLLImportAttr>())->isInherited()) {
@@ -3155,23 +3855,39 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
bool IsInstantiation) {
Decl *dcl = D.getAs<Decl>();
Stmt *Body = BodyArg.takeAs<Stmt>();
- if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(dcl)) {
+
+ FunctionDecl *FD = 0;
+ FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
+ if (FunTmpl)
+ FD = FunTmpl->getTemplatedDecl();
+ else
+ FD = dyn_cast_or_null<FunctionDecl>(dcl);
+
+ if (FD) {
FD->setBody(Body);
-
+ if (FD->isMain())
+ // C and C++ allow for main to automagically return 0.
+ // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
+ FD->setHasImplicitReturnZero(true);
+ else
+ CheckFallThroughForFunctionDef(FD, Body);
+
if (!FD->isInvalidDecl())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
-
+
// C++ [basic.def.odr]p2:
// [...] A virtual member function is used if it is not pure. [...]
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
if (Method->isVirtual() && !Method->isPure())
MarkDeclarationReferenced(Method->getLocation(), Method);
-
+
assert(FD == getCurFunctionDecl() && "Function parsing confused");
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
-
+ CheckFallThroughForFunctionDef(MD, Body);
+ MD->setEndLoc(Body->getLocEnd());
+
if (!MD->isInvalidDecl())
DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
} else {
@@ -3184,21 +3900,21 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
// Verify and clean out per-function state.
assert(&getLabelMap() == &FunctionLabelMap && "Didn't pop block right?");
-
+
// Check goto/label use.
for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
I = FunctionLabelMap.begin(), E = FunctionLabelMap.end(); I != E; ++I) {
LabelStmt *L = I->second;
-
+
// Verify that we have no forward references left. If so, there was a goto
// or address of a label taken, but no definition of it. Label fwd
// definitions are indicated with a null substmt.
if (L->getSubStmt() != 0)
continue;
-
+
// Emit error.
Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName();
-
+
// At this point, we have gotos that use the bogus label. Stitch it into
// the function body so that they aren't leaked and that the AST is well
// formed.
@@ -3207,7 +3923,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
L->Destroy(Context);
continue;
}
-
+
// Otherwise, the body is valid: we want to stitch the label decl into the
// function somewhere so that it is properly owned and so that the goto
// has a valid target. Do this by creating a new compound stmt with the
@@ -3231,17 +3947,20 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
if (CurFunctionNeedsScopeChecking)
DiagnoseInvalidJumps(Body);
- // C++ constructors that have function-try-blocks can't have return statements
- // in the handlers of that block. (C++ [except.handle]p14) Verify this.
- if (isa<CXXConstructorDecl>(dcl) && isa<CXXTryStmt>(Body))
+ // C++ constructors that have function-try-blocks can't have return
+ // statements in the handlers of that block. (C++ [except.handle]p14)
+ // Verify this.
+ if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body))
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
+ if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
+ computeBaseOrMembersToDestroy(Destructor);
return D;
}
/// ImplicitlyDefineFunction - An undeclared identifier was used in a function
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
-NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
+NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
IdentifierInfo &II, Scope *S) {
// Before we produce a declaration for an implicitly defined
// function, see whether there was a locally-scoped declaration of
@@ -3256,25 +3975,26 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
}
// Extension in C99. Legal in C90, but warn about it.
- if (getLangOptions().C99)
+ static const unsigned int BuiltinLen = strlen("__builtin_");
+ if (II.getLength() > BuiltinLen &&
+ std::equal(II.getName(), II.getName() + BuiltinLen, "__builtin_"))
+ Diag(Loc, diag::warn_builtin_unknown) << &II;
+ else if (getLangOptions().C99)
Diag(Loc, diag::ext_implicit_function_decl) << &II;
else
Diag(Loc, diag::warn_implicit_function_decl) << &II;
-
- // FIXME: handle stuff like:
- // void foo() { extern float X(); }
- // void bar() { X(); } <-- implicit decl for X in another scope.
// Set a Declarator for the implicit definition: int foo();
const char *Dummy;
DeclSpec DS;
- bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy);
+ unsigned DiagID;
+ bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID);
Error = Error; // Silence warning.
assert(!Error && "Error setting up implicit decl!");
Declarator D(DS, Declarator::BlockContext);
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
0, 0, false, SourceLocation(),
- false, 0,0,0, Loc, D),
+ false, 0,0,0, Loc, Loc, D),
SourceLocation());
D.SetIdentifier(&II, Loc);
@@ -3282,8 +4002,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
DeclContext *PrevDC = CurContext;
CurContext = Context.getTranslationUnitDecl();
-
- FunctionDecl *FD =
+
+ FunctionDecl *FD =
dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D).getAs<Decl>());
FD->setImplicit();
@@ -3306,7 +4026,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
// If this is a built-in function, map its builtin attributes to
// actual attributes.
- if (unsigned BuiltinID = FD->getBuiltinID(Context)) {
+ if (unsigned BuiltinID = FD->getBuiltinID()) {
// Handle printf-formatting attributes.
unsigned FormatIdx;
bool HasVAListArg;
@@ -3324,15 +4044,18 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
if (!FD->getAttr<ConstAttr>())
FD->addAttr(::new (Context) ConstAttr());
}
+
+ if (Context.BuiltinInfo.isNoReturn(BuiltinID))
+ FD->addAttr(::new (Context) NoReturnAttr());
}
IdentifierInfo *Name = FD->getIdentifier();
if (!Name)
return;
- if ((!getLangOptions().CPlusPlus &&
+ if ((!getLangOptions().CPlusPlus &&
FD->getDeclContext()->isTranslationUnit()) ||
(isa<LinkageSpecDecl>(FD->getDeclContext()) &&
- cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() ==
+ cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() ==
LinkageSpecDecl::lang_c)) {
// Okay: this could be a libc/libm/Objective-C function we know
// about.
@@ -3340,13 +4063,16 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
return;
if (Name->isStr("NSLog") || Name->isStr("NSLogv")) {
+ // FIXME: NSLog and NSLogv should be target specific
if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) {
// FIXME: We known better than our headers.
const_cast<FormatAttr *>(Format)->setType("printf");
- } else
+ } else
FD->addAttr(::new (Context) FormatAttr("printf", 1,
Name->isStr("NSLogv") ? 0 : 2));
} else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
+ // FIXME: asprintf and vasprintf aren't C99 functions. Should they be
+ // target-specific builtins, perhaps?
if (!FD->getAttr<FormatAttr>())
FD->addAttr(::new (Context) FormatAttr("printf", 2,
Name->isStr("vasprintf") ? 0 : 3));
@@ -3356,16 +4082,16 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) {
assert(D.getIdentifier() && "Wrong callback for declspec without declarator");
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
-
+
// Scope manipulation handled by caller.
TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext,
D.getIdentifierLoc(),
- D.getIdentifier(),
+ D.getIdentifier(),
T);
-
- if (TagType *TT = dyn_cast<TagType>(T)) {
+
+ if (const TagType *TT = T->getAs<TagType>()) {
TagDecl *TD = TT->getDecl();
-
+
// If the TagDecl that the TypedefDecl points to is an anonymous decl
// keep track of the TypedefDecl.
if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl())
@@ -3382,7 +4108,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) {
/// as a redeclaration of the given tag declaration.
///
/// \returns true if the new tag kind is acceptable, false otherwise.
-bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
+bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
TagDecl::TagKind NewTag,
SourceLocation NewTagLoc,
const IdentifierInfo &Name) {
@@ -3402,7 +4128,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
TagDecl::TagKind OldTag = Previous->getTagKind();
if (OldTag == NewTag)
return true;
-
+
if ((OldTag == TagDecl::TK_struct || OldTag == TagDecl::TK_class) &&
(NewTag == TagDecl::TK_struct || NewTag == TagDecl::TK_class)) {
// Warn about the struct/class tag mismatch.
@@ -3423,33 +4149,58 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the
/// former case, Name will be non-null. In the later case, Name will be null.
-/// TagSpec indicates what kind of tag this is. TK indicates whether this is a
+/// TagSpec indicates what kind of tag this is. TUK indicates whether this is a
/// reference/declaration/definition of a tag.
-Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
+Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
- bool &OwnedDecl) {
+ MultiTemplateParamsArg TemplateParameterLists,
+ bool &OwnedDecl, bool &IsDependent) {
// If this is not a definition, it must have a name.
- assert((Name != 0 || TK == TK_Definition) &&
+ assert((Name != 0 || TUK == TUK_Definition) &&
"Nameless record must be a definition!");
OwnedDecl = false;
- TagDecl::TagKind Kind;
- switch (TagSpec) {
- default: assert(0 && "Unknown tag type!");
- case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
- case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
- case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
- case DeclSpec::TST_enum: Kind = TagDecl::TK_enum; break;
+ TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
+
+ // FIXME: Check explicit specializations more carefully.
+ bool isExplicitSpecialization = false;
+ if (TUK != TUK_Reference) {
+ if (TemplateParameterList *TemplateParams
+ = MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
+ (TemplateParameterList**)TemplateParameterLists.get(),
+ TemplateParameterLists.size(),
+ isExplicitSpecialization)) {
+ if (TemplateParams->size() > 0) {
+ // This is a declaration or definition of a class template (which may
+ // be a member of another template).
+ OwnedDecl = false;
+ DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc,
+ SS, Name, NameLoc, Attr,
+ TemplateParams,
+ AS);
+ TemplateParameterLists.release();
+ return Result.get();
+ } else {
+ // The "template<>" header is extraneous.
+ Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
+ << ElaboratedType::getNameForTagKind(Kind) << Name;
+ isExplicitSpecialization = true;
+ }
+ }
+
+ TemplateParameterLists.release();
}
-
+
DeclContext *SearchDC = CurContext;
DeclContext *DC = CurContext;
NamedDecl *PrevDecl = 0;
-
+ bool isStdBadAlloc = false;
bool Invalid = false;
+ bool RedeclarationOnly = (TUK != TUK_Reference);
+
if (Name && SS.isNotEmpty()) {
// We have a nested-name tag ('struct foo::bar').
@@ -3459,18 +4210,35 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
goto CreateNewDecl;
}
+ // If this is a friend or a reference to a class in a dependent
+ // context, don't try to make a decl for it.
+ if (TUK == TUK_Friend || TUK == TUK_Reference) {
+ DC = computeDeclContext(SS, false);
+ if (!DC) {
+ IsDependent = true;
+ return DeclPtrTy();
+ }
+ }
+
if (RequireCompleteDeclContext(SS))
return DeclPtrTy::make((Decl *)0);
- DC = computeDeclContext(SS);
+ DC = computeDeclContext(SS, true);
SearchDC = DC;
// Look-up name inside 'foo::'.
- PrevDecl
- = dyn_cast_or_null<TagDecl>(
- LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl());
+ LookupResult R;
+ LookupQualifiedName(R, DC, Name, LookupTagName, RedeclarationOnly);
+
+ if (R.isAmbiguous()) {
+ DiagnoseAmbiguousLookup(R, Name, NameLoc, SS.getRange());
+ return DeclPtrTy();
+ }
+
+ if (R.getKind() == LookupResult::Found)
+ PrevDecl = dyn_cast<TagDecl>(R.getFoundDecl());
// A tag 'foo::bar' must already exist.
- if (PrevDecl == 0) {
+ if (!PrevDecl) {
Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange();
Name = 0;
Invalid = true;
@@ -3482,8 +4250,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
// FIXME: We're looking into outer scopes here, even when we
// shouldn't be. Doing so can result in ambiguities that we
// shouldn't be diagnosing.
- LookupResult R = LookupName(S, Name, LookupTagName,
- /*RedeclarationOnly=*/(TK != TK_Reference));
+ LookupResult R;
+ LookupName(R, S, Name, LookupTagName, RedeclarationOnly);
if (R.isAmbiguous()) {
DiagnoseAmbiguousLookup(R, Name, NameLoc);
// FIXME: This is not best way to recover from case like:
@@ -3494,11 +4262,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
Name = 0;
PrevDecl = 0;
Invalid = true;
- }
- else
- PrevDecl = R;
+ } else
+ PrevDecl = R.getAsSingleDecl(Context);
- if (!getLangOptions().CPlusPlus && TK != TK_Reference) {
+ if (!getLangOptions().CPlusPlus && TUK != TUK_Reference) {
// FIXME: This makes sure that we ignore the contexts associated
// with C structs, unions, and enums when looking for a matching
// tag declaration or definition. See the similar lookup tweak
@@ -3515,23 +4282,37 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
PrevDecl = 0;
}
+ if (getLangOptions().CPlusPlus && Name && DC && StdNamespace &&
+ DC->Equals(StdNamespace) && Name->isStr("bad_alloc")) {
+ // This is a declaration of or a reference to "std::bad_alloc".
+ isStdBadAlloc = true;
+
+ if (!PrevDecl && StdBadAlloc) {
+ // std::bad_alloc has been implicitly declared (but made invisible to
+ // name lookup). Fill in this implicit declaration as the previous
+ // declaration, so that the declarations get chained appropriately.
+ PrevDecl = StdBadAlloc;
+ }
+ }
+
if (PrevDecl) {
// Check whether the previous declaration is usable.
(void)DiagnoseUseOfDecl(PrevDecl, NameLoc);
-
+
if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
// If this is a use of a previous tag, or if the tag is already declared
// in the same scope (so that the definition/declaration completes or
// rementions the tag), reuse the decl.
- if (TK == TK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) {
+ if (TUK == TUK_Reference || TUK == TUK_Friend ||
+ isDeclInScope(PrevDecl, SearchDC, S)) {
// Make sure that this wasn't declared as an enum and now used as a
// struct or something similar.
if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
- bool SafeToContinue
+ bool SafeToContinue
= (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
Kind != TagDecl::TK_enum);
if (SafeToContinue)
- Diag(KWLoc, diag::err_use_with_wrong_tag)
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
<< CodeModificationHint::CreateReplacement(SourceRange(KWLoc),
PrevTagDecl->getKindName());
@@ -3539,7 +4320,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
Diag(PrevDecl->getLocation(), diag::note_previous_use);
- if (SafeToContinue)
+ if (SafeToContinue)
Kind = PrevTagDecl->getTagKind();
else {
// Recover by making this an anonymous redefinition.
@@ -3556,27 +4337,35 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
// for the consumer of this Decl to know it doesn't own it.
// For our current ASTs this shouldn't be a problem, but will
// need to be changed with DeclGroups.
- if (TK == TK_Reference)
+ if (TUK == TUK_Reference || TUK == TUK_Friend)
return DeclPtrTy::make(PrevDecl);
// Diagnose attempts to redefine a tag.
- if (TK == TK_Definition) {
+ if (TUK == TUK_Definition) {
if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) {
- Diag(NameLoc, diag::err_redefinition) << Name;
- Diag(Def->getLocation(), diag::note_previous_definition);
- // If this is a redefinition, recover by making this
- // struct be anonymous, which will make any later
- // references get the previous definition.
- Name = 0;
- PrevDecl = 0;
- Invalid = true;
+ // If we're defining a specialization and the previous definition
+ // is from an implicit instantiation, don't emit an error
+ // here; we'll catch this in the general case below.
+ if (!isExplicitSpecialization ||
+ !isa<CXXRecordDecl>(Def) ||
+ cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization) {
+ Diag(NameLoc, diag::err_redefinition) << Name;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ // If this is a redefinition, recover by making this
+ // struct be anonymous, which will make any later
+ // references get the previous definition.
+ Name = 0;
+ PrevDecl = 0;
+ Invalid = true;
+ }
} else {
// If the type is currently being defined, complain
// about a nested redefinition.
TagType *Tag = cast<TagType>(Context.getTagDeclType(PrevTagDecl));
if (Tag->isBeingDefined()) {
Diag(NameLoc, diag::err_nested_redefinition) << Name;
- Diag(PrevTagDecl->getLocation(),
+ Diag(PrevTagDecl->getLocation(),
diag::note_previous_definition);
Name = 0;
PrevDecl = 0;
@@ -3589,10 +4378,11 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
}
}
// If we get here we have (another) forward declaration or we
- // have a definition. Just create a new decl.
+ // have a definition. Just create a new decl.
+
} else {
// If we get here, this is a definition of a new tag type in a nested
- // scope, e.g. "struct foo; void bar() { struct foo; }", just create a
+ // scope, e.g. "struct foo; void bar() { struct foo; }", just create a
// new decl/type. We set PrevDecl to NULL so that the entities
// have distinct types.
PrevDecl = 0;
@@ -3617,10 +4407,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
PrevDecl = 0;
}
}
- } else if (TK == TK_Reference && SS.isEmpty() && Name &&
+ } else if (TUK == TUK_Reference && SS.isEmpty() && Name &&
(Kind != TagDecl::TK_enum || !getLangOptions().CPlusPlus)) {
// C++ [basic.scope.pdecl]p5:
- // -- for an elaborated-type-specifier of the form
+ // -- for an elaborated-type-specifier of the form
//
// class-key identifier
//
@@ -3641,26 +4431,38 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
//
// Find the context where we'll be declaring the tag.
// FIXME: We would like to maintain the current DeclContext as the
- // lexical context,
+ // lexical context,
while (SearchDC->isRecord())
SearchDC = SearchDC->getParent();
// Find the scope where we'll be declaring the tag.
- while (S->isClassScope() ||
+ while (S->isClassScope() ||
(getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) ||
((S->getFlags() & Scope::DeclScope) == 0) ||
- (S->getEntity() &&
+ (S->getEntity() &&
((DeclContext *)S->getEntity())->isTransparentContext()))
S = S->getParent();
+
+ } else if (TUK == TUK_Friend && SS.isEmpty() && Name) {
+ // C++ [namespace.memdef]p3:
+ // If a friend declaration in a non-local class first declares a
+ // class or function, the friend class or function is a member of
+ // the innermost enclosing namespace.
+ while (!SearchDC->isFileContext())
+ SearchDC = SearchDC->getParent();
+
+ // The entity of a decl scope is a DeclContext; see PushDeclContext.
+ while (S->getEntity() != SearchDC)
+ S = S->getParent();
}
CreateNewDecl:
-
+
// If there is an identifier, use the location of the identifier as the
// location of the decl, otherwise use the location of the struct/union
// keyword.
SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc;
-
+
// Otherwise, create a new declaration. If there is a previous
// declaration of the same entity, the two will be linked via
// PrevDecl.
@@ -3669,10 +4471,10 @@ CreateNewDecl:
if (Kind == TagDecl::TK_enum) {
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
// enum X { A, B, C } D; D should chain to X.
- New = EnumDecl::Create(Context, SearchDC, Loc, Name,
+ New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc,
cast_or_null<EnumDecl>(PrevDecl));
// If this is an undefined enum, warn.
- if (TK != TK_Definition && !Invalid) {
+ if (TUK != TUK_Definition && !Invalid) {
unsigned DK = getLangOptions().CPlusPlus? diag::err_forward_ref_enum
: diag::ext_forward_ref_enum;
Diag(Loc, DK);
@@ -3682,12 +4484,15 @@ CreateNewDecl:
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
// struct X { int A; } D; D should chain to X.
- if (getLangOptions().CPlusPlus)
+ if (getLangOptions().CPlusPlus) {
// FIXME: Look for a way to use RecordDecl for simple structs.
- New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
+ New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc,
cast_or_null<CXXRecordDecl>(PrevDecl));
- else
- New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
+
+ if (isStdBadAlloc && (!StdBadAlloc || StdBadAlloc->isImplicit()))
+ StdBadAlloc = cast<CXXRecordDecl>(New);
+ } else
+ New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc,
cast_or_null<RecordDecl>(PrevDecl));
}
@@ -3704,7 +4509,7 @@ CreateNewDecl:
// the #pragma tokens are effectively skipped over during the
// parsing of the struct).
if (unsigned Alignment = getPragmaPackAlignment())
- New->addAttr(::new (Context) PackedAttr(Alignment * 8));
+ New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8));
}
if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) {
@@ -3713,12 +4518,14 @@ CreateNewDecl:
// shall not be declared with the same name as a typedef-name
// that is declared in that scope and refers to a type other
// than the class or enumeration itself.
- LookupResult Lookup = LookupName(S, Name, LookupOrdinaryName, true);
+ LookupResult Lookup;
+ LookupName(Lookup, S, Name, LookupOrdinaryName, true);
TypedefDecl *PrevTypedef = 0;
- if (Lookup.getKind() == LookupResult::Found)
- PrevTypedef = dyn_cast<TypedefDecl>(Lookup.getAsDecl());
+ if (NamedDecl *Prev = Lookup.getAsSingleDecl(Context))
+ PrevTypedef = dyn_cast<TypedefDecl>(Prev);
- if (PrevTypedef && isDeclInScope(PrevTypedef, SearchDC, S) &&
+ NamedDecl *PrevTypedefNamed = PrevTypedef;
+ if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) &&
Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) !=
Context.getCanonicalType(Context.getTypeDeclType(New))) {
Diag(Loc, diag::err_tag_definition_of_typedef)
@@ -3729,6 +4536,11 @@ CreateNewDecl:
}
}
+ // If this is a specialization of a member class (of a class template),
+ // check the specialization.
+ if (isExplicitSpecialization && CheckMemberSpecialization(New, PrevDecl))
+ Invalid = true;
+
if (Invalid)
New->setInvalidDecl();
@@ -3744,21 +4556,45 @@ CreateNewDecl:
// lexical context will be different from the semantic context.
New->setLexicalDeclContext(CurContext);
+ // Mark this as a friend decl if applicable.
+ if (TUK == TUK_Friend)
+ New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ PrevDecl != NULL);
+
// Set the access specifier.
- if (!Invalid)
+ if (!Invalid && TUK != TUK_Friend)
SetMemberAccessSpecifier(New, PrevDecl, AS);
- if (TK == TK_Definition)
+ if (TUK == TUK_Definition)
New->startDefinition();
-
+
// If this has an identifier, add it to the scope stack.
- if (Name) {
+ if (TUK == TUK_Friend) {
+ // We might be replacing an existing declaration in the lookup tables;
+ // if so, borrow its access specifier.
+ if (PrevDecl)
+ New->setAccess(PrevDecl->getAccess());
+
+ // Friend tag decls are visible in fairly strange ways.
+ if (!CurContext->isDependentContext()) {
+ DeclContext *DC = New->getDeclContext()->getLookupContext();
+ DC->makeDeclVisibleInContext(New, /* Recoverable = */ false);
+ if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
+ PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false);
+ }
+ } else if (Name) {
S = getNonFieldDeclScope(S);
PushOnScopeChains(New, S);
} else {
CurContext->addDecl(New);
}
+ // If this is the C FILE type, notify the AST context.
+ if (IdentifierInfo *II = New->getIdentifier())
+ if (!New->isInvalidDecl() &&
+ New->getDeclContext()->getLookupContext()->isTranslationUnit() &&
+ II->isStr("FILE"))
+ Context.setFILEDecl(New);
+
OwnedDecl = true;
return DeclPtrTy::make(New);
}
@@ -3774,7 +4610,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
FieldCollector->StartClass();
if (Record->getIdentifier()) {
- // C++ [class]p2:
+ // C++ [class]p2:
// [...] The class-name is also inserted into the scope of the
// class itself; this is known as the injected-class-name. For
// purposes of access checking, the injected-class-name is treated
@@ -3782,21 +4618,25 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
CXXRecordDecl *InjectedClassName
= CXXRecordDecl::Create(Context, Record->getTagKind(),
CurContext, Record->getLocation(),
- Record->getIdentifier(), Record);
+ Record->getIdentifier(),
+ Record->getTagKeywordLoc(),
+ Record);
InjectedClassName->setImplicit();
InjectedClassName->setAccess(AS_public);
if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate())
InjectedClassName->setDescribedClassTemplate(Template);
PushOnScopeChains(InjectedClassName, S);
- assert(InjectedClassName->isInjectedClassName() &&
+ assert(InjectedClassName->isInjectedClassName() &&
"Broken injected-class-name");
}
}
}
-void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD) {
+void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
+ SourceLocation RBraceLoc) {
AdjustDeclIfTemplate(TagD);
TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
+ Tag->setRBraceLoc(RBraceLoc);
if (isa<CXXRecordDecl>(Tag))
FieldCollector->FinishClass();
@@ -3809,9 +4649,13 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD) {
}
// Note that FieldName may be null for anonymous bitfields.
-bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
- QualType FieldTy, const Expr *BitWidth) {
-
+bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
+ QualType FieldTy, const Expr *BitWidth,
+ bool *ZeroWidth) {
+ // Default to true; that shouldn't confuse checks for emptiness
+ if (ZeroWidth)
+ *ZeroWidth = true;
+
// C99 6.7.2.1p4 - verify the field type.
// C++ 9.6p3: A bit-field shall have integral or enumeration type.
if (!FieldTy->isDependentType() && !FieldTy->isIntegralType()) {
@@ -3834,13 +4678,16 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
if (VerifyIntegerConstantExpression(BitWidth, &Value))
return true;
+ if (Value != 0 && ZeroWidth)
+ *ZeroWidth = false;
+
// Zero-width bitfield is ok for anonymous field.
if (Value == 0 && FieldName)
return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName;
-
+
if (Value.isSigned() && Value.isNegative()) {
if (FieldName)
- return Diag(FieldLoc, diag::err_bitfield_has_negative_width)
+ return Diag(FieldLoc, diag::err_bitfield_has_negative_width)
<< FieldName << Value.toString(10);
return Diag(FieldLoc, diag::err_anon_bitfield_has_negative_width)
<< Value.toString(10);
@@ -3863,7 +4710,7 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
/// ActOnField - Each field of a struct/union/class is passed into this in order
/// to create a FieldDecl object for it.
Sema::DeclPtrTy Sema::ActOnField(Scope *S, DeclPtrTy TagD,
- SourceLocation DeclStart,
+ SourceLocation DeclStart,
Declarator &D, ExprTy *BitfieldWidth) {
FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD.getAs<Decl>()),
DeclStart, D, static_cast<Expr*>(BitfieldWidth),
@@ -3880,8 +4727,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
IdentifierInfo *II = D.getIdentifier();
SourceLocation Loc = DeclStart;
if (II) Loc = D.getIdentifierLoc();
-
- QualType T = GetTypeForDeclarator(D, S);
+
+ DeclaratorInfo *DInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &DInfo);
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
@@ -3890,7 +4738,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
- NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true);
+ NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, true);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
@@ -3902,10 +4750,12 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
if (PrevDecl && !isDeclInScope(PrevDecl, Record, S))
PrevDecl = 0;
- FieldDecl *NewFD
- = CheckFieldDecl(II, T, Record, Loc,
- D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable,
- BitWidth, AS, PrevDecl, &D);
+ bool Mutable
+ = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
+ SourceLocation TSSL = D.getSourceRange().getBegin();
+ FieldDecl *NewFD
+ = CheckFieldDecl(II, T, DInfo, Record, Loc, Mutable, BitWidth, TSSL,
+ AS, PrevDecl, &D);
if (NewFD->isInvalidDecl() && PrevDecl) {
// Don't introduce NewFD into scope; there's already something
// with the same name in the same scope.
@@ -3926,10 +4776,12 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
///
/// \returns a new FieldDecl.
///
-/// \todo The Declarator argument is a hack. It will be removed once
-FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
+/// \todo The Declarator argument is a hack. It will be removed once
+FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
+ DeclaratorInfo *DInfo,
RecordDecl *Record, SourceLocation Loc,
- bool Mutable, Expr *BitWidth,
+ bool Mutable, Expr *BitWidth,
+ SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D) {
IdentifierInfo *II = Name.getAsIdentifierInfo();
@@ -3957,25 +4809,26 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
Diag(Loc, diag::err_typecheck_negative_array_size);
else
Diag(Loc, diag::err_typecheck_field_variable_size);
- T = Context.IntTy;
InvalidDecl = true;
}
}
-
+
// Fields can not have abstract class types
- if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl,
+ if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl,
AbstractFieldType))
InvalidDecl = true;
-
+
+ bool ZeroWidth = false;
// If this is declared as a bit-field, check the bit-field.
- if (BitWidth && VerifyBitField(Loc, II, T, BitWidth)) {
+ if (BitWidth && VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) {
InvalidDecl = true;
DeleteExpr(BitWidth);
BitWidth = 0;
+ ZeroWidth = false;
}
-
- FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, BitWidth,
- Mutable);
+
+ FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, DInfo,
+ BitWidth, Mutable);
if (InvalidDecl)
NewFD->setInvalidDecl();
@@ -3985,8 +4838,61 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
NewFD->setInvalidDecl();
}
- if (getLangOptions().CPlusPlus && !T->isPODType())
- cast<CXXRecordDecl>(Record)->setPOD(false);
+ if (getLangOptions().CPlusPlus) {
+ QualType EltTy = Context.getBaseElementType(T);
+
+ CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record);
+
+ if (!T->isPODType())
+ CXXRecord->setPOD(false);
+ if (!ZeroWidth)
+ CXXRecord->setEmpty(false);
+
+ if (const RecordType *RT = EltTy->getAs<RecordType>()) {
+ CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
+
+ if (!RDecl->hasTrivialConstructor())
+ CXXRecord->setHasTrivialConstructor(false);
+ if (!RDecl->hasTrivialCopyConstructor())
+ CXXRecord->setHasTrivialCopyConstructor(false);
+ if (!RDecl->hasTrivialCopyAssignment())
+ CXXRecord->setHasTrivialCopyAssignment(false);
+ if (!RDecl->hasTrivialDestructor())
+ CXXRecord->setHasTrivialDestructor(false);
+
+ // C++ 9.5p1: An object of a class with a non-trivial
+ // constructor, a non-trivial copy constructor, a non-trivial
+ // destructor, or a non-trivial copy assignment operator
+ // cannot be a member of a union, nor can an array of such
+ // objects.
+ // TODO: C++0x alters this restriction significantly.
+ if (Record->isUnion()) {
+ // We check for copy constructors before constructors
+ // because otherwise we'll never get complaints about
+ // copy constructors.
+
+ const CXXSpecialMember invalid = (CXXSpecialMember) -1;
+
+ CXXSpecialMember member;
+ if (!RDecl->hasTrivialCopyConstructor())
+ member = CXXCopyConstructor;
+ else if (!RDecl->hasTrivialConstructor())
+ member = CXXDefaultConstructor;
+ else if (!RDecl->hasTrivialCopyAssignment())
+ member = CXXCopyAssignment;
+ else if (!RDecl->hasTrivialDestructor())
+ member = CXXDestructor;
+ else
+ member = invalid;
+
+ if (member != invalid) {
+ Diag(Loc, diag::err_illegal_union_member) << Name << member;
+ DiagnoseNontrivial(RT, member);
+ NewFD->setInvalidDecl();
+ }
+ }
+ }
+ }
// FIXME: We need to pass in the attributes given an AST
// representation, not a parser representation.
@@ -4013,7 +4919,131 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
return NewFD;
}
-/// TranslateIvarVisibility - Translate visibility from a token ID to an
+/// DiagnoseNontrivial - Given that a class has a non-trivial
+/// special member, figure out why.
+void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
+ QualType QT(T, 0U);
+ CXXRecordDecl* RD = cast<CXXRecordDecl>(T->getDecl());
+
+ // Check whether the member was user-declared.
+ switch (member) {
+ case CXXDefaultConstructor:
+ if (RD->hasUserDeclaredConstructor()) {
+ typedef CXXRecordDecl::ctor_iterator ctor_iter;
+ for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce; ++ci)
+ if (!ci->isImplicitlyDefined(Context)) {
+ SourceLocation CtorLoc = ci->getLocation();
+ Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+
+ assert(0 && "found no user-declared constructors");
+ return;
+ }
+ break;
+
+ case CXXCopyConstructor:
+ if (RD->hasUserDeclaredCopyConstructor()) {
+ SourceLocation CtorLoc =
+ RD->getCopyConstructor(Context, 0)->getLocation();
+ Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+
+ case CXXCopyAssignment:
+ if (RD->hasUserDeclaredCopyAssignment()) {
+ // FIXME: this should use the location of the copy
+ // assignment, not the type.
+ SourceLocation TyLoc = RD->getSourceRange().getBegin();
+ Diag(TyLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+
+ case CXXDestructor:
+ if (RD->hasUserDeclaredDestructor()) {
+ SourceLocation DtorLoc = RD->getDestructor(Context)->getLocation();
+ Diag(DtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+ }
+
+ typedef CXXRecordDecl::base_class_iterator base_iter;
+
+ // Virtual bases and members inhibit trivial copying/construction,
+ // but not trivial destruction.
+ if (member != CXXDestructor) {
+ // Check for virtual bases. vbases includes indirect virtual bases,
+ // so we just iterate through the direct bases.
+ for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi)
+ if (bi->isVirtual()) {
+ SourceLocation BaseLoc = bi->getSourceRange().getBegin();
+ Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1;
+ return;
+ }
+
+ // Check for virtual methods.
+ typedef CXXRecordDecl::method_iterator meth_iter;
+ for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
+ ++mi) {
+ if (mi->isVirtual()) {
+ SourceLocation MLoc = mi->getSourceRange().getBegin();
+ Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0;
+ return;
+ }
+ }
+ }
+
+ bool (CXXRecordDecl::*hasTrivial)() const;
+ switch (member) {
+ case CXXDefaultConstructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break;
+ case CXXCopyConstructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
+ case CXXCopyAssignment:
+ hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break;
+ case CXXDestructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break;
+ default:
+ assert(0 && "unexpected special member"); return;
+ }
+
+ // Check for nontrivial bases (and recurse).
+ for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) {
+ const RecordType *BaseRT = bi->getType()->getAs<RecordType>();
+ assert(BaseRT);
+ CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl());
+ if (!(BaseRecTy->*hasTrivial)()) {
+ SourceLocation BaseLoc = bi->getSourceRange().getBegin();
+ Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member;
+ DiagnoseNontrivial(BaseRT, member);
+ return;
+ }
+ }
+
+ // Check for nontrivial members (and recurse).
+ typedef RecordDecl::field_iterator field_iter;
+ for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
+ ++fi) {
+ QualType EltTy = Context.getBaseElementType((*fi)->getType());
+ if (const RecordType *EltRT = EltTy->getAs<RecordType>()) {
+ CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
+
+ if (!(EltRD->*hasTrivial)()) {
+ SourceLocation FLoc = (*fi)->getLocation();
+ Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
+ DiagnoseNontrivial(EltRT, member);
+ return;
+ }
+ }
+ }
+
+ assert(0 && "found no explanation for non-trivial member");
+}
+
+/// TranslateIvarVisibility - Translate visibility from a token ID to an
/// AST enum value.
static ObjCIvarDecl::AccessControl
TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) {
@@ -4026,24 +5056,25 @@ TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) {
}
}
-/// ActOnIvar - Each ivar field of an objective-c class is passed into this
+/// ActOnIvar - Each ivar field of an objective-c class is passed into this
/// in order to create an IvarDecl object for it.
Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
- SourceLocation DeclStart,
+ SourceLocation DeclStart,
DeclPtrTy IntfDecl,
Declarator &D, ExprTy *BitfieldWidth,
tok::ObjCKeywordKind Visibility) {
-
+
IdentifierInfo *II = D.getIdentifier();
Expr *BitWidth = (Expr*)BitfieldWidth;
SourceLocation Loc = DeclStart;
if (II) Loc = D.getIdentifierLoc();
-
+
// FIXME: Unnamed fields can be handled in various different ways, for
// example, unnamed unions inject all members into the struct namespace!
-
- QualType T = GetTypeForDeclarator(D, S);
-
+
+ DeclaratorInfo *DInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &DInfo);
+
if (BitWidth) {
// 6.7.2.1p3, 6.7.2.1p4
if (VerifyBitField(Loc, II, T, BitWidth)) {
@@ -4053,43 +5084,42 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
}
} else {
// Not a bitfield.
-
+
// validate II.
-
+
}
-
+
// C99 6.7.2.1p8: A member of a structure or union may have any type other
// than a variably modified type.
if (T->isVariablyModifiedType()) {
Diag(Loc, diag::err_typecheck_ivar_variable_size);
D.setInvalidType();
}
-
+
// Get the visibility (access control) for this ivar.
- ObjCIvarDecl::AccessControl ac =
+ ObjCIvarDecl::AccessControl ac =
Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility)
: ObjCIvarDecl::None;
// Must set ivar's DeclContext to its enclosing interface.
Decl *EnclosingDecl = IntfDecl.getAs<Decl>();
DeclContext *EnclosingContext;
- if (ObjCImplementationDecl *IMPDecl =
+ if (ObjCImplementationDecl *IMPDecl =
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
// Case of ivar declared in an implementation. Context is that of its class.
ObjCInterfaceDecl* IDecl = IMPDecl->getClassInterface();
assert(IDecl && "No class- ActOnIvar");
EnclosingContext = cast_or_null<DeclContext>(IDecl);
- }
- else
+ } else
EnclosingContext = dyn_cast<DeclContext>(EnclosingDecl);
assert(EnclosingContext && "null DeclContext for ivar - ActOnIvar");
-
+
// Construct the decl.
- ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context,
- EnclosingContext, Loc, II, T,ac,
- (Expr *)BitfieldWidth);
-
+ ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context,
+ EnclosingContext, Loc, II, T,
+ DInfo, ac, (Expr *)BitfieldWidth);
+
if (II) {
- NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true);
+ NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, true);
if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S)
&& !isa<TagDecl>(PrevDecl)) {
Diag(Loc, diag::err_duplicate_member) << II;
@@ -4100,7 +5130,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
// Process attributes attached to the ivar.
ProcessDeclAttributes(S, NewID, D);
-
+
if (D.isInvalidType())
NewID->setInvalidDecl();
@@ -4121,7 +5151,7 @@ void Sema::ActOnFields(Scope* S,
AttributeList *Attr) {
Decl *EnclosingDecl = RecDecl.getAs<Decl>();
assert(EnclosingDecl && "missing record or interface decl");
-
+
// If the decl this is being inserted into is invalid, then it may be a
// redeclaration or some other bogus case. Don't try to add fields to it.
if (EnclosingDecl->isInvalidDecl()) {
@@ -4129,7 +5159,7 @@ void Sema::ActOnFields(Scope* S,
return;
}
-
+
// Verify that all the fields are okay.
unsigned NumNamedMembers = 0;
llvm::SmallVector<FieldDecl*, 32> RecFields;
@@ -4137,7 +5167,7 @@ void Sema::ActOnFields(Scope* S,
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
for (unsigned i = 0; i != NumFields; ++i) {
FieldDecl *FD = cast<FieldDecl>(Fields[i].getAs<Decl>());
-
+
// Get the type for the field.
Type *FDTy = FD->getType().getTypePtr();
@@ -4145,12 +5175,12 @@ void Sema::ActOnFields(Scope* S,
// Remember all fields written by the user.
RecFields.push_back(FD);
}
-
+
// If the field is already invalid for some reason, don't emit more
// diagnostics about it.
if (FD->isInvalidDecl())
continue;
-
+
// C99 6.7.2.1p2:
// A structure or union shall not contain a member with
// incomplete or function type (hence, a structure shall not
@@ -4182,13 +5212,13 @@ void Sema::ActOnFields(Scope* S,
if (Record)
Record->setHasFlexibleArrayMember(true);
} else if (!FDTy->isDependentType() &&
- RequireCompleteType(FD->getLocation(), FD->getType(),
+ RequireCompleteType(FD->getLocation(), FD->getType(),
diag::err_field_incomplete)) {
// Incomplete type
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
continue;
- } else if (const RecordType *FDTTy = FDTy->getAsRecordType()) {
+ } else if (const RecordType *FDTTy = FDTy->getAs<RecordType>()) {
if (FDTTy->getDecl()->hasFlexibleArrayMember()) {
// If this is a member of a union, then entire union becomes "flexible".
if (Record && Record->isUnion()) {
@@ -4210,13 +5240,20 @@ void Sema::ActOnFields(Scope* S,
}
}
}
+ if (Record && FDTTy->getDecl()->hasObjectMember())
+ Record->setHasObjectMember(true);
} else if (FDTy->isObjCInterfaceType()) {
/// A field cannot be an Objective-c object
Diag(FD->getLocation(), diag::err_statically_allocated_object);
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
continue;
- }
+ } else if (getLangOptions().ObjC1 &&
+ getLangOptions().getGCMode() != LangOptions::NonGC &&
+ Record &&
+ (FD->getType()->isObjCObjectPointerType() ||
+ FD->getType().isObjCGCStrong()))
+ Record->setHasObjectMember(true);
// Keep track of the number of named members.
if (FD->getIdentifier())
++NumNamedMembers;
@@ -4239,7 +5276,7 @@ void Sema::ActOnFields(Scope* S,
// Must enforce the rule that ivars in the base classes may not be
// duplicates.
if (ID->getSuperClass()) {
- for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(),
+ for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(),
IVE = ID->ivar_end(); IVI != IVE; ++IVI) {
ObjCIvarDecl* Ivar = (*IVI);
@@ -4253,7 +5290,7 @@ void Sema::ActOnFields(Scope* S,
}
}
}
- } else if (ObjCImplementationDecl *IMPDecl =
+ } else if (ObjCImplementationDecl *IMPDecl =
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl");
for (unsigned I = 0, N = RecFields.size(); I != N; ++I)
@@ -4294,7 +5331,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
EltTy = Val->getType();
}
}
-
+
if (!Val) {
if (LastEnumConst) {
// Assign the last value + 1.
@@ -4304,7 +5341,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// Check for overflow on increment.
if (EnumVal < LastEnumConst->getInitVal())
Diag(IdLoc, diag::warn_enum_value_overflow);
-
+
EltTy = LastEnumConst->getType();
} else {
// First value, set to zero.
@@ -4312,10 +5349,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy)));
}
}
-
+
val.release();
return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
- Val, EnumVal);
+ Val, EnumVal);
}
@@ -4332,10 +5369,10 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
// The scope passed in may not be a decl scope. Zip up the scope tree until
// we find one that is.
S = getNonFieldDeclScope(S);
-
+
// Verify that there isn't already something declared with this name in this
// scope.
- NamedDecl *PrevDecl = LookupName(S, Id, LookupOrdinaryName);
+ NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(IdLoc, PrevDecl);
@@ -4371,28 +5408,34 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, DeclPtrTy EnumDeclX,
- DeclPtrTy *Elements, unsigned NumElements) {
+ DeclPtrTy *Elements, unsigned NumElements,
+ Scope *S, AttributeList *Attr) {
EnumDecl *Enum = cast<EnumDecl>(EnumDeclX.getAs<Decl>());
QualType EnumType = Context.getTypeDeclType(Enum);
-
+
+ if (Attr)
+ ProcessDeclAttributeList(S, Enum, Attr);
+
// TODO: If the result value doesn't fit in an int, it must be a long or long
// long value. ISO C does not support this, but GCC does as an extension,
// emit a warning.
unsigned IntWidth = Context.Target.getIntWidth();
-
+ unsigned CharWidth = Context.Target.getCharWidth();
+ unsigned ShortWidth = Context.Target.getShortWidth();
+
// Verify that all the values are okay, compute the size of the values, and
// reverse the list.
unsigned NumNegativeBits = 0;
unsigned NumPositiveBits = 0;
-
+
// Keep track of whether all elements have type int.
bool AllElementsInt = true;
-
+
for (unsigned i = 0; i != NumElements; ++i) {
EnumConstantDecl *ECD =
cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>());
if (!ECD) continue; // Already issued a diagnostic.
-
+
// If the enum value doesn't fit in an int, emit an extension warning.
const llvm::APSInt &InitVal = ECD->getInitVal();
assert(InitVal.getBitWidth() >= IntWidth &&
@@ -4405,7 +5448,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
Diag(ECD->getLocation(), diag::ext_enum_value_not_int)
<< InitVal.toString(10);
}
-
+
// Keep track of the size of positive and negative values.
if (InitVal.isUnsigned() || InitVal.isNonNegative())
NumPositiveBits = std::max(NumPositiveBits,
@@ -4416,28 +5459,39 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// Keep track of whether every enum element has type int (very commmon).
if (AllElementsInt)
- AllElementsInt = ECD->getType() == Context.IntTy;
+ AllElementsInt = ECD->getType() == Context.IntTy;
}
-
+
// Figure out the type that should be used for this enum.
- // FIXME: Support attribute(packed) on enums and -fshort-enums.
+ // FIXME: Support -fshort-enums.
QualType BestType;
unsigned BestWidth;
-
+
+ bool Packed = Enum->getAttr<PackedAttr>() ? true : false;
+
if (NumNegativeBits) {
- // If there is a negative value, figure out the smallest integer type (of
+ // If there is a negative value, figure out the smallest integer type (of
// int/long/longlong) that fits.
- if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
+ // If it's packed, check also if it fits a char or a short.
+ if (Packed && NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) {
+ BestType = Context.SignedCharTy;
+ BestWidth = CharWidth;
+ } else if (Packed && NumNegativeBits <= ShortWidth &&
+ NumPositiveBits < ShortWidth) {
+ BestType = Context.ShortTy;
+ BestWidth = ShortWidth;
+ }
+ else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
BestType = Context.IntTy;
BestWidth = IntWidth;
} else {
BestWidth = Context.Target.getLongWidth();
-
+
if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth)
BestType = Context.LongTy;
else {
BestWidth = Context.Target.getLongLongWidth();
-
+
if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth)
Diag(Enum->getLocation(), diag::warn_enum_too_large);
BestType = Context.LongLongTy;
@@ -4446,7 +5500,15 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
} else {
// If there is no negative value, figure out which of uint, ulong, ulonglong
// fits.
- if (NumPositiveBits <= IntWidth) {
+ // If it's packed, check also if it fits a char or a short.
+ if (Packed && NumPositiveBits <= CharWidth) {
+ BestType = Context.UnsignedCharTy;
+ BestWidth = CharWidth;
+ } else if (Packed && NumPositiveBits <= ShortWidth) {
+ BestType = Context.UnsignedShortTy;
+ BestWidth = ShortWidth;
+ }
+ else if (NumPositiveBits <= IntWidth) {
BestType = Context.UnsignedIntTy;
BestWidth = IntWidth;
} else if (NumPositiveBits <=
@@ -4459,7 +5521,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
BestType = Context.UnsignedLongLongTy;
}
}
-
+
// Loop over all of the enumerator constants, changing their types to match
// the type of the enum if needed.
for (unsigned i = 0; i != NumElements; ++i) {
@@ -4481,7 +5543,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
if (getLangOptions().CPlusPlus)
// C++ [dcl.enum]p4: Following the closing brace of an
// enum-specifier, each enumerator has the type of its
- // enumeration.
+ // enumeration.
ECD->setType(EnumType);
continue; // Already int type.
}
@@ -4508,7 +5570,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
if (getLangOptions().CPlusPlus)
// C++ [dcl.enum]p4: Following the closing brace of an
// enum-specifier, each enumerator has the type of its
- // enumeration.
+ // enumeration.
ECD->setType(EnumType);
continue;
} else {
@@ -4521,20 +5583,22 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
InitVal.extOrTrunc(NewWidth);
InitVal.setIsSigned(NewSign);
ECD->setInitVal(InitVal);
-
+
// Adjust the Expr initializer and type.
if (ECD->getInitExpr())
- ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, ECD->getInitExpr(),
+ ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy,
+ CastExpr::CK_Unknown,
+ ECD->getInitExpr(),
/*isLvalue=*/false));
if (getLangOptions().CPlusPlus)
// C++ [dcl.enum]p4: Following the closing brace of an
// enum-specifier, each enumerator has the type of its
- // enumeration.
+ // enumeration.
ECD->setType(EnumType);
else
ECD->setType(NewTy);
}
-
+
Enum->completeDefinition(Context, BestType);
}
@@ -4551,15 +5615,15 @@ Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc) {
- Decl *PrevDecl = LookupName(TUScope, Name, LookupOrdinaryName);
+ Decl *PrevDecl = LookupSingleName(TUScope, Name, LookupOrdinaryName);
- // FIXME: This implementation is an ugly hack!
if (PrevDecl) {
PrevDecl->addAttr(::new (Context) WeakAttr());
- return;
+ } else {
+ (void)WeakUndeclaredIdentifiers.insert(
+ std::pair<IdentifierInfo*,WeakInfo>
+ (Name, WeakInfo((IdentifierInfo*)0, NameLoc)));
}
- Diag(PragmaLoc, diag::err_unsupported_pragma_weak);
- return;
}
void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
@@ -4567,14 +5631,15 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc,
SourceLocation AliasNameLoc) {
- Decl *PrevDecl = LookupName(TUScope, Name, LookupOrdinaryName);
+ Decl *PrevDecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName);
+ WeakInfo W = WeakInfo(Name, NameLoc);
- // FIXME: This implementation is an ugly hack!
if (PrevDecl) {
- PrevDecl->addAttr(::new (Context) AliasAttr(AliasName->getName()));
- PrevDecl->addAttr(::new (Context) WeakAttr());
- return;
+ if (!PrevDecl->hasAttr<AliasAttr>())
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(PrevDecl))
+ DeclApplyPragmaWeak(TUScope, ND, W);
+ } else {
+ (void)WeakUndeclaredIdentifiers.insert(
+ std::pair<IdentifierInfo*,WeakInfo>(AliasName, W));
}
- Diag(PragmaLoc, diag::err_unsupported_pragma_weak);
- return;
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 2b71df722459b..50ebb49e7d5b4 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -17,46 +17,53 @@
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Parse/DeclSpec.h"
-#include <llvm/ADT/StringExtras.h>
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Helper functions
//===----------------------------------------------------------------------===//
-static const FunctionType *getFunctionType(Decl *d, bool blocksToo = true) {
+static const FunctionType *getFunctionType(const Decl *d,
+ bool blocksToo = true) {
QualType Ty;
- if (ValueDecl *decl = dyn_cast<ValueDecl>(d))
+ if (const ValueDecl *decl = dyn_cast<ValueDecl>(d))
Ty = decl->getType();
- else if (FieldDecl *decl = dyn_cast<FieldDecl>(d))
+ else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d))
Ty = decl->getType();
- else if (TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
+ else if (const TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
Ty = decl->getUnderlyingType();
else
return 0;
-
+
if (Ty->isFunctionPointerType())
- Ty = Ty->getAsPointerType()->getPointeeType();
+ Ty = Ty->getAs<PointerType>()->getPointeeType();
else if (blocksToo && Ty->isBlockPointerType())
- Ty = Ty->getAsBlockPointerType()->getPointeeType();
+ Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
- return Ty->getAsFunctionType();
+ return Ty->getAs<FunctionType>();
}
// FIXME: We should provide an abstraction around a method or function
// to provide the following bits of information.
/// isFunctionOrMethod - Return true if the given decl has function
+/// type (function or function-typed variable).
+static bool isFunction(const Decl *d) {
+ return getFunctionType(d, false) != NULL;
+}
+
+/// isFunctionOrMethod - Return true if the given decl has function
/// type (function or function-typed variable) or an Objective-C
/// method.
-static bool isFunctionOrMethod(Decl *d) {
- return getFunctionType(d, false) || isa<ObjCMethodDecl>(d);
+static bool isFunctionOrMethod(const Decl *d) {
+ return isFunction(d)|| isa<ObjCMethodDecl>(d);
}
/// isFunctionOrMethodOrBlock - Return true if the given decl has function
/// type (function or function-typed variable) or an Objective-C
/// method or a block.
-static bool isFunctionOrMethodOrBlock(Decl *d) {
+static bool isFunctionOrMethodOrBlock(const Decl *d) {
if (isFunctionOrMethod(d))
return true;
// check for block is more involved.
@@ -70,7 +77,7 @@ static bool isFunctionOrMethodOrBlock(Decl *d) {
/// hasFunctionProto - Return true if the given decl has a argument
/// information. This decl should have already passed
/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
-static bool hasFunctionProto(Decl *d) {
+static bool hasFunctionProto(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d))
return isa<FunctionProtoType>(FnTy);
else {
@@ -82,7 +89,7 @@ static bool hasFunctionProto(Decl *d) {
/// getFunctionOrMethodNumArgs - Return number of function or method
/// arguments. It is an error to call this on a K&R function (use
/// hasFunctionProto first).
-static unsigned getFunctionOrMethodNumArgs(Decl *d) {
+static unsigned getFunctionOrMethodNumArgs(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d))
return cast<FunctionProtoType>(FnTy)->getNumArgs();
if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
@@ -90,22 +97,22 @@ static unsigned getFunctionOrMethodNumArgs(Decl *d) {
return cast<ObjCMethodDecl>(d)->param_size();
}
-static QualType getFunctionOrMethodArgType(Decl *d, unsigned Idx) {
+static QualType getFunctionOrMethodArgType(const Decl *d, unsigned Idx) {
if (const FunctionType *FnTy = getFunctionType(d))
return cast<FunctionProtoType>(FnTy)->getArgType(Idx);
if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
return BD->getParamDecl(Idx)->getType();
-
+
return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType();
}
-static QualType getFunctionOrMethodResultType(Decl *d) {
+static QualType getFunctionOrMethodResultType(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d))
return cast<FunctionProtoType>(FnTy)->getResultType();
return cast<ObjCMethodDecl>(d)->getResultType();
}
-static bool isFunctionOrMethodVariadic(Decl *d) {
+static bool isFunctionOrMethodVariadic(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d)) {
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
return proto->isVariadic();
@@ -117,30 +124,30 @@ static bool isFunctionOrMethodVariadic(Decl *d) {
}
static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
- const PointerType *PT = T->getAsPointerType();
+ const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
if (!PT)
return false;
-
- const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAsObjCInterfaceType();
+
+ const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAs<ObjCInterfaceType>();
if (!ClsT)
return false;
-
+
IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier();
-
+
// FIXME: Should we walk the chain of classes?
return ClsName == &Ctx.Idents.get("NSString") ||
ClsName == &Ctx.Idents.get("NSMutableString");
}
static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
- const PointerType *PT = T->getAsPointerType();
+ const PointerType *PT = T->getAs<PointerType>();
if (!PT)
return false;
- const RecordType *RT = PT->getPointeeType()->getAsRecordType();
+ const RecordType *RT = PT->getPointeeType()->getAs<RecordType>();
if (!RT)
return false;
-
+
const RecordDecl *RD = RT->getDecl();
if (RD->getTagKind() != TagDecl::TK_struct)
return false;
@@ -156,14 +163,14 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
// least add some helper functions to check most argument patterns (#
// and types of args).
-static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
+static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
const AttributeList &Attr, Sema &S) {
TypedefDecl *tDecl = dyn_cast<TypedefDecl>(d);
if (tDecl == 0) {
S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
return;
}
-
+
QualType curType = tDecl->getUnderlyingType();
Expr *sizeExpr;
@@ -187,21 +194,20 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc());
if (!T.isNull()) {
tDecl->setUnderlyingType(T);
-
+
// Remember this typedef decl, we will need it later for diagnostics.
S.ExtVectorDecls.push_back(tDecl);
}
}
-/// HandleVectorSizeAttribute - this attribute is only applicable to
-/// integral and float scalars, although arrays, pointers, and function
-/// return values are allowed in conjunction with this construct. Aggregates
-/// with this attribute are invalid, even if they are of the same size as a
-/// corresponding scalar.
-/// The raw attribute should contain precisely 1 argument, the vector size
-/// for the variable, measured in bytes. If curType and rawAttr are well
-/// formed, this routine will return a new vector type.
+/// HandleVectorSizeAttribute - this attribute is only applicable to integral
+/// and float scalars, although arrays, pointers, and function return values are
+/// allowed in conjunction with this construct. Aggregates with this attribute
+/// are invalid, even if they are of the same size as a corresponding scalar.
+/// The raw attribute should contain precisely 1 argument, the vector size for
+/// the variable, measured in bytes. If curType and rawAttr are well formed,
+/// this routine will return a new vector type.
static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
QualType CurType;
if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
@@ -213,7 +219,7 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
<< "vector_size" << SourceRange(Attr.getLoc(), Attr.getLoc());
return;
}
-
+
// Check the attribute arugments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
@@ -226,8 +232,8 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
<< "vector_size" << sizeExpr->getSourceRange();
return;
}
- // navigate to the base type - we need to provide for vector pointers,
- // vector arrays, and functions returning vectors.
+ // navigate to the base type - we need to provide for vector pointers, vector
+ // arrays, and functions returning vectors.
if (CurType->isPointerType() || CurType->isArrayType() ||
CurType->isFunctionType()) {
S.Diag(Attr.getLoc(), diag::err_unsupported_vector_size) << CurType;
@@ -252,8 +258,8 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType));
// vecSize is specified in bytes - convert to bits.
- unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8);
-
+ unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8);
+
// the vector size needs to be an integral multiple of the type size.
if (vectorSize % typeSize) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
@@ -265,14 +271,14 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
<< sizeExpr->getSourceRange();
return;
}
-
+
// Success! Instantiate the vector type, the number of elements is > 0, and
// not required to be a power of 2, unlike GCC.
CurType = S.Context.getVectorType(CurType, vectorSize/typeSize);
-
+
if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
VD->setType(CurType);
- else
+ else
cast<TypedefDecl>(D)->setUnderlyingType(CurType);
}
@@ -282,9 +288,9 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
if (TagDecl *TD = dyn_cast<TagDecl>(d))
- TD->addAttr(::new (S.Context) PackedAttr(1));
+ TD->addAttr(::new (S.Context) PackedAttr);
else if (FieldDecl *FD = dyn_cast<FieldDecl>(d)) {
// If the alignment is less than or equal to 8 bits, the packed attribute
// has no effect.
@@ -293,7 +299,7 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
<< Attr.getName() << FD->getType();
else
- FD->addAttr(::new (S.Context) PackedAttr(1));
+ FD->addAttr(::new (S.Context) PackedAttr);
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -304,7 +310,7 @@ static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
// The IBOutlet attribute only applies to instance variables of Objective-C
// classes.
if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))
@@ -314,23 +320,23 @@ static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // GCC ignores the nonnull attribute on K&R style function
- // prototypes, so we ignore it as well
+ // GCC ignores the nonnull attribute on K&R style function prototypes, so we
+ // ignore it as well
if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
}
-
+
unsigned NumArgs = getFunctionOrMethodNumArgs(d);
// The nonnull attribute only applies to pointers.
llvm::SmallVector<unsigned, 10> NonNullArgs;
-
+
for (AttributeList::arg_iterator I=Attr.arg_begin(),
E=Attr.arg_end(); I!=E; ++I) {
-
-
+
+
// The argument must be an integer constant expression.
Expr *Ex = static_cast<Expr *>(*I);
llvm::APSInt ArgNum(32);
@@ -339,38 +345,38 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< "nonnull" << Ex->getSourceRange();
return;
}
-
+
unsigned x = (unsigned) ArgNum.getZExtValue();
-
+
if (x < 1 || x > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "nonnull" << I.getArgNum() << Ex->getSourceRange();
return;
}
-
+
--x;
// Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(d, x);
- if (!T->isPointerType() && !T->isBlockPointerType()) {
+ QualType T = getFunctionOrMethodArgType(d, x);
+ if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
// FIXME: Should also highlight argument in decl.
S.Diag(Attr.getLoc(), diag::err_nonnull_pointers_only)
<< "nonnull" << Ex->getSourceRange();
continue;
}
-
+
NonNullArgs.push_back(x);
}
-
- // If no arguments were specified to __attribute__((nonnull)) then all
- // pointer arguments have a nonnull attribute.
+
+ // If no arguments were specified to __attribute__((nonnull)) then all pointer
+ // arguments have a nonnull attribute.
if (NonNullArgs.empty()) {
for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) {
QualType T = getFunctionOrMethodArgType(d, I);
- if (T->isPointerType() || T->isBlockPointerType())
+ if (T->isAnyPointerType() || T->isBlockPointerType())
NonNullArgs.push_back(I);
}
-
+
if (NonNullArgs.empty()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers);
return;
@@ -389,26 +395,26 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
-
+
Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
-
+
if (Str == 0 || Str->isWide()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "alias" << 1;
return;
}
-
+
const char *Alias = Str->getStrData();
unsigned AliasLen = Str->getByteLength();
-
+
// FIXME: check if target symbol exists in current file
-
+
d->addAttr(::new (S.Context) AliasAttr(std::string(Alias, AliasLen)));
}
-static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
+static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
@@ -421,10 +427,28 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
<< Attr.getName() << 0 /*function*/;
return;
}
-
+
d->addAttr(::new (S.Context) AlwaysInlineAttr());
}
+static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
+ QualType RetTy = FD->getResultType();
+ if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
+ d->addAttr(::new (S.Context) MallocAttr());
+ return;
+ }
+ }
+
+ S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only);
+}
+
static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
// check the attribute arguments.
@@ -441,18 +465,18 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
return false;
}
}
-
+
return true;
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (HandleCommonNoReturnAttr(d, Attr, S))
+ if (HandleCommonNoReturnAttr(d, Attr, S))
d->addAttr(::new (S.Context) NoReturnAttr());
}
static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
- if (HandleCommonNoReturnAttr(d, Attr, S))
+ if (HandleCommonNoReturnAttr(d, Attr, S))
d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
}
@@ -462,13 +486,13 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
}
-
+
d->addAttr(::new (S.Context) UnusedAttr());
}
@@ -478,7 +502,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
if (const VarDecl *VD = dyn_cast<VarDecl>(d)) {
if (VD->hasLocalStorage() || VD->hasExternalStorage()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
@@ -489,7 +513,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 2 /*variable and function*/;
return;
}
-
+
d->addAttr(::new (S.Context) UsedAttr());
}
@@ -499,7 +523,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
<< "0 or 1";
return;
- }
+ }
int priority = 65535; // FIXME: Do not hardcode such constants.
if (Attr.getNumArgs() > 0) {
@@ -512,7 +536,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
priority = Idx.getZExtValue();
}
-
+
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
@@ -528,7 +552,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
<< "0 or 1";
return;
- }
+ }
int priority = 65535; // FIXME: Do not hardcode such constants.
if (Attr.getNumArgs() > 0) {
@@ -541,7 +565,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
priority = Idx.getZExtValue();
}
-
+
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
@@ -557,7 +581,7 @@ static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) DeprecatedAttr());
}
@@ -567,7 +591,7 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) UnavailableAttr());
}
@@ -577,21 +601,21 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
-
+
Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
-
+
if (Str == 0 || Str->isWide()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "visibility" << 1;
return;
}
-
+
const char *TypeStr = Str->getStrData();
unsigned TypeLen = Str->getByteLength();
VisibilityAttr::VisibilityTypes type;
-
+
if (TypeLen == 7 && !memcmp(TypeStr, "default", 7))
type = VisibilityAttr::DefaultVisibility;
else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6))
@@ -604,7 +628,7 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
return;
}
-
+
d->addAttr(::new (S.Context) VisibilityAttr(type));
}
@@ -614,13 +638,13 @@ static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
if (OCI == 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface);
return;
}
-
+
D->addAttr(::new (S.Context) ObjCExceptionAttr());
}
@@ -632,7 +656,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
QualType T = TD->getUnderlyingType();
if (!T->isPointerType() ||
- !T->getAsPointerType()->getPointeeType()->isRecordType()) {
+ !T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
return;
}
@@ -640,7 +664,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
D->addAttr(::new (S.Context) ObjCNSObjectAttr());
}
-static void
+static void
HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
@@ -656,17 +680,17 @@ HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (!Attr.getParameterName()) {
+ if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "blocks" << 1;
return;
}
-
+
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
-
+
BlocksAttr::BlocksAttrTypes type;
if (Attr.getParameterName()->isStr("byref"))
type = BlocksAttr::ByRef;
@@ -675,7 +699,7 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< "blocks" << Attr.getParameterName();
return;
}
-
+
d->addAttr(::new (S.Context) BlocksAttr(type));
}
@@ -685,8 +709,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
<< "0, 1 or 2";
return;
- }
-
+ }
+
int sentinel = 0;
if (Attr.getNumArgs() > 0) {
Expr *E = static_cast<Expr *>(Attr.getArg(0));
@@ -697,7 +721,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
sentinel = Idx.getZExtValue();
-
+
if (sentinel < 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero)
<< E->getSourceRange();
@@ -715,7 +739,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
nullPos = Idx.getZExtValue();
-
+
if (nullPos > 1 || nullPos < 0) {
// FIXME: This error message could be improved, it would be nice
// to say what the bounds actually are.
@@ -726,39 +750,38 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
- const FunctionType *FT = FD->getType()->getAsFunctionType();
+ const FunctionType *FT = FD->getType()->getAs<FunctionType>();
assert(FT && "FunctionDecl has non-function type?");
-
+
if (isa<FunctionNoProtoType>(FT)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments);
return;
}
-
+
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
return;
- }
+ }
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) {
if (!MD->isVariadic()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
return;
}
} else if (isa<BlockDecl>(d)) {
- // Note! BlockDecl is typeless. Variadic diagnostics
- // will be issued by the caller.
+ // Note! BlockDecl is typeless. Variadic diagnostics will be issued by the
+ // caller.
;
} else if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
QualType Ty = V->getType();
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
- const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
- : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType();
+ const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
+ : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
int m = Ty->isFunctionPointerType() ? 0 : 1;
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
return;
}
- }
- else {
+ } else {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 6 /*function, method or block */;
return;
@@ -785,7 +808,7 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
<< Attr.getName() << 0 /*function*/;
return;
}
-
+
Fn->addAttr(::new (S.Context) WarnUnusedResultAttr());
}
@@ -796,13 +819,26 @@ static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
+ /* weak only applies to non-static declarations */
+ bool isStatic = false;
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ isStatic = VD->getStorageClass() == VarDecl::Static;
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ isStatic = FD->getStorageClass() == FunctionDecl::Static;
+ }
+ if (isStatic) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) <<
+ dyn_cast<NamedDecl>(D)->getNameAsString();
+ return;
+ }
+
// TODO: could also be applied to methods?
if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
}
-
+
D->addAttr(::new (S.Context) WeakAttr());
}
@@ -811,7 +847,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
- }
+ }
// weak_import only applies to variable & function declarations.
bool isDef = false;
@@ -830,7 +866,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Merge should handle any subsequent violations.
if (isDef) {
- S.Diag(Attr.getLoc(),
+ S.Diag(Attr.getLoc(),
diag::warn_attribute_weak_import_invalid_on_definition)
<< "weak_import" << 2 /*variable and function*/;
return;
@@ -904,8 +940,8 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- // Currently, the dllexport attribute is ignored for inlined functions,
- // unless the -fkeep-inline-functions flag has been used. Warning is emitted;
+ // Currently, the dllexport attribute is ignored for inlined functions, unless
+ // the -fkeep-inline-functions flag has been used. Warning is emitted;
if (FD->isInline()) {
// FIXME: ... unless the -fkeep-inline-functions flag has been used.
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
@@ -947,15 +983,25 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Make sure that there is a string literal as the sections's single
// argument.
- StringLiteral *SE =
- dyn_cast<StringLiteral>(static_cast<Expr *>(Attr.getArg(0)));
+ Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
+ StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
if (!SE) {
- // FIXME
- S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string);
+ S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) << "section";
+ return;
+ }
+
+ std::string SectionStr(SE->getStrData(), SE->getByteLength());
+
+ // If the target wants to validate the section specifier, make it happen.
+ std::string Error = S.Context.Target.isValidSectionSpecifier(SectionStr);
+ if (Error.empty()) {
+ D->addAttr(::new (S.Context) SectionAttr(SectionStr));
return;
}
- D->addAttr(::new (S.Context) SectionAttr(std::string(SE->getStrData(),
- SE->getByteLength())));
+
+ S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
+ << Error;
+
}
static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1011,7 +1057,7 @@ static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) NoThrowAttr());
}
@@ -1021,7 +1067,7 @@ static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) ConstAttr());
}
@@ -1031,7 +1077,7 @@ static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) PureAttr());
}
@@ -1039,33 +1085,34 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// Match gcc which ignores cleanup attrs when compiling C++.
if (S.getLangOptions().CPlusPlus)
return;
-
- if (!Attr.getParameterName()) {
+
+ if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
-
+
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
-
+
VarDecl *VD = dyn_cast<VarDecl>(d);
-
+
if (!VD || !VD->hasLocalStorage()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup";
return;
}
-
+
// Look up the function
- NamedDecl *CleanupDecl = S.LookupName(S.TUScope, Attr.getParameterName(),
- Sema::LookupOrdinaryName);
+ NamedDecl *CleanupDecl
+ = S.LookupSingleName(S.TUScope, Attr.getParameterName(),
+ Sema::LookupOrdinaryName);
if (!CleanupDecl) {
S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) <<
Attr.getParameterName();
return;
}
-
+
FunctionDecl *FD = dyn_cast<FunctionDecl>(CleanupDecl);
if (!FD) {
S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_function) <<
@@ -1078,24 +1125,24 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
Attr.getParameterName();
return;
}
-
+
// We're currently more strict than GCC about what function types we accept.
// If this ever proves to be a problem it should be easy to fix.
QualType Ty = S.Context.getPointerType(VD->getType());
QualType ParamTy = FD->getParamDecl(0)->getType();
if (S.CheckAssignmentConstraints(ParamTy, Ty) != Sema::Compatible) {
- S.Diag(Attr.getLoc(),
+ S.Diag(Attr.getLoc(),
diag::err_attribute_cleanup_func_arg_incompatible_type) <<
Attr.getParameterName() << ParamTy << Ty;
return;
}
-
+
d->addAttr(::new (S.Context) CleanupAttr(FD));
}
-/// Handle __attribute__((format_arg((idx)))) attribute
-/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
-static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+/// Handle __attribute__((format_arg((idx)))) attribute based on
+/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
@@ -1105,9 +1152,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 0 /*function*/;
return;
}
- // FIXME: in C++ the implicit 'this' function parameter also counts.
- // this is needed in order to be compatible with GCC
- // the index must start with 1.
+ // FIXME: in C++ the implicit 'this' function parameter also counts. this is
+ // needed in order to be compatible with GCC the index must start with 1.
unsigned NumArgs = getFunctionOrMethodNumArgs(d);
unsigned FirstIdx = 1;
// checks for the 2nd argument
@@ -1118,46 +1164,46 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< "format" << 2 << IdxExpr->getSourceRange();
return;
}
-
+
if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "format" << 2 << IdxExpr->getSourceRange();
return;
}
-
+
unsigned ArgIdx = Idx.getZExtValue() - 1;
-
+
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
-
+
bool not_nsstring_type = !isNSStringType(Ty, S.Context);
if (not_nsstring_type &&
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
- !Ty->getAsPointerType()->getPointeeType()->isCharType())) {
+ !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
// FIXME: Should highlight the actual expression that has the wrong type.
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
- << (not_nsstring_type ? "a string type" : "an NSString")
+ << (not_nsstring_type ? "a string type" : "an NSString")
<< IdxExpr->getSourceRange();
return;
- }
+ }
Ty = getFunctionOrMethodResultType(d);
if (!isNSStringType(Ty, S.Context) &&
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
- !Ty->getAsPointerType()->getPointeeType()->isCharType())) {
+ !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
// FIXME: Should highlight the actual expression that has the wrong type.
S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not)
- << (not_nsstring_type ? "string type" : "NSString")
+ << (not_nsstring_type ? "string type" : "NSString")
<< IdxExpr->getSourceRange();
return;
- }
-
+ }
+
d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue()));
}
-/// Handle __attribute__((format(type,idx,firstarg))) attributes
-/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
+/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!Attr.getParameterName()) {
@@ -1177,9 +1223,6 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- // FIXME: in C++ the implicit 'this' function parameter also counts.
- // this is needed in order to be compatible with GCC
- // the index must start in 1 and the limit is numargs+1
unsigned NumArgs = getFunctionOrMethodNumArgs(d);
unsigned FirstIdx = 1;
@@ -1197,19 +1240,23 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
bool is_NSString = false;
bool is_strftime = false;
bool is_CFString = false;
-
+
switch (FormatLen) {
default: break;
case 5: Supported = !memcmp(Format, "scanf", 5); break;
case 6: Supported = !memcmp(Format, "printf", 6); break;
- case 7: Supported = !memcmp(Format, "strfmon", 7); break;
+ case 7: Supported = !memcmp(Format, "printf0", 7) ||
+ !memcmp(Format, "strfmon", 7) ||
+ !memcmp(Format, "cmn_err", 7); break;
case 8:
Supported = (is_strftime = !memcmp(Format, "strftime", 8)) ||
(is_NSString = !memcmp(Format, "NSString", 8)) ||
+ !memcmp(Format, "vcmn_err", 8) ||
+ !memcmp(Format, "zcmn_err", 8) ||
(is_CFString = !memcmp(Format, "CFString", 8));
break;
}
-
+
if (!Supported) {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
<< "format" << Attr.getParameterName()->getName();
@@ -1225,6 +1272,16 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
+ // FIXME: We should handle the implicit 'this' parameter in a more generic
+ // way that can be used for other arguments.
+ bool HasImplicitThisParam = false;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(d)) {
+ if (MD->isInstance()) {
+ HasImplicitThisParam = true;
+ NumArgs++;
+ }
+ }
+
if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "format" << 2 << IdxExpr->getSourceRange();
@@ -1233,7 +1290,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// FIXME: Do we need to bounds check?
unsigned ArgIdx = Idx.getZExtValue() - 1;
-
+
+ if (HasImplicitThisParam) ArgIdx--;
+
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
@@ -1251,9 +1310,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
<< "an NSString" << IdxExpr->getSourceRange();
return;
- }
+ }
} else if (!Ty->isPointerType() ||
- !Ty->getAsPointerType()->getPointeeType()->isCharType()) {
+ !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) {
// FIXME: Should highlight the actual expression that has the wrong type.
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
<< "a string type" << IdxExpr->getSourceRange();
@@ -1321,7 +1380,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
}
if (!RD->isDefinition()) {
- S.Diag(Attr.getLoc(),
+ S.Diag(Attr.getLoc(),
diag::warn_transparent_union_attribute_not_definition);
return;
}
@@ -1336,7 +1395,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
FieldDecl *FirstField = *Field;
QualType FirstType = FirstField->getType();
if (FirstType->isFloatingType() || FirstType->isVectorType()) {
- S.Diag(FirstField->getLocation(),
+ S.Diag(FirstField->getLocation(),
diag::warn_transparent_union_attribute_floating);
return;
}
@@ -1349,13 +1408,13 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
S.Context.getTypeAlign(FieldType) != FirstAlign) {
// Warn if we drop the attribute.
bool isSize = S.Context.getTypeSize(FieldType) != FirstSize;
- unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
+ unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
: S.Context.getTypeAlign(FieldType);
- S.Diag(Field->getLocation(),
+ S.Diag(Field->getLocation(),
diag::warn_transparent_union_attribute_field_size_align)
<< isSize << Field->getDeclName() << FieldBits;
unsigned FirstBits = isSize? FirstSize : FirstAlign;
- S.Diag(FirstField->getLocation(),
+ S.Diag(FirstField->getLocation(),
diag::note_transparent_union_first_field_size_align)
<< isSize << FirstBits;
return;
@@ -1371,13 +1430,13 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
- Expr *argExpr = static_cast<Expr *>(Attr.getArg(0));
- StringLiteral *SE = dyn_cast<StringLiteral>(argExpr);
-
+ Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
+ StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
+
// Make sure that there is a string literal as the annotation's single
// argument.
if (!SE) {
- S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string);
+ S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
return;
}
d->addAttr(::new (S.Context) AnnotateAttr(std::string(SE->getStrData(),
@@ -1399,7 +1458,7 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) AlignedAttr(Align));
return;
}
-
+
Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Alignment(32);
if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) {
@@ -1408,7 +1467,7 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
- S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two)
+ S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two)
<< alignmentExpr->getSourceRange();
return;
}
@@ -1416,13 +1475,12 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) AlignedAttr(Alignment.getZExtValue() * 8));
}
-/// HandleModeAttr - This attribute modifies the width of a decl with
-/// primitive type.
-///
-/// Despite what would be logical, the mode attribute is a decl attribute,
-/// not a type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make
-/// 'G' be HImode, not an intermediate pointer.
+/// HandleModeAttr - This attribute modifies the width of a decl with primitive
+/// type.
///
+/// Despite what would be logical, the mode attribute is a decl attribute, not a
+/// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be
+/// HImode, not an intermediate pointer.
static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// This attribute isn't documented, but glibc uses it. It changes
// the width of an int or unsigned int to the specified size.
@@ -1495,7 +1553,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- if (!OldTy->getAsBuiltinType() && !OldTy->isComplexType())
+ if (!OldTy->getAs<BuiltinType>() && !OldTy->isComplexType())
S.Diag(Attr.getLoc(), diag::err_mode_not_primitive);
else if (IntegerMode) {
if (!OldTy->isIntegralType())
@@ -1581,7 +1639,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
cast<ValueDecl>(D)->setType(NewTy);
}
-static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void HandleNoDebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() > 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
@@ -1593,24 +1651,24 @@ static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 0 /*function*/;
return;
}
-
- d->addAttr(::new (S.Context) NodebugAttr());
+
+ d->addAttr(::new (S.Context) NoDebugAttr());
}
-static void HandleNoinlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
}
-
- d->addAttr(::new (S.Context) NoinlineAttr());
+
+ d->addAttr(::new (S.Context) NoInlineAttr());
}
static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1619,19 +1677,19 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
if (Fn == 0) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
}
-
+
if (!Fn->isInline()) {
S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline);
return;
}
-
+
d->addAttr(::new (S.Context) GNUInlineAttr());
}
@@ -1679,23 +1737,26 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
QualType RetTy;
-
+
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
RetTy = MD->getResultType();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
RetTy = FD->getResultType();
else {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 3 /* function or method */;
+ SourceLocation L = Attr.getLoc();
+ S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(L, L) << Attr.getName() << 3 /* function or method */;
return;
}
-
- if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType())) {
- S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
- << Attr.getName();
- return;
+
+ if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAs<PointerType>()
+ || RetTy->getAs<ObjCObjectPointerType>())) {
+ SourceLocation L = Attr.getLoc();
+ S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
+ << SourceRange(L, L) << Attr.getName();
+ return;
}
-
+
switch (Attr.getKind()) {
default:
assert(0 && "invalid ownership attribute");
@@ -1716,7 +1777,8 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
/// the attribute applies to decls. If the attribute is a type attribute, just
/// silently ignore it.
-static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) {
+static void ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) {
if (Attr.isDeclspecAttribute())
// FIXME: Try to deal with __declspec attributes!
return;
@@ -1724,14 +1786,15 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break;
case AttributeList::AT_address_space:
case AttributeList::AT_objc_gc:
- // Ignore these, these are type attributes, handled by ProcessTypeAttributes.
+ // Ignore these, these are type attributes, handled by
+ // ProcessTypeAttributes.
break;
case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break;
case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break;
- case AttributeList::AT_always_inline:
+ case AttributeList::AT_always_inline:
HandleAlwaysInlineAttr (D, Attr, S); break;
case AttributeList::AT_analyzer_noreturn:
- HandleAnalyzerNoReturnAttr (D, Attr, S); break;
+ HandleAnalyzerNoReturnAttr (D, Attr, S); break;
case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break;
case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break;
@@ -1746,6 +1809,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
case AttributeList::AT_gnu_inline: HandleGNUInlineAttr(D, Attr, S); break;
case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
+ case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break;
case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break;
case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break;
@@ -1783,10 +1847,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break;
case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break;
case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break;
- case AttributeList::AT_nodebug: HandleNodebugAttr (D, Attr, S); break;
- case AttributeList::AT_noinline: HandleNoinlineAttr (D, Attr, S); break;
+ case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break;
+ case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break;
case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break;
- case AttributeList::IgnoredAttribute:
+ case AttributeList::IgnoredAttribute:
case AttributeList::AT_no_instrument_function: // Interacts with -pg.
// Just ignore
break;
@@ -1805,14 +1869,66 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *Attr
}
}
+/// DeclClonePragmaWeak - clone existing decl (maybe definition),
+/// #pragma weak needs a non-definition decl and source may not have one
+NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
+ assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
+ NamedDecl *NewD = 0;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
+ FD->getLocation(), DeclarationName(II),
+ FD->getType(), FD->getDeclaratorInfo());
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
+ VD->getLocation(), II,
+ VD->getType(), VD->getDeclaratorInfo(),
+ VD->getStorageClass());
+ }
+ return NewD;
+}
+
+/// DeclApplyPragmaWeak - A declaration (maybe definition) needs #pragma weak
+/// applied to it, possibly with an alias.
+void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
+ if (W.getUsed()) return; // only do this once
+ W.setUsed(true);
+ if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
+ IdentifierInfo *NDId = ND->getIdentifier();
+ NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias());
+ NewD->addAttr(::new (Context) AliasAttr(NDId->getName()));
+ NewD->addAttr(::new (Context) WeakAttr());
+ WeakTopLevelDecl.push_back(NewD);
+ // FIXME: "hideous" code from Sema::LazilyCreateBuiltin
+ // to insert Decl at TU scope, sorry.
+ DeclContext *SavedContext = CurContext;
+ CurContext = Context.getTranslationUnitDecl();
+ PushOnScopeChains(NewD, S);
+ CurContext = SavedContext;
+ } else { // just add weak to existing
+ ND->addAttr(::new (Context) WeakAttr());
+ }
+}
+
/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
/// it, apply them to D. This is a bit tricky because PD can have attributes
/// specified in many different places, and we need to find and apply them all.
void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
+ // Handle #pragma weak
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ if (ND->hasLinkage()) {
+ WeakInfo W = WeakUndeclaredIdentifiers.lookup(ND->getIdentifier());
+ if (W != WeakInfo()) {
+ // Identifier referenced by #pragma weak before it was declared
+ DeclApplyPragmaWeak(S, ND, W);
+ WeakUndeclaredIdentifiers[ND->getIdentifier()] = W;
+ }
+ }
+ }
+
// Apply decl attributes from the DeclSpec if present.
if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes())
ProcessDeclAttributeList(S, D, Attrs);
-
+
// Walk the declarator structure, applying decl attributes that were in a type
// position to the decl itself. This handles cases like:
// int *__attr__(x)** D;
@@ -1820,7 +1936,7 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
ProcessDeclAttributeList(S, D, Attrs);
-
+
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
ProcessDeclAttributeList(S, D, Attrs);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 75ceb19165550..acb2a67770285 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -12,18 +12,20 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "SemaInherit.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include <algorithm> // for std::equal
#include <map>
+#include <set>
using namespace clang;
@@ -37,13 +39,13 @@ namespace {
/// contains any ill-formed subexpressions. For example, this will
/// diagnose the use of local variables or parameters within the
/// default argument expression.
- class VISIBILITY_HIDDEN CheckDefaultArgumentVisitor
+ class VISIBILITY_HIDDEN CheckDefaultArgumentVisitor
: public StmtVisitor<CheckDefaultArgumentVisitor, bool> {
Expr *DefaultArg;
Sema *S;
public:
- CheckDefaultArgumentVisitor(Expr *defarg, Sema *s)
+ CheckDefaultArgumentVisitor(Expr *defarg, Sema *s)
: DefaultArg(defarg), S(s) {}
bool VisitExpr(Expr *Node);
@@ -54,7 +56,7 @@ namespace {
/// VisitExpr - Visit all of the children of this expression.
bool CheckDefaultArgumentVisitor::VisitExpr(Expr *Node) {
bool IsInvalid = false;
- for (Stmt::child_iterator I = Node->child_begin(),
+ for (Stmt::child_iterator I = Node->child_begin(),
E = Node->child_end(); I != E; ++I)
IsInvalid |= Visit(*I);
return IsInvalid;
@@ -74,7 +76,7 @@ namespace {
// evaluated. Parameters of a function declared before a default
// argument expression are in scope and can hide namespace and
// class member names.
- return S->Diag(DRE->getSourceRange().getBegin(),
+ return S->Diag(DRE->getSourceRange().getBegin(),
diag::err_param_default_argument_references_param)
<< Param->getDeclName() << DefaultArg->getSourceRange();
} else if (VarDecl *VDecl = dyn_cast<VarDecl>(Decl)) {
@@ -82,7 +84,7 @@ namespace {
// Local variables shall not be used in default argument
// expressions.
if (VDecl->isBlockVarDecl())
- return S->Diag(DRE->getSourceRange().getBegin(),
+ return S->Diag(DRE->getSourceRange().getBegin(),
diag::err_param_default_argument_references_local)
<< VDecl->getDeclName() << DefaultArg->getSourceRange();
}
@@ -101,15 +103,48 @@ namespace {
}
}
+bool
+Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg,
+ SourceLocation EqualLoc) {
+ QualType ParamType = Param->getType();
+
+ if (RequireCompleteType(Param->getLocation(), Param->getType(),
+ diag::err_typecheck_decl_incomplete_type)) {
+ Param->setInvalidDecl();
+ return true;
+ }
+
+ Expr *Arg = (Expr *)DefaultArg.get();
+
+ // C++ [dcl.fct.default]p5
+ // A default argument expression is implicitly converted (clause
+ // 4) to the parameter type. The default argument expression has
+ // the same semantic constraints as the initializer expression in
+ // a declaration of a variable of the parameter type, using the
+ // copy-initialization semantics (8.5).
+ if (CheckInitializerTypes(Arg, ParamType, EqualLoc,
+ Param->getDeclName(), /*DirectInit=*/false))
+ return true;
+
+ Arg = MaybeCreateCXXExprWithTemporaries(Arg, /*DestroyTemps=*/false);
+
+ // Okay: add the default argument to the parameter
+ Param->setDefaultArg(Arg);
+
+ DefaultArg.release();
+
+ return false;
+}
+
/// ActOnParamDefaultArgument - Check whether the default argument
/// provided for a function parameter is well-formed. If so, attach it
/// to the parameter declaration.
void
-Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
+Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
ExprArg defarg) {
if (!param || !defarg.get())
return;
-
+
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
UnparsedDefaultArgLocs.erase(Param);
@@ -124,25 +159,6 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
return;
}
- // C++ [dcl.fct.default]p5
- // A default argument expression is implicitly converted (clause
- // 4) to the parameter type. The default argument expression has
- // the same semantic constraints as the initializer expression in
- // a declaration of a variable of the parameter type, using the
- // copy-initialization semantics (8.5).
- Expr *DefaultArgPtr = DefaultArg.get();
- bool DefaultInitFailed = CheckInitializerTypes(DefaultArgPtr, ParamType,
- EqualLoc,
- Param->getDeclName(),
- /*DirectInit=*/false);
- if (DefaultArgPtr != DefaultArg.get()) {
- DefaultArg.take();
- DefaultArg.reset(DefaultArgPtr);
- }
- if (DefaultInitFailed) {
- return;
- }
-
// Check that the default argument is well-formed
CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg.get(), this);
if (DefaultArgChecker.Visit(DefaultArg.get())) {
@@ -150,27 +166,23 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
return;
}
- DefaultArgPtr = MaybeCreateCXXExprWithTemporaries(DefaultArg.take(),
- /*DestroyTemps=*/false);
-
- // Okay: add the default argument to the parameter
- Param->setDefaultArg(DefaultArgPtr);
+ SetParamDefaultArgument(Param, move(DefaultArg), EqualLoc);
}
/// ActOnParamUnparsedDefaultArgument - We've seen a default
/// argument for a function parameter, but we can't parse it yet
/// because we're inside a class definition. Note that this default
/// argument will be parsed later.
-void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
+void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
SourceLocation ArgLoc) {
if (!param)
return;
-
+
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
if (Param)
Param->setUnparsedDefaultArg();
-
+
UnparsedDefaultArgLocs[Param] = ArgLoc;
}
@@ -179,11 +191,11 @@ void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
void Sema::ActOnParamDefaultArgumentError(DeclPtrTy param) {
if (!param)
return;
-
+
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
-
+
Param->setInvalidDecl();
-
+
UnparsedDefaultArgLocs.erase(Param);
}
@@ -230,7 +242,6 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
bool Invalid = false;
// C++ [dcl.fct.default]p4:
- //
// For non-template functions, default arguments can be added in
// later declarations of a function in the same
// scope. Declarations in different scopes have completely
@@ -242,25 +253,97 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
// arguments supplied in this or previous declarations. A
// default argument shall not be redefined by a later
// declaration (not even to the same value).
+ //
+ // C++ [dcl.fct.default]p6:
+ // Except for member functions of class templates, the default arguments
+ // in a member function definition that appears outside of the class
+ // definition are added to the set of default arguments provided by the
+ // member function declaration in the class definition.
for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) {
ParmVarDecl *OldParam = Old->getParamDecl(p);
ParmVarDecl *NewParam = New->getParamDecl(p);
- if(OldParam->getDefaultArg() && NewParam->getDefaultArg()) {
- Diag(NewParam->getLocation(),
+ if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) {
+ Diag(NewParam->getLocation(),
diag::err_param_default_argument_redefinition)
- << NewParam->getDefaultArg()->getSourceRange();
- Diag(OldParam->getLocation(), diag::note_previous_definition);
+ << NewParam->getDefaultArgRange();
+
+ // Look for the function declaration where the default argument was
+ // actually written, which may be a declaration prior to Old.
+ for (FunctionDecl *Older = Old->getPreviousDeclaration();
+ Older; Older = Older->getPreviousDeclaration()) {
+ if (!Older->getParamDecl(p)->hasDefaultArg())
+ break;
+
+ OldParam = Older->getParamDecl(p);
+ }
+
+ Diag(OldParam->getLocation(), diag::note_previous_definition)
+ << OldParam->getDefaultArgRange();
Invalid = true;
- } else if (OldParam->getDefaultArg()) {
+ } else if (OldParam->hasDefaultArg()) {
// Merge the old default argument into the new parameter
- NewParam->setDefaultArg(OldParam->getDefaultArg());
+ if (OldParam->hasUninstantiatedDefaultArg())
+ NewParam->setUninstantiatedDefaultArg(
+ OldParam->getUninstantiatedDefaultArg());
+ else
+ NewParam->setDefaultArg(OldParam->getDefaultArg());
+ } else if (NewParam->hasDefaultArg()) {
+ if (New->getDescribedFunctionTemplate()) {
+ // Paragraph 4, quoted above, only applies to non-template functions.
+ Diag(NewParam->getLocation(),
+ diag::err_param_default_argument_template_redecl)
+ << NewParam->getDefaultArgRange();
+ Diag(Old->getLocation(), diag::note_template_prev_declaration)
+ << false;
+ } else if (New->getTemplateSpecializationKind()
+ != TSK_ImplicitInstantiation &&
+ New->getTemplateSpecializationKind() != TSK_Undeclared) {
+ // C++ [temp.expr.spec]p21:
+ // Default function arguments shall not be specified in a declaration
+ // or a definition for one of the following explicit specializations:
+ // - the explicit specialization of a function template;
+ // - the explicit specialization of a member function template;
+ // - the explicit specialization of a member function of a class
+ // template where the class template specialization to which the
+ // member function specialization belongs is implicitly
+ // instantiated.
+ Diag(NewParam->getLocation(), diag::err_template_spec_default_arg)
+ << (New->getTemplateSpecializationKind() ==TSK_ExplicitSpecialization)
+ << New->getDeclName()
+ << NewParam->getDefaultArgRange();
+ } else if (New->getDeclContext()->isDependentContext()) {
+ // C++ [dcl.fct.default]p6 (DR217):
+ // Default arguments for a member function of a class template shall
+ // be specified on the initial declaration of the member function
+ // within the class template.
+ //
+ // Reading the tea leaves a bit in DR217 and its reference to DR205
+ // leads me to the conclusion that one cannot add default function
+ // arguments for an out-of-line definition of a member function of a
+ // dependent type.
+ int WhichKind = 2;
+ if (CXXRecordDecl *Record
+ = dyn_cast<CXXRecordDecl>(New->getDeclContext())) {
+ if (Record->getDescribedClassTemplate())
+ WhichKind = 0;
+ else if (isa<ClassTemplatePartialSpecializationDecl>(Record))
+ WhichKind = 1;
+ else
+ WhichKind = 2;
+ }
+
+ Diag(NewParam->getLocation(),
+ diag::err_param_default_argument_member_template_redecl)
+ << WhichKind
+ << NewParam->getDefaultArgRange();
+ }
}
}
if (CheckEquivalentExceptionSpec(
- Old->getType()->getAsFunctionProtoType(), Old->getLocation(),
- New->getType()->getAsFunctionProtoType(), New->getLocation())) {
+ Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
+ New->getType()->getAs<FunctionProtoType>(), New->getLocation())) {
Invalid = true;
}
@@ -277,7 +360,7 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
// Find first parameter with a default argument
for (p = 0; p < NumParams; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
- if (Param->getDefaultArg())
+ if (Param->hasDefaultArg())
break;
}
@@ -288,19 +371,19 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
// declarations. A default argument shall not be redefined
// by a later declaration (not even to the same value).
unsigned LastMissingDefaultArg = 0;
- for(; p < NumParams; ++p) {
+ for (; p < NumParams; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
- if (!Param->getDefaultArg()) {
+ if (!Param->hasDefaultArg()) {
if (Param->isInvalidDecl())
/* We already complained about this parameter. */;
else if (Param->getIdentifier())
- Diag(Param->getLocation(),
+ Diag(Param->getLocation(),
diag::err_param_default_argument_missing_name)
<< Param->getIdentifier();
else
- Diag(Param->getLocation(),
+ Diag(Param->getLocation(),
diag::err_param_default_argument_missing);
-
+
LastMissingDefaultArg = p;
}
}
@@ -329,7 +412,7 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
const CXXScopeSpec *SS) {
CXXRecordDecl *CurDecl;
if (SS && SS->isSet() && !SS->isInvalid()) {
- DeclContext *DC = computeDeclContext(*SS);
+ DeclContext *DC = computeDeclContext(*SS, true);
CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);
} else
CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
@@ -340,7 +423,7 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
return false;
}
-/// \brief Check the validity of a C++ base class specifier.
+/// \brief Check the validity of a C++ base class specifier.
///
/// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics
/// and returns NULL otherwise.
@@ -348,7 +431,7 @@ CXXBaseSpecifier *
Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
- QualType BaseType,
+ QualType BaseType,
SourceLocation BaseLoc) {
// C++ [class.union]p1:
// A union shall not have base classes.
@@ -359,7 +442,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
}
if (BaseType->isDependentType())
- return new CXXBaseSpecifier(SpecifierRange, Virtual,
+ return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
Class->getTagKind() == RecordDecl::TK_class,
Access, BaseType);
@@ -379,16 +462,21 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// C++ [class.derived]p2:
// The class-name in a base-specifier shall not be an incompletely
// defined class.
- if (RequireCompleteType(BaseLoc, BaseType, diag::err_incomplete_base_class,
- SpecifierRange))
+ if (RequireCompleteType(BaseLoc, BaseType,
+ PDiag(diag::err_incomplete_base_class)
+ << SpecifierRange))
return 0;
- // If the base class is polymorphic, the new one is, too.
- RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl();
+ // If the base class is polymorphic or isn't empty, the new one is/isn't, too.
+ RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->getDecl();
assert(BaseDecl && "Record type has no declaration");
BaseDecl = BaseDecl->getDefinition(Context);
assert(BaseDecl && "Base type is not incomplete, but has no definition");
- if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic())
+ CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
+ assert(CXXBaseDecl && "Base type is not a C++ type");
+ if (!CXXBaseDecl->isEmpty())
+ Class->setEmpty(false);
+ if (CXXBaseDecl->isPolymorphic())
Class->setPolymorphic(true);
// C++ [dcl.init.aggr]p1:
@@ -400,33 +488,59 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// C++ [class.ctor]p5:
// A constructor is trivial if its class has no virtual base classes.
Class->setHasTrivialConstructor(false);
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if its class has no virtual base classes.
+ Class->setHasTrivialCopyConstructor(false);
+
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if its class has no virtual
+ // base classes.
+ Class->setHasTrivialCopyAssignment(false);
+
+ // C++0x [meta.unary.prop] is_empty:
+ // T is a class type, but not a union type, with ... no virtual base
+ // classes
+ Class->setEmpty(false);
} else {
// C++ [class.ctor]p5:
- // A constructor is trivial if all the direct base classes of its
+ // A constructor is trivial if all the direct base classes of its
// class have trivial constructors.
- Class->setHasTrivialConstructor(cast<CXXRecordDecl>(BaseDecl)->
- hasTrivialConstructor());
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialConstructor())
+ Class->setHasTrivialConstructor(false);
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if all the direct base classes of its
+ // class have trivial copy constructors.
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyConstructor())
+ Class->setHasTrivialCopyConstructor(false);
+
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if all the direct base classes
+ // of its class have trivial copy assignment operators.
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyAssignment())
+ Class->setHasTrivialCopyAssignment(false);
}
// C++ [class.ctor]p3:
// A destructor is trivial if all the direct base classes of its class
// have trivial destructors.
- Class->setHasTrivialDestructor(cast<CXXRecordDecl>(BaseDecl)->
- hasTrivialDestructor());
-
+ if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialDestructor())
+ Class->setHasTrivialDestructor(false);
+
// Create the base specifier.
// FIXME: Allocate via ASTContext?
- return new CXXBaseSpecifier(SpecifierRange, Virtual,
- Class->getTagKind() == RecordDecl::TK_class,
+ return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
+ Class->getTagKind() == RecordDecl::TK_class,
Access, BaseType);
}
/// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is
/// one entry in the base class list of a class specifier, for
-/// example:
-/// class foo : public bar, virtual private baz {
+/// example:
+/// class foo : public bar, virtual private baz {
/// 'public bar' and 'virtual private baz' are each base-specifiers.
-Sema::BaseResult
+Sema::BaseResult
Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
TypeTy *basetype, SourceLocation BaseLoc) {
@@ -435,12 +549,12 @@ Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange,
AdjustDeclIfTemplate(classdecl);
CXXRecordDecl *Class = cast<CXXRecordDecl>(classdecl.getAs<Decl>());
- QualType BaseType = QualType::getFromOpaquePtr(basetype);
+ QualType BaseType = GetTypeFromParser(basetype);
if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
Virtual, Access,
BaseType, BaseLoc))
return BaseSpec;
-
+
return true;
}
@@ -461,7 +575,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
unsigned NumGoodBases = 0;
bool Invalid = false;
for (unsigned idx = 0; idx < NumBases; ++idx) {
- QualType NewBaseType
+ QualType NewBaseType
= Context.getCanonicalType(Bases[idx]->getType());
NewBaseType = NewBaseType.getUnqualifiedType();
@@ -476,7 +590,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
// Delete the duplicate base class specifier; we're going to
// overwrite its pointer later.
- delete Bases[idx];
+ Context.Deallocate(Bases[idx]);
Invalid = true;
} else {
@@ -492,7 +606,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
// Delete the remaining (good) base class specifiers, since their
// data has been copied into the CXXRecordDecl.
for (unsigned idx = 0; idx < NumGoodBases; ++idx)
- delete Bases[idx];
+ Context.Deallocate(Bases[idx]);
return Invalid;
}
@@ -500,7 +614,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
/// ActOnBaseSpecifiers - Attach the given base specifiers to the
/// class, after checking whether there are any duplicate base
/// classes.
-void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
+void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
unsigned NumBases) {
if (!ClassDecl || !Bases || !NumBases)
return;
@@ -510,6 +624,139 @@ void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
(CXXBaseSpecifier**)(Bases), NumBases);
}
+/// \brief Determine whether the type \p Derived is a C++ class that is
+/// derived from the type \p Base.
+bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
+ if (!getLangOptions().CPlusPlus)
+ return false;
+
+ const RecordType *DerivedRT = Derived->getAs<RecordType>();
+ if (!DerivedRT)
+ return false;
+
+ const RecordType *BaseRT = Base->getAs<RecordType>();
+ if (!BaseRT)
+ return false;
+
+ CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl());
+ CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl());
+ return DerivedRD->isDerivedFrom(BaseRD);
+}
+
+/// \brief Determine whether the type \p Derived is a C++ class that is
+/// derived from the type \p Base.
+bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
+ if (!getLangOptions().CPlusPlus)
+ return false;
+
+ const RecordType *DerivedRT = Derived->getAs<RecordType>();
+ if (!DerivedRT)
+ return false;
+
+ const RecordType *BaseRT = Base->getAs<RecordType>();
+ if (!BaseRT)
+ return false;
+
+ CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl());
+ CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl());
+ return DerivedRD->isDerivedFrom(BaseRD, Paths);
+}
+
+/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
+/// conversion (where Derived and Base are class types) is
+/// well-formed, meaning that the conversion is unambiguous (and
+/// that all of the base classes are accessible). Returns true
+/// and emits a diagnostic if the code is ill-formed, returns false
+/// otherwise. Loc is the location where this routine should point to
+/// if there is an error, and Range is the source range to highlight
+/// if there is an error.
+bool
+Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
+ unsigned InaccessibleBaseID,
+ unsigned AmbigiousBaseConvID,
+ SourceLocation Loc, SourceRange Range,
+ DeclarationName Name) {
+ // First, determine whether the path from Derived to Base is
+ // ambiguous. This is slightly more expensive than checking whether
+ // the Derived to Base conversion exists, because here we need to
+ // explore multiple paths to determine if there is an ambiguity.
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ bool DerivationOkay = IsDerivedFrom(Derived, Base, Paths);
+ assert(DerivationOkay &&
+ "Can only be used with a derived-to-base conversion");
+ (void)DerivationOkay;
+
+ if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
+ // Check that the base class can be accessed.
+ return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc,
+ Name);
+ }
+
+ // We know that the derived-to-base conversion is ambiguous, and
+ // we're going to produce a diagnostic. Perform the derived-to-base
+ // search just one more time to compute all of the possible paths so
+ // that we can print them out. This is more expensive than any of
+ // the previous derived-to-base checks we've done, but at this point
+ // performance isn't as much of an issue.
+ Paths.clear();
+ Paths.setRecordingPaths(true);
+ bool StillOkay = IsDerivedFrom(Derived, Base, Paths);
+ assert(StillOkay && "Can only be used with a derived-to-base conversion");
+ (void)StillOkay;
+
+ // Build up a textual representation of the ambiguous paths, e.g.,
+ // D -> B -> A, that will be used to illustrate the ambiguous
+ // conversions in the diagnostic. We only print one of the paths
+ // to each base class subobject.
+ std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
+
+ Diag(Loc, AmbigiousBaseConvID)
+ << Derived << Base << PathDisplayStr << Range << Name;
+ return true;
+}
+
+bool
+Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
+ SourceLocation Loc, SourceRange Range) {
+ return CheckDerivedToBaseConversion(Derived, Base,
+ diag::err_conv_to_inaccessible_base,
+ diag::err_ambiguous_derived_to_base_conv,
+ Loc, Range, DeclarationName());
+}
+
+
+/// @brief Builds a string representing ambiguous paths from a
+/// specific derived class to different subobjects of the same base
+/// class.
+///
+/// This function builds a string that can be used in error messages
+/// to show the different paths that one can take through the
+/// inheritance hierarchy to go from the derived class to different
+/// subobjects of a base class. The result looks something like this:
+/// @code
+/// struct D -> struct B -> struct A
+/// struct D -> struct C -> struct A
+/// @endcode
+std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) {
+ std::string PathDisplayStr;
+ std::set<unsigned> DisplayedPaths;
+ for (CXXBasePaths::paths_iterator Path = Paths.begin();
+ Path != Paths.end(); ++Path) {
+ if (DisplayedPaths.insert(Path->back().SubobjectNumber).second) {
+ // We haven't displayed a path to this particular base
+ // class subobject yet.
+ PathDisplayStr += "\n ";
+ PathDisplayStr += Context.getTypeDeclType(Paths.getOrigin()).getAsString();
+ for (CXXBasePath::const_iterator Element = Path->begin();
+ Element != Path->end(); ++Element)
+ PathDisplayStr += " -> " + Element->Base->getType().getAsString();
+ }
+ }
+
+ return PathDisplayStr;
+}
+
//===----------------------------------------------------------------------===//
// C++ class member Handling
//===----------------------------------------------------------------------===//
@@ -520,6 +767,7 @@ void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
/// any.
Sema::DeclPtrTy
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
+ MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BW, ExprTy *InitExpr, bool Deleted) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationName Name = GetNameForDeclarator(D);
@@ -529,6 +777,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
bool isFunc = D.isFunctionDeclarator();
+ assert(!DS.isFriendSpecified());
+
// C++ 9.2p6: A member shall not be declared to have automatic storage
// duration (auto, register) or with the extern storage-class-specifier.
// C++ 7.1.1p8: The mutable specifier can be applied only to names of class
@@ -546,7 +796,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function);
else
Diag(DS.getThreadSpecLoc(), diag::err_mutable_function);
-
+
// FIXME: It would be nicer if the keyword was ignored only for this
// declarator. Otherwise we could get follow-up errors.
D.getMutableDeclSpec().ClearStorageClassSpecs();
@@ -585,7 +835,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// typedef int f();
// f a;
//
- QualType TDType = QualType::getFromOpaquePtr(DS.getTypeRep());
+ QualType TDType = GetTypeFromParser(DS.getTypeRep());
isFunc = TDType->isFunctionType();
}
@@ -595,11 +845,13 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Decl *Member;
if (isInstField) {
+ // FIXME: Check for template parameters!
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
AS);
assert(Member && "HandleField never returns null");
} else {
- Member = ActOnDeclarator(S, D).getAs<Decl>();
+ Member = HandleDeclarator(S, D, move(TemplateParameterLists), false)
+ .getAs<Decl>();
if (!Member) {
if (BitWidth) DeleteExpr(BitWidth);
return DeclPtrTy();
@@ -622,16 +874,21 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// A function typedef ("typedef int f(); f a;").
// C++ 9.6p3: A bit-field shall have integral or enumeration type.
Diag(Loc, diag::err_not_integral_type_bitfield)
- << Name << cast<ValueDecl>(Member)->getType()
+ << Name << cast<ValueDecl>(Member)->getType()
<< BitWidth->getSourceRange();
}
-
+
DeleteExpr(BitWidth);
BitWidth = 0;
Member->setInvalidDecl();
}
Member->setAccess(AS);
+
+ // If we have declared a member function template, set the access of the
+ // templated declaration as well.
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member))
+ FunTmpl->getTemplatedDecl()->setAccess(AS);
}
assert((Name || isInstField) && "No identifier for non-field ?");
@@ -649,7 +906,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
}
/// ActOnMemInitializer - Handle a C++ member initializer.
-Sema::MemInitResult
+Sema::MemInitResult
Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
Scope *S,
const CXXScopeSpec &SS,
@@ -662,8 +919,10 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
SourceLocation RParenLoc) {
if (!ConstructorD)
return true;
-
- CXXConstructorDecl *Constructor
+
+ AdjustDeclIfTemplate(ConstructorD);
+
+ CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(ConstructorD.getAs<Decl>());
if (!Constructor) {
// The user wrote a constructor initializer on a function that is
@@ -688,141 +947,657 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!SS.getScopeRep() && !TemplateTypeTy) {
// Look for a member, first.
FieldDecl *Member = 0;
- DeclContext::lookup_result Result
+ DeclContext::lookup_result Result
= ClassDecl->lookup(MemberOrBase);
if (Result.first != Result.second)
Member = dyn_cast<FieldDecl>(*Result.first);
// FIXME: Handle members of an anonymous union.
- if (Member) {
- // FIXME: Perform direct initialization of the member.
- return new CXXBaseOrMemberInitializer(Member, (Expr **)Args, NumArgs,
- IdLoc);
- }
+ if (Member)
+ return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
+ RParenLoc);
}
// It didn't name a member, so see if it names a class.
- TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy
+ TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy
: getTypeName(*MemberOrBase, IdLoc, S, &SS);
if (!BaseTy)
return Diag(IdLoc, diag::err_mem_init_not_member_or_class)
<< MemberOrBase << SourceRange(IdLoc, RParenLoc);
-
- QualType BaseType = QualType::getFromOpaquePtr(BaseTy);
- if (!BaseType->isRecordType() && !BaseType->isDependentType())
- return Diag(IdLoc, diag::err_base_init_does_not_name_class)
- << BaseType << SourceRange(IdLoc, RParenLoc);
- // C++ [class.base.init]p2:
- // [...] Unless the mem-initializer-id names a nonstatic data
- // member of the constructor’s class or a direct or virtual base
- // of that class, the mem-initializer is ill-formed. A
- // mem-initializer-list can initialize a base class using any
- // name that denotes that base class type.
-
- // First, check for a direct base class.
- const CXXBaseSpecifier *DirectBaseSpec = 0;
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- if (Context.getCanonicalType(BaseType).getUnqualifiedType() ==
- Context.getCanonicalType(Base->getType()).getUnqualifiedType()) {
- // We found a direct base of this type. That's what we're
- // initializing.
- DirectBaseSpec = &*Base;
- break;
+ QualType BaseType = GetTypeFromParser(BaseTy);
+
+ return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc,
+ RParenLoc, ClassDecl);
+}
+
+Sema::MemInitResult
+Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
+ unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation RParenLoc) {
+ bool HasDependentArg = false;
+ for (unsigned i = 0; i < NumArgs; i++)
+ HasDependentArg |= Args[i]->isTypeDependent();
+
+ CXXConstructorDecl *C = 0;
+ QualType FieldType = Member->getType();
+ if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+ FieldType = Array->getElementType();
+ if (FieldType->isDependentType()) {
+ // Can't check init for dependent type.
+ } else if (FieldType->getAs<RecordType>()) {
+ if (!HasDependentArg) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ C = PerformInitializationByConstructor(FieldType,
+ MultiExprArg(*this,
+ (void**)Args,
+ NumArgs),
+ IdLoc,
+ SourceRange(IdLoc, RParenLoc),
+ Member->getDeclName(), IK_Direct,
+ ConstructorArgs);
+
+ if (C) {
+ // Take over the constructor arguments as our own.
+ NumArgs = ConstructorArgs.size();
+ Args = (Expr **)ConstructorArgs.take();
+ }
}
+ } else if (NumArgs != 1 && NumArgs != 0) {
+ return Diag(IdLoc, diag::err_mem_initializer_mismatch)
+ << Member->getDeclName() << SourceRange(IdLoc, RParenLoc);
+ } else if (!HasDependentArg) {
+ Expr *NewExp;
+ if (NumArgs == 0) {
+ if (FieldType->isReferenceType()) {
+ Diag(IdLoc, diag::err_null_intialized_reference_member)
+ << Member->getDeclName();
+ return Diag(Member->getLocation(), diag::note_declared_at);
+ }
+ NewExp = new (Context) CXXZeroInitValueExpr(FieldType, IdLoc, RParenLoc);
+ NumArgs = 1;
+ }
+ else
+ NewExp = (Expr*)Args[0];
+ if (PerformCopyInitialization(NewExp, FieldType, "passing"))
+ return true;
+ Args[0] = NewExp;
}
-
- // Check for a virtual base class.
- // FIXME: We might be able to short-circuit this if we know in advance that
- // there are no virtual bases.
- const CXXBaseSpecifier *VirtualBaseSpec = 0;
- if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
- // We haven't found a base yet; search the class hierarchy for a
- // virtual base class.
- BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
- if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) {
- for (BasePaths::paths_iterator Path = Paths.begin();
- Path != Paths.end(); ++Path) {
- if (Path->back().Base->isVirtual()) {
- VirtualBaseSpec = Path->back().Base;
- break;
+ // FIXME: Perform direct initialization of the member.
+ return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args,
+ NumArgs, C, IdLoc, RParenLoc);
+}
+
+Sema::MemInitResult
+Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
+ unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) {
+ bool HasDependentArg = false;
+ for (unsigned i = 0; i < NumArgs; i++)
+ HasDependentArg |= Args[i]->isTypeDependent();
+
+ if (!BaseType->isDependentType()) {
+ if (!BaseType->isRecordType())
+ return Diag(IdLoc, diag::err_base_init_does_not_name_class)
+ << BaseType << SourceRange(IdLoc, RParenLoc);
+
+ // C++ [class.base.init]p2:
+ // [...] Unless the mem-initializer-id names a nonstatic data
+ // member of the constructor’s class or a direct or virtual base
+ // of that class, the mem-initializer is ill-formed. A
+ // mem-initializer-list can initialize a base class using any
+ // name that denotes that base class type.
+
+ // First, check for a direct base class.
+ const CXXBaseSpecifier *DirectBaseSpec = 0;
+ for (CXXRecordDecl::base_class_const_iterator Base =
+ ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) {
+ if (Context.getCanonicalType(BaseType).getUnqualifiedType() ==
+ Context.getCanonicalType(Base->getType()).getUnqualifiedType()) {
+ // We found a direct base of this type. That's what we're
+ // initializing.
+ DirectBaseSpec = &*Base;
+ break;
+ }
+ }
+
+ // Check for a virtual base class.
+ // FIXME: We might be able to short-circuit this if we know in advance that
+ // there are no virtual bases.
+ const CXXBaseSpecifier *VirtualBaseSpec = 0;
+ if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
+ // We haven't found a base yet; search the class hierarchy for a
+ // virtual base class.
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) {
+ for (CXXBasePaths::paths_iterator Path = Paths.begin();
+ Path != Paths.end(); ++Path) {
+ if (Path->back().Base->isVirtual()) {
+ VirtualBaseSpec = Path->back().Base;
+ break;
+ }
}
}
}
+
+ // C++ [base.class.init]p2:
+ // If a mem-initializer-id is ambiguous because it designates both
+ // a direct non-virtual base class and an inherited virtual base
+ // class, the mem-initializer is ill-formed.
+ if (DirectBaseSpec && VirtualBaseSpec)
+ return Diag(IdLoc, diag::err_base_init_direct_and_virtual)
+ << BaseType << SourceRange(IdLoc, RParenLoc);
+ // C++ [base.class.init]p2:
+ // Unless the mem-initializer-id names a nonstatic data membeer of the
+ // constructor's class ot a direst or virtual base of that class, the
+ // mem-initializer is ill-formed.
+ if (!DirectBaseSpec && !VirtualBaseSpec)
+ return Diag(IdLoc, diag::err_not_direct_base_or_virtual)
+ << BaseType << ClassDecl->getNameAsCString()
+ << SourceRange(IdLoc, RParenLoc);
}
- // C++ [base.class.init]p2:
- // If a mem-initializer-id is ambiguous because it designates both
- // a direct non-virtual base class and an inherited virtual base
- // class, the mem-initializer is ill-formed.
- if (DirectBaseSpec && VirtualBaseSpec)
- return Diag(IdLoc, diag::err_base_init_direct_and_virtual)
- << MemberOrBase << SourceRange(IdLoc, RParenLoc);
- // C++ [base.class.init]p2:
- // Unless the mem-initializer-id names a nonstatic data membeer of the
- // constructor's class ot a direst or virtual base of that class, the
- // mem-initializer is ill-formed.
- if (!DirectBaseSpec && !VirtualBaseSpec)
- return Diag(IdLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << ClassDecl->getNameAsCString()
- << SourceRange(IdLoc, RParenLoc);
-
+ CXXConstructorDecl *C = 0;
+ if (!BaseType->isDependentType() && !HasDependentArg) {
+ DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(BaseType));
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ C = PerformInitializationByConstructor(BaseType,
+ MultiExprArg(*this,
+ (void**)Args, NumArgs),
+ IdLoc, SourceRange(IdLoc, RParenLoc),
+ Name, IK_Direct,
+ ConstructorArgs);
+ if (C) {
+ // Take over the constructor arguments as our own.
+ NumArgs = ConstructorArgs.size();
+ Args = (Expr **)ConstructorArgs.take();
+ }
+ }
+
+ return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args,
+ NumArgs, C, IdLoc, RParenLoc);
+}
+
+void
+Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers,
+ llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
+ llvm::SmallVectorImpl<FieldDecl *>&Fields) {
+ // We need to build the initializer AST according to order of construction
+ // and not what user specified in the Initializers list.
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
+ llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
+ bool HasDependentBaseInit = false;
+
+ for (unsigned i = 0; i < NumInitializers; i++) {
+ CXXBaseOrMemberInitializer *Member = Initializers[i];
+ if (Member->isBaseInitializer()) {
+ if (Member->getBaseClass()->isDependentType())
+ HasDependentBaseInit = true;
+ AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
+ } else {
+ AllBaseFields[Member->getMember()] = Member;
+ }
+ }
+
+ if (HasDependentBaseInit) {
+ // FIXME. This does not preserve the ordering of the initializers.
+ // Try (with -Wreorder)
+ // template<class X> struct A {};
+ // template<class X> struct B : A<X> {
+ // B() : x1(10), A<X>() {}
+ // int x1;
+ // };
+ // B<int> x;
+ // On seeing one dependent type, we should essentially exit this routine
+ // while preserving user-declared initializer list. When this routine is
+ // called during instantiatiation process, this routine will rebuild the
+ // oderdered initializer list correctly.
+
+ // If we have a dependent base initialization, we can't determine the
+ // association between initializers and bases; just dump the known
+ // initializers into the list, and don't try to deal with other bases.
+ for (unsigned i = 0; i < NumInitializers; i++) {
+ CXXBaseOrMemberInitializer *Member = Initializers[i];
+ if (Member->isBaseInitializer())
+ AllToInit.push_back(Member);
+ }
+ } else {
+ // Push virtual bases before others.
+ for (CXXRecordDecl::base_class_iterator VBase =
+ ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
+ if (VBase->getType()->isDependentType())
+ continue;
+ if (CXXBaseOrMemberInitializer *Value =
+ AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
+ CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null");
+ if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context))
+ MarkDeclarationReferenced(Value->getSourceLocation(), Ctor);
+ AllToInit.push_back(Value);
+ }
+ else {
+ CXXRecordDecl *VBaseDecl =
+ cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ assert(VBaseDecl && "setBaseOrMemberInitializers - VBaseDecl null");
+ CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context);
+ if (!Ctor)
+ Bases.push_back(VBase);
+ else
+ MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
+
+ CXXBaseOrMemberInitializer *Member =
+ new (Context) CXXBaseOrMemberInitializer(VBase->getType(), 0, 0,
+ Ctor,
+ SourceLocation(),
+ SourceLocation());
+ AllToInit.push_back(Member);
+ }
+ }
+
+ for (CXXRecordDecl::base_class_iterator Base =
+ ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); Base != E; ++Base) {
+ // Virtuals are in the virtual base list and already constructed.
+ if (Base->isVirtual())
+ continue;
+ // Skip dependent types.
+ if (Base->getType()->isDependentType())
+ continue;
+ if (CXXBaseOrMemberInitializer *Value =
+ AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
+ CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null");
+ if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context))
+ MarkDeclarationReferenced(Value->getSourceLocation(), Ctor);
+ AllToInit.push_back(Value);
+ }
+ else {
+ CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null");
+ CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context);
+ if (!Ctor)
+ Bases.push_back(Base);
+ else
+ MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
+
+ CXXBaseOrMemberInitializer *Member =
+ new (Context) CXXBaseOrMemberInitializer(Base->getType(), 0, 0,
+ BaseDecl->getDefaultConstructor(Context),
+ SourceLocation(),
+ SourceLocation());
+ AllToInit.push_back(Member);
+ }
+ }
+ }
+
+ // non-static data members.
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); Field != E; ++Field) {
+ if ((*Field)->isAnonymousStructOrUnion()) {
+ if (const RecordType *FieldClassType =
+ Field->getType()->getAs<RecordType>()) {
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
+ EA = FieldClassDecl->field_end(); FA != EA; FA++) {
+ if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) {
+ // 'Member' is the anonymous union field and 'AnonUnionMember' is
+ // set to the anonymous union data member used in the initializer
+ // list.
+ Value->setMember(*Field);
+ Value->setAnonUnionMember(*FA);
+ AllToInit.push_back(Value);
+ break;
+ }
+ }
+ }
+ continue;
+ }
+ if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) {
+ QualType FT = (*Field)->getType();
+ if (const RecordType* RT = FT->getAs<RecordType>()) {
+ CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RT->getDecl());
+ assert(FieldRecDecl && "setBaseOrMemberInitializers - BaseDecl null");
+ if (CXXConstructorDecl *Ctor =
+ FieldRecDecl->getDefaultConstructor(Context))
+ MarkDeclarationReferenced(Value->getSourceLocation(), Ctor);
+ }
+ AllToInit.push_back(Value);
+ continue;
+ }
+
+ QualType FT = Context.getBaseElementType((*Field)->getType());
+ if (const RecordType* RT = FT->getAs<RecordType>()) {
+ CXXConstructorDecl *Ctor =
+ cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context);
+ if (!Ctor && !FT->isDependentType())
+ Fields.push_back(*Field);
+ CXXBaseOrMemberInitializer *Member =
+ new (Context) CXXBaseOrMemberInitializer((*Field), 0, 0,
+ Ctor,
+ SourceLocation(),
+ SourceLocation());
+ AllToInit.push_back(Member);
+ if (Ctor)
+ MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
+ if (FT.isConstQualified() && (!Ctor || Ctor->isTrivial())) {
+ Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ }
+ }
+ else if (FT->isReferenceType()) {
+ Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getDeclName();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ }
+ else if (FT.isConstQualified()) {
+ Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ }
+ }
+
+ NumInitializers = AllToInit.size();
+ if (NumInitializers > 0) {
+ Constructor->setNumBaseOrMemberInitializers(NumInitializers);
+ CXXBaseOrMemberInitializer **baseOrMemberInitializers =
+ new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
+
+ Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
+ for (unsigned Idx = 0; Idx < NumInitializers; ++Idx)
+ baseOrMemberInitializers[Idx] = AllToInit[Idx];
+ }
+}
+
+void
+Sema::BuildBaseOrMemberInitializers(ASTContext &C,
+ CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers
+ ) {
+ llvm::SmallVector<CXXBaseSpecifier *, 4>Bases;
+ llvm::SmallVector<FieldDecl *, 4>Members;
+
+ setBaseOrMemberInitializers(Constructor,
+ Initializers, NumInitializers, Bases, Members);
+ for (unsigned int i = 0; i < Bases.size(); i++)
+ Diag(Bases[i]->getSourceRange().getBegin(),
+ diag::err_missing_default_constructor) << 0 << Bases[i]->getType();
+ for (unsigned int i = 0; i < Members.size(); i++)
+ Diag(Members[i]->getLocation(), diag::err_missing_default_constructor)
+ << 1 << Members[i]->getType();
+}
+
+static void *GetKeyForTopLevelField(FieldDecl *Field) {
+ // For anonymous unions, use the class declaration as the key.
+ if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
+ if (RT->getDecl()->isAnonymousStructOrUnion())
+ return static_cast<void *>(RT->getDecl());
+ }
+ return static_cast<void *>(Field);
+}
+
+static void *GetKeyForBase(QualType BaseType) {
+ if (const RecordType *RT = BaseType->getAs<RecordType>())
+ return (void *)RT;
+
+ assert(0 && "Unexpected base type!");
+ return 0;
+}
- return new CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, NumArgs,
- IdLoc);
+static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member,
+ bool MemberMaybeAnon = false) {
+ // For fields injected into the class via declaration of an anonymous union,
+ // use its anonymous union class declaration as the unique key.
+ if (Member->isMemberInitializer()) {
+ FieldDecl *Field = Member->getMember();
+
+ // After BuildBaseOrMemberInitializers call, Field is the anonymous union
+ // data member of the class. Data member used in the initializer list is
+ // in AnonUnionMember field.
+ if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
+ Field = Member->getAnonUnionMember();
+ if (Field->getDeclContext()->isRecord()) {
+ RecordDecl *RD = cast<RecordDecl>(Field->getDeclContext());
+ if (RD->isAnonymousStructOrUnion())
+ return static_cast<void *>(RD);
+ }
+ return static_cast<void *>(Field);
+ }
+
+ return GetKeyForBase(QualType(Member->getBaseClass(), 0));
}
-void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
+void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
MemInitTy **MemInits, unsigned NumMemInits) {
if (!ConstructorDecl)
return;
-
- CXXConstructorDecl *Constructor
+
+ AdjustDeclIfTemplate(ConstructorDecl);
+
+ CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
-
+
if (!Constructor) {
Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
return;
}
- llvm::DenseMap<void*, CXXBaseOrMemberInitializer *>Members;
- bool err = false;
+
+ if (!Constructor->isDependentContext()) {
+ llvm::DenseMap<void*, CXXBaseOrMemberInitializer *>Members;
+ bool err = false;
+ for (unsigned i = 0; i < NumMemInits; i++) {
+ CXXBaseOrMemberInitializer *Member =
+ static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]);
+ void *KeyToMember = GetKeyForMember(Member);
+ CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
+ if (!PrevMember) {
+ PrevMember = Member;
+ continue;
+ }
+ if (FieldDecl *Field = Member->getMember())
+ Diag(Member->getSourceLocation(),
+ diag::error_multiple_mem_initialization)
+ << Field->getNameAsString();
+ else {
+ Type *BaseClass = Member->getBaseClass();
+ assert(BaseClass && "ActOnMemInitializers - neither field or base");
+ Diag(Member->getSourceLocation(),
+ diag::error_multiple_base_initialization)
+ << QualType(BaseClass, 0);
+ }
+ Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
+ << 0;
+ err = true;
+ }
+
+ if (err)
+ return;
+ }
+
+ BuildBaseOrMemberInitializers(Context, Constructor,
+ reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
+ NumMemInits);
+
+ if (Constructor->isDependentContext())
+ return;
+
+ if (Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
+ Diagnostic::Ignored &&
+ Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
+ Diagnostic::Ignored)
+ return;
+
+ // Also issue warning if order of ctor-initializer list does not match order
+ // of 1) base class declarations and 2) order of non-static data members.
+ llvm::SmallVector<const void*, 32> AllBaseOrMembers;
+
+ CXXRecordDecl *ClassDecl
+ = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ // Push virtual bases before others.
+ for (CXXRecordDecl::base_class_iterator VBase =
+ ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); VBase != E; ++VBase)
+ AllBaseOrMembers.push_back(GetKeyForBase(VBase->getType()));
+
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); Base != E; ++Base) {
+ // Virtuals are alread in the virtual base list and are constructed
+ // first.
+ if (Base->isVirtual())
+ continue;
+ AllBaseOrMembers.push_back(GetKeyForBase(Base->getType()));
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); Field != E; ++Field)
+ AllBaseOrMembers.push_back(GetKeyForTopLevelField(*Field));
+
+ int Last = AllBaseOrMembers.size();
+ int curIndex = 0;
+ CXXBaseOrMemberInitializer *PrevMember = 0;
for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member =
+ CXXBaseOrMemberInitializer *Member =
static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]);
- void *KeyToMember = Member->getBaseOrMember();
- // For fields injected into the class via declaration of an anonymous union,
- // use its anonymous union class declaration as the unique key.
- if (FieldDecl *Field = Member->getMember())
- if (Field->getDeclContext()->isRecord() &&
- cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
- KeyToMember = static_cast<void *>(Field->getDeclContext());
- CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
- if (!PrevMember) {
- PrevMember = Member;
- continue;
+ void *MemberInCtorList = GetKeyForMember(Member, true);
+
+ for (; curIndex < Last; curIndex++)
+ if (MemberInCtorList == AllBaseOrMembers[curIndex])
+ break;
+ if (curIndex == Last) {
+ assert(PrevMember && "Member not in member list?!");
+ // Initializer as specified in ctor-initializer list is out of order.
+ // Issue a warning diagnostic.
+ if (PrevMember->isBaseInitializer()) {
+ // Diagnostics is for an initialized base class.
+ Type *BaseClass = PrevMember->getBaseClass();
+ Diag(PrevMember->getSourceLocation(),
+ diag::warn_base_initialized)
+ << QualType(BaseClass, 0);
+ } else {
+ FieldDecl *Field = PrevMember->getMember();
+ Diag(PrevMember->getSourceLocation(),
+ diag::warn_field_initialized)
+ << Field->getNameAsString();
+ }
+ // Also the note!
+ if (FieldDecl *Field = Member->getMember())
+ Diag(Member->getSourceLocation(),
+ diag::note_fieldorbase_initialized_here) << 0
+ << Field->getNameAsString();
+ else {
+ Type *BaseClass = Member->getBaseClass();
+ Diag(Member->getSourceLocation(),
+ diag::note_fieldorbase_initialized_here) << 1
+ << QualType(BaseClass, 0);
+ }
+ for (curIndex = 0; curIndex < Last; curIndex++)
+ if (MemberInCtorList == AllBaseOrMembers[curIndex])
+ break;
}
- if (FieldDecl *Field = Member->getMember())
- Diag(Member->getSourceLocation(),
- diag::error_multiple_mem_initialization)
- << Field->getNameAsString();
- else {
- Type *BaseClass = Member->getBaseClass();
- assert(BaseClass && "ActOnMemInitializers - neither field or base");
- Diag(Member->getSourceLocation(),
- diag::error_multiple_base_initialization)
- << BaseClass->getDesugaredType(true);
+ PrevMember = Member;
+ }
+}
+
+void
+Sema::computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Destructor->getDeclContext());
+ llvm::SmallVector<uintptr_t, 32> AllToDestruct;
+
+ for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
+ if (VBase->getType()->isDependentType())
+ continue;
+ // Skip over virtual bases which have trivial destructors.
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context))
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
+
+ uintptr_t Member =
+ reinterpret_cast<uintptr_t>(VBase->getType().getTypePtr())
+ | CXXDestructorDecl::VBASE;
+ AllToDestruct.push_back(Member);
+ }
+ for (CXXRecordDecl::base_class_iterator Base =
+ ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); Base != E; ++Base) {
+ if (Base->isVirtual())
+ continue;
+ if (Base->getType()->isDependentType())
+ continue;
+ // Skip over virtual bases which have trivial destructors.
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context))
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
+ uintptr_t Member =
+ reinterpret_cast<uintptr_t>(Base->getType().getTypePtr())
+ | CXXDestructorDecl::DRCTNONVBASE;
+ AllToDestruct.push_back(Member);
+ }
+
+ // non-static data members.
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); Field != E; ++Field) {
+ QualType FieldType = Context.getBaseElementType((*Field)->getType());
+
+ if (const RecordType* RT = FieldType->getAs<RecordType>()) {
+ // Skip over virtual bases which have trivial destructors.
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->hasTrivialDestructor())
+ continue;
+ if (const CXXDestructorDecl *Dtor =
+ FieldClassDecl->getDestructor(Context))
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
+ uintptr_t Member = reinterpret_cast<uintptr_t>(*Field);
+ AllToDestruct.push_back(Member);
}
- Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
- << 0;
- err = true;
}
- if (!err)
- Constructor->setBaseOrMemberInitializers(Context,
- reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
- NumMemInits);
+
+ unsigned NumDestructions = AllToDestruct.size();
+ if (NumDestructions > 0) {
+ Destructor->setNumBaseOrMemberDestructions(NumDestructions);
+ uintptr_t *BaseOrMemberDestructions =
+ new (Context) uintptr_t [NumDestructions];
+ // Insert in reverse order.
+ for (int Idx = NumDestructions-1, i=0 ; Idx >= 0; --Idx)
+ BaseOrMemberDestructions[i++] = AllToDestruct[Idx];
+ Destructor->setBaseOrMemberDestructions(BaseOrMemberDestructions);
+ }
+}
+
+void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
+ if (!CDtorDecl)
+ return;
+
+ AdjustDeclIfTemplate(CDtorDecl);
+
+ if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>()))
+ BuildBaseOrMemberInitializers(Context,
+ Constructor,
+ (CXXBaseOrMemberInitializer **)0, 0);
}
namespace {
@@ -836,58 +1611,58 @@ namespace {
private:
MethodList Methods;
-
+
void Collect(const CXXRecordDecl* RD, MethodList& Methods);
-
+
public:
- PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD)
+ PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD)
: Context(Ctx) {
-
+
MethodList List;
Collect(RD, List);
-
+
// Copy the temporary list to methods, and make sure to ignore any
// null entries.
for (size_t i = 0, e = List.size(); i != e; ++i) {
if (List[i])
Methods.push_back(List[i]);
- }
+ }
}
-
+
bool empty() const { return Methods.empty(); }
-
+
MethodList::const_iterator methods_begin() { return Methods.begin(); }
MethodList::const_iterator methods_end() { return Methods.end(); }
};
-
- void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD,
+
+ void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD,
MethodList& Methods) {
// First, collect the pure virtual methods for the base classes.
for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
- if (const RecordType *RT = Base->getType()->getAsRecordType()) {
+ if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
if (BaseDecl && BaseDecl->isAbstract())
Collect(BaseDecl, Methods);
}
}
-
+
// Next, zero out any pure virtual methods that this class overrides.
typedef llvm::SmallPtrSet<const CXXMethodDecl*, 4> MethodSetTy;
-
+
MethodSetTy OverriddenMethods;
size_t MethodsSize = Methods.size();
- for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end();
+ for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end();
i != e; ++i) {
// Traverse the record, looking for methods.
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) {
- // If the method is pre virtual, add it to the methods vector.
+ // If the method is pure virtual, add it to the methods vector.
if (MD->isPure()) {
Methods.push_back(MD);
continue;
}
-
+
// Otherwise, record all the overridden methods in our set.
for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
E = MD->end_overridden_methods(); I != E; ++I) {
@@ -896,82 +1671,92 @@ namespace {
}
}
}
-
- // Now go through the methods and zero out all the ones we know are
+
+ // Now go through the methods and zero out all the ones we know are
// overridden.
for (size_t i = 0, e = MethodsSize; i != e; ++i) {
if (OverriddenMethods.count(Methods[i]))
Methods[i] = 0;
}
-
+
}
}
-bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
+
+bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
unsigned DiagID, AbstractDiagSelID SelID,
const CXXRecordDecl *CurrentRD) {
-
+ if (SelID == -1)
+ return RequireNonAbstractType(Loc, T,
+ PDiag(DiagID), CurrentRD);
+ else
+ return RequireNonAbstractType(Loc, T,
+ PDiag(DiagID) << SelID, CurrentRD);
+}
+
+bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ const CXXRecordDecl *CurrentRD) {
if (!getLangOptions().CPlusPlus)
return false;
-
+
if (const ArrayType *AT = Context.getAsArrayType(T))
- return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID,
+ return RequireNonAbstractType(Loc, AT->getElementType(), PD,
CurrentRD);
-
- if (const PointerType *PT = T->getAsPointerType()) {
+
+ if (const PointerType *PT = T->getAs<PointerType>()) {
// Find the innermost pointer type.
- while (const PointerType *T = PT->getPointeeType()->getAsPointerType())
+ while (const PointerType *T = PT->getPointeeType()->getAs<PointerType>())
PT = T;
-
+
if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType()))
- return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID,
- CurrentRD);
+ return RequireNonAbstractType(Loc, AT->getElementType(), PD, CurrentRD);
}
-
- const RecordType *RT = T->getAsRecordType();
+
+ const RecordType *RT = T->getAs<RecordType>();
if (!RT)
return false;
-
+
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
if (!RD)
return false;
if (CurrentRD && CurrentRD != RD)
return false;
-
+
if (!RD->isAbstract())
return false;
-
- Diag(Loc, DiagID) << RD->getDeclName() << SelID;
-
+
+ Diag(Loc, PD) << RD->getDeclName();
+
// Check if we've already emitted the list of pure virtual functions for this
// class.
if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD))
return true;
-
+
PureVirtualMethodCollector Collector(Context, RD);
-
- for (PureVirtualMethodCollector::MethodList::const_iterator I =
+
+ for (PureVirtualMethodCollector::MethodList::const_iterator I =
Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) {
const CXXMethodDecl *MD = *I;
-
- Diag(MD->getLocation(), diag::note_pure_virtual_function) <<
+
+ Diag(MD->getLocation(), diag::note_pure_virtual_function) <<
MD->getDeclName();
}
if (!PureVirtualClassDiagSet)
PureVirtualClassDiagSet.reset(new RecordDeclSetTy);
PureVirtualClassDiagSet->insert(RD);
-
+
return true;
}
namespace {
- class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser
+ class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser
: public DeclVisitor<AbstractClassUsageDiagnoser, bool> {
Sema &SemaRef;
CXXRecordDecl *AbstractClass;
-
+
bool VisitDeclContext(const DeclContext *DC) {
bool Invalid = false;
@@ -981,7 +1766,7 @@ namespace {
return Invalid;
}
-
+
public:
AbstractClassUsageDiagnoser(Sema& SemaRef, CXXRecordDecl *ac)
: SemaRef(SemaRef), AbstractClass(ac) {
@@ -992,36 +1777,36 @@ namespace {
if (FD->isThisDeclarationADefinition()) {
// No need to do the check if we're in a definition, because it requires
// that the return/param types are complete.
- // because that requires
+ // because that requires
return VisitDeclContext(FD);
}
-
+
// Check the return type.
- QualType RTy = FD->getType()->getAsFunctionType()->getResultType();
- bool Invalid =
+ QualType RTy = FD->getType()->getAs<FunctionType>()->getResultType();
+ bool Invalid =
SemaRef.RequireNonAbstractType(FD->getLocation(), RTy,
diag::err_abstract_type_in_decl,
Sema::AbstractReturnType,
AbstractClass);
- for (FunctionDecl::param_const_iterator I = FD->param_begin(),
+ for (FunctionDecl::param_const_iterator I = FD->param_begin(),
E = FD->param_end(); I != E; ++I) {
const ParmVarDecl *VD = *I;
- Invalid |=
+ Invalid |=
SemaRef.RequireNonAbstractType(VD->getLocation(),
- VD->getOriginalType(),
- diag::err_abstract_type_in_decl,
+ VD->getOriginalType(),
+ diag::err_abstract_type_in_decl,
Sema::AbstractParamType,
AbstractClass);
}
return Invalid;
}
-
+
bool VisitDecl(const Decl* D) {
if (const DeclContext *DC = dyn_cast<DeclContext>(D))
return VisitDeclContext(DC);
-
+
return false;
}
};
@@ -1033,7 +1818,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
SourceLocation RBrac) {
if (!TagDecl)
return;
-
+
AdjustDeclIfTemplate(TagDecl);
ActOnFields(S, RLoc, TagDecl,
(DeclPtrTy*)FieldCollector->getCurFields(),
@@ -1044,37 +1829,13 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
// Collect all the pure virtual methods and see if this is an abstract
// class after all.
PureVirtualMethodCollector Collector(Context, RD);
- if (!Collector.empty())
+ if (!Collector.empty())
RD->setAbstract(true);
}
-
- if (RD->isAbstract())
+
+ if (RD->isAbstract())
AbstractClassUsageDiagnoser(*this, RD);
-
- if (RD->hasTrivialConstructor() || RD->hasTrivialDestructor()) {
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- // All the nonstatic data members must have trivial constructors.
- QualType FTy = i->getType();
- while (const ArrayType *AT = Context.getAsArrayType(FTy))
- FTy = AT->getElementType();
-
- if (const RecordType *RT = FTy->getAsRecordType()) {
- CXXRecordDecl *FieldRD = cast<CXXRecordDecl>(RT->getDecl());
-
- if (!FieldRD->hasTrivialConstructor())
- RD->setHasTrivialConstructor(false);
- if (!FieldRD->hasTrivialDestructor())
- RD->setHasTrivialDestructor(false);
-
- // If RD has neither a trivial constructor nor a trivial destructor
- // we don't need to continue checking.
- if (!RD->hasTrivialConstructor() && !RD->hasTrivialDestructor())
- break;
- }
- }
- }
-
+
if (!RD->isDependentType())
AddImplicitlyDeclaredMembersToClass(RD);
}
@@ -1085,8 +1846,8 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
/// [special]p1). This routine can only be executed just before the
/// definition of the class is complete.
void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
- QualType ClassType = Context.getTypeDeclType(ClassDecl);
- ClassType = Context.getCanonicalType(ClassType);
+ CanQualType ClassType
+ = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
// FIXME: Implicit declarations have exception specifications, which are
// the union of the specifications of the implicitly called functions.
@@ -1098,18 +1859,20 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// user-declared constructor for class X, a default constructor is
// implicitly declared. An implicitly-declared default constructor
// is an inline public member of its class.
- DeclarationName Name
+ DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(ClassType);
- CXXConstructorDecl *DefaultCon =
+ CXXConstructorDecl *DefaultCon =
CXXConstructorDecl::Create(Context, ClassDecl,
ClassDecl->getLocation(), Name,
Context.getFunctionType(Context.VoidTy,
0, 0, false, 0),
+ /*DInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
DefaultCon->setAccess(AS_public);
DefaultCon->setImplicit();
+ DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
ClassDecl->addDecl(DefaultCon);
}
@@ -1133,8 +1896,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
HasConstCopyConstructor && Base != ClassDecl->bases_end(); ++Base) {
const CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
- HasConstCopyConstructor
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ HasConstCopyConstructor
= BaseClassDecl->hasConstCopyConstructor(Context);
}
@@ -1148,10 +1911,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
QualType FieldType = (*Field)->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
- const CXXRecordDecl *FieldClassDecl
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
+ const CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- HasConstCopyConstructor
+ HasConstCopyConstructor
= FieldClassDecl->hasConstCopyConstructor(Context);
}
}
@@ -1167,7 +1930,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// An implicitly-declared copy constructor is an inline public
// member of its class.
- DeclarationName Name
+ DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(ClassType);
CXXConstructorDecl *CopyConstructor
= CXXConstructorDecl::Create(Context, ClassDecl,
@@ -1175,17 +1938,20 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(Context.VoidTy,
&ArgType, 1,
false, 0),
+ /*DInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setImplicit();
+ CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
- ArgType, VarDecl::None, 0);
+ ArgType, /*DInfo=*/0,
+ VarDecl::None, 0);
CopyConstructor->setParams(Context, &FromParam, 1);
ClassDecl->addDecl(CopyConstructor);
}
@@ -1213,8 +1979,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
HasConstCopyAssignment && Base != ClassDecl->bases_end(); ++Base) {
const CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
- HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context);
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ const CXXMethodDecl *MD = 0;
+ HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context,
+ MD);
}
// -- for all the nonstatic data members of X that are of a class
@@ -1227,11 +1995,12 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
QualType FieldType = (*Field)->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
const CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
+ const CXXMethodDecl *MD = 0;
HasConstCopyAssignment
- = FieldClassDecl->hasConstCopyAssignment(Context);
+ = FieldClassDecl->hasConstCopyAssignment(Context, MD);
}
}
@@ -1253,15 +2022,18 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name,
Context.getFunctionType(RetType, &ArgType, 1,
false, 0),
- /*isStatic=*/false, /*isInline=*/true);
+ /*DInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
+ CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
+ CopyAssignment->setCopyAssignment(true);
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
- ArgType, VarDecl::None, 0);
+ ArgType, /*DInfo=*/0,
+ VarDecl::None, 0);
CopyAssignment->setParams(Context, &FromParam, 1);
// Don't call addedAssignmentOperator. There is no way to distinguish an
@@ -1274,9 +2046,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// If a class has no user-declared destructor, a destructor is
// declared implicitly. An implicitly-declared destructor is an
// inline public member of its class.
- DeclarationName Name
+ DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
- CXXDestructorDecl *Destructor
+ CXXDestructorDecl *Destructor
= CXXDestructorDecl::Create(Context, ClassDecl,
ClassDecl->getLocation(), Name,
Context.getFunctionType(Context.VoidTy,
@@ -1285,16 +2057,25 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
Destructor->setImplicit();
+ Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
ClassDecl->addDecl(Destructor);
}
}
void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
- TemplateDecl *Template = TemplateD.getAs<TemplateDecl>();
- if (!Template)
+ Decl *D = TemplateD.getAs<Decl>();
+ if (!D)
+ return;
+
+ TemplateParameterList *Params = 0;
+ if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
+ Params = Template->getTemplateParameters();
+ else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(D))
+ Params = PartialSpec->getTemplateParameters();
+ else
return;
- TemplateParameterList *Params = Template->getTemplateParameters();
for (TemplateParameterList::iterator Param = Params->begin(),
ParamEnd = Params->end();
Param != ParamEnd; ++Param) {
@@ -1317,10 +2098,12 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
if (!MethodD)
return;
-
+
+ AdjustDeclIfTemplate(MethodD);
+
CXXScopeSpec SS;
FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
- QualType ClassTy
+ QualType ClassTy
= Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
SS.setScopeRep(
NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
@@ -1335,7 +2118,7 @@ void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) {
if (!ParamD)
return;
-
+
ParmVarDecl *Param = cast<ParmVarDecl>(ParamD.getAs<Decl>());
// If this parameter has an unparsed default argument, clear it out
@@ -1357,10 +2140,12 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) {
void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
if (!MethodD)
return;
-
+
+ AdjustDeclIfTemplate(MethodD);
+
FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
CXXScopeSpec SS;
- QualType ClassTy
+ QualType ClassTy
= Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
SS.setScopeRep(
NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
@@ -1408,26 +2193,26 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
D.setInvalidType();
SC = FunctionDecl::None;
}
-
+
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
if (FTI.TypeQuals != 0) {
- if (FTI.TypeQuals & QualType::Const)
+ if (FTI.TypeQuals & Qualifiers::Const)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor)
<< "const" << SourceRange(D.getIdentifierLoc());
- if (FTI.TypeQuals & QualType::Volatile)
+ if (FTI.TypeQuals & Qualifiers::Volatile)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor)
<< "volatile" << SourceRange(D.getIdentifierLoc());
- if (FTI.TypeQuals & QualType::Restrict)
+ if (FTI.TypeQuals & Qualifiers::Restrict)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor)
<< "restrict" << SourceRange(D.getIdentifierLoc());
}
-
+
// Rebuild the function type "R" without any type qualifiers (in
// case any of the errors above fired) and with "void" as the
// return type, since constructors don't have return types. We
// *always* have to do this, because GetTypeForDeclarator will
// put in a result type of "int" when none was specified.
- const FunctionProtoType *Proto = R->getAsFunctionProtoType();
+ const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
Proto->getNumArgs(),
Proto->isVariadic(), 0);
@@ -1437,7 +2222,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
/// well-formedness, issuing any diagnostics required. Returns true if
/// the constructor declarator is invalid.
void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
- CXXRecordDecl *ClassDecl
+ CXXRecordDecl *ClassDecl
= dyn_cast<CXXRecordDecl>(Constructor->getDeclContext());
if (!ClassDecl)
return Constructor->setInvalidDecl();
@@ -1448,8 +2233,8 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
// either there are no other parameters or else all other
// parameters have default arguments.
if (!Constructor->isInvalidDecl() &&
- ((Constructor->getNumParams() == 1) ||
- (Constructor->getNumParams() > 1 &&
+ ((Constructor->getNumParams() == 1) ||
+ (Constructor->getNumParams() > 1 &&
Constructor->getParamDecl(1)->hasDefaultArg()))) {
QualType ParamType = Constructor->getParamDecl(0)->getType();
QualType ClassTy = Context.getTagDeclType(ClassDecl);
@@ -1460,12 +2245,12 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
Constructor->setInvalidDecl();
}
}
-
+
// Notify the class that we've added a constructor.
ClassDecl->addedConstructor(Context, Constructor);
}
-static inline bool
+static inline bool
FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) {
return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
FTI.ArgInfo[0].Param &&
@@ -1485,7 +2270,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D,
// (7.1.3); however, a typedef-name that names a class shall not
// be used as the identifier in the declarator for a destructor
// declaration.
- QualType DeclaratorType = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
+ QualType DeclaratorType = GetTypeFromParser(D.getDeclaratorIdType());
if (isa<TypedefType>(DeclaratorType)) {
Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
<< DeclaratorType;
@@ -1521,16 +2306,16 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D,
<< SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
<< SourceRange(D.getIdentifierLoc());
}
-
+
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
if (FTI.TypeQuals != 0 && !D.isInvalidType()) {
- if (FTI.TypeQuals & QualType::Const)
+ if (FTI.TypeQuals & Qualifiers::Const)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor)
<< "const" << SourceRange(D.getIdentifierLoc());
- if (FTI.TypeQuals & QualType::Volatile)
+ if (FTI.TypeQuals & Qualifiers::Volatile)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor)
<< "volatile" << SourceRange(D.getIdentifierLoc());
- if (FTI.TypeQuals & QualType::Restrict)
+ if (FTI.TypeQuals & Qualifiers::Restrict)
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor)
<< "restrict" << SourceRange(D.getIdentifierLoc());
D.setInvalidType();
@@ -1545,7 +2330,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D,
D.setInvalidType();
}
- // Make sure the destructor isn't variadic.
+ // Make sure the destructor isn't variadic.
if (FTI.isVariadic) {
Diag(D.getIdentifierLoc(), diag::err_destructor_variadic);
D.setInvalidType();
@@ -1569,8 +2354,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC) {
// C++ [class.conv.fct]p1:
// Neither parameter types nor return type can be specified. The
- // type of a conversion function (8.3.5) is “function taking no
- // parameter returning conversion-type-id.”
+ // type of a conversion function (8.3.5) is "function taking no
+ // parameter returning conversion-type-id."
if (SC == FunctionDecl::Static) {
if (!D.isInvalidType())
Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member)
@@ -1594,7 +2379,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
}
// Make sure we don't have any parameters.
- if (R->getAsFunctionProtoType()->getNumArgs() > 0) {
+ if (R->getAs<FunctionProtoType>()->getNumArgs() > 0) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
// Delete the parameters.
@@ -1602,8 +2387,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
D.setInvalidType();
}
- // Make sure the conversion function isn't variadic.
- if (R->getAsFunctionProtoType()->isVariadic() && !D.isInvalidType()) {
+ // Make sure the conversion function isn't variadic.
+ if (R->getAs<FunctionProtoType>()->isVariadic() && !D.isInvalidType()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
D.setInvalidType();
}
@@ -1611,7 +2396,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// C++ [class.conv.fct]p4:
// The conversion-type-id shall not represent a function type nor
// an array type.
- QualType ConvType = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
+ QualType ConvType = GetTypeFromParser(D.getDeclaratorIdType());
if (ConvType->isArrayType()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array);
ConvType = Context.getPointerType(ConvType);
@@ -1624,13 +2409,13 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// Rebuild the function type "R" without any parameters (in case any
// of the errors above fired) and with the conversion type as the
- // return type.
- R = Context.getFunctionType(ConvType, 0, 0, false,
- R->getAsFunctionProtoType()->getTypeQuals());
+ // return type.
+ R = Context.getFunctionType(ConvType, 0, 0, false,
+ R->getAs<FunctionProtoType>()->getTypeQuals());
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
- Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::warn_explicit_conversion_functions)
<< SourceRange(D.getDeclSpec().getExplicitSpecLoc());
}
@@ -1642,9 +2427,6 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
assert(Conversion && "Expected to receive a conversion function declaration");
- // Set the lexical context of this conversion function
- Conversion->setLexicalDeclContext(CurContext);
-
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Conversion->getDeclContext());
// Make sure we aren't redeclaring the conversion function.
@@ -1658,9 +2440,9 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
// or to (possibly cv-qualified) void.
// FIXME: Suppress this warning if the conversion function ends up being a
// virtual function that overrides a virtual function in a base class.
- QualType ClassType
+ QualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
- if (const ReferenceType *ConvTypeRef = ConvType->getAsReferenceType())
+ if (const ReferenceType *ConvTypeRef = ConvType->getAs<ReferenceType>())
ConvType = ConvTypeRef->getPointeeType();
if (ConvType->isRecordType()) {
ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType();
@@ -1676,20 +2458,26 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
}
if (Conversion->getPreviousDeclaration()) {
+ const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration();
+ if (FunctionTemplateDecl *ConversionTemplate
+ = Conversion->getDescribedFunctionTemplate())
+ ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration();
OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator
+ for (OverloadedFunctionDecl::function_iterator
Conv = Conversions->function_begin(),
ConvEnd = Conversions->function_end();
Conv != ConvEnd; ++Conv) {
- if (*Conv
- == cast_or_null<NamedDecl>(Conversion->getPreviousDeclaration())) {
+ if (*Conv == ExpectedPrevDecl) {
*Conv = Conversion;
return DeclPtrTy::make(Conversion);
}
}
assert(Conversion->isInvalidDecl() && "Conversion should not get here.");
- } else
- ClassDecl->addConversionFunction(Context, Conversion);
+ } else if (FunctionTemplateDecl *ConversionTemplate
+ = Conversion->getDescribedFunctionTemplate())
+ ClassDecl->addConversionFunction(ConversionTemplate);
+ else if (!Conversion->getPrimaryTemplate()) // ignore specializations
+ ClassDecl->addConversionFunction(Conversion);
return DeclPtrTy::make(Conversion);
}
@@ -1718,9 +2506,9 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// original-namespace-definition is the name of the namespace. Subsequently
// in that declarative region, it is treated as an original-namespace-name.
- NamedDecl *PrevDecl = LookupName(DeclRegionScope, II, LookupOrdinaryName,
- true);
-
+ NamedDecl *PrevDecl
+ = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName, true);
+
if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
// This is an extended namespace definition.
// Attach this namespace decl to the chain of extended namespace
@@ -1728,7 +2516,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
OrigNS->setNextNamespace(Namespc);
Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace());
- // Remove the previous declaration from the scope.
+ // Remove the previous declaration from the scope.
if (DeclRegionScope->isDeclScope(DeclPtrTy::make(OrigNS))) {
IdResolver.RemoveDecl(OrigNS);
DeclRegionScope->RemoveDecl(DeclPtrTy::make(OrigNS));
@@ -1740,11 +2528,57 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
Namespc->setInvalidDecl();
// Continue on to push Namespc as current DeclContext and return it.
- }
+ } else if (II->isStr("std") &&
+ CurContext->getLookupContext()->isTranslationUnit()) {
+ // This is the first "real" definition of the namespace "std", so update
+ // our cache of the "std" namespace to point at this definition.
+ if (StdNamespace) {
+ // We had already defined a dummy namespace "std". Link this new
+ // namespace definition to the dummy namespace "std".
+ StdNamespace->setNextNamespace(Namespc);
+ StdNamespace->setLocation(IdentLoc);
+ Namespc->setOriginalNamespace(StdNamespace->getOriginalNamespace());
+ }
+
+ // Make our StdNamespace cache point at the first real definition of the
+ // "std" namespace.
+ StdNamespace = Namespc;
+ }
PushOnScopeChains(Namespc, DeclRegionScope);
} else {
- // FIXME: Handle anonymous namespaces
+ // Anonymous namespaces.
+
+ // C++ [namespace.unnamed]p1. An unnamed-namespace-definition
+ // behaves as if it were replaced by
+ // namespace unique { /* empty body */ }
+ // using namespace unique;
+ // namespace unique { namespace-body }
+ // where all occurrences of 'unique' in a translation unit are
+ // replaced by the same identifier and this identifier differs
+ // from all other identifiers in the entire program.
+
+ // We just create the namespace with an empty name and then add an
+ // implicit using declaration, just like the standard suggests.
+ //
+ // CodeGen enforces the "universally unique" aspect by giving all
+ // declarations semantically contained within an anonymous
+ // namespace internal linkage.
+
+ assert(Namespc->isAnonymousNamespace());
+ CurContext->addDecl(Namespc);
+
+ UsingDirectiveDecl* UD
+ = UsingDirectiveDecl::Create(Context, CurContext,
+ /* 'using' */ LBrace,
+ /* 'namespace' */ SourceLocation(),
+ /* qualifier */ SourceRange(),
+ /* NNS */ NULL,
+ /* identifier */ SourceLocation(),
+ Namespc,
+ /* Ancestor */ CurContext);
+ UD->setImplicit();
+ CurContext->addDecl(UD);
}
// Although we could have an invalid decl (i.e. the namespace name is a
@@ -1781,13 +2615,14 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
UsingDirectiveDecl *UDir = 0;
// Lookup namespace name.
- LookupResult R = LookupParsedName(S, &SS, NamespcName,
- LookupNamespaceName, false);
+ LookupResult R;
+ LookupParsedName(R, S, &SS, NamespcName, LookupNamespaceName, false);
if (R.isAmbiguous()) {
DiagnoseAmbiguousLookup(R, NamespcName, IdentLoc);
return DeclPtrTy();
}
- if (NamedDecl *NS = R) {
+ if (!R.empty()) {
+ NamedDecl *NS = R.getFoundDecl();
assert(isa<NamespaceDecl>(NS) && "expected namespace decl");
// C++ [namespace.udir]p1:
// A using-directive specifies that the names in the nominated
@@ -1796,8 +2631,8 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
// unqualified name lookup (3.4.1), the names appear as if they
// were declared in the nearest enclosing namespace which
// contains both the using-directive and the nominated
- // namespace. [Note: in this context, “contains” means “contains
- // directly or indirectly”. ]
+ // namespace. [Note: in this context, "contains" means "contains
+ // directly or indirectly". ]
// Find enclosing context containing both using-directive and
// nominated namespace.
@@ -1805,9 +2640,9 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
while (CommonAncestor && !CommonAncestor->Encloses(CurContext))
CommonAncestor = CommonAncestor->getParent();
- UDir = UsingDirectiveDecl::Create(Context,
+ UDir = UsingDirectiveDecl::Create(Context,
CurContext, UsingLoc,
- NamespcLoc,
+ NamespcLoc,
SS.getRange(),
(NestedNameSpecifier *)SS.getScopeRep(),
IdentLoc,
@@ -1837,45 +2672,124 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
- SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
- SourceLocation IdentLoc,
- IdentifierInfo *TargetName,
- OverloadedOperatorKind Op,
- AttributeList *AttrList,
- bool IsTypeName) {
- assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
+ AccessSpecifier AS,
+ SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *TargetName,
+ OverloadedOperatorKind Op,
+ AttributeList *AttrList,
+ bool IsTypeName) {
assert((TargetName || Op) && "Invalid TargetName.");
- assert(IdentLoc.isValid() && "Invalid TargetName location.");
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
- UsingDecl *UsingAlias = 0;
-
DeclarationName Name;
if (TargetName)
Name = TargetName;
else
Name = Context.DeclarationNames.getCXXOperatorName(Op);
-
- // Lookup target name.
- LookupResult R = LookupParsedName(S, &SS, Name, LookupOrdinaryName, false);
- if (NamedDecl *NS = R) {
- if (IsTypeName && !isa<TypeDecl>(NS)) {
- Diag(IdentLoc, diag::err_using_typename_non_type);
- }
- UsingAlias = UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(),
- NS->getLocation(), UsingLoc, NS,
- static_cast<NestedNameSpecifier *>(SS.getScopeRep()),
- IsTypeName);
- PushOnScopeChains(UsingAlias, S);
- } else {
- Diag(IdentLoc, diag::err_using_requires_qualname) << SS.getRange();
+ NamedDecl *UD = BuildUsingDeclaration(UsingLoc, SS, IdentLoc,
+ Name, AttrList, IsTypeName);
+ if (UD) {
+ PushOnScopeChains(UD, S);
+ UD->setAccess(AS);
}
+ return DeclPtrTy::make(UD);
+}
+
+NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ DeclarationName Name,
+ AttributeList *AttrList,
+ bool IsTypeName) {
+ assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
+ assert(IdentLoc.isValid() && "Invalid TargetName location.");
+
// FIXME: We ignore attributes for now.
delete AttrList;
- return DeclPtrTy::make(UsingAlias);
+
+ if (SS.isEmpty()) {
+ Diag(IdentLoc, diag::err_using_requires_qualname);
+ return 0;
+ }
+
+ NestedNameSpecifier *NNS =
+ static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+
+ if (isUnknownSpecialization(SS)) {
+ return UnresolvedUsingDecl::Create(Context, CurContext, UsingLoc,
+ SS.getRange(), NNS,
+ IdentLoc, Name, IsTypeName);
+ }
+
+ DeclContext *LookupContext = 0;
+
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) {
+ // C++0x N2914 [namespace.udecl]p3:
+ // A using-declaration used as a member-declaration shall refer to a member
+ // of a base class of the class being defined, shall refer to a member of an
+ // anonymous union that is a member of a base class of the class being
+ // defined, or shall refer to an enumerator for an enumeration type that is
+ // a member of a base class of the class being defined.
+ const Type *Ty = NNS->getAsType();
+ if (!Ty || !IsDerivedFrom(Context.getTagDeclType(RD), QualType(Ty, 0))) {
+ Diag(SS.getRange().getBegin(),
+ diag::err_using_decl_nested_name_specifier_is_not_a_base_class)
+ << NNS << RD->getDeclName();
+ return 0;
+ }
+
+ QualType BaseTy = Context.getCanonicalType(QualType(Ty, 0));
+ LookupContext = BaseTy->getAs<RecordType>()->getDecl();
+ } else {
+ // C++0x N2914 [namespace.udecl]p8:
+ // A using-declaration for a class member shall be a member-declaration.
+ if (NNS->getKind() == NestedNameSpecifier::TypeSpec) {
+ Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_class_member)
+ << SS.getRange();
+ return 0;
+ }
+
+ // C++0x N2914 [namespace.udecl]p9:
+ // In a using-declaration, a prefix :: refers to the global namespace.
+ if (NNS->getKind() == NestedNameSpecifier::Global)
+ LookupContext = Context.getTranslationUnitDecl();
+ else
+ LookupContext = NNS->getAsNamespace();
+ }
+
+
+ // Lookup target name.
+ LookupResult R;
+ LookupQualifiedName(R, LookupContext, Name, LookupOrdinaryName);
+
+ if (R.empty()) {
+ Diag(IdentLoc, diag::err_no_member)
+ << Name << LookupContext << SS.getRange();
+ return 0;
+ }
+
+ // FIXME: handle ambiguity?
+ NamedDecl *ND = R.getAsSingleDecl(Context);
+
+ if (IsTypeName && !isa<TypeDecl>(ND)) {
+ Diag(IdentLoc, diag::err_using_typename_non_type);
+ return 0;
+ }
+
+ // C++0x N2914 [namespace.udecl]p6:
+ // A using-declaration shall not name a namespace.
+ if (isa<NamespaceDecl>(ND)) {
+ Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace)
+ << SS.getRange();
+ return 0;
+ }
+
+ return UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(),
+ ND->getLocation(), UsingLoc, ND, NNS, IsTypeName);
}
/// getNamespaceDecl - Returns the namespace a decl represents. If the decl
@@ -1886,26 +2800,29 @@ static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) {
return dyn_cast_or_null<NamespaceDecl>(D);
}
-Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
+Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
IdentifierInfo *Alias,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident) {
-
+
// Lookup the namespace name.
- LookupResult R = LookupParsedName(S, &SS, Ident, LookupNamespaceName, false);
+ LookupResult R;
+ LookupParsedName(R, S, &SS, Ident, LookupNamespaceName, false);
// Check if we have a previous declaration with the same name.
- if (NamedDecl *PrevDecl = LookupName(S, Alias, LookupOrdinaryName, true)) {
+ if (NamedDecl *PrevDecl
+ = LookupSingleName(S, Alias, LookupOrdinaryName, true)) {
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
- // We already have an alias with the same name that points to the same
+ // We already have an alias with the same name that points to the same
// namespace, so don't create a new one.
- if (!R.isAmbiguous() && AD->getNamespace() == getNamespaceDecl(R))
+ if (!R.isAmbiguous() && !R.empty() &&
+ AD->getNamespace() == getNamespaceDecl(R.getFoundDecl()))
return DeclPtrTy();
}
-
+
unsigned DiagID = isa<NamespaceDecl>(PrevDecl) ? diag::err_redefinition :
diag::err_redefinition_different_kind;
Diag(AliasLoc, DiagID) << Alias;
@@ -1917,18 +2834,18 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
DiagnoseAmbiguousLookup(R, Ident, IdentLoc);
return DeclPtrTy();
}
-
- if (!R) {
+
+ if (R.empty()) {
Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange();
return DeclPtrTy();
}
-
+
NamespaceAliasDecl *AliasDecl =
- NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc,
- Alias, SS.getRange(),
+ NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc,
+ Alias, SS.getRange(),
(NestedNameSpecifier *)SS.getScopeRep(),
- IdentLoc, R);
-
+ IdentLoc, R.getFoundDecl());
+
CurContext->addDecl(AliasDecl);
return DeclPtrTy::make(AliasDecl);
}
@@ -1938,11 +2855,11 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
!Constructor->isUsed()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
-
+
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(Constructor->getDeclContext());
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- // Before the implicitly-declared default constructor for a class is
+ // Before the implicitly-declared default constructor for a class is
// implicitly defined, all the implicitly-declared default constructors
// for its base class and its non-static data members shall have been
// implicitly defined.
@@ -1950,16 +2867,16 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (!BaseClassDecl->hasTrivialConstructor()) {
- if (CXXConstructorDecl *BaseCtor =
+ if (CXXConstructorDecl *BaseCtor =
BaseClassDecl->getDefaultConstructor(Context))
MarkDeclarationReferenced(CurrentLocation, BaseCtor);
else {
- Diag(CurrentLocation, diag::err_defining_default_ctor)
- << Context.getTagDeclType(ClassDecl) << 1
+ Diag(CurrentLocation, diag::err_defining_default_ctor)
+ << Context.getTagDeclType(ClassDecl) << 0
<< Context.getTagDeclType(BaseClassDecl);
- Diag(BaseClassDecl->getLocation(), diag::note_previous_class_decl)
+ Diag(BaseClassDecl->getLocation(), diag::note_previous_class_decl)
<< Context.getTagDeclType(BaseClassDecl);
err = true;
}
@@ -1970,32 +2887,31 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
QualType FieldType = Context.getCanonicalType((*Field)->getType());
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (!FieldClassDecl->hasTrivialConstructor()) {
- if (CXXConstructorDecl *FieldCtor =
+ if (CXXConstructorDecl *FieldCtor =
FieldClassDecl->getDefaultConstructor(Context))
MarkDeclarationReferenced(CurrentLocation, FieldCtor);
else {
- Diag(CurrentLocation, diag::err_defining_default_ctor)
- << Context.getTagDeclType(ClassDecl) << 0 <<
+ Diag(CurrentLocation, diag::err_defining_default_ctor)
+ << Context.getTagDeclType(ClassDecl) << 1 <<
Context.getTagDeclType(FieldClassDecl);
- Diag(FieldClassDecl->getLocation(), diag::note_previous_class_decl)
+ Diag((*Field)->getLocation(), diag::note_field_decl);
+ Diag(FieldClassDecl->getLocation(), diag::note_previous_class_decl)
<< Context.getTagDeclType(FieldClassDecl);
err = true;
}
}
- }
- else if (FieldType->isReferenceType()) {
- Diag(CurrentLocation, diag::err_unintialized_member)
- << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString();
+ } else if (FieldType->isReferenceType()) {
+ Diag(CurrentLocation, diag::err_unintialized_member)
+ << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
err = true;
- }
- else if (FieldType.isConstQualified()) {
- Diag(CurrentLocation, diag::err_unintialized_member)
- << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getNameAsCString();
+ } else if (FieldType.isConstQualified()) {
+ Diag(CurrentLocation, diag::err_unintialized_member)
+ << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
err = true;
}
@@ -2007,47 +2923,47 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
- CXXDestructorDecl *Destructor) {
+ CXXDestructorDecl *Destructor) {
assert((Destructor->isImplicit() && !Destructor->isUsed()) &&
"DefineImplicitDestructor - call it for implicit default dtor");
-
+
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(Destructor->getDeclContext());
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
// C++ [class.dtor] p5
- // Before the implicitly-declared default destructor for a class is
+ // Before the implicitly-declared default destructor for a class is
// implicitly defined, all the implicitly-declared default destructors
// for its base class and its non-static data members shall have been
// implicitly defined.
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (!BaseClassDecl->hasTrivialDestructor()) {
- if (CXXDestructorDecl *BaseDtor =
+ if (CXXDestructorDecl *BaseDtor =
const_cast<CXXDestructorDecl*>(BaseClassDecl->getDestructor(Context)))
MarkDeclarationReferenced(CurrentLocation, BaseDtor);
else
- assert(false &&
+ assert(false &&
"DefineImplicitDestructor - missing dtor in a base class");
}
}
-
+
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
E = ClassDecl->field_end(); Field != E; ++Field) {
QualType FieldType = Context.getCanonicalType((*Field)->getType());
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (!FieldClassDecl->hasTrivialDestructor()) {
- if (CXXDestructorDecl *FieldDtor =
+ if (CXXDestructorDecl *FieldDtor =
const_cast<CXXDestructorDecl*>(
FieldClassDecl->getDestructor(Context)))
MarkDeclarationReferenced(CurrentLocation, FieldDtor);
else
- assert(false &&
+ assert(false &&
"DefineImplicitDestructor - missing dtor in class of a data member");
}
}
@@ -2061,10 +2977,10 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
MethodDecl->getOverloadedOperator() == OO_Equal &&
!MethodDecl->isUsed()) &&
"DefineImplicitOverloadedAssign - call it for implicit assignment op");
-
+
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(MethodDecl->getDeclContext());
-
+
// C++[class.copy] p12
// Before the implicitly-declared copy assignment operator for a class is
// implicitly defined, all implicitly-declared copy assignment operators
@@ -2074,8 +2990,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
- if (CXXMethodDecl *BaseAssignOpMethod =
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (CXXMethodDecl *BaseAssignOpMethod =
getAssignOperatorMethod(MethodDecl->getParamDecl(0), BaseClassDecl))
MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
}
@@ -2084,30 +3000,28 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
QualType FieldType = Context.getCanonicalType((*Field)->getType());
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXMethodDecl *FieldAssignOpMethod =
+ if (CXXMethodDecl *FieldAssignOpMethod =
getAssignOperatorMethod(MethodDecl->getParamDecl(0), FieldClassDecl))
MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
- }
- else if (FieldType->isReferenceType()) {
- Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
- << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString();
- Diag((*Field)->getLocation(), diag::note_declared_at);
+ } else if (FieldType->isReferenceType()) {
+ Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
+ << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
+ Diag(Field->getLocation(), diag::note_declared_at);
Diag(CurrentLocation, diag::note_first_required_here);
err = true;
- }
- else if (FieldType.isConstQualified()) {
- Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
- << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getNameAsCString();
- Diag((*Field)->getLocation(), diag::note_declared_at);
+ } else if (FieldType.isConstQualified()) {
+ Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
+ << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
+ Diag(Field->getLocation(), diag::note_declared_at);
Diag(CurrentLocation, diag::note_first_required_here);
err = true;
}
}
if (!err)
- MethodDecl->setUsed();
+ MethodDecl->setUsed();
}
CXXMethodDecl *
@@ -2116,24 +3030,22 @@ Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
QualType LHSType = Context.getTypeDeclType(ClassDecl);
QualType RHSType(LHSType);
// If class's assignment operator argument is const/volatile qualified,
- // look for operator = (const/volatile B&). Otherwise, look for
+ // look for operator = (const/volatile B&). Otherwise, look for
// operator = (B&).
- if (ParmDecl->getType().isConstQualified())
- RHSType.addConst();
- if (ParmDecl->getType().isVolatileQualified())
- RHSType.addVolatile();
- ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
- LHSType,
+ RHSType = Context.getCVRQualifiedType(RHSType,
+ ParmDecl->getType().getCVRQualifiers());
+ ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
+ LHSType,
SourceLocation()));
- ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
- RHSType,
+ ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
+ RHSType,
SourceLocation()));
Expr *Args[2] = { &*LHS, &*RHS };
OverloadCandidateSet CandidateSet;
- AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
+ AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
CandidateSet);
OverloadCandidateSet::iterator Best;
- if (BestViableFunction(CandidateSet,
+ if (BestViableFunction(CandidateSet,
ClassDecl->getLocation(), Best) == OR_Success)
return cast<CXXMethodDecl>(Best->Function);
assert(false &&
@@ -2144,24 +3056,24 @@ Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *CopyConstructor,
unsigned TypeQuals) {
- assert((CopyConstructor->isImplicit() &&
+ assert((CopyConstructor->isImplicit() &&
CopyConstructor->isCopyConstructor(Context, TypeQuals) &&
!CopyConstructor->isUsed()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
-
+
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
// C++ [class.copy] p209
- // Before the implicitly-declared copy constructor for a class is
+ // Before the implicitly-declared copy constructor for a class is
// implicitly defined, all the implicitly-declared copy constructors
// for its base class and its non-static data members shall have been
// implicitly defined.
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
Base != ClassDecl->bases_end(); ++Base) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
- if (CXXConstructorDecl *BaseCopyCtor =
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (CXXConstructorDecl *BaseCopyCtor =
BaseClassDecl->getCopyConstructor(Context, TypeQuals))
MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
}
@@ -2171,10 +3083,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
QualType FieldType = Context.getCanonicalType((*Field)->getType());
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXConstructorDecl *FieldCopyCtor =
+ if (CXXConstructorDecl *FieldCopyCtor =
FieldClassDecl->getCopyConstructor(Context, TypeQuals))
MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
}
@@ -2182,27 +3094,92 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CopyConstructor->setUsed();
}
-void Sema::InitializeVarWithConstructor(VarDecl *VD,
+Sema::OwningExprResult
+Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ CXXConstructorDecl *Constructor,
+ MultiExprArg ExprArgs) {
+ bool Elidable = false;
+
+ // C++ [class.copy]p15:
+ // Whenever a temporary class object is copied using a copy constructor, and
+ // this object and the copy have the same cv-unqualified type, an
+ // implementation is permitted to treat the original and the copy as two
+ // different ways of referring to the same object and not perform a copy at
+ // all, even if the class copy constructor or destructor have side effects.
+
+ // FIXME: Is this enough?
+ if (Constructor->isCopyConstructor(Context)) {
+ Expr *E = ((Expr **)ExprArgs.get())[0];
+ while (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E))
+ E = BE->getSubExpr();
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr();
+
+ if (isa<CallExpr>(E) || isa<CXXTemporaryObjectExpr>(E))
+ Elidable = true;
+ }
+
+ return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
+ Elidable, move(ExprArgs));
+}
+
+/// BuildCXXConstructExpr - Creates a complete call to a constructor,
+/// including handling of its default argument expressions.
+Sema::OwningExprResult
+Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ CXXConstructorDecl *Constructor, bool Elidable,
+ MultiExprArg ExprArgs) {
+ unsigned NumExprs = ExprArgs.size();
+ Expr **Exprs = (Expr **)ExprArgs.release();
+
+ return Owned(CXXConstructExpr::Create(Context, DeclInitType, Constructor,
+ Elidable, Exprs, NumExprs));
+}
+
+Sema::OwningExprResult
+Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor,
+ QualType Ty,
+ SourceLocation TyBeginLoc,
+ MultiExprArg Args,
+ SourceLocation RParenLoc) {
+ unsigned NumExprs = Args.size();
+ Expr **Exprs = (Expr **)Args.release();
+
+ return Owned(new (Context) CXXTemporaryObjectExpr(Context, Constructor, Ty,
+ TyBeginLoc, Exprs,
+ NumExprs, RParenLoc));
+}
+
+
+bool Sema::InitializeVarWithConstructor(VarDecl *VD,
CXXConstructorDecl *Constructor,
- QualType DeclInitType,
- Expr **Exprs, unsigned NumExprs) {
- Expr *Temp = CXXConstructExpr::Create(Context, DeclInitType, Constructor,
- false, Exprs, NumExprs);
+ QualType DeclInitType,
+ MultiExprArg Exprs) {
+ OwningExprResult TempResult =
+ BuildCXXConstructExpr(VD->getLocation(), DeclInitType, Constructor,
+ move(Exprs));
+ if (TempResult.isInvalid())
+ return true;
+
+ Expr *Temp = TempResult.takeAs<Expr>();
MarkDeclarationReferenced(VD->getLocation(), Constructor);
+ Temp = MaybeCreateCXXExprWithTemporaries(Temp, /*DestroyTemps=*/true);
VD->setInit(Context, Temp);
+
+ return false;
}
-void Sema::MarkDestructorReferenced(SourceLocation Loc, QualType DeclInitType)
-{
+void Sema::FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(
- DeclInitType->getAsRecordType()->getDecl());
+ DeclInitType->getAs<RecordType>()->getDecl());
if (!ClassDecl->hasTrivialDestructor())
- if (CXXDestructorDecl *Destructor =
+ if (CXXDestructorDecl *Destructor =
const_cast<CXXDestructorDecl*>(ClassDecl->getDestructor(Context)))
- MarkDeclarationReferenced(Loc, Destructor);
+ MarkDeclarationReferenced(VD->getLocation(), Destructor);
}
-/// AddCXXDirectInitializerToDecl - This action is called immediately after
+/// AddCXXDirectInitializerToDecl - This action is called immediately after
/// ActOnDeclarator, when a C++ direct initializer is present.
/// e.g: "int x(1);"
void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
@@ -2218,7 +3195,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
// the initializer.
if (RealDecl == 0)
return;
-
+
VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
if (!VDecl) {
Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
@@ -2226,9 +3203,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
return;
}
- // FIXME: Need to handle dependent types and expressions here.
-
- // We will treat direct-initialization as a copy-initialization:
+ // We will represent direct-initialization similarly to copy-initialization:
// int x(1); -as-> int x = 1;
// ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c);
//
@@ -2238,6 +3213,24 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
// exactly form was it (like the CodeGen) can handle both cases without
// special case code.
+ // If either the declaration has a dependent type or if any of the expressions
+ // is type-dependent, we represent the initialization via a ParenListExpr for
+ // later use during template instantiation.
+ if (VDecl->getType()->isDependentType() ||
+ Expr::hasAnyTypeDependentArguments((Expr **)Exprs.get(), Exprs.size())) {
+ // Let clients know that initialization was done with a direct initializer.
+ VDecl->setCXXDirectInitializer(true);
+
+ // Store the initialization expressions as a ParenListExpr.
+ unsigned NumExprs = Exprs.size();
+ VDecl->setInit(Context,
+ new (Context) ParenListExpr(Context, LParenLoc,
+ (Expr **)Exprs.release(),
+ NumExprs, RParenLoc));
+ return;
+ }
+
+
// C++ 8.5p11:
// The form of initialization (using parentheses or '=') is generally
// insignificant, but does matter when the entity being initialized has a
@@ -2254,23 +3247,25 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
}
if (VDecl->getType()->isRecordType()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
CXXConstructorDecl *Constructor
= PerformInitializationByConstructor(DeclInitType,
- (Expr **)Exprs.get(), NumExprs,
+ move(Exprs),
VDecl->getLocation(),
SourceRange(VDecl->getLocation(),
RParenLoc),
VDecl->getDeclName(),
- IK_Direct);
+ IK_Direct,
+ ConstructorArgs);
if (!Constructor)
RealDecl->setInvalidDecl();
else {
VDecl->setCXXDirectInitializer(true);
- InitializeVarWithConstructor(VDecl, Constructor, DeclInitType,
- (Expr**)Exprs.release(), NumExprs);
- // FIXME. Must do all that is needed to destroy the object
- // on scope exit. For now, just mark the destructor as used.
- MarkDestructorReferenced(VDecl->getLocation(), DeclInitType);
+ if (InitializeVarWithConstructor(VDecl, Constructor, DeclInitType,
+ move_arg(ConstructorArgs)))
+ RealDecl->setInvalidDecl();
+ FinalizeVarWithDestructor(VDecl, DeclInitType);
}
return;
}
@@ -2291,31 +3286,41 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
/*DirectInit=*/true);
}
-/// PerformInitializationByConstructor - Perform initialization by
-/// constructor (C++ [dcl.init]p14), which may occur as part of
-/// direct-initialization or copy-initialization. We are initializing
-/// an object of type @p ClassType with the given arguments @p
-/// Args. @p Loc is the location in the source code where the
-/// initializer occurs (e.g., a declaration, member initializer,
-/// functional cast, etc.) while @p Range covers the whole
-/// initialization. @p InitEntity is the entity being initialized,
-/// which may by the name of a declaration or a type. @p Kind is the
-/// kind of initialization we're performing, which affects whether
-/// explicit constructors will be considered. When successful, returns
-/// the constructor that will be used to perform the initialization;
-/// when the initialization fails, emits a diagnostic and returns
-/// null.
+/// \brief Perform initialization by constructor (C++ [dcl.init]p14), which
+/// may occur as part of direct-initialization or copy-initialization.
+///
+/// \param ClassType the type of the object being initialized, which must have
+/// class type.
+///
+/// \param ArgsPtr the arguments provided to initialize the object
+///
+/// \param Loc the source location where the initialization occurs
+///
+/// \param Range the source range that covers the entire initialization
+///
+/// \param InitEntity the name of the entity being initialized, if known
+///
+/// \param Kind the type of initialization being performed
+///
+/// \param ConvertedArgs a vector that will be filled in with the
+/// appropriately-converted arguments to the constructor (if initialization
+/// succeeded).
+///
+/// \returns the constructor used to initialize the object, if successful.
+/// Otherwise, emits a diagnostic and returns NULL.
CXXConstructorDecl *
Sema::PerformInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg ArgsPtr,
SourceLocation Loc, SourceRange Range,
DeclarationName InitEntity,
- InitializationKind Kind) {
- const RecordType *ClassRec = ClassType->getAsRecordType();
+ InitializationKind Kind,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) {
+ const RecordType *ClassRec = ClassType->getAs<RecordType>();
assert(ClassRec && "Can only initialize a class type here");
-
- // C++ [dcl.init]p14:
- //
+ Expr **Args = (Expr **)ArgsPtr.get();
+ unsigned NumArgs = ArgsPtr.size();
+
+ // C++ [dcl.init]p14:
// If the initialization is direct-initialization, or if it is
// copy-initialization where the cv-unqualified version of the
// source type is the same class as, or a derived class of, the
@@ -2330,17 +3335,31 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
OverloadCandidateSet CandidateSet;
// Add constructors to the overload set.
- DeclarationName ConstructorName
+ DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ClassType.getUnqualifiedType()));
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
Con != ConEnd; ++Con) {
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
+ if (ConstructorTmpl)
+ Constructor
+ = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
+ else
+ Constructor = cast<CXXConstructorDecl>(*Con);
+
if ((Kind == IK_Direct) ||
- (Kind == IK_Copy && Constructor->isConvertingConstructor()) ||
- (Kind == IK_Default && Constructor->isDefaultConstructor()))
- AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ (Kind == IK_Copy &&
+ Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
+ (Kind == IK_Default && Constructor->isDefaultConstructor())) {
+ if (ConstructorTmpl)
+ AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0,
+ Args, NumArgs, CandidateSet);
+ else
+ AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ }
}
// FIXME: When we decide not to synthesize the implicitly-declared
@@ -2349,9 +3368,10 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Loc, Best)) {
case OR_Success:
- // We found a constructor. Return it.
- return cast<CXXConstructorDecl>(Best->Function);
-
+ // We found a constructor. Break out so that we can convert the arguments
+ // appropriately.
+ break;
+
case OR_No_Viable_Function:
if (InitEntity)
Diag(Loc, diag::err_ovl_no_viable_function_in_init)
@@ -2361,7 +3381,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
<< ClassType << Range;
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
return 0;
-
+
case OR_Ambiguous:
if (InitEntity)
Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
@@ -2382,8 +3402,85 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return 0;
}
+
+ // Convert the arguments, fill in default arguments, etc.
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
+ if (CompleteConstructorCall(Constructor, move(ArgsPtr), Loc, ConvertedArgs))
+ return 0;
- return 0;
+ return Constructor;
+}
+
+/// \brief Given a constructor and the set of arguments provided for the
+/// constructor, convert the arguments and add any required default arguments
+/// to form a proper call to this constructor.
+///
+/// \returns true if an error occurred, false otherwise.
+bool
+Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
+ MultiExprArg ArgsPtr,
+ SourceLocation Loc,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) {
+ // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
+ unsigned NumArgs = ArgsPtr.size();
+ Expr **Args = (Expr **)ArgsPtr.get();
+
+ const FunctionProtoType *Proto
+ = Constructor->getType()->getAs<FunctionProtoType>();
+ assert(Proto && "Constructor without a prototype?");
+ unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumArgsToCheck = NumArgs;
+
+ // If too few arguments are available, we'll fill in the rest with defaults.
+ if (NumArgs < NumArgsInProto) {
+ NumArgsToCheck = NumArgsInProto;
+ ConvertedArgs.reserve(NumArgsInProto);
+ } else {
+ ConvertedArgs.reserve(NumArgs);
+ if (NumArgs > NumArgsInProto)
+ NumArgsToCheck = NumArgsInProto;
+ }
+
+ // Convert arguments
+ for (unsigned i = 0; i != NumArgsToCheck; i++) {
+ QualType ProtoArgType = Proto->getArgType(i);
+
+ Expr *Arg;
+ if (i < NumArgs) {
+ Arg = Args[i];
+
+ // Pass the argument.
+ if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
+ return true;
+
+ Args[i] = 0;
+ } else {
+ ParmVarDecl *Param = Constructor->getParamDecl(i);
+
+ OwningExprResult DefArg = BuildCXXDefaultArgExpr(Loc, Constructor, Param);
+ if (DefArg.isInvalid())
+ return true;
+
+ Arg = DefArg.takeAs<Expr>();
+ }
+
+ ConvertedArgs.push_back(Arg);
+ }
+
+ // If this is a variadic call, handle args passed through "...".
+ if (Proto->isVariadic()) {
+ // Promote the arguments (C99 6.5.2.2p7).
+ for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
+ Expr *Arg = Args[i];
+ if (DefaultVariadicArgumentPromotion(Arg, VariadicConstructor))
+ return true;
+
+ ConvertedArgs.push_back(Arg);
+ Args[i] = 0;
+ }
+ }
+
+ return false;
}
/// CompareReferenceRelationship - Compare the two types T1 and T2 to
@@ -2393,8 +3490,8 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
/// type, and the first type (T1) is the pointee type of the reference
/// type being initialized.
-Sema::ReferenceCompareResult
-Sema::CompareReferenceRelationship(QualType T1, QualType T2,
+Sema::ReferenceCompareResult
+Sema::CompareReferenceRelationship(QualType T1, QualType T2,
bool& DerivedToBase) {
assert(!T1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
@@ -2406,8 +3503,8 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2,
QualType UnqualT2 = T2.getUnqualifiedType();
// C++ [dcl.init.ref]p4:
- // Given types “cv1 T1” and “cv2 T2,” “cv1 T1” is
- // reference-related to “cv2 T2” if T1 is the same type as T2, or
+ // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
+ // reference-related to "cv2 T2" if T1 is the same type as T2, or
// T1 is a base class of T2.
if (UnqualT1 == UnqualT2)
DerivedToBase = false;
@@ -2420,7 +3517,7 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2,
// least).
// C++ [dcl.init.ref]p4:
- // "cv1 T1” is reference-compatible with “cv2 T2” if T1 is
+ // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
// reference-related to T2 and cv1 is the same cv-qualification
// as, or greater cv-qualification than, cv2. For purposes of
// overload resolution, cases for which cv1 is greater
@@ -2450,27 +3547,28 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2,
/// When @p AllowExplicit, we also permit explicit user-defined
/// conversion functions.
/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue.
-bool
+bool
Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
- ImplicitConversionSequence *ICS,
+ SourceLocation DeclLoc,
bool SuppressUserConversions,
- bool AllowExplicit, bool ForceRValue) {
+ bool AllowExplicit, bool ForceRValue,
+ ImplicitConversionSequence *ICS) {
assert(DeclType->isReferenceType() && "Reference init needs a reference");
- QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
+ QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType();
QualType T2 = Init->getType();
// If the initializer is the address of an overloaded function, try
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
if (Context.getCanonicalType(T2) == Context.OverloadTy) {
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
ICS != 0);
if (Fn) {
// Since we're performing this reference-initialization for
// real, update the initializer with the resulting function.
if (!ICS) {
- if (DiagnoseUseOfDecl(Fn, Init->getSourceRange().getBegin()))
+ if (DiagnoseUseOfDecl(Fn, DeclLoc))
return true;
FixOverloadedFunctionReference(Init, Fn);
@@ -2485,7 +3583,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
bool DerivedToBase = false;
Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression :
Init->isLvalue(Context);
- ReferenceCompareResult RefRelationship
+ ReferenceCompareResult RefRelationship
= CompareReferenceRelationship(T1, T2, DerivedToBase);
// Most paths end in a failed conversion.
@@ -2493,8 +3591,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ICS->ConversionKind = ImplicitConversionSequence::BadConversion;
// C++ [dcl.init.ref]p5:
- // A reference to type “cv1 T1” is initialized by an expression
- // of type “cv2 T2” as follows:
+ // A reference to type "cv1 T1" is initialized by an expression
+ // of type "cv2 T2" as follows:
// -- If the initializer expression
@@ -2505,14 +3603,14 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// A&& r = b;
if (isRValRef && InitLvalue == Expr::LV_Valid) {
if (!ICS)
- Diag(Init->getSourceRange().getBegin(), diag::err_lvalue_to_rvalue_ref)
+ Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref)
<< Init->getSourceRange();
return true;
}
bool BindsDirectly = false;
- // -- is an lvalue (but is not a bit-field), and “cv1 T1” is
- // reference-compatible with “cv2 T2,” or
+ // -- is an lvalue (but is not a bit-field), and "cv1 T1" is
+ // reference-compatible with "cv2 T2," or
//
// Note that the bit-field check is skipped if we are just computing
// the implicit conversion sequence (C++ [over.best.ics]p2).
@@ -2546,40 +3644,54 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
return false;
} else {
// Perform the conversion.
- // FIXME: Binding to a subobject of the lvalue is going to require more
- // AST annotation than this.
- ImpCastExprToType(Init, T1, /*isLvalue=*/true);
+ CastExpr::CastKind CK = CastExpr::CK_NoOp;
+ if (DerivedToBase)
+ CK = CastExpr::CK_DerivedToBase;
+ else if(CheckExceptionSpecCompatibility(Init, T1))
+ return true;
+ ImpCastExprToType(Init, T1, CK, /*isLvalue=*/true);
}
}
// -- has a class type (i.e., T2 is a class type) and can be
- // implicitly converted to an lvalue of type “cv3 T3,”
- // where “cv1 T1” is reference-compatible with “cv3 T3”
+ // implicitly converted to an lvalue of type "cv3 T3,"
+ // where "cv1 T1" is reference-compatible with "cv3 T3"
// 92) (this conversion is selected by enumerating the
// applicable conversion functions (13.3.1.6) and choosing
// the best one through overload resolution (13.3)),
- if (!isRValRef && !SuppressUserConversions && T2->isRecordType()) {
- // FIXME: Look for conversions in base classes!
- CXXRecordDecl *T2RecordDecl
- = dyn_cast<CXXRecordDecl>(T2->getAsRecordType()->getDecl());
+ if (!isRValRef && !SuppressUserConversions && T2->isRecordType() &&
+ !RequireCompleteType(SourceLocation(), T2, 0)) {
+ CXXRecordDecl *T2RecordDecl
+ = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet;
- OverloadedFunctionDecl *Conversions
- = T2RecordDecl->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator Func
+ OverloadedFunctionDecl *Conversions
+ = T2RecordDecl->getVisibleConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
-
+ FunctionTemplateDecl *ConvTemplate
+ = dyn_cast<FunctionTemplateDecl>(*Func);
+ CXXConversionDecl *Conv;
+ if (ConvTemplate)
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast<CXXConversionDecl>(*Func);
+
// If the conversion function doesn't return a reference type,
// it can't be considered for this conversion.
if (Conv->getConversionType()->isLValueReferenceType() &&
- (AllowExplicit || !Conv->isExplicit()))
- AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
+ (AllowExplicit || !Conv->isExplicit())) {
+ if (ConvTemplate)
+ AddTemplateConversionCandidate(ConvTemplate, Init, DeclType,
+ CandidateSet);
+ else
+ AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
+ }
}
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Init->getLocStart(), Best)) {
+ switch (BestViableFunction(CandidateSet, DeclLoc, Best)) {
case OR_Success:
// This is a direct binding.
BindsDirectly = true;
@@ -2604,17 +3716,33 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
"Expected a direct reference binding!");
return false;
} else {
- // Perform the conversion.
- // FIXME: Binding to a subobject of the lvalue is going to require more
- // AST annotation than this.
- ImpCastExprToType(Init, T1, /*isLvalue=*/true);
+ OwningExprResult InitConversion =
+ BuildCXXCastArgument(DeclLoc, QualType(),
+ CastExpr::CK_UserDefinedConversion,
+ cast<CXXMethodDecl>(Best->Function),
+ Owned(Init));
+ Init = InitConversion.takeAs<Expr>();
+
+ if (CheckExceptionSpecCompatibility(Init, T1))
+ return true;
+ ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion,
+ /*isLvalue=*/true);
}
break;
case OR_Ambiguous:
- assert(false && "Ambiguous reference binding conversions not implemented.");
+ if (ICS) {
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
+ Cand != CandidateSet.end(); ++Cand)
+ if (Cand->Viable)
+ ICS->ConversionFunctionSet.push_back(Cand->Function);
+ break;
+ }
+ Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType()
+ << Init->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return true;
-
+
case OR_No_Viable_Function:
case OR_Deleted:
// There was no suitable conversion, or we found a deleted
@@ -2622,7 +3750,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
break;
}
}
-
+
if (BindsDirectly) {
// C++ [dcl.init.ref]p4:
// [...] In all cases where the reference-related or
@@ -2636,9 +3764,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// complain about errors, because we should not be checking for
// ambiguity (or inaccessibility) unless the reference binding
// actually happens.
- if (DerivedToBase)
- return CheckDerivedToBaseConversion(T2, T1,
- Init->getSourceRange().getBegin(),
+ if (DerivedToBase)
+ return CheckDerivedToBaseConversion(T2, T1, DeclLoc,
Init->getSourceRange());
else
return false;
@@ -2647,25 +3774,24 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// -- Otherwise, the reference shall be to a non-volatile const
// type (i.e., cv1 shall be const), or the reference shall be an
// rvalue reference and the initializer expression shall be an rvalue.
- if (!isRValRef && T1.getCVRQualifiers() != QualType::Const) {
+ if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) {
if (!ICS)
- Diag(Init->getSourceRange().getBegin(),
- diag::err_not_reference_to_const_init)
+ Diag(DeclLoc, diag::err_not_reference_to_const_init)
<< T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value")
<< T2 << Init->getSourceRange();
return true;
}
// -- If the initializer expression is an rvalue, with T2 a
- // class type, and “cv1 T1” is reference-compatible with
- // “cv2 T2,” the reference is bound in one of the
+ // class type, and "cv1 T1" is reference-compatible with
+ // "cv2 T2," the reference is bound in one of the
// following ways (the choice is implementation-defined):
//
// -- The reference is bound to the object represented by
// the rvalue (see 3.10) or to a sub-object within that
// object.
//
- // -- A temporary of type “cv1 T2” [sic] is created, and
+ // -- A temporary of type "cv1 T2" [sic] is created, and
// a constructor is called to copy the entire rvalue
// object into the temporary. The reference is bound to
// the temporary or to a sub-object within the
@@ -2693,14 +3819,17 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ICS->Standard.RRefBinding = isRValRef;
ICS->Standard.CopyConstructor = 0;
} else {
- // FIXME: Binding to a subobject of the rvalue is going to require more
- // AST annotation than this.
- ImpCastExprToType(Init, T1, /*isLvalue=*/false);
+ CastExpr::CastKind CK = CastExpr::CK_NoOp;
+ if (DerivedToBase)
+ CK = CastExpr::CK_DerivedToBase;
+ else if(CheckExceptionSpecCompatibility(Init, T1))
+ return true;
+ ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false);
}
return false;
}
- // -- Otherwise, a temporary of type “cv1 T1” is created and
+ // -- Otherwise, a temporary of type "cv1 T1" is created and
// initialized from the initializer expression using the
// rules for a non-reference copy initialization (8.5). The
// reference is then bound to the temporary. If T1 is
@@ -2713,8 +3842,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// added qualification. But that wasn't the case, so the reference
// initialization fails.
if (!ICS)
- Diag(Init->getSourceRange().getBegin(),
- diag::err_reference_init_drops_quals)
+ Diag(DeclLoc, diag::err_reference_init_drops_quals)
<< T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value")
<< T2 << Init->getSourceRange();
return true;
@@ -2728,8 +3856,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
if (SuppressUserConversions && RefRelationship == Ref_Incompatible &&
(T1->isRecordType() || T2->isRecordType())) {
if (!ICS)
- Diag(Init->getSourceRange().getBegin(),
- diag::err_typecheck_convert_incompatible)
+ Diag(DeclLoc, diag::err_typecheck_convert_incompatible)
<< DeclType << Init->getType() << "initializing" << Init->getSourceRange();
return true;
}
@@ -2737,7 +3864,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// Actually try to convert the initializer to T1.
if (ICS) {
// C++ [over.ics.ref]p2:
- //
+ //
// When a parameter of reference type is not bound directly to
// an argument expression, the conversion sequence is the one
// required to convert the argument expression to the
@@ -2747,19 +3874,48 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// the argument expression. Any difference in top-level
// cv-qualification is subsumed by the initialization itself
// and does not constitute a conversion.
- *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions);
+ *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+
// Of course, that's still a reference binding.
if (ICS->ConversionKind == ImplicitConversionSequence::StandardConversion) {
ICS->Standard.ReferenceBinding = true;
ICS->Standard.RRefBinding = isRValRef;
- } else if(ICS->ConversionKind ==
+ } else if (ICS->ConversionKind ==
ImplicitConversionSequence::UserDefinedConversion) {
ICS->UserDefined.After.ReferenceBinding = true;
ICS->UserDefined.After.RRefBinding = isRValRef;
}
return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
} else {
- return PerformImplicitConversion(Init, T1, "initializing");
+ ImplicitConversionSequence Conversions;
+ bool badConversion = PerformImplicitConversion(Init, T1, "initializing",
+ false, false,
+ Conversions);
+ if (badConversion) {
+ if ((Conversions.ConversionKind ==
+ ImplicitConversionSequence::BadConversion)
+ && !Conversions.ConversionFunctionSet.empty()) {
+ Diag(DeclLoc,
+ diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange();
+ for (int j = Conversions.ConversionFunctionSet.size()-1;
+ j >= 0; j--) {
+ FunctionDecl *Func = Conversions.ConversionFunctionSet[j];
+ Diag(Func->getLocation(), diag::err_ovl_candidate);
+ }
+ }
+ else {
+ if (isRValRef)
+ Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref)
+ << Init->getSourceRange();
+ else
+ Diag(DeclLoc, diag::err_invalid_initialization)
+ << DeclType << Init->getType() << Init->getSourceRange();
+ }
+ }
+ return badConversion;
}
}
@@ -2772,7 +3928,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
OverloadedOperatorKind Op = FnDecl->getOverloadedOperator();
- // C++ [over.oper]p5:
+ // C++ [over.oper]p5:
// The allocation and deallocation functions, operator new,
// operator new[], operator delete and operator delete[], are
// described completely in 3.7.3. The attributes and restrictions
@@ -2815,13 +3971,13 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// An operator function cannot have default arguments (8.3.6),
// except where explicitly stated below.
//
- // Only the function-call operator allows default arguments
+ // Only the function-call operator allows default arguments
// (C++ [over.call]p1).
if (Op != OO_Call) {
for (FunctionDecl::param_iterator Param = FnDecl->param_begin();
Param != FnDecl->param_end(); ++Param) {
if ((*Param)->hasUnparsedDefaultArg())
- return Diag((*Param)->getLocation(),
+ return Diag((*Param)->getLocation(),
diag::err_operator_overload_default_arg)
<< FnDecl->getDeclName();
else if (Expr *DefArg = (*Param)->getDefaultArg())
@@ -2846,7 +4002,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// [...] Operator functions cannot have more or fewer parameters
// than the number required for the corresponding operator, as
// described in the rest of this subclause.
- unsigned NumParams = FnDecl->getNumParams()
+ unsigned NumParams = FnDecl->getNumParams()
+ (isa<CXXMethodDecl>(FnDecl)? 1 : 0);
if (Op != OO_Call &&
((NumParams == 1 && !CanBeUnaryOperator) ||
@@ -2870,7 +4026,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// Overloaded operators other than operator() cannot be variadic.
if (Op != OO_Call &&
- FnDecl->getType()->getAsFunctionProtoType()->isVariadic()) {
+ FnDecl->getType()->getAs<FunctionProtoType>()->isVariadic()) {
return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic)
<< FnDecl->getDeclName();
}
@@ -2895,12 +4051,12 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
if ((Op == OO_PlusPlus || Op == OO_MinusMinus) && NumParams == 2) {
ParmVarDecl *LastParam = FnDecl->getParamDecl(FnDecl->getNumParams() - 1);
bool ParamIsInt = false;
- if (const BuiltinType *BT = LastParam->getType()->getAsBuiltinType())
+ if (const BuiltinType *BT = LastParam->getType()->getAs<BuiltinType>())
ParamIsInt = BT->getKind() == BuiltinType::Int;
if (!ParamIsInt)
return Diag(LastParam->getLocation(),
- diag::err_operator_overload_post_incdec_must_be_int)
+ diag::err_operator_overload_post_incdec_must_be_int)
<< LastParam->getType() << (Op == OO_MinusMinus);
}
@@ -2910,6 +4066,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
assert(isa<CXXMethodDecl>(FnDecl) &&
"Overloaded = not member, but not filtered.");
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
+ Method->setCopyAssignment(true);
Method->getParent()->addedAssignmentOperator(Context, Method);
}
@@ -2938,11 +4095,11 @@ Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S,
Diag(LangLoc, diag::err_bad_language);
return DeclPtrTy();
}
-
+
// FIXME: Add all the various semantics of linkage specifications
-
+
LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext,
- LangLoc, Language,
+ LangLoc, Language,
LBraceLoc.isValid());
CurContext->addDecl(D);
PushDeclContext(S, D);
@@ -2965,6 +4122,7 @@ Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S,
/// occurs within a C++ catch clause, returning the newly-created
/// variable.
VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
+ DeclaratorInfo *DInfo,
IdentifierInfo *Name,
SourceLocation Loc,
SourceRange Range) {
@@ -2980,7 +4138,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
// The exception-declaration shall not denote a pointer or reference to an
// incomplete type, other than [cv] void*.
// N2844 forbids rvalue references.
- if(!ExDeclType->isDependentType() && ExDeclType->isRValueReferenceType()) {
+ if (!ExDeclType->isDependentType() && ExDeclType->isRValueReferenceType()) {
Diag(Loc, diag::err_catch_rvalue_ref) << Range;
Invalid = true;
}
@@ -2988,11 +4146,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
QualType BaseType = ExDeclType;
int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference
unsigned DK = diag::err_catch_incomplete;
- if (const PointerType *Ptr = BaseType->getAsPointerType()) {
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
BaseType = Ptr->getPointeeType();
Mode = 1;
DK = diag::err_catch_incomplete_ptr;
- } else if(const ReferenceType *Ref = BaseType->getAsReferenceType()) {
+ } else if (const ReferenceType *Ref = BaseType->getAs<ReferenceType>()) {
// For the purpose of error recovery, we treat rvalue refs like lvalue refs.
BaseType = Ref->getPointeeType();
Mode = 2;
@@ -3002,7 +4160,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
!BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK))
Invalid = true;
- if (!Invalid && !ExDeclType->isDependentType() &&
+ if (!Invalid && !ExDeclType->isDependentType() &&
RequireNonAbstractType(Loc, ExDeclType,
diag::err_abstract_type_in_decl,
AbstractVariableType))
@@ -3013,9 +4171,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
// FIXME: Need to check for abstract classes.
- VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
- Name, ExDeclType, VarDecl::None,
- Range.getBegin());
+ VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
+ Name, ExDeclType, DInfo, VarDecl::None);
if (Invalid)
ExDecl->setInvalidDecl();
@@ -3026,11 +4183,12 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
/// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch
/// handler.
Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
- QualType ExDeclType = GetTypeForDeclarator(D, S);
+ DeclaratorInfo *DInfo = 0;
+ QualType ExDeclType = GetTypeForDeclarator(D, S, &DInfo);
bool Invalid = D.isInvalidType();
IdentifierInfo *II = D.getIdentifier();
- if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) {
+ if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) {
// The scope should be freshly made just for us. There is just no way
// it contains any previous declaration.
assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl)));
@@ -3046,14 +4204,14 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
Invalid = true;
}
- VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType,
+ VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, DInfo,
D.getIdentifier(),
D.getIdentifierLoc(),
D.getDeclSpec().getSourceRange());
if (Invalid)
ExDecl->setInvalidDecl();
-
+
// Add the exception declaration into this scope.
if (II)
PushOnScopeChains(ExDecl, S);
@@ -3064,11 +4222,11 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
return DeclPtrTy::make(ExDecl);
}
-Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
ExprArg assertexpr,
ExprArg assertmessageexpr) {
Expr *AssertExpr = (Expr *)assertexpr.get();
- StringLiteral *AssertMessage =
+ StringLiteral *AssertMessage =
cast<StringLiteral>((Expr *)assertmessageexpr.get());
if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) {
@@ -3080,32 +4238,305 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
}
if (Value == 0) {
- std::string str(AssertMessage->getStrData(),
+ std::string str(AssertMessage->getStrData(),
AssertMessage->getByteLength());
- Diag(AssertLoc, diag::err_static_assert_failed)
+ Diag(AssertLoc, diag::err_static_assert_failed)
<< str << AssertExpr->getSourceRange();
}
}
-
+
assertexpr.release();
assertmessageexpr.release();
- Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc,
+ Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc,
AssertExpr, AssertMessage);
-
+
CurContext->addDecl(Decl);
return DeclPtrTy::make(Decl);
}
-bool Sema::ActOnFriendDecl(Scope *S, SourceLocation FriendLoc, DeclPtrTy Dcl) {
- if (!(S->getFlags() & Scope::ClassScope)) {
- Diag(FriendLoc, diag::err_friend_decl_outside_class);
- return true;
+/// Handle a friend type declaration. This works in tandem with
+/// ActOnTag.
+///
+/// Notes on friend class templates:
+///
+/// We generally treat friend class declarations as if they were
+/// declaring a class. So, for example, the elaborated type specifier
+/// in a friend declaration is required to obey the restrictions of a
+/// class-head (i.e. no typedefs in the scope chain), template
+/// parameters are required to match up with simple template-ids, &c.
+/// However, unlike when declaring a template specialization, it's
+/// okay to refer to a template specialization without an empty
+/// template parameter declaration, e.g.
+/// friend class A<T>::B<unsigned>;
+/// We permit this as a special case; if there are any template
+/// parameters present at all, require proper matching, i.e.
+/// template <> template <class T> friend class A<int>::B;
+Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S,
+ const DeclSpec &DS,
+ MultiTemplateParamsArg TempParams) {
+ SourceLocation Loc = DS.getSourceRange().getBegin();
+
+ assert(DS.isFriendSpecified());
+ assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
+
+ // Try to convert the decl specifier to a type. This works for
+ // friend templates because ActOnTag never produces a ClassTemplateDecl
+ // for a TUK_Friend.
+ bool invalid = false;
+ QualType SourceTy;
+ QualType T = ConvertDeclSpecToType(DS, Loc, invalid, SourceTy);
+ if (invalid) return DeclPtrTy();
+
+ // This is definitely an error in C++98. It's probably meant to
+ // be forbidden in C++0x, too, but the specification is just
+ // poorly written.
+ //
+ // The problem is with declarations like the following:
+ // template <T> friend A<T>::foo;
+ // where deciding whether a class C is a friend or not now hinges
+ // on whether there exists an instantiation of A that causes
+ // 'foo' to equal C. There are restrictions on class-heads
+ // (which we declare (by fiat) elaborated friend declarations to
+ // be) that makes this tractable.
+ //
+ // FIXME: handle "template <> friend class A<T>;", which
+ // is possibly well-formed? Who even knows?
+ if (TempParams.size() && !isa<ElaboratedType>(T)) {
+ Diag(Loc, diag::err_tagless_friend_type_template)
+ << DS.getSourceRange();
+ return DeclPtrTy();
}
-
- return false;
+
+ // C++ [class.friend]p2:
+ // An elaborated-type-specifier shall be used in a friend declaration
+ // for a class.*
+ // * The class-key of the elaborated-type-specifier is required.
+ // This is one of the rare places in Clang where it's legitimate to
+ // ask about the "spelling" of the type.
+ if (!getLangOptions().CPlusPlus0x && !isa<ElaboratedType>(T)) {
+ // If we evaluated the type to a record type, suggest putting
+ // a tag in front.
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RecordDecl *RD = RT->getDecl();
+
+ std::string InsertionText = std::string(" ") + RD->getKindName();
+
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type)
+ << (unsigned) RD->getTagKind()
+ << T
+ << SourceRange(DS.getFriendSpecLoc())
+ << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
+ InsertionText);
+ return DeclPtrTy();
+ }else {
+ Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
+ << DS.getSourceRange();
+ return DeclPtrTy();
+ }
+ }
+
+ // Enum types cannot be friends.
+ if (T->getAs<EnumType>()) {
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend)
+ << SourceRange(DS.getFriendSpecLoc());
+ return DeclPtrTy();
+ }
+
+ // C++98 [class.friend]p1: A friend of a class is a function
+ // or class that is not a member of the class . . .
+ // But that's a silly restriction which nobody implements for
+ // inner classes, and C++0x removes it anyway, so we only report
+ // this (as a warning) if we're being pedantic.
+ if (!getLangOptions().CPlusPlus0x)
+ if (const RecordType *RT = T->getAs<RecordType>())
+ if (RT->getDecl()->getDeclContext() == CurContext)
+ Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
+
+ Decl *D;
+ if (TempParams.size())
+ D = FriendTemplateDecl::Create(Context, CurContext, Loc,
+ TempParams.size(),
+ (TemplateParameterList**) TempParams.release(),
+ T.getTypePtr(),
+ DS.getFriendSpecLoc());
+ else
+ D = FriendDecl::Create(Context, CurContext, Loc, T.getTypePtr(),
+ DS.getFriendSpecLoc());
+ D->setAccess(AS_public);
+ CurContext->addDecl(D);
+
+ return DeclPtrTy::make(D);
+}
+
+Sema::DeclPtrTy
+Sema::ActOnFriendFunctionDecl(Scope *S,
+ Declarator &D,
+ bool IsDefinition,
+ MultiTemplateParamsArg TemplateParams) {
+ const DeclSpec &DS = D.getDeclSpec();
+
+ assert(DS.isFriendSpecified());
+ assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
+
+ SourceLocation Loc = D.getIdentifierLoc();
+ DeclaratorInfo *DInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &DInfo);
+
+ // C++ [class.friend]p1
+ // A friend of a class is a function or class....
+ // Note that this sees through typedefs, which is intended.
+ // It *doesn't* see through dependent types, which is correct
+ // according to [temp.arg.type]p3:
+ // If a declaration acquires a function type through a
+ // type dependent on a template-parameter and this causes
+ // a declaration that does not use the syntactic form of a
+ // function declarator to have a function type, the program
+ // is ill-formed.
+ if (!T->isFunctionType()) {
+ Diag(Loc, diag::err_unexpected_friend);
+
+ // It might be worthwhile to try to recover by creating an
+ // appropriate declaration.
+ return DeclPtrTy();
+ }
+
+ // C++ [namespace.memdef]p3
+ // - If a friend declaration in a non-local class first declares a
+ // class or function, the friend class or function is a member
+ // of the innermost enclosing namespace.
+ // - The name of the friend is not found by simple name lookup
+ // until a matching declaration is provided in that namespace
+ // scope (either before or after the class declaration granting
+ // friendship).
+ // - If a friend function is called, its name may be found by the
+ // name lookup that considers functions from namespaces and
+ // classes associated with the types of the function arguments.
+ // - When looking for a prior declaration of a class or a function
+ // declared as a friend, scopes outside the innermost enclosing
+ // namespace scope are not considered.
+
+ CXXScopeSpec &ScopeQual = D.getCXXScopeSpec();
+ DeclarationName Name = GetNameForDeclarator(D);
+ assert(Name);
+
+ // The context we found the declaration in, or in which we should
+ // create the declaration.
+ DeclContext *DC;
+
+ // FIXME: handle local classes
+
+ // Recover from invalid scope qualifiers as if they just weren't there.
+ NamedDecl *PrevDecl = 0;
+ if (!ScopeQual.isInvalid() && ScopeQual.isSet()) {
+ // FIXME: RequireCompleteDeclContext
+ DC = computeDeclContext(ScopeQual);
+
+ // FIXME: handle dependent contexts
+ if (!DC) return DeclPtrTy();
+
+ LookupResult R;
+ LookupQualifiedName(R, DC, Name, LookupOrdinaryName, true);
+ PrevDecl = R.getAsSingleDecl(Context);
+
+ // If searching in that context implicitly found a declaration in
+ // a different context, treat it like it wasn't found at all.
+ // TODO: better diagnostics for this case. Suggesting the right
+ // qualified scope would be nice...
+ if (!PrevDecl || !PrevDecl->getDeclContext()->Equals(DC)) {
+ D.setInvalidType();
+ Diag(Loc, diag::err_qualified_friend_not_found) << Name << T;
+ return DeclPtrTy();
+ }
+
+ // C++ [class.friend]p1: A friend of a class is a function or
+ // class that is not a member of the class . . .
+ if (DC->Equals(CurContext))
+ Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+
+ // Otherwise walk out to the nearest namespace scope looking for matches.
+ } else {
+ // TODO: handle local class contexts.
+
+ DC = CurContext;
+ while (true) {
+ // Skip class contexts. If someone can cite chapter and verse
+ // for this behavior, that would be nice --- it's what GCC and
+ // EDG do, and it seems like a reasonable intent, but the spec
+ // really only says that checks for unqualified existing
+ // declarations should stop at the nearest enclosing namespace,
+ // not that they should only consider the nearest enclosing
+ // namespace.
+ while (DC->isRecord())
+ DC = DC->getParent();
+
+ LookupResult R;
+ LookupQualifiedName(R, DC, Name, LookupOrdinaryName, true);
+ PrevDecl = R.getAsSingleDecl(Context);
+
+ // TODO: decide what we think about using declarations.
+ if (PrevDecl)
+ break;
+
+ if (DC->isFileContext()) break;
+ DC = DC->getParent();
+ }
+
+ // C++ [class.friend]p1: A friend of a class is a function or
+ // class that is not a member of the class . . .
+ // C++0x changes this for both friend types and functions.
+ // Most C++ 98 compilers do seem to give an error here, so
+ // we do, too.
+ if (PrevDecl && DC->Equals(CurContext) && !getLangOptions().CPlusPlus0x)
+ Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+ }
+
+ if (DC->isFileContext()) {
+ // This implies that it has to be an operator or function.
+ if (D.getKind() == Declarator::DK_Constructor ||
+ D.getKind() == Declarator::DK_Destructor ||
+ D.getKind() == Declarator::DK_Conversion) {
+ Diag(Loc, diag::err_introducing_special_friend) <<
+ (D.getKind() == Declarator::DK_Constructor ? 0 :
+ D.getKind() == Declarator::DK_Destructor ? 1 : 2);
+ return DeclPtrTy();
+ }
+ }
+
+ bool Redeclaration = false;
+ NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, PrevDecl,
+ move(TemplateParams),
+ IsDefinition,
+ Redeclaration);
+ if (!ND) return DeclPtrTy();
+
+ assert(ND->getDeclContext() == DC);
+ assert(ND->getLexicalDeclContext() == CurContext);
+
+ // Add the function declaration to the appropriate lookup tables,
+ // adjusting the redeclarations list as necessary. We don't
+ // want to do this yet if the friending class is dependent.
+ //
+ // Also update the scope-based lookup if the target context's
+ // lookup context is in lexical scope.
+ if (!CurContext->isDependentContext()) {
+ DC = DC->getLookupContext();
+ DC->makeDeclVisibleInContext(ND, /* Recoverable=*/ false);
+ if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
+ PushOnScopeChains(ND, EnclosingScope, /*AddToContext=*/ false);
+ }
+
+ FriendDecl *FrD = FriendDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), ND,
+ DS.getFriendSpecLoc());
+ FrD->setAccess(AS_public);
+ CurContext->addDecl(FrD);
+
+ return DeclPtrTy::make(ND);
}
void Sema::SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc) {
+ AdjustDeclIfTemplate(dcl);
+
Decl *Dcl = dcl.getAs<Decl>();
FunctionDecl *Fn = dyn_cast<FunctionDecl>(Dcl);
if (!Fn) {
@@ -3142,21 +4573,21 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
}
}
-bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
+bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- QualType NewTy = New->getType()->getAsFunctionType()->getResultType();
- QualType OldTy = Old->getType()->getAsFunctionType()->getResultType();
+ QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType();
+ QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType();
QualType CNewTy = Context.getCanonicalType(NewTy);
QualType COldTy = Context.getCanonicalType(OldTy);
- if (CNewTy == COldTy &&
+ if (CNewTy == COldTy &&
CNewTy.getCVRQualifiers() == COldTy.getCVRQualifiers())
return false;
-
+
// Check if the return types are covariant
QualType NewClassTy, OldClassTy;
-
+
/// Both types must be pointers or references to classes.
if (PointerType *NewPT = dyn_cast<PointerType>(NewTy)) {
if (PointerType *OldPT = dyn_cast<PointerType>(OldTy)) {
@@ -3169,14 +4600,14 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
OldClassTy = OldRT->getPointeeType();
}
}
-
+
// The return types aren't either both pointers or references to a class type.
if (NewClassTy.isNull()) {
- Diag(New->getLocation(),
+ Diag(New->getLocation(),
diag::err_different_return_type_for_overriding_virtual_function)
<< New->getDeclName() << NewTy << OldTy;
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
-
+
return true;
}
@@ -3189,9 +4620,9 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
return true;
}
-
+
// Check if we the conversion from derived to base is valid.
- if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
+ if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
diag::err_covariant_return_inaccessible_base,
diag::err_covariant_return_ambiguous_derived_to_base_conv,
// FIXME: Should this point to the return type?
@@ -3200,7 +4631,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
return true;
}
}
-
+
// The qualifiers of the return types must be the same.
if (CNewTy.getCVRQualifiers() != COldTy.getCVRQualifiers()) {
Diag(New->getLocation(),
@@ -3209,7 +4640,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
return true;
};
-
+
// The new class type must have the same or less qualifiers as the old type.
if (NewClassTy.isMoreQualifiedThan(OldClassTy)) {
@@ -3219,7 +4650,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
return true;
};
-
+
return false;
}
@@ -3229,6 +4660,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
/// static data member of class X, names should be looked up in the scope of
/// class X.
void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) {
+ AdjustDeclIfTemplate(Dcl);
+
Decl *D = Dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it.
if (D == 0)
@@ -3238,13 +4671,13 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) {
// int foo::bar;
if (!D->isOutOfLine())
return;
-
+
// C++ [basic.lookup.unqual]p13
//
// A name used in the definition of a static data member of class X
// (after the qualified-id of the static member) is looked up as if the name
// was used in a member function of X.
-
+
// Change current context into the context of the initializing declaration.
EnterDeclaratorContext(S, D->getDeclContext());
}
@@ -3252,6 +4685,8 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) {
/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an
/// initializer for the declaration 'Dcl'.
void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) {
+ AdjustDeclIfTemplate(Dcl);
+
Decl *D = Dcl.getAs<Decl>();
// If there is no declaration, there was an error parsing it.
if (D == 0)
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 5cf48d6da0c86..22a517934c7ef 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -25,10 +25,10 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
if (GetterMethod &&
GetterMethod->getResultType() != property->getType()) {
AssignConvertType result = Incompatible;
- if (Context.isObjCObjectPointerType(property->getType()))
+ if (property->getType()->isObjCObjectPointerType())
result = CheckAssignmentConstraints(GetterMethod->getResultType(), property->getType());
if (result != Compatible) {
- Diag(Loc, diag::warn_accessor_property_type_mismatch)
+ Diag(Loc, diag::warn_accessor_property_type_mismatch)
<< property->getDeclName()
<< GetterMethod->getSelector();
Diag(GetterMethod->getLocation(), diag::note_declared_at);
@@ -43,7 +43,7 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
assert(getCurMethodDecl() == 0 && "Method parsing confused");
ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D.getAs<Decl>());
-
+
// If we don't have a valid method decl, simply return.
if (!MDecl)
return;
@@ -55,7 +55,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
AddInstanceMethodToGlobalPool(MDecl);
else
AddFactoryMethodToGlobalPool(MDecl);
-
+
// Allow all of Sema to see that we are entering a method definition.
PushDeclContext(FnBodyScope, MDecl);
@@ -64,7 +64,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
// Insert the invisible arguments, self and _cmd!
MDecl->createImplicitParams(Context, MDecl->getClassInterface());
-
+
PushOnScopeChains(MDecl->getSelfDecl(), FnBodyScope);
PushOnScopeChains(MDecl->getCmdDecl(), FnBodyScope);
@@ -82,9 +82,9 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs,
SourceLocation EndProtoLoc, AttributeList *AttrList) {
assert(ClassName && "Missing class identifier");
-
+
// Check for another declaration kind with the same name.
- NamedDecl *PrevDecl = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(ClassLoc, PrevDecl);
@@ -96,7 +96,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
}
-
+
ObjCInterfaceDecl* IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (IDecl) {
// Class already seen. Is it a forward declaration?
@@ -111,72 +111,78 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
} else {
IDecl->setLocation(AtInterfaceLoc);
IDecl->setForwardDecl(false);
+ IDecl->setClassLoc(ClassLoc);
}
} else {
- IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
+ IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
ClassName, ClassLoc);
if (AttrList)
ProcessDeclAttributeList(TUScope, IDecl, AttrList);
-
+
PushOnScopeChains(IDecl, TUScope);
}
-
+
if (SuperName) {
// Check if a different kind of symbol declared in this scope.
- PrevDecl = LookupName(TUScope, SuperName, LookupOrdinaryName);
-
- ObjCInterfaceDecl *SuperClassDecl =
- dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
-
- // Diagnose classes that inherit from deprecated classes.
- if (SuperClassDecl)
- (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc);
-
- if (PrevDecl && SuperClassDecl == 0) {
- // The previous declaration was not a class decl. Check if we have a
- // typedef. If we do, get the underlying class type.
- if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
- QualType T = TDecl->getUnderlyingType();
- if (T->isObjCInterfaceType()) {
- if (NamedDecl *IDecl = T->getAsObjCInterfaceType()->getDecl())
- SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
+ PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName);
+ if (PrevDecl == IDecl) {
+ Diag(SuperLoc, diag::err_recursive_superclass)
+ << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
+ IDecl->setLocEnd(ClassLoc);
+ } else {
+ ObjCInterfaceDecl *SuperClassDecl =
+ dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+
+ // Diagnose classes that inherit from deprecated classes.
+ if (SuperClassDecl)
+ (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc);
+
+ if (PrevDecl && SuperClassDecl == 0) {
+ // The previous declaration was not a class decl. Check if we have a
+ // typedef. If we do, get the underlying class type.
+ if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
+ QualType T = TDecl->getUnderlyingType();
+ if (T->isObjCInterfaceType()) {
+ if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl())
+ SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
+ }
+ }
+
+ // This handles the following case:
+ //
+ // typedef int SuperClass;
+ // @interface MyClass : SuperClass {} @end
+ //
+ if (!SuperClassDecl) {
+ Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
}
}
-
- // This handles the following case:
- //
- // typedef int SuperClass;
- // @interface MyClass : SuperClass {} @end
- //
- if (!SuperClassDecl) {
- Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+
+ if (!dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
+ if (!SuperClassDecl)
+ Diag(SuperLoc, diag::err_undef_superclass)
+ << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
+ else if (SuperClassDecl->isForwardDecl())
+ Diag(SuperLoc, diag::err_undef_superclass)
+ << SuperClassDecl->getDeclName() << ClassName
+ << SourceRange(AtInterfaceLoc, ClassLoc);
}
+ IDecl->setSuperClass(SuperClassDecl);
+ IDecl->setSuperClassLoc(SuperLoc);
+ IDecl->setLocEnd(SuperLoc);
}
-
- if (!dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
- if (!SuperClassDecl)
- Diag(SuperLoc, diag::err_undef_superclass)
- << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
- else if (SuperClassDecl->isForwardDecl())
- Diag(SuperLoc, diag::err_undef_superclass)
- << SuperClassDecl->getDeclName() << ClassName
- << SourceRange(AtInterfaceLoc, ClassLoc);
- }
- IDecl->setSuperClass(SuperClassDecl);
- IDecl->setSuperClassLoc(SuperLoc);
- IDecl->setLocEnd(SuperLoc);
} else { // we have a root class.
IDecl->setLocEnd(ClassLoc);
}
-
+
/// Check then save referenced protocols.
if (NumProtoRefs) {
IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
Context);
IDecl->setLocEnd(EndProtoLoc);
}
-
+
CheckObjCDeclScope(IDecl);
return DeclPtrTy::make(IDecl);
}
@@ -184,12 +190,12 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
/// ActOnCompatiblityAlias - this action is called after complete parsing of
/// @compatibility_alias declaration. It sets up the alias relationships.
Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
- IdentifierInfo *AliasName,
+ IdentifierInfo *AliasName,
SourceLocation AliasLocation,
IdentifierInfo *ClassName,
SourceLocation ClassLocation) {
// Look for previous declaration of alias name
- NamedDecl *ADecl = LookupName(TUScope, AliasName, LookupOrdinaryName);
+ NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName);
if (ADecl) {
if (isa<ObjCCompatibleAliasDecl>(ADecl))
Diag(AliasLocation, diag::warn_previous_alias_decl);
@@ -199,13 +205,13 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
return DeclPtrTy();
}
// Check for class declaration
- NamedDecl *CDeclU = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCInterfaceType()) {
- if (NamedDecl *IDecl = T->getAsObjCInterfaceType()->getDecl()) {
+ if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) {
ClassName = IDecl->getIdentifier();
- CDeclU = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
}
}
}
@@ -216,11 +222,11 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
Diag(CDeclU->getLocation(), diag::note_previous_declaration);
return DeclPtrTy();
}
-
+
// Everything checked out, instantiate a new alias declaration AST.
- ObjCCompatibleAliasDecl *AliasDecl =
+ ObjCCompatibleAliasDecl *AliasDecl =
ObjCCompatibleAliasDecl::Create(Context, CurContext, AtLoc, AliasName, CDecl);
-
+
if (!CheckObjCDeclScope(AliasDecl))
PushOnScopeChains(AliasDecl, TUScope);
@@ -230,17 +236,16 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
void Sema::CheckForwardProtocolDeclarationForCircularDependency(
IdentifierInfo *PName,
SourceLocation &Ploc, SourceLocation PrevLoc,
- const ObjCList<ObjCProtocolDecl> &PList)
-{
+ const ObjCList<ObjCProtocolDecl> &PList) {
for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(),
E = PList.end(); I != E; ++I) {
-
+
if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier())) {
if (PDecl->getIdentifier() == PName) {
Diag(Ploc, diag::err_protocol_has_circular_dependency);
Diag(PrevLoc, diag::note_previous_definition);
}
- CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
+ CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
PDecl->getLocation(), PDecl->getReferencedProtocols());
}
}
@@ -267,16 +272,16 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
return DeclPtrTy::make(PDecl);
}
ObjCList<ObjCProtocolDecl> PList;
- PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
+ PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
CheckForwardProtocolDeclarationForCircularDependency(
ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
PList.Destroy(Context);
-
+
// Make sure the cached decl gets a valid start location.
PDecl->setLocation(AtProtoInterfaceLoc);
PDecl->setForwardDecl(false);
} else {
- PDecl = ObjCProtocolDecl::Create(Context, CurContext,
+ PDecl = ObjCProtocolDecl::Create(Context, CurContext,
AtProtoInterfaceLoc,ProtocolName);
PushOnScopeChains(PDecl, TUScope);
PDecl->setForwardDecl(false);
@@ -288,8 +293,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context);
PDecl->setLocEnd(EndProtoLoc);
}
-
- CheckObjCDeclScope(PDecl);
+
+ CheckObjCDeclScope(PDecl);
return DeclPtrTy::make(PDecl);
}
@@ -308,7 +313,7 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
<< ProtocolId[i].first;
continue;
}
-
+
(void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second);
// If this is a forward declaration and we are supposed to warn in this
@@ -324,12 +329,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
/// attributes and types and warns on a variety of inconsistencies.
///
void
-Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
+Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
ObjCPropertyDecl *SuperProperty,
const IdentifierInfo *inheritedName) {
- ObjCPropertyDecl::PropertyAttributeKind CAttr =
+ ObjCPropertyDecl::PropertyAttributeKind CAttr =
Property->getPropertyAttributes();
- ObjCPropertyDecl::PropertyAttributeKind SAttr =
+ ObjCPropertyDecl::PropertyAttributeKind SAttr =
SuperProperty->getPropertyAttributes();
if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
&& (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
@@ -343,27 +348,27 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
!= (SAttr & ObjCPropertyDecl::OBJC_PR_retain))
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "retain" << inheritedName;
-
+
if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
!= (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic))
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "atomic" << inheritedName;
if (Property->getSetterName() != SuperProperty->getSetterName())
Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "setter" << inheritedName;
+ << Property->getDeclName() << "setter" << inheritedName;
if (Property->getGetterName() != SuperProperty->getGetterName())
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "getter" << inheritedName;
- QualType LHSType =
+ QualType LHSType =
Context.getCanonicalType(SuperProperty->getType());
- QualType RHSType =
+ QualType RHSType =
Context.getCanonicalType(Property->getType());
-
+
if (!Context.typesAreCompatible(LHSType, RHSType)) {
// FIXME: Incorporate this test with typesAreCompatible.
if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType())
- if (ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
+ if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
return;
Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
<< Property->getType() << SuperProperty->getType() << inheritedName;
@@ -387,7 +392,7 @@ void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
E = IDecl->prop_end(); I != E; ++I) {
ObjCPropertyDecl *PDecl = (*I);
if (SuperPDecl->getIdentifier() == PDecl->getIdentifier())
- DiagnosePropertyMismatch(PDecl, SuperPDecl,
+ DiagnosePropertyMismatch(PDecl, SuperPDecl,
SDecl->getIdentifier());
}
}
@@ -450,7 +455,7 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
E = MDecl->protocol_end(); P != E; ++P)
// Merge properties of category (*P) into IDECL's
MergeOneProtocolPropertiesIntoClass(CatDecl, *P);
-
+
// Go thru the list of protocols for this category and recursively merge
// their properties into this class as well.
for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(),
@@ -470,7 +475,7 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
E = MDecl->protocol_end(); P != E; ++P)
// Merge properties of class (*P) into IDECL's
MergeOneProtocolPropertiesIntoClass(IDecl, *P);
-
+
// Go thru the list of protocols for this class and recursively merge
// their properties into this class as well.
for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(),
@@ -487,7 +492,7 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
/// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of
/// a class method in its extension.
///
-void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
+void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
ObjCInterfaceDecl *ID) {
if (!ID)
return; // Possibly due to previous error
@@ -520,12 +525,12 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
unsigned NumElts,
AttributeList *attrList) {
llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols;
-
+
for (unsigned i = 0; i != NumElts; ++i) {
IdentifierInfo *Ident = IdentList[i].first;
ObjCProtocolDecl *PDecl = LookupProtocol(Ident);
if (PDecl == 0) { // Not already seen?
- PDecl = ObjCProtocolDecl::Create(Context, CurContext,
+ PDecl = ObjCProtocolDecl::Create(Context, CurContext,
IdentList[i].second, Ident);
PushOnScopeChains(PDecl, TUScope);
}
@@ -533,8 +538,8 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
ProcessDeclAttributeList(TUScope, PDecl, attrList);
Protocols.push_back(PDecl);
}
-
- ObjCForwardProtocolDecl *PDecl =
+
+ ObjCForwardProtocolDecl *PDecl =
ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc,
&Protocols[0], Protocols.size());
CurContext->addDecl(PDecl);
@@ -550,7 +555,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
SourceLocation EndProtoLoc) {
- ObjCCategoryDecl *CDecl =
+ ObjCCategoryDecl *CDecl =
ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, CategoryName);
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
@@ -564,7 +569,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
}
CDecl->setClassInterface(IDecl);
-
+
// If the interface is deprecated, warn about it.
(void)DiagnoseUseOfDecl(IDecl, ClassLoc);
@@ -583,10 +588,15 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
CDecl->insertNextClassCategory();
if (NumProtoRefs) {
- CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context);
+ CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ Context);
CDecl->setLocEnd(EndProtoLoc);
+ // Protocols in the class extension belong to the class.
+ if (!CDecl->getIdentifier())
+ IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs,
+ NumProtoRefs,Context);
}
-
+
CheckObjCDeclScope(CDecl);
return DeclPtrTy::make(CDecl);
}
@@ -599,7 +609,20 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *CatName, SourceLocation CatLoc) {
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
- ObjCCategoryImplDecl *CDecl =
+ ObjCCategoryDecl *CatIDecl = 0;
+ if (IDecl) {
+ CatIDecl = IDecl->FindCategoryDeclaration(CatName);
+ if (!CatIDecl) {
+ // Category @implementation with no corresponding @interface.
+ // Create and install one.
+ CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(),
+ CatName);
+ CatIDecl->setClassInterface(IDecl);
+ CatIDecl->insertNextClassCategory();
+ }
+ }
+
+ ObjCCategoryImplDecl *CDecl =
ObjCCategoryImplDecl::Create(Context, CurContext, AtCatImplLoc, CatName,
IDecl);
/// Check that class of this category is already completely declared.
@@ -609,10 +632,17 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
- /// TODO: Check that CatName, category name, is not used in another
- // implementation.
- ObjCCategoryImpls.push_back(CDecl);
-
+ /// Check that CatName, category name, is not used in another implementation.
+ if (CatIDecl) {
+ if (CatIDecl->getImplementation()) {
+ Diag(ClassLoc, diag::err_dup_implementation_category) << ClassName
+ << CatName;
+ Diag(CatIDecl->getImplementation()->getLocation(),
+ diag::note_previous_definition);
+ } else
+ CatIDecl->setImplementation(CDecl);
+ }
+
CheckObjCDeclScope(CDecl);
return DeclPtrTy::make(CDecl);
}
@@ -620,34 +650,35 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
SourceLocation AtClassImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
- IdentifierInfo *SuperClassname,
+ IdentifierInfo *SuperClassname,
SourceLocation SuperClassLoc) {
ObjCInterfaceDecl* IDecl = 0;
// Check for another declaration kind with the same name.
- NamedDecl *PrevDecl = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ NamedDecl *PrevDecl
+ = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
} else {
// Is there an interface declaration of this class; if not, warn!
- IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (!IDecl || IDecl->isForwardDecl()) {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
IDecl = 0;
}
}
-
+
// Check that super class name is valid class name
ObjCInterfaceDecl* SDecl = 0;
if (SuperClassname) {
// Check if a different kind of symbol declared in this scope.
- PrevDecl = LookupName(TUScope, SuperClassname, LookupOrdinaryName);
+ PrevDecl = LookupSingleName(TUScope, SuperClassname, LookupOrdinaryName);
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(SuperClassLoc, diag::err_redefinition_different_kind)
<< SuperClassname;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
} else {
- SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (!SDecl)
Diag(SuperClassLoc, diag::err_undef_superclass)
<< SuperClassname << ClassName;
@@ -660,14 +691,14 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
}
}
}
-
+
if (!IDecl) {
// Legacy case of @implementation with no corresponding @interface.
// Build, chain & install the interface decl into the identifier.
// FIXME: Do we support attributes on the @implementation? If so we should
// copy them over.
- IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
+ IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
ClassName, ClassLoc, false, true);
IDecl->setSuperClass(SDecl);
IDecl->setLocEnd(ClassLoc);
@@ -679,20 +710,24 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
// declaration; the user cannot reopen it.
IDecl->setForwardDecl(false);
}
-
- ObjCImplementationDecl* IMPDecl =
- ObjCImplementationDecl::Create(Context, CurContext, AtClassImplLoc,
+
+ ObjCImplementationDecl* IMPDecl =
+ ObjCImplementationDecl::Create(Context, CurContext, AtClassImplLoc,
IDecl, SDecl);
-
+
if (CheckObjCDeclScope(IMPDecl))
return DeclPtrTy::make(IMPDecl);
-
+
// Check that there is no duplicate implementation of this class.
- if (LookupObjCImplementation(ClassName))
+ if (IDecl->getImplementation()) {
// FIXME: Don't leak everything!
Diag(ClassLoc, diag::err_dup_implementation_class) << ClassName;
- else // add it to the list.
+ Diag(IDecl->getImplementation()->getLocation(),
+ diag::note_previous_definition);
+ } else { // add it to the list.
+ IDecl->setImplementation(IMPDecl);
PushOnScopeChains(IMPDecl, TUScope);
+ }
return DeclPtrTy::make(IMPDecl);
}
@@ -714,21 +749,21 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
// If implementation has empty ivar list, just return.
if (numIvars == 0)
return;
-
+
assert(ivars && "missing @implementation ivars");
-
+
// Check interface's Ivar list against those in the implementation.
// names and types must match.
//
unsigned j = 0;
- ObjCInterfaceDecl::ivar_iterator
+ ObjCInterfaceDecl::ivar_iterator
IVI = IDecl->ivar_begin(), IVE = IDecl->ivar_end();
for (; numIvars > 0 && IVI != IVE; ++IVI) {
ObjCIvarDecl* ImplIvar = ivars[j++];
ObjCIvarDecl* ClsIvar = *IVI;
assert (ImplIvar && "missing implementation ivar");
assert (ClsIvar && "missing class ivar");
-
+
// First, make sure the types match.
if (Context.getCanonicalType(ImplIvar->getType()) !=
Context.getCanonicalType(ClsIvar->getType())) {
@@ -745,7 +780,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
<< ImplIvar->getIdentifier();
Diag(ClsBitWidth->getLocStart(), diag::note_previous_definition);
}
- }
+ }
// Make sure the names are identical.
if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) {
Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name)
@@ -754,7 +789,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
}
--numIvars;
}
-
+
if (numIvars > 0)
Diag(ivars[j]->getLocation(), diag::err_inconsistant_ivar_count);
else if (IVI != IVE)
@@ -774,22 +809,23 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
ObjCMethodDecl *IntfMethodDecl) {
if (!Context.typesAreCompatible(IntfMethodDecl->getResultType(),
ImpMethodDecl->getResultType()) &&
- !QualifiedIdConformsQualifiedId(IntfMethodDecl->getResultType(),
- ImpMethodDecl->getResultType())) {
- Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_ret_types)
+ !Context.QualifiedIdConformsQualifiedId(IntfMethodDecl->getResultType(),
+ ImpMethodDecl->getResultType())) {
+ Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_ret_types)
<< ImpMethodDecl->getDeclName() << IntfMethodDecl->getResultType()
<< ImpMethodDecl->getResultType();
Diag(IntfMethodDecl->getLocation(), diag::note_previous_definition);
}
-
+
for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(),
IF = IntfMethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
IM != EM; ++IM, ++IF) {
if (Context.typesAreCompatible((*IF)->getType(), (*IM)->getType()) ||
- QualifiedIdConformsQualifiedId((*IF)->getType(), (*IM)->getType()))
+ Context.QualifiedIdConformsQualifiedId((*IF)->getType(),
+ (*IM)->getType()))
continue;
-
- Diag((*IM)->getLocation(), diag::warn_conflicting_param_types)
+
+ Diag((*IM)->getLocation(), diag::warn_conflicting_param_types)
<< ImpMethodDecl->getDeclName() << (*IF)->getType()
<< (*IM)->getType();
Diag((*IF)->getLocation(), diag::note_previous_definition);
@@ -804,43 +840,41 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
// by far the most common case.
if (!PDecl->isReadOnly())
return false;
- // Even if property is ready only, if interface has a user defined setter,
+ // Even if property is ready only, if interface has a user defined setter,
// it is not considered read only.
if (IDecl->getInstanceMethod(PDecl->getSetterName()))
return false;
-
+
// Main class has the property as 'readonly'. Must search
- // through the category list to see if the property's
+ // through the category list to see if the property's
// attribute has been over-ridden to 'readwrite'.
for (ObjCCategoryDecl *Category = IDecl->getCategoryList();
Category; Category = Category->getNextClassCategory()) {
- // Even if property is ready only, if a category has a user defined setter,
- // it is not considered read only.
+ // Even if property is ready only, if a category has a user defined setter,
+ // it is not considered read only.
if (Category->getInstanceMethod(PDecl->getSetterName()))
return false;
- ObjCPropertyDecl *P =
+ ObjCPropertyDecl *P =
Category->FindPropertyDeclaration(PDecl->getIdentifier());
if (P && !P->isReadOnly())
return false;
}
-
+
// Also, check for definition of a setter method in the implementation if
// all else failed.
if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) {
- if (ObjCImplementationDecl *IMD =
+ if (ObjCImplementationDecl *IMD =
dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) {
if (IMD->getInstanceMethod(PDecl->getSetterName()))
return false;
- }
- else if (ObjCCategoryImplDecl *CIMD =
- dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
+ } else if (ObjCCategoryImplDecl *CIMD =
+ dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
if (CIMD->getInstanceMethod(PDecl->getSetterName()))
return false;
}
}
// Lastly, look through the implementation (if one is in scope).
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(IDecl->getIdentifier()))
+ if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation())
if (ImpDecl->getInstanceMethod(PDecl->getSetterName()))
return false;
// If all fails, look at the super class.
@@ -866,11 +900,11 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
ObjCInterfaceDecl *Super = IDecl->getSuperClass();
ObjCInterfaceDecl *NSIDecl = 0;
if (getLangOptions().NeXTRuntime) {
- // check to see if class implements forwardInvocation method and objects
- // of this class are derived from 'NSProxy' so that to forward requests
+ // check to see if class implements forwardInvocation method and objects
+ // of this class are derived from 'NSProxy' so that to forward requests
// from one object to another.
- // Under such conditions, which means that every method possible is
- // implemented in the class, we should not issue "Method definition not
+ // Under such conditions, which means that every method possible is
+ // implemented in the class, we should not issue "Method definition not
// found" warnings.
// FIXME: Use a general GetUnarySelector method for this.
IdentifierInfo* II = &Context.Idents.get("forwardInvocation");
@@ -880,7 +914,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// need be implemented in the implementation.
NSIDecl = IDecl->lookupInheritedClass(&Context.Idents.get("NSProxy"));
}
-
+
// If a method lookup fails locally we still need to look and see if
// the method was implemented by a base class or an inherited
// protocol. This lookup is slow, but occurs rarely in correct code
@@ -888,24 +922,24 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// check unimplemented instance methods.
if (!NSIDecl)
- for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
+ for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
E = PDecl->instmeth_end(); I != E; ++I) {
ObjCMethodDecl *method = *I;
- if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
+ if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
!method->isSynthesized() && !InsMap.count(method->getSelector()) &&
- (!Super ||
+ (!Super ||
!Super->lookupInstanceMethod(method->getSelector()))) {
// Ugly, but necessary. Method declared in protcol might have
// have been synthesized due to a property declared in the class which
// uses the protocol.
- ObjCMethodDecl *MethodInClass =
+ ObjCMethodDecl *MethodInClass =
IDecl->lookupInstanceMethod(method->getSelector());
if (!MethodInClass || !MethodInClass->isSynthesized())
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl);
}
}
// check unimplemented class methods
- for (ObjCProtocolDecl::classmeth_iterator
+ for (ObjCProtocolDecl::classmeth_iterator
I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
I != E; ++I) {
ObjCMethodDecl *method = *I;
@@ -930,8 +964,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool &IncompleteImpl,
- bool ImmediateClass)
-{
+ bool ImmediateClass) {
// Check and see if instance methods in class interface have been
// implemented in the implementation class. If so, their types match.
for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(),
@@ -939,28 +972,27 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
if (InsMapSeen.count((*I)->getSelector()))
continue;
InsMapSeen.insert((*I)->getSelector());
- if (!(*I)->isSynthesized() &&
+ if (!(*I)->isSynthesized() &&
!InsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
continue;
- }
- else {
- ObjCMethodDecl *ImpMethodDecl =
+ } else {
+ ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getInstanceMethod((*I)->getSelector());
- ObjCMethodDecl *IntfMethodDecl =
+ ObjCMethodDecl *IntfMethodDecl =
CDecl->getInstanceMethod((*I)->getSelector());
- assert(IntfMethodDecl &&
+ assert(IntfMethodDecl &&
"IntfMethodDecl is null in ImplMethodsVsClassMethods");
// ImpMethodDecl may be null as in a @dynamic property.
if (ImpMethodDecl)
WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl);
}
}
-
+
// Check and see if class methods in class interface have been
// implemented in the implementation class. If so, their types match.
- for (ObjCInterfaceDecl::classmeth_iterator
+ for (ObjCInterfaceDecl::classmeth_iterator
I = CDecl->classmeth_begin(), E = CDecl->classmeth_end(); I != E; ++I) {
if (ClsMapSeen.count((*I)->getSelector()))
continue;
@@ -968,11 +1000,10 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
if (!ClsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
- }
- else {
+ } else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getClassMethod((*I)->getSelector());
- ObjCMethodDecl *IntfMethodDecl =
+ ObjCMethodDecl *IntfMethodDecl =
CDecl->getClassMethod((*I)->getSelector());
WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl);
}
@@ -981,26 +1012,26 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
// Check for any implementation of a methods declared in protocol.
for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(),
E = I->protocol_end(); PI != E; ++PI)
- MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl,
(*PI), IncompleteImpl, false);
if (I->getSuperClass())
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
+ IMPDecl,
I->getSuperClass(), IncompleteImpl, false);
}
}
-void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
- ObjCContainerDecl* CDecl,
+void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* CDecl,
bool IncompleteImpl) {
llvm::DenseSet<Selector> InsMap;
// Check and see if instance methods in class interface have been
// implemented in the implementation class.
- for (ObjCImplementationDecl::instmeth_iterator
+ for (ObjCImplementationDecl::instmeth_iterator
I = IMPDecl->instmeth_begin(), E = IMPDecl->instmeth_end(); I!=E; ++I)
InsMap.insert((*I)->getSelector());
-
+
// Check and see if properties declared in the interface have either 1)
// an implementation or 2) there is a @synthesize/@dynamic implementation
// of the property in the @implementation.
@@ -1012,7 +1043,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
continue;
ObjCPropertyImplDecl *PI = 0;
// Is there a matching propery synthesize/dynamic?
- for (ObjCImplDecl::propimpl_iterator
+ for (ObjCImplDecl::propimpl_iterator
I = IMPDecl->propimpl_begin(),
EI = IMPDecl->propimpl_end(); I != EI; ++I)
if ((*I)->getPropertyDecl() == Prop) {
@@ -1022,44 +1053,44 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
if (PI)
continue;
if (!InsMap.count(Prop->getGetterName())) {
- Diag(Prop->getLocation(),
- diag::warn_setter_getter_impl_required)
+ Diag(Prop->getLocation(),
+ diag::warn_setter_getter_impl_required)
<< Prop->getDeclName() << Prop->getGetterName();
Diag(IMPDecl->getLocation(),
diag::note_property_impl_required);
}
-
+
if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
- Diag(Prop->getLocation(),
- diag::warn_setter_getter_impl_required)
+ Diag(Prop->getLocation(),
+ diag::warn_setter_getter_impl_required)
<< Prop->getDeclName() << Prop->getSetterName();
Diag(IMPDecl->getLocation(),
diag::note_property_impl_required);
}
}
-
+
llvm::DenseSet<Selector> ClsMap;
- for (ObjCImplementationDecl::classmeth_iterator
+ for (ObjCImplementationDecl::classmeth_iterator
I = IMPDecl->classmeth_begin(),
E = IMPDecl->classmeth_end(); I != E; ++I)
ClsMap.insert((*I)->getSelector());
-
+
// Check for type conflict of methods declared in a class/protocol and
// its implementation; if any.
llvm::DenseSet<Selector> InsMapSeen, ClsMapSeen;
- MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl, CDecl,
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl, CDecl,
IncompleteImpl, true);
-
+
// Check the protocol list for unimplemented methods in the @implementation
// class.
// Check and see if class methods in class interface have been
// implemented in the implementation class.
-
+
if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(),
E = I->protocol_end(); PI != E; ++PI)
- CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
+ CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
InsMap, ClsMap, I);
// Check class extensions (unnamed categories)
for (ObjCCategoryDecl *Categories = I->getCategoryList();
@@ -1070,24 +1101,29 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
}
}
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
- E = C->protocol_end(); PI != E; ++PI)
- CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
- InsMap, ClsMap, C->getClassInterface());
+ // For extended class, unimplemented methods in its protocols will
+ // be reported in the primary class.
+ if (C->getIdentifier()) {
+ for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
+ E = C->protocol_end(); PI != E; ++PI)
+ CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
+ InsMap, ClsMap, C->getClassInterface());
+ }
} else
assert(false && "invalid ObjCContainerDecl type.");
}
-/// ActOnForwardClassDeclaration -
+/// ActOnForwardClassDeclaration -
Action::DeclPtrTy
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
IdentifierInfo **IdentList,
unsigned NumElts) {
llvm::SmallVector<ObjCInterfaceDecl*, 32> Interfaces;
-
+
for (unsigned i = 0; i != NumElts; ++i) {
// Check for another declaration kind with the same name.
- NamedDecl *PrevDecl = LookupName(TUScope, IdentList[i], LookupOrdinaryName);
+ NamedDecl *PrevDecl
+ = LookupSingleName(TUScope, IdentList[i], LookupOrdinaryName);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl);
@@ -1101,30 +1137,32 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
// typedef NSObject < XCElementTogglerP > XCElementToggler;
// @class XCElementToggler;
//
- // FIXME: Make an extension?
+ // FIXME: Make an extension?
TypedefDecl *TDD = dyn_cast<TypedefDecl>(PrevDecl);
if (!TDD || !isa<ObjCInterfaceType>(TDD->getUnderlyingType())) {
Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i];
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- }
- else if (TDD) {
- // a forward class declaration matching a typedef name of a class
- // refers to the underlying class.
- if (ObjCInterfaceType * OI =
+ } else if (TDD) {
+ // a forward class declaration matching a typedef name of a class refers
+ // to the underlying class.
+ if (ObjCInterfaceType * OI =
dyn_cast<ObjCInterfaceType>(TDD->getUnderlyingType()))
PrevDecl = OI->getDecl();
}
}
- ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (!IDecl) { // Not already seen? Make a forward decl.
- IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
- IdentList[i], SourceLocation(), true);
+ IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
+ IdentList[i],
+ // FIXME: need to get the 'real'
+ // identifier loc from the parser.
+ AtClassLoc, true);
PushOnScopeChains(IDecl, TUScope);
}
Interfaces.push_back(IDecl);
}
-
+
ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc,
&Interfaces[0],
Interfaces.size());
@@ -1137,12 +1175,12 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
/// MatchTwoMethodDeclarations - Checks that two methods have matching type and
/// returns true, or false, accordingly.
/// TODO: Handle protocol list; such as id<p1,p2> in type comparisons
-bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
+bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
const ObjCMethodDecl *PrevMethod,
bool matchBasedOnSizeAndAlignment) {
QualType T1 = Context.getCanonicalType(Method->getResultType());
QualType T2 = Context.getCanonicalType(PrevMethod->getResultType());
-
+
if (T1 != T2) {
// The result types are different.
if (!matchBasedOnSizeAndAlignment)
@@ -1154,11 +1192,11 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
return false;
}
-
+
ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
E = Method->param_end();
ObjCMethodDecl::param_iterator PrevI = PrevMethod->param_begin();
-
+
for (; ParamI != E; ++ParamI, ++PrevI) {
assert(PrevI != PrevMethod->param_end() && "Param mismatch");
T1 = Context.getCanonicalType((*ParamI)->getType());
@@ -1183,7 +1221,7 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
///
/// This routine should only be called once, when neither the instance
/// nor the factory method pool has an entry for this selector.
-Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel,
+Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel,
bool isInstance) {
assert(ExternalSource && "We need an external AST source");
assert(InstanceMethodPool.find(Sel) == InstanceMethodPool.end() &&
@@ -1194,12 +1232,12 @@ Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel,
// Read the method list from the external source.
std::pair<ObjCMethodList, ObjCMethodList> Methods
= ExternalSource->ReadMethodPool(Sel);
-
+
if (isInstance) {
if (Methods.second.Method)
FactoryMethodPool[Sel] = Methods.second;
return InstanceMethodPool.insert(std::make_pair(Sel, Methods.first)).first;
- }
+ }
if (Methods.first.Method)
InstanceMethodPool[Sel] = Methods.first;
@@ -1225,21 +1263,22 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
Entry.Next = 0;
return;
}
-
+
// We've seen a method with this name, see if we have already seen this type
// signature.
for (ObjCMethodList *List = &Entry; List; List = List->Next)
if (MatchTwoMethodDeclarations(Method, List->Method))
return;
-
+
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
Entry.Next = new ObjCMethodList(Method, Entry.Next);
}
// FIXME: Finish implementing -Wno-strict-selector-match.
-ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel,
- SourceRange R) {
+ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel,
+ SourceRange R,
+ bool warn) {
llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
= InstanceMethodPool.find(Sel);
if (Pos == InstanceMethodPool.end()) {
@@ -1251,12 +1290,12 @@ ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel,
ObjCMethodList &MethList = Pos->second;
bool issueWarning = false;
-
+
if (MethList.Method && MethList.Next) {
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
// This checks if the methods differ by size & alignment.
if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
- issueWarning = true;
+ issueWarning = warn;
}
if (issueWarning && (MethList.Method && MethList.Next)) {
Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
@@ -1288,11 +1327,11 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
} else {
// We've seen a method with this name, now check the type signature(s).
bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method);
-
- for (ObjCMethodList *Next = FirstMethod.Next; !match && Next;
+
+ for (ObjCMethodList *Next = FirstMethod.Next; !match && Next;
Next = Next->Next)
match = MatchTwoMethodDeclarations(Method, Next->Method);
-
+
if (!match) {
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
@@ -1302,12 +1341,12 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
}
}
-ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
+ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
SourceRange R) {
llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
= FactoryMethodPool.find(Sel);
if (Pos == FactoryMethodPool.end()) {
- if (ExternalSource && !InstanceMethodPool.count(Sel))
+ if (ExternalSource && !InstanceMethodPool.count(Sel))
Pos = ReadMethodPool(Sel, /*isInstance=*/false);
else
return 0;
@@ -1315,7 +1354,7 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
ObjCMethodList &MethList = Pos->second;
bool issueWarning = false;
-
+
if (MethList.Method && MethList.Next) {
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
// This checks if the methods differ by size & alignment.
@@ -1333,28 +1372,28 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
return MethList.Method;
}
-/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
+/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
/// have the property type and issue diagnostics if they don't.
/// Also synthesize a getter/setter method if none exist (and update the
/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized
/// methods is the "right" thing to do.
-void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
+void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ObjCContainerDecl *CD) {
ObjCMethodDecl *GetterMethod, *SetterMethod;
-
- GetterMethod = CD->getInstanceMethod(property->getGetterName());
+
+ GetterMethod = CD->getInstanceMethod(property->getGetterName());
SetterMethod = CD->getInstanceMethod(property->getSetterName());
- DiagnosePropertyAccessorMismatch(property, GetterMethod,
+ DiagnosePropertyAccessorMismatch(property, GetterMethod,
property->getLocation());
-
+
if (SetterMethod) {
- if (Context.getCanonicalType(SetterMethod->getResultType())
+ if (Context.getCanonicalType(SetterMethod->getResultType())
!= Context.VoidTy)
Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
if (SetterMethod->param_size() != 1 ||
((*SetterMethod->param_begin())->getType() != property->getType())) {
- Diag(property->getLocation(),
- diag::warn_accessor_property_type_mismatch)
+ Diag(property->getLocation(),
+ diag::warn_accessor_property_type_mismatch)
<< property->getDeclName()
<< SetterMethod->getSelector();
Diag(SetterMethod->getLocation(), diag::note_declared_at);
@@ -1369,14 +1408,14 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// declarations jive in that situation (which it is not currently).
if (!GetterMethod) {
// No instance method of same name as property getter name was found.
- // Declare a getter method and add it to the list of methods
+ // Declare a getter method and add it to the list of methods
// for this class.
- GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
- property->getLocation(), property->getGetterName(),
- property->getType(), CD, true, false, true,
- (property->getPropertyImplementation() ==
- ObjCPropertyDecl::Optional) ?
- ObjCMethodDecl::Optional :
+ GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
+ property->getLocation(), property->getGetterName(),
+ property->getType(), CD, true, false, true,
+ (property->getPropertyImplementation() ==
+ ObjCPropertyDecl::Optional) ?
+ ObjCMethodDecl::Optional :
ObjCMethodDecl::Required);
CD->addDecl(GetterMethod);
} else
@@ -1390,22 +1429,23 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// Find the default setter and if one not found, add one.
if (!SetterMethod) {
// No instance method of same name as property setter name was found.
- // Declare a setter method and add it to the list of methods
+ // Declare a setter method and add it to the list of methods
// for this class.
- SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
- property->getLocation(),
- property->getSetterName(),
+ SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
+ property->getLocation(),
+ property->getSetterName(),
Context.VoidTy, CD, true, false, true,
- (property->getPropertyImplementation() ==
- ObjCPropertyDecl::Optional) ?
- ObjCMethodDecl::Optional :
+ (property->getPropertyImplementation() ==
+ ObjCPropertyDecl::Optional) ?
+ ObjCMethodDecl::Optional :
ObjCMethodDecl::Required);
// Invent the arguments for the setter. We don't bother making a
// nice name for the argument.
ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
- property->getLocation(),
+ property->getLocation(),
property->getIdentifier(),
property->getType(),
+ /*DInfo=*/0,
VarDecl::None,
0);
SetterMethod->setMethodParams(Context, &Argument, 1);
@@ -1416,7 +1456,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
SetterMethod->setSynthesized(true);
property->setSetterMethodDecl(SetterMethod);
}
- // Add any synthesized methods to the global pool. This allows us to
+ // Add any synthesized methods to the global pool. This allows us to
// handle the following, which is supported by GCC (and part of the design).
//
// @interface Foo
@@ -1429,9 +1469,46 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// }
//
if (GetterMethod)
- AddInstanceMethodToGlobalPool(GetterMethod);
+ AddInstanceMethodToGlobalPool(GetterMethod);
if (SetterMethod)
- AddInstanceMethodToGlobalPool(SetterMethod);
+ AddInstanceMethodToGlobalPool(SetterMethod);
+}
+
+/// CompareMethodParamsInBaseAndSuper - This routine compares methods with
+/// identical selector names in current and its super classes and issues
+/// a warning if any of their argument types are incompatible.
+void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl,
+ ObjCMethodDecl *Method,
+ bool IsInstance) {
+ ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
+ if (ID == 0) return;
+
+ while (ObjCInterfaceDecl *SD = ID->getSuperClass()) {
+ ObjCMethodDecl *SuperMethodDecl =
+ SD->lookupMethod(Method->getSelector(), IsInstance);
+ if (SuperMethodDecl == 0) {
+ ID = SD;
+ continue;
+ }
+ ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
+ E = Method->param_end();
+ ObjCMethodDecl::param_iterator PrevI = SuperMethodDecl->param_begin();
+ for (; ParamI != E; ++ParamI, ++PrevI) {
+ // Number of parameters are the same and is guaranteed by selector match.
+ assert(PrevI != SuperMethodDecl->param_end() && "Param mismatch");
+ QualType T1 = Context.getCanonicalType((*ParamI)->getType());
+ QualType T2 = Context.getCanonicalType((*PrevI)->getType());
+ // If type of arguement of method in this class does not match its
+ // respective argument type in the super class method, issue warning;
+ if (!Context.typesAreCompatible(T1, T2)) {
+ Diag((*ParamI)->getLocation(), diag::ext_typecheck_base_super)
+ << T1 << T2;
+ Diag(SuperMethodDecl->getLocation(), diag::note_previous_declaration);
+ return;
+ }
+ }
+ ID = SD;
+ }
}
// Note: For class/category implemenations, allMethods/allProperties is
@@ -1447,8 +1524,8 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
// should be true.
if (!ClassDecl)
return;
-
- bool isInterfaceDeclKind =
+
+ bool isInterfaceDeclKind =
isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl)
|| isa<ObjCProtocolDecl>(ClassDecl);
bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
@@ -1467,9 +1544,9 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
if (Method->isInstanceMethod()) {
/// Check for instance method of the same name with incompatible types
const ObjCMethodDecl *&PrevMethod = InsMap[Method->getSelector()];
- bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
+ bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
: false;
- if ((isInterfaceDeclKind && PrevMethod && !match)
+ if ((isInterfaceDeclKind && PrevMethod && !match)
|| (checkIdenticalMethods && match)) {
Diag(Method->getLocation(), diag::err_duplicate_method_decl)
<< Method->getDeclName();
@@ -1479,14 +1556,16 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
InsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "id".
AddInstanceMethodToGlobalPool(Method);
+ // verify that the instance method conforms to the same definition of
+ // parent methods if it shadows one.
+ CompareMethodParamsInBaseAndSuper(ClassDecl, Method, true);
}
- }
- else {
+ } else {
/// Check for class method of the same name with incompatible types
const ObjCMethodDecl *&PrevMethod = ClsMap[Method->getSelector()];
- bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
+ bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
: false;
- if ((isInterfaceDeclKind && PrevMethod && !match)
+ if ((isInterfaceDeclKind && PrevMethod && !match)
|| (checkIdenticalMethods && match)) {
Diag(Method->getLocation(), diag::err_duplicate_method_decl)
<< Method->getDeclName();
@@ -1496,17 +1575,20 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
ClsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "Class".
AddFactoryMethodToGlobalPool(Method);
+ // verify that the class method conforms to the same definition of
+ // parent methods if it shadows one.
+ CompareMethodParamsInBaseAndSuper(ClassDecl, Method, false);
}
}
}
if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
- // Compares properties declared in this class to those of its
+ // Compares properties declared in this class to those of its
// super class.
ComparePropertiesInBaseAndSuper(I);
MergeProtocolPropertiesIntoClass(I, DeclPtrTy::make(I));
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
// Categories are used to extend the class by declaring new methods.
- // By the same token, they are also used to add new properties. No
+ // By the same token, they are also used to add new properties. No
// need to compare the added property to those in the class.
// Merge protocol properties into category
@@ -1525,13 +1607,13 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
CDecl->setAtEndLoc(AtEndLoc);
}
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
- IC->setLocEnd(AtEndLoc);
+ IC->setAtEndLoc(AtEndLoc);
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
ImplMethodsVsClassMethods(IC, IDecl);
- } else if (ObjCCategoryImplDecl* CatImplClass =
+ } else if (ObjCCategoryImplDecl* CatImplClass =
dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
- CatImplClass->setLocEnd(AtEndLoc);
-
+ CatImplClass->setAtEndLoc(AtEndLoc);
+
// Find category interface decl and then check that all methods declared
// in this interface are implemented in the category @implementation.
if (ObjCInterfaceDecl* IDecl = CatImplClass->getClassInterface()) {
@@ -1560,7 +1642,7 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
/// CvtQTToAstBitMask - utility routine to produce an AST bitmask for
/// objective-c's type qualifier from the parser version of the same info.
-static Decl::ObjCDeclQualifier
+static Decl::ObjCDeclQualifier
CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) {
Decl::ObjCDeclQualifier ret = Decl::OBJC_TQ_None;
if (PQTVal & ObjCDeclSpec::DQ_In)
@@ -1595,13 +1677,14 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
// Make sure we can establish a context for the method.
if (!ClassDecl) {
Diag(MethodLoc, diag::error_missing_method_context);
+ FunctionLabelMap.clear();
return DeclPtrTy();
}
QualType resultDeclType;
-
+
if (ReturnType) {
- resultDeclType = QualType::getFromOpaquePtr(ReturnType);
-
+ resultDeclType = GetTypeFromParser(ReturnType);
+
// Methods cannot return interface types. All ObjC objects are
// passed by reference.
if (resultDeclType->isObjCInterfaceType()) {
@@ -1611,54 +1694,56 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
}
} else // get the type for "id".
resultDeclType = Context.getObjCIdType();
-
- ObjCMethodDecl* ObjCMethod =
+
+ ObjCMethodDecl* ObjCMethod =
ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, resultDeclType,
- cast<DeclContext>(ClassDecl),
+ cast<DeclContext>(ClassDecl),
MethodType == tok::minus, isVariadic,
false,
- MethodDeclKind == tok::objc_optional ?
- ObjCMethodDecl::Optional :
+ MethodDeclKind == tok::objc_optional ?
+ ObjCMethodDecl::Optional :
ObjCMethodDecl::Required);
-
+
llvm::SmallVector<ParmVarDecl*, 16> Params;
-
+
for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) {
QualType ArgType, UnpromotedArgType;
-
+
if (ArgInfo[i].Type == 0) {
UnpromotedArgType = ArgType = Context.getObjCIdType();
} else {
- UnpromotedArgType = ArgType = QualType::getFromOpaquePtr(ArgInfo[i].Type);
+ UnpromotedArgType = ArgType = GetTypeFromParser(ArgInfo[i].Type);
// Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
ArgType = adjustParameterType(ArgType);
}
-
+
ParmVarDecl* Param;
if (ArgType == UnpromotedArgType)
Param = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc,
ArgInfo[i].Name, ArgType,
+ /*DInfo=*/0, //FIXME: Pass info here.
VarDecl::None, 0);
else
Param = OriginalParmVarDecl::Create(Context, ObjCMethod,
ArgInfo[i].NameLoc,
ArgInfo[i].Name, ArgType,
+ /*DInfo=*/0, //FIXME: Pass info here.
UnpromotedArgType,
VarDecl::None, 0);
-
+
if (ArgType->isObjCInterfaceType()) {
Diag(ArgInfo[i].NameLoc,
diag::err_object_cannot_be_passed_returned_by_value)
<< 1 << ArgType;
Param->setInvalidDecl();
}
-
+
Param->setObjCDeclQualifier(
CvtQTToAstBitMask(ArgInfo[i].DeclSpec.getObjCDeclQualifier()));
-
+
// Apply the attributes to the parameter.
ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
-
+
Params.push_back(Param);
}
@@ -1669,12 +1754,12 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
if (AttrList)
ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
-
- // For implementations (which can be very "coarse grain"), we add the
- // method now. This allows the AST to implement lookup methods that work
- // incrementally (without waiting until we parse the @end). It also allows
+
+ // For implementations (which can be very "coarse grain"), we add the
+ // method now. This allows the AST to implement lookup methods that work
+ // incrementally (without waiting until we parse the @end). It also allows
// us to flag multiple declaration errors as they occur.
- if (ObjCImplementationDecl *ImpDecl =
+ if (ObjCImplementationDecl *ImpDecl =
dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
if (MethodType == tok::minus) {
PrevMethod = ImpDecl->getInstanceMethod(Sel);
@@ -1685,9 +1770,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
}
if (AttrList)
Diag(EndLoc, diag::warn_attribute_method_def);
- }
- else if (ObjCCategoryImplDecl *CatImpDecl =
- dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
+ } else if (ObjCCategoryImplDecl *CatImpDecl =
+ dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
if (MethodType == tok::minus) {
PrevMethod = CatImpDecl->getInstanceMethod(Sel);
CatImpDecl->addInstanceMethod(ObjCMethod);
@@ -1703,11 +1787,11 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl)
<< ObjCMethod->getDeclName();
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
- }
+ }
return DeclPtrTy::make(ObjCMethod);
}
-void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
+void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
SourceLocation Loc,
unsigned &Attributes) {
// FIXME: Improve the reported location.
@@ -1724,8 +1808,8 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
"assign" :
(Attributes & ObjCDeclSpec::DQ_PR_copy) ?
"copy" : "retain";
-
- Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ?
+
+ Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ?
diag::err_objc_property_attr_mutually_exclusive :
diag::warn_objc_property_attr_mutually_exclusive)
<< "readonly" << which;
@@ -1733,7 +1817,9 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
// Check for copy or retain on non-object types.
if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
- !Context.isObjCObjectPointerType(PropertyTy)) {
+ !PropertyTy->isObjCObjectPointerType() &&
+ !PropertyTy->isBlockPointerType() &&
+ !Context.isObjCNSObjectType(PropertyTy)) {
Diag(Loc, diag::err_objc_property_requires_object)
<< (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
@@ -1745,7 +1831,7 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "assign" << "copy";
Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
- }
+ }
if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "assign" << "retain";
@@ -1764,15 +1850,15 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
ObjCDeclSpec::DQ_PR_retain)) &&
!(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- Context.isObjCObjectPointerType(PropertyTy)) {
+ PropertyTy->isObjCObjectPointerType()) {
// Skip this warning in gc-only mode.
- if (getLangOptions().getGCMode() != LangOptions::GCOnly)
+ if (getLangOptions().getGCMode() != LangOptions::GCOnly)
Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
// If non-gc code warn that this is likely inappropriate.
if (getLangOptions().getGCMode() == LangOptions::NonGC)
Diag(Loc, diag::warn_objc_property_default_assign_on_object);
-
+
// FIXME: Implement warning dependent on NSCopying being
// implemented. See also:
// <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496>
@@ -1785,7 +1871,7 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
}
-Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
+Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
FieldDeclarator &FD,
ObjCDeclSpec &ODS,
Selector GetterSel,
@@ -1797,11 +1883,11 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
// default is readwrite!
!(Attributes & ObjCDeclSpec::DQ_PR_readonly));
- // property is defaulted to 'assign' if it is readwrite and is
+ // property is defaulted to 'assign' if it is readwrite and is
// not retain or copy
bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) ||
- (isReadWrite &&
- !(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
+ (isReadWrite &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
!(Attributes & ObjCDeclSpec::DQ_PR_copy)));
QualType T = GetTypeForDeclarator(FD.D, S);
Decl *ClassDecl = ClassCategory.getAs<Decl>();
@@ -1810,20 +1896,20 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
CheckObjCPropertyAttributes(T, AtLoc, Attributes);
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
if (!CDecl->getIdentifier()) {
- // This is a continuation class. property requires special
+ // This is a continuation class. property requires special
// handling.
if ((CCPrimary = CDecl->getClassInterface())) {
// Find the property in continuation class's primary class only.
ObjCPropertyDecl *PIDecl = 0;
IdentifierInfo *PropertyId = FD.D.getIdentifier();
- for (ObjCInterfaceDecl::prop_iterator
+ for (ObjCInterfaceDecl::prop_iterator
I = CCPrimary->prop_begin(), E = CCPrimary->prop_end();
I != E; ++I)
if ((*I)->getIdentifier() == PropertyId) {
PIDecl = *I;
break;
}
-
+
if (PIDecl) {
// property 'PIDecl's readonly attribute will be over-ridden
// with continuation class's readwrite property attribute!
@@ -1838,12 +1924,11 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
if (Attributes & ObjCDeclSpec::DQ_PR_copy)
PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
PIDecl->setSetterName(SetterSel);
- }
- else
- Diag(AtLoc, diag::err_use_continuation_class)
+ } else
+ Diag(AtLoc, diag::err_use_continuation_class)
<< CCPrimary->getDeclName();
*isOverridingProperty = true;
- // Make sure setter decl is synthesized, and added to primary
+ // Make sure setter decl is synthesized, and added to primary
// class's list.
ProcessPropertyDecl(PIDecl, CCPrimary);
return DeclPtrTy();
@@ -1855,52 +1940,72 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
Diag(CDecl->getLocation(), diag::err_continuation_class);
*isOverridingProperty = true;
return DeclPtrTy();
- }
+ }
}
+ // Issue a warning if property is 'assign' as default and its object, which is
+ // gc'able conforms to NSCopying protocol
+ if (getLangOptions().getGCMode() != LangOptions::NonGC &&
+ isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
+ if (T->isObjCObjectPointerType()) {
+ QualType InterfaceTy = T->getPointeeType();
+ if (const ObjCInterfaceType *OIT =
+ InterfaceTy->getAs<ObjCInterfaceType>()) {
+ ObjCInterfaceDecl *IDecl = OIT->getDecl();
+ if (IDecl)
+ if (ObjCProtocolDecl* PNSCopying =
+ LookupProtocol(&Context.Idents.get("NSCopying")))
+ if (IDecl->ClassImplementsProtocol(PNSCopying, true))
+ Diag(AtLoc, diag::warn_implements_nscopying)
+ << FD.D.getIdentifier();
+ }
+ }
+ if (T->isObjCInterfaceType())
+ Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object);
+
DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
assert(DC && "ClassDecl is not a DeclContext");
ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
- FD.D.getIdentifierLoc(),
+ FD.D.getIdentifierLoc(),
FD.D.getIdentifier(), T);
DC->addDecl(PDecl);
-
+
if (T->isArrayType() || T->isFunctionType()) {
Diag(AtLoc, diag::err_property_type) << T;
PDecl->setInvalidDecl();
}
-
+
ProcessDeclAttributes(S, PDecl, FD.D);
// Regardless of setter/getter attribute, we save the default getter/setter
// selector names in anticipation of declaration of setter/getter methods.
PDecl->setGetterName(GetterSel);
PDecl->setSetterName(SetterSel);
-
+
if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
-
+
if (Attributes & ObjCDeclSpec::DQ_PR_getter)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
-
+
if (Attributes & ObjCDeclSpec::DQ_PR_setter)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
-
+
if (isReadWrite)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
-
+
if (Attributes & ObjCDeclSpec::DQ_PR_retain)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
-
+
if (Attributes & ObjCDeclSpec::DQ_PR_copy)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
-
+
if (isAssign)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
-
+
if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
-
+
if (MethodImplKind == tok::objc_required)
PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
else if (MethodImplKind == tok::objc_optional)
@@ -1910,7 +2015,7 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
// Make sure setter/getters are declared here.
if (CCPrimary)
ProcessPropertyDecl(PDecl, CCPrimary);
-
+
return DeclPtrTy::make(PDecl);
}
@@ -1918,9 +2023,9 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
/// builds the AST node for a property implementation declaration; declared
/// as @synthesize or @dynamic.
///
-Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
+Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
SourceLocation PropertyLoc,
- bool Synthesize,
+ bool Synthesize,
DeclPtrTy ClassCatImpDecl,
IdentifierInfo *PropertyId,
IdentifierInfo *PropertyIvar) {
@@ -1940,29 +2045,28 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
IDecl = IC->getClassInterface();
// We always synthesize an interface for an implementation
// without an interface decl. So, IDecl is always non-zero.
- assert(IDecl &&
+ assert(IDecl &&
"ActOnPropertyImplDecl - @implementation without @interface");
-
+
// Look for this property declaration in the @implementation's @interface
property = IDecl->FindPropertyDeclaration(PropertyId);
if (!property) {
Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
return DeclPtrTy();
}
- }
- else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
+ } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
if (Synthesize) {
Diag(AtLoc, diag::error_synthesize_category_decl);
return DeclPtrTy();
- }
+ }
IDecl = CatImplClass->getClassInterface();
if (!IDecl) {
Diag(AtLoc, diag::error_missing_property_interface);
return DeclPtrTy();
}
- ObjCCategoryDecl *Category =
+ ObjCCategoryDecl *Category =
IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
-
+
// If category for this implementation not found, it is an error which
// has already been reported eralier.
if (!Category)
@@ -1990,10 +2094,10 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
if (!Ivar) {
DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl);
- assert(EnclosingContext &&
+ assert(EnclosingContext &&
"null DeclContext for synthesized ivar - ActOnPropertyImplDecl");
- Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc,
- PropertyIvar, PropType,
+ Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc,
+ PropertyIvar, PropType, /*Dinfo=*/0,
ObjCIvarDecl::Public,
(Expr *)0);
Ivar->setLexicalDeclContext(IDecl);
@@ -2001,35 +2105,34 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
property->setPropertyIvarDecl(Ivar);
if (!getLangOptions().ObjCNonFragileABI)
Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId;
- // Note! I deliberately want it to fall thru so, we have a
+ // Note! I deliberately want it to fall thru so, we have a
// a property implementation and to avoid future warnings.
- }
- else if (getLangOptions().ObjCNonFragileABI &&
- ClassDeclared != IDecl) {
+ } else if (getLangOptions().ObjCNonFragileABI &&
+ ClassDeclared != IDecl) {
Diag(PropertyLoc, diag::error_ivar_in_superclass_use)
- << property->getDeclName() << Ivar->getDeclName()
+ << property->getDeclName() << Ivar->getDeclName()
<< ClassDeclared->getDeclName();
Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
<< Ivar << Ivar->getNameAsCString();
// Note! I deliberately want it to fall thru so more errors are caught.
}
QualType IvarType = Context.getCanonicalType(Ivar->getType());
-
+
// Check that type of property and its ivar are type compatible.
if (PropType != IvarType) {
if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
Diag(PropertyLoc, diag::error_property_ivar_type)
<< property->getDeclName() << Ivar->getDeclName();
- // Note! I deliberately want it to fall thru so, we have a
+ // Note! I deliberately want it to fall thru so, we have a
// a property implementation and to avoid future warnings.
}
-
+
// FIXME! Rules for properties are somewhat different that those
// for assignments. Use a new routine to consolidate all cases;
// specifically for property redeclarations as well as for ivars.
QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType();
QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
- if (lhsType != rhsType &&
+ if (lhsType != rhsType &&
lhsType->isArithmeticType()) {
Diag(PropertyLoc, diag::error_property_ivar_type)
<< property->getDeclName() << Ivar->getDeclName();
@@ -2042,78 +2145,77 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
<< property->getDeclName() << Ivar->getDeclName();
// Fall thru - see previous comment
}
- if ((Context.isObjCObjectPointerType(property->getType()) ||
+ if ((property->getType()->isObjCObjectPointerType() ||
PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
getLangOptions().getGCMode() != LangOptions::NonGC) {
Diag(PropertyLoc, diag::error_strong_property)
<< property->getDeclName() << Ivar->getDeclName();
- // Fall thru - see previous comment
+ // Fall thru - see previous comment
}
}
} else if (PropertyIvar)
// @dynamic
Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
assert (property && "ActOnPropertyImplDecl - property declaration missing");
- ObjCPropertyImplDecl *PIDecl =
- ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
- property,
- (Synthesize ?
- ObjCPropertyImplDecl::Synthesize
+ ObjCPropertyImplDecl *PIDecl =
+ ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
+ property,
+ (Synthesize ?
+ ObjCPropertyImplDecl::Synthesize
: ObjCPropertyImplDecl::Dynamic),
Ivar);
if (IC) {
if (Synthesize)
- if (ObjCPropertyImplDecl *PPIDecl =
+ if (ObjCPropertyImplDecl *PPIDecl =
IC->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyLoc, diag::error_duplicate_ivar_use)
- << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
<< PropertyIvar;
Diag(PPIDecl->getLocation(), diag::note_previous_use);
}
-
- if (ObjCPropertyImplDecl *PPIDecl
+
+ if (ObjCPropertyImplDecl *PPIDecl
= IC->FindPropertyImplDecl(PropertyId)) {
Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
return DeclPtrTy();
}
IC->addPropertyImplementation(PIDecl);
- }
- else {
+ } else {
if (Synthesize)
- if (ObjCPropertyImplDecl *PPIDecl =
+ if (ObjCPropertyImplDecl *PPIDecl =
CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyLoc, diag::error_duplicate_ivar_use)
- << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
<< PropertyIvar;
Diag(PPIDecl->getLocation(), diag::note_previous_use);
}
-
- if (ObjCPropertyImplDecl *PPIDecl =
+
+ if (ObjCPropertyImplDecl *PPIDecl =
CatImplClass->FindPropertyImplDecl(PropertyId)) {
Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
return DeclPtrTy();
- }
+ }
CatImplClass->addPropertyImplementation(PIDecl);
}
-
+
return DeclPtrTy::make(PIDecl);
}
bool Sema::CheckObjCDeclScope(Decl *D) {
if (isa<TranslationUnitDecl>(CurContext->getLookupContext()))
return false;
-
+
Diag(D->getLocation(), diag::err_objc_decls_may_only_appear_in_global_scope);
D->setInvalidDecl();
-
+
return true;
}
/// Called whenever @defs(ClassName) is encountered in the source. Inserts the
/// instance variables of ClassName into Decls.
-void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
+void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
IdentifierInfo *ClassName,
llvm::SmallVectorImpl<DeclPtrTy> &Decls) {
// Check that ClassName is a valid class
@@ -2126,7 +2228,7 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
Diag(DeclStart, diag::err_atdef_nonfragile_interface);
return;
}
-
+
// Collect the instance variables
llvm::SmallVector<FieldDecl*, 32> RecFields;
Context.CollectObjCIvars(Class, RecFields);
@@ -2139,7 +2241,7 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
ID->getBitWidth());
Decls.push_back(Sema::DeclPtrTy::make(FD));
}
-
+
// Introduce all of these fields into the appropriate scope.
for (llvm::SmallVectorImpl<DeclPtrTy>::iterator D = Decls.begin();
D != Decls.end(); ++D) {
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
new file mode 100644
index 0000000000000..bdd00b84049d3
--- /dev/null
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -0,0 +1,320 @@
+//===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides Sema routines for C++ exception specification testing.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+namespace clang {
+
+static const FunctionProtoType *GetUnderlyingFunction(QualType T)
+{
+ if (const PointerType *PtrTy = T->getAs<PointerType>())
+ T = PtrTy->getPointeeType();
+ else if (const ReferenceType *RefTy = T->getAs<ReferenceType>())
+ T = RefTy->getPointeeType();
+ else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
+ T = MPTy->getPointeeType();
+ return T->getAs<FunctionProtoType>();
+}
+
+/// CheckSpecifiedExceptionType - Check if the given type is valid in an
+/// exception specification. Incomplete types, or pointers to incomplete types
+/// other than void are not allowed.
+bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
+ // FIXME: This may not correctly work with the fix for core issue 437,
+ // where a class's own type is considered complete within its body. But
+ // perhaps RequireCompleteType itself should contain this logic?
+
+ // C++ 15.4p2: A type denoted in an exception-specification shall not denote
+ // an incomplete type.
+ if (RequireCompleteType(Range.getBegin(), T,
+ PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/0 << Range))
+ return true;
+
+ // C++ 15.4p2: A type denoted in an exception-specification shall not denote
+ // an incomplete type a pointer or reference to an incomplete type, other
+ // than (cv) void*.
+ int kind;
+ if (const PointerType* IT = T->getAs<PointerType>()) {
+ T = IT->getPointeeType();
+ kind = 1;
+ } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) {
+ T = IT->getPointeeType();
+ kind = 2;
+ } else
+ return false;
+
+ if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T,
+ PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/kind << Range))
+ return true;
+
+ return false;
+}
+
+/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
+/// to member to a function with an exception specification. This means that
+/// it is invalid to add another level of indirection.
+bool Sema::CheckDistantExceptionSpec(QualType T) {
+ if (const PointerType *PT = T->getAs<PointerType>())
+ T = PT->getPointeeType();
+ else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
+ T = PT->getPointeeType();
+ else
+ return false;
+
+ const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
+ if (!FnT)
+ return false;
+
+ return FnT->hasExceptionSpec();
+}
+
+/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
+/// exception specifications. Exception specifications are equivalent if
+/// they allow exactly the same set of exception types. It does not matter how
+/// that is achieved. See C++ [except.spec]p2.
+bool Sema::CheckEquivalentExceptionSpec(
+ const FunctionProtoType *Old, SourceLocation OldLoc,
+ const FunctionProtoType *New, SourceLocation NewLoc) {
+ return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
+ diag::note_previous_declaration,
+ Old, OldLoc, New, NewLoc);
+}
+
+/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
+/// exception specifications. Exception specifications are equivalent if
+/// they allow exactly the same set of exception types. It does not matter how
+/// that is achieved. See C++ [except.spec]p2.
+bool Sema::CheckEquivalentExceptionSpec(
+ const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Old, SourceLocation OldLoc,
+ const FunctionProtoType *New, SourceLocation NewLoc) {
+ bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
+ bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
+ if (OldAny && NewAny)
+ return false;
+ if (OldAny || NewAny) {
+ Diag(NewLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(OldLoc, NoteID);
+ return true;
+ }
+
+ bool Success = true;
+ // Both have a definite exception spec. Collect the first set, then compare
+ // to the second.
+ llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
+ for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
+ E = Old->exception_end(); I != E; ++I)
+ OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType());
+
+ for (FunctionProtoType::exception_iterator I = New->exception_begin(),
+ E = New->exception_end(); I != E && Success; ++I) {
+ CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType();
+ if(OldTypes.count(TypePtr))
+ NewTypes.insert(TypePtr);
+ else
+ Success = false;
+ }
+
+ Success = Success && OldTypes.size() == NewTypes.size();
+
+ if (Success) {
+ return false;
+ }
+ Diag(NewLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(OldLoc, NoteID);
+ return true;
+}
+
+/// CheckExceptionSpecSubset - Check whether the second function type's
+/// exception specification is a subset (or equivalent) of the first function
+/// type. This is used by override and pointer assignment checks.
+bool Sema::CheckExceptionSpecSubset(
+ const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Superset, SourceLocation SuperLoc,
+ const FunctionProtoType *Subset, SourceLocation SubLoc) {
+ // FIXME: As usual, we could be more specific in our error messages, but
+ // that better waits until we've got types with source locations.
+
+ if (!SubLoc.isValid())
+ SubLoc = SuperLoc;
+
+ // If superset contains everything, we're done.
+ if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec())
+ return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+
+ // It does not. If the subset contains everything, we've failed.
+ if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) {
+ Diag(SubLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(SuperLoc, NoteID);
+ return true;
+ }
+
+ // Neither contains everything. Do a proper comparison.
+ for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
+ SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
+ // Take one type from the subset.
+ QualType CanonicalSubT = Context.getCanonicalType(*SubI);
+ // Unwrap pointers and references so that we can do checks within a class
+ // hierarchy. Don't unwrap member pointers; they don't have hierarchy
+ // conversions on the pointee.
+ bool SubIsPointer = false;
+ if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
+ CanonicalSubT = RefTy->getPointeeType();
+ if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
+ CanonicalSubT = PtrTy->getPointeeType();
+ SubIsPointer = true;
+ }
+ bool SubIsClass = CanonicalSubT->isRecordType();
+ CanonicalSubT = CanonicalSubT.getUnqualifiedType();
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+
+ bool Contained = false;
+ // Make sure it's in the superset.
+ for (FunctionProtoType::exception_iterator SuperI =
+ Superset->exception_begin(), SuperE = Superset->exception_end();
+ SuperI != SuperE; ++SuperI) {
+ QualType CanonicalSuperT = Context.getCanonicalType(*SuperI);
+ // SubT must be SuperT or derived from it, or pointer or reference to
+ // such types.
+ if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
+ CanonicalSuperT = RefTy->getPointeeType();
+ if (SubIsPointer) {
+ if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
+ CanonicalSuperT = PtrTy->getPointeeType();
+ else {
+ continue;
+ }
+ }
+ CanonicalSuperT = CanonicalSuperT.getUnqualifiedType();
+ // If the types are the same, move on to the next type in the subset.
+ if (CanonicalSubT == CanonicalSuperT) {
+ Contained = true;
+ break;
+ }
+
+ // Otherwise we need to check the inheritance.
+ if (!SubIsClass || !CanonicalSuperT->isRecordType())
+ continue;
+
+ Paths.clear();
+ if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
+ continue;
+
+ if (Paths.isAmbiguous(CanonicalSuperT))
+ continue;
+
+ if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true))
+ continue;
+
+ Contained = true;
+ break;
+ }
+ if (!Contained) {
+ Diag(SubLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(SuperLoc, NoteID);
+ return true;
+ }
+ }
+ // We've run half the gauntlet.
+ return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+}
+
+static bool CheckSpecForTypesEquivalent(Sema &S,
+ const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
+ QualType Target, SourceLocation TargetLoc,
+ QualType Source, SourceLocation SourceLoc)
+{
+ const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
+ if (!TFunc)
+ return false;
+ const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);
+ if (!SFunc)
+ return false;
+
+ return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
+ SFunc, SourceLoc);
+}
+
+/// CheckParamExceptionSpec - Check if the parameter and return types of the
+/// two functions have equivalent exception specs. This is part of the
+/// assignment and override compatibility check. We do not check the parameters
+/// of parameter function pointers recursively, as no sane programmer would
+/// even be able to write such a function type.
+bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Target, SourceLocation TargetLoc,
+ const FunctionProtoType *Source, SourceLocation SourceLoc)
+{
+ if (CheckSpecForTypesEquivalent(*this,
+ PDiag(diag::err_deep_exception_specs_differ) << 0, 0,
+ Target->getResultType(), TargetLoc,
+ Source->getResultType(), SourceLoc))
+ return true;
+
+ // We shouldn't even be testing this unless the arguments are otherwise
+ // compatible.
+ assert(Target->getNumArgs() == Source->getNumArgs() &&
+ "Functions have different argument counts.");
+ for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) {
+ if (CheckSpecForTypesEquivalent(*this,
+ PDiag(diag::err_deep_exception_specs_differ) << 1, 0,
+ Target->getArgType(i), TargetLoc,
+ Source->getArgType(i), SourceLoc))
+ return true;
+ }
+ return false;
+}
+
+bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
+{
+ // First we check for applicability.
+ // Target type must be a function, function pointer or function reference.
+ const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
+ if (!ToFunc)
+ return false;
+
+ // SourceType must be a function or function pointer.
+ const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
+ if (!FromFunc)
+ return false;
+
+ // Now we've got the correct types on both sides, check their compatibility.
+ // This means that the source of the conversion can only throw a subset of
+ // the exceptions of the target, and any exception specs on arguments or
+ // return types must be equivalent.
+ return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs,
+ 0, ToFunc, From->getSourceRange().getBegin(),
+ FromFunc, SourceLocation());
+}
+
+bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old) {
+ return CheckExceptionSpecSubset(diag::err_override_exception_spec,
+ diag::note_overridden_virtual_function,
+ Old->getType()->getAs<FunctionProtoType>(),
+ Old->getLocation(),
+ New->getType()->getAs<FunctionProtoType>(),
+ New->getLocation());
+}
+
+} // end namespace clang
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index a5e5083964222..d8e49c7d69410 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -14,18 +14,20 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LiteralSupport.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Designator.h"
#include "clang/Parse/Scope.h"
using namespace clang;
+
/// \brief Determine whether the use of this declaration is valid, and
/// emit any corresponding diagnostics.
///
@@ -44,12 +46,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
// stuff. Don't warn if we are implementing a deprecated
// construct.
bool isSilenced = false;
-
+
if (NamedDecl *ND = getCurFunctionOrMethodDecl()) {
// If this reference happens *in* a deprecated function or method, don't
// warn.
isSilenced = ND->getAttr<DeprecatedAttr>();
-
+
// If this is an Objective-C method implementation, check to see if the
// method was deprecated on the declaration, not the definition.
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND)) {
@@ -57,14 +59,14 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
// ObjCImplementationDecl.
if (ObjCImplementationDecl *Impl
= dyn_cast<ObjCImplementationDecl>(MD->getParent())) {
-
+
MD = Impl->getClassInterface()->getMethod(MD->getSelector(),
MD->isInstanceMethod());
isSilenced |= MD && MD->getAttr<DeprecatedAttr>();
}
}
}
-
+
if (!isSilenced)
Diag(Loc, diag::warn_deprecated) << D->getDeclName();
}
@@ -88,18 +90,17 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
}
/// DiagnoseSentinelCalls - This routine checks on method dispatch calls
-/// (and other functions in future), which have been declared with sentinel
+/// (and other functions in future), which have been declared with sentinel
/// attribute. It warns if call does not have the sentinel argument.
///
void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
- Expr **Args, unsigned NumArgs)
-{
+ Expr **Args, unsigned NumArgs) {
const SentinelAttr *attr = D->getAttr<SentinelAttr>();
- if (!attr)
+ if (!attr)
return;
int sentinelPos = attr->getSentinel();
int nullPos = attr->getNullPos();
-
+
// FIXME. ObjCMethodDecl and FunctionDecl need be derived from the same common
// base class. Then we won't be needing two versions of the same code.
unsigned int i = 0;
@@ -116,8 +117,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
warnNotEnoughArgs = (P != E || i >= NumArgs);
isMethod = 1;
- }
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// skip over named parameters.
ObjCMethodDecl::param_iterator P, E = FD->param_end();
for (P = FD->param_begin(); (P != E && i < NumArgs); ++P) {
@@ -127,14 +127,13 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
++i;
}
warnNotEnoughArgs = (P != E || i >= NumArgs);
- }
- else if (VarDecl *V = dyn_cast<VarDecl>(D)) {
+ } else if (VarDecl *V = dyn_cast<VarDecl>(D)) {
// block or function pointer call.
QualType Ty = V->getType();
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
- const FunctionType *FT = Ty->isFunctionPointerType()
- ? Ty->getAsPointerType()->getPointeeType()->getAsFunctionType()
- : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType();
+ const FunctionType *FT = Ty->isFunctionPointerType()
+ ? Ty->getAs<PointerType>()->getPointeeType()->getAs<FunctionType>()
+ : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) {
unsigned NumArgsInProto = Proto->getNumArgs();
unsigned k;
@@ -148,11 +147,9 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
if (Ty->isBlockPointerType())
isMethod = 2;
- }
- else
+ } else
return;
- }
- else
+ } else
return;
if (warnNotEnoughArgs) {
@@ -176,7 +173,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
Expr *sentinelExpr = Args[sentinel];
if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() ||
- !sentinelExpr->isNullPointerConstant(Context))) {
+ !sentinelExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull))) {
Diag(Loc, diag::warn_missing_sentinel) << isMethod;
Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
}
@@ -198,7 +196,8 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
if (Ty->isFunctionType())
- ImpCastExprToType(E, Context.getPointerType(Ty));
+ ImpCastExprToType(E, Context.getPointerType(Ty),
+ CastExpr::CK_FunctionToPointerDecay);
else if (Ty->isArrayType()) {
// In C90 mode, arrays only promote to pointers if the array expression is
// an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has
@@ -213,54 +212,20 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
//
if (getLangOptions().C99 || getLangOptions().CPlusPlus ||
E->isLvalue(Context) == Expr::LV_Valid)
- ImpCastExprToType(E, Context.getArrayDecayedType(Ty));
+ ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
+ CastExpr::CK_ArrayToPointerDecay);
}
}
-/// \brief Whether this is a promotable bitfield reference according
-/// to C99 6.3.1.1p2, bullet 2.
-///
-/// \returns the type this bit-field will promote to, or NULL if no
-/// promotion occurs.
-static QualType isPromotableBitField(Expr *E, ASTContext &Context) {
- FieldDecl *Field = E->getBitField();
- if (!Field)
- return QualType();
-
- const BuiltinType *BT = Field->getType()->getAsBuiltinType();
- if (!BT)
- return QualType();
-
- if (BT->getKind() != BuiltinType::Bool &&
- BT->getKind() != BuiltinType::Int &&
- BT->getKind() != BuiltinType::UInt)
- return QualType();
-
- llvm::APSInt BitWidthAP;
- if (!Field->getBitWidth()->isIntegerConstantExpr(BitWidthAP, Context))
- return QualType();
-
- uint64_t BitWidth = BitWidthAP.getZExtValue();
- uint64_t IntSize = Context.getTypeSize(Context.IntTy);
- if (BitWidth < IntSize ||
- (Field->getType()->isSignedIntegerType() && BitWidth == IntSize))
- return Context.IntTy;
-
- if (BitWidth == IntSize && Field->getType()->isUnsignedIntegerType())
- return Context.UnsignedIntTy;
-
- return QualType();
-}
-
/// UsualUnaryConversions - Performs various conversions that are common to most
-/// operators (C99 6.3). The conversions of array and function types are
+/// operators (C99 6.3). The conversions of array and function types are
/// sometimes surpressed. For example, the array->pointer conversion doesn't
/// apply if the array is an argument to the sizeof or address (&) operators.
/// In these instances, this routine should *not* be called.
Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
QualType Ty = Expr->getType();
assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
-
+
// C99 6.3.1.1p2:
//
// The following may be used in an expression wherever an int or
@@ -274,33 +239,33 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
// value is converted to an int; otherwise, it is converted to an
// unsigned int. These are called the integer promotions. All
// other types are unchanged by the integer promotions.
+ QualType PTy = Context.isPromotableBitField(Expr);
+ if (!PTy.isNull()) {
+ ImpCastExprToType(Expr, PTy);
+ return Expr;
+ }
if (Ty->isPromotableIntegerType()) {
- ImpCastExprToType(Expr, Context.IntTy);
+ QualType PT = Context.getPromotedIntegerType(Ty);
+ ImpCastExprToType(Expr, PT);
return Expr;
- } else {
- QualType T = isPromotableBitField(Expr, Context);
- if (!T.isNull()) {
- ImpCastExprToType(Expr, T);
- return Expr;
- }
- }
-
+ }
+
DefaultFunctionArrayConversion(Expr);
return Expr;
}
/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
-/// do not have a prototype. Arguments that have type float are promoted to
+/// do not have a prototype. Arguments that have type float are promoted to
/// double. All other argument types are converted by UsualUnaryConversions().
void Sema::DefaultArgumentPromotion(Expr *&Expr) {
QualType Ty = Expr->getType();
assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type");
-
+
// If this is a 'float' (CVR qualified or typedef) promote to double.
- if (const BuiltinType *BT = Ty->getAsBuiltinType())
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
if (BT->getKind() == BuiltinType::Float)
return ImpCastExprToType(Expr, Context.DoubleTy);
-
+
UsualUnaryConversions(Expr);
}
@@ -310,14 +275,14 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) {
/// completely illegal.
bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
DefaultArgumentPromotion(Expr);
-
+
if (Expr->getType()->isObjCInterfaceType()) {
Diag(Expr->getLocStart(),
diag::err_cannot_pass_objc_interface_to_vararg)
<< Expr->getType() << CT;
return true;
}
-
+
if (!Expr->getType()->isPODType())
Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg)
<< Expr->getType() << CT;
@@ -328,7 +293,7 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
/// UsualArithmeticConversions - Performs various conversions that are common to
/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
-/// routine returns the first non-arithmetic type found. The client is
+/// routine returns the first non-arithmetic type found. The client is
/// responsible for emitting appropriate error diagnostics.
/// FIXME: verify the conversion rules for "complex int" are consistent with
/// GCC.
@@ -339,11 +304,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
UsualUnaryConversions(rhsExpr);
- // For conversion purposes, we ignore any qualifiers.
+ // For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhs =
Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType();
- QualType rhs =
+ QualType rhs =
Context.getCanonicalType(rhsExpr->getType()).getUnqualifiedType();
// If both types are identical, no conversion is needed.
@@ -356,159 +321,20 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
return lhs;
// Perform bitfield promotions.
- QualType LHSBitfieldPromoteTy = isPromotableBitField(lhsExpr, Context);
+ QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr);
if (!LHSBitfieldPromoteTy.isNull())
lhs = LHSBitfieldPromoteTy;
- QualType RHSBitfieldPromoteTy = isPromotableBitField(rhsExpr, Context);
+ QualType RHSBitfieldPromoteTy = Context.isPromotableBitField(rhsExpr);
if (!RHSBitfieldPromoteTy.isNull())
rhs = RHSBitfieldPromoteTy;
- QualType destType = UsualArithmeticConversionsType(lhs, rhs);
+ QualType destType = Context.UsualArithmeticConversionsType(lhs, rhs);
if (!isCompAssign)
ImpCastExprToType(lhsExpr, destType);
ImpCastExprToType(rhsExpr, destType);
return destType;
}
-QualType Sema::UsualArithmeticConversionsType(QualType lhs, QualType rhs) {
- // Perform the usual unary conversions. We do this early so that
- // integral promotions to "int" can allow us to exit early, in the
- // lhs == rhs check. Also, for conversion purposes, we ignore any
- // qualifiers. For example, "const float" and "float" are
- // equivalent.
- if (lhs->isPromotableIntegerType())
- lhs = Context.IntTy;
- else
- lhs = lhs.getUnqualifiedType();
- if (rhs->isPromotableIntegerType())
- rhs = Context.IntTy;
- else
- rhs = rhs.getUnqualifiedType();
-
- // If both types are identical, no conversion is needed.
- if (lhs == rhs)
- return lhs;
-
- // If either side is a non-arithmetic type (e.g. a pointer), we are done.
- // The caller can deal with this (e.g. pointer + int).
- if (!lhs->isArithmeticType() || !rhs->isArithmeticType())
- return lhs;
-
- // At this point, we have two different arithmetic types.
-
- // Handle complex types first (C99 6.3.1.8p1).
- if (lhs->isComplexType() || rhs->isComplexType()) {
- // if we have an integer operand, the result is the complex type.
- if (rhs->isIntegerType() || rhs->isComplexIntegerType()) {
- // convert the rhs to the lhs complex type.
- return lhs;
- }
- if (lhs->isIntegerType() || lhs->isComplexIntegerType()) {
- // convert the lhs to the rhs complex type.
- return rhs;
- }
- // This handles complex/complex, complex/float, or float/complex.
- // When both operands are complex, the shorter operand is converted to the
- // type of the longer, and that is the type of the result. This corresponds
- // to what is done when combining two real floating-point operands.
- // The fun begins when size promotion occur across type domains.
- // From H&S 6.3.4: When one operand is complex and the other is a real
- // floating-point type, the less precise type is converted, within it's
- // real or complex domain, to the precision of the other type. For example,
- // when combining a "long double" with a "double _Complex", the
- // "double _Complex" is promoted to "long double _Complex".
- int result = Context.getFloatingTypeOrder(lhs, rhs);
-
- if (result > 0) { // The left side is bigger, convert rhs.
- rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs);
- } else if (result < 0) { // The right side is bigger, convert lhs.
- lhs = Context.getFloatingTypeOfSizeWithinDomain(rhs, lhs);
- }
- // At this point, lhs and rhs have the same rank/size. Now, make sure the
- // domains match. This is a requirement for our implementation, C99
- // does not require this promotion.
- if (lhs != rhs) { // Domains don't match, we have complex/float mix.
- if (lhs->isRealFloatingType()) { // handle "double, _Complex double".
- return rhs;
- } else { // handle "_Complex double, double".
- return lhs;
- }
- }
- return lhs; // The domain/size match exactly.
- }
- // Now handle "real" floating types (i.e. float, double, long double).
- if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) {
- // if we have an integer operand, the result is the real floating type.
- if (rhs->isIntegerType()) {
- // convert rhs to the lhs floating point type.
- return lhs;
- }
- if (rhs->isComplexIntegerType()) {
- // convert rhs to the complex floating point type.
- return Context.getComplexType(lhs);
- }
- if (lhs->isIntegerType()) {
- // convert lhs to the rhs floating point type.
- return rhs;
- }
- if (lhs->isComplexIntegerType()) {
- // convert lhs to the complex floating point type.
- return Context.getComplexType(rhs);
- }
- // We have two real floating types, float/complex combos were handled above.
- // Convert the smaller operand to the bigger result.
- int result = Context.getFloatingTypeOrder(lhs, rhs);
- if (result > 0) // convert the rhs
- return lhs;
- assert(result < 0 && "illegal float comparison");
- return rhs; // convert the lhs
- }
- if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) {
- // Handle GCC complex int extension.
- const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType();
- const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType();
-
- if (lhsComplexInt && rhsComplexInt) {
- if (Context.getIntegerTypeOrder(lhsComplexInt->getElementType(),
- rhsComplexInt->getElementType()) >= 0)
- return lhs; // convert the rhs
- return rhs;
- } else if (lhsComplexInt && rhs->isIntegerType()) {
- // convert the rhs to the lhs complex type.
- return lhs;
- } else if (rhsComplexInt && lhs->isIntegerType()) {
- // convert the lhs to the rhs complex type.
- return rhs;
- }
- }
- // Finally, we have two differing integer types.
- // The rules for this case are in C99 6.3.1.8
- int compare = Context.getIntegerTypeOrder(lhs, rhs);
- bool lhsSigned = lhs->isSignedIntegerType(),
- rhsSigned = rhs->isSignedIntegerType();
- QualType destType;
- if (lhsSigned == rhsSigned) {
- // Same signedness; use the higher-ranked type
- destType = compare >= 0 ? lhs : rhs;
- } else if (compare != (lhsSigned ? 1 : -1)) {
- // The unsigned type has greater than or equal rank to the
- // signed type, so use the unsigned type
- destType = lhsSigned ? rhs : lhs;
- } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) {
- // The two types are different widths; if we are here, that
- // means the signed type is larger than the unsigned type, so
- // use the signed type.
- destType = lhsSigned ? lhs : rhs;
- } else {
- // The signed type is higher-ranked than the unsigned type,
- // but isn't actually any bigger (like unsigned int and long
- // on most 32-bit systems). Use the unsigned type corresponding
- // to the signed type.
- destType = Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
- }
- return destType;
-}
-
//===----------------------------------------------------------------------===//
// Semantic Analysis for various Expression Types
//===----------------------------------------------------------------------===//
@@ -546,9 +372,9 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
StrTy = Context.getConstantArrayType(StrTy,
llvm::APInt(32, Literal.GetNumStringChars()+1),
ArrayType::Normal, 0);
-
+
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
- return Owned(StringLiteral::Create(Context, Literal.GetString(),
+ return Owned(StringLiteral::Create(Context, Literal.GetString(),
Literal.GetStringLength(),
Literal.AnyWide, StrTy,
&StringTokLocs[0],
@@ -569,7 +395,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
// we wanted to.
if (CurBlock->TheDecl == VD->getDeclContext())
return false;
-
+
// If this is an enum constant or function, it is constant, don't snapshot.
if (isa<EnumConstantDecl>(VD) || isa<FunctionDecl>(VD))
return false;
@@ -580,7 +406,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
if (const VarDecl *Var = dyn_cast<VarDecl>(VD))
if (!Var->hasLocalStorage())
return false;
-
+
// Blocks that have these can't be constant.
CurBlock->hasBlockDeclRefExprs = true;
@@ -594,15 +420,15 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
// having a reference outside it.
if (NextBlock->TheDecl == VD->getDeclContext())
break;
-
+
// Otherwise, the DeclRef from the inner block causes the outer one to need
// a snapshot as well.
NextBlock->hasBlockDeclRefExprs = true;
}
-
+
return true;
-}
-
+}
+
/// ActOnIdentifierExpr - The parser read an identifier in expression context,
@@ -628,35 +454,35 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
const CXXScopeSpec *SS) {
if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) {
Diag(Loc,
- diag::err_auto_variable_cannot_appear_in_own_initializer)
+ diag::err_auto_variable_cannot_appear_in_own_initializer)
<< D->getDeclName();
return ExprError();
}
-
+
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) {
if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) {
- Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
+ Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
<< D->getIdentifier() << FD->getDeclName();
- Diag(D->getLocation(), diag::note_local_variable_declared_here)
+ Diag(D->getLocation(), diag::note_local_variable_declared_here)
<< D->getIdentifier();
return ExprError();
}
}
}
}
-
+
MarkDeclarationReferenced(Loc, D);
-
+
Expr *E;
if (SS && !SS->isEmpty()) {
- E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
+ E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
ValueDependent, SS->getRange(),
static_cast<NestedNameSpecifier *>(SS->getScopeRep()));
} else
E = new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
-
+
return Owned(E);
}
@@ -665,14 +491,14 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
/// is Record.
static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context,
RecordDecl *Record) {
- assert(Record->isAnonymousStructOrUnion() &&
+ assert(Record->isAnonymousStructOrUnion() &&
"Record must be an anonymous struct or union!");
-
+
// FIXME: Once Decls are directly linked together, this will be an O(1)
// operation rather than a slow walk through DeclContext's vector (which
// itself will be eliminated). DeclGroups might make this even better.
DeclContext *Ctx = Record->getDeclContext();
- for (DeclContext::decl_iterator D = Ctx->decls_begin(),
+ for (DeclContext::decl_iterator D = Ctx->decls_begin(),
DEnd = Ctx->decls_end();
D != DEnd; ++D) {
if (*D == Record) {
@@ -721,7 +547,7 @@ VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
break;
}
Ctx = Ctx->getParent();
- } while (Ctx->isRecord() &&
+ } while (Ctx->isRecord() &&
cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion());
return BaseObject;
@@ -733,7 +559,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
Expr *BaseObjectExpr,
SourceLocation OpLoc) {
llvm::SmallVector<FieldDecl *, 4> AnonFields;
- VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
+ VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
AnonFields);
// Build the expression that refers to the base object, from
@@ -741,7 +567,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
// of the anonymous union objects and, eventually, the field we
// found via name lookup.
bool BaseObjectIsPointer = false;
- unsigned ExtraQuals = 0;
+ Qualifiers BaseQuals;
if (BaseObject) {
// BaseObject is an anonymous struct/union variable (and is,
// therefore, not part of another non-anonymous record).
@@ -749,29 +575,30 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
MarkDeclarationReferenced(Loc, BaseObject);
BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(),
SourceLocation());
- ExtraQuals
- = Context.getCanonicalType(BaseObject->getType()).getCVRQualifiers();
+ BaseQuals
+ = Context.getCanonicalType(BaseObject->getType()).getQualifiers();
} else if (BaseObjectExpr) {
// The caller provided the base object expression. Determine
// whether its a pointer and whether it adds any qualifiers to the
// anonymous struct/union fields we're looking into.
QualType ObjectType = BaseObjectExpr->getType();
- if (const PointerType *ObjectPtr = ObjectType->getAsPointerType()) {
+ if (const PointerType *ObjectPtr = ObjectType->getAs<PointerType>()) {
BaseObjectIsPointer = true;
ObjectType = ObjectPtr->getPointeeType();
}
- ExtraQuals = Context.getCanonicalType(ObjectType).getCVRQualifiers();
+ BaseQuals
+ = Context.getCanonicalType(ObjectType).getQualifiers();
} else {
// We've found a member of an anonymous struct/union that is
// inside a non-anonymous struct/union, so in a well-formed
// program our base object expression is "this".
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
if (!MD->isStatic()) {
- QualType AnonFieldType
+ QualType AnonFieldType
= Context.getTagDeclType(
cast<RecordDecl>(AnonFields.back()->getDeclContext()));
QualType ThisType = Context.getTagDeclType(MD->getParent());
- if ((Context.getCanonicalType(AnonFieldType)
+ if ((Context.getCanonicalType(AnonFieldType)
== Context.getCanonicalType(ThisType)) ||
IsDerivedFrom(ThisType, AnonFieldType)) {
// Our base object expression is "this".
@@ -783,10 +610,10 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method)
<< Field->getDeclName());
}
- ExtraQuals = MD->getTypeQualifiers();
+ BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers());
}
- if (!BaseObjectExpr)
+ if (!BaseObjectExpr)
return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use)
<< Field->getDeclName());
}
@@ -794,20 +621,35 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
// Build the implicit member references to the field of the
// anonymous struct/union.
Expr *Result = BaseObjectExpr;
+ Qualifiers ResultQuals = BaseQuals;
for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
FI = AnonFields.rbegin(), FIEnd = AnonFields.rend();
FI != FIEnd; ++FI) {
QualType MemberType = (*FI)->getType();
- if (!(*FI)->isMutable()) {
- unsigned combinedQualifiers
- = MemberType.getCVRQualifiers() | ExtraQuals;
- MemberType = MemberType.getQualifiedType(combinedQualifiers);
- }
+ Qualifiers MemberTypeQuals =
+ Context.getCanonicalType(MemberType).getQualifiers();
+
+ // CVR attributes from the base are picked up by members,
+ // except that 'mutable' members don't pick up 'const'.
+ if ((*FI)->isMutable())
+ ResultQuals.removeConst();
+
+ // GC attributes are never picked up by members.
+ ResultQuals.removeObjCGCAttr();
+
+ // TR 18037 does not allow fields to be declared with address spaces.
+ assert(!MemberTypeQuals.hasAddressSpace());
+
+ Qualifiers NewQuals = ResultQuals + MemberTypeQuals;
+ if (NewQuals != MemberTypeQuals)
+ MemberType = Context.getQualifiedType(MemberType, NewQuals);
+
MarkDeclarationReferenced(Loc, *FI);
+ // FIXME: Might this end up being a qualified name?
Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
OpLoc, MemberType);
BaseObjectIsPointer = false;
- ExtraQuals = Context.getCanonicalType(MemberType).getCVRQualifiers();
+ ResultQuals = NewQuals;
}
return Owned(Result);
@@ -835,7 +677,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
Sema::OwningExprResult
Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
DeclarationName Name, bool HasTrailingLParen,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec *SS,
bool isAddressOfOperand) {
// Could be enum-constant, value decl, instance variable, etc.
if (SS && SS->isInvalid())
@@ -848,12 +690,13 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// FIXME: Member of the current instantiation.
if (SS && isDependentScopeSpecifier(*SS)) {
return Owned(new (Context) UnresolvedDeclRefExpr(Name, Context.DependentTy,
- Loc, SS->getRange(),
- static_cast<NestedNameSpecifier *>(SS->getScopeRep())));
+ Loc, SS->getRange(),
+ static_cast<NestedNameSpecifier *>(SS->getScopeRep()),
+ isAddressOfOperand));
}
- LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName,
- false, true, Loc);
+ LookupResult Lookup;
+ LookupParsedName(Lookup, S, SS, Name, LookupOrdinaryName, false, true, Loc);
if (Lookup.isAmbiguous()) {
DiagnoseAmbiguousLookup(Lookup, Name, Loc,
@@ -861,8 +704,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
: SourceRange());
return ExprError();
}
-
- NamedDecl *D = Lookup.getAsDecl();
+
+ NamedDecl *D = Lookup.getAsSingleDecl(Context);
// If this reference is in an Objective-C method, then ivar lookup happens as
// well.
@@ -870,8 +713,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
if (II && getCurMethodDecl()) {
// There are two cases to handle here. 1) scoped lookup could have failed,
// in which case we should look for an ivar. 2) scoped lookup could have
- // found a decl, but that decl is outside the current instance method (i.e.
- // a global variable). In these two cases, we do a lookup for an ivar with
+ // found a decl, but that decl is outside the current instance method (i.e.
+ // a global variable). In these two cases, we do a lookup for an ivar with
// this name, if the lookup sucedes, we replace it our current decl.
if (D == 0 || D->isDefinedOutsideFunctionOrMethod()) {
ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
@@ -880,12 +723,12 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// Check if referencing a field with __attribute__((deprecated)).
if (DiagnoseUseOfDecl(IV, Loc))
return ExprError();
-
+
// If we're referencing an invalid decl, just return this as a silent
// error node. The error diagnostic was already emitted on the decl.
if (IV->isInvalidDecl())
return ExprError();
-
+
bool IsClsMethod = getCurMethodDecl()->isClassMethod();
// If a class method attemps to use a free standing ivar, this is
// an error.
@@ -901,15 +744,15 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// FIXME: This should use a new expr for a direct reference, don't
// turn this into Self->ivar, just return a BareIVarExpr or something.
IdentifierInfo &II = Context.Idents.get("self");
- OwningExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false);
+ OwningExprResult SelfExpr = ActOnIdentifierExpr(S, SourceLocation(),
+ II, false);
MarkDeclarationReferenced(Loc, IV);
- return Owned(new (Context)
- ObjCIvarRefExpr(IV, IV->getType(), Loc,
+ return Owned(new (Context)
+ ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.takeAs<Expr>(), true, true));
}
}
- }
- else if (getCurMethodDecl()->isInstanceMethod()) {
+ } else if (getCurMethodDecl()->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
@@ -922,10 +765,10 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// Needed to implement property "super.method" notation.
if (D == 0 && II->isStr("super")) {
QualType T;
-
+
if (getCurMethodDecl()->isInstanceMethod())
- T = Context.getPointerType(Context.getObjCInterfaceType(
- getCurMethodDecl()->getClassInterface()));
+ T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
+ getCurMethodDecl()->getClassInterface()));
else
T = Context.getObjCClassType();
return Owned(new (Context) ObjCSuperExpr(Loc, T));
@@ -934,7 +777,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// Determine whether this name might be a candidate for
// argument-dependent lookup.
- bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
+ bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
HasTrailingLParen;
if (ADL && D == 0) {
@@ -960,8 +803,9 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// If this name wasn't predeclared and if this is not a function call,
// diagnose the problem.
if (SS && !SS->isEmpty())
- return ExprError(Diag(Loc, diag::err_typecheck_no_member)
- << Name << SS->getRange());
+ return ExprError(Diag(Loc, diag::err_no_member)
+ << Name << computeDeclContext(*SS, false)
+ << SS->getRange());
else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
return ExprError(Diag(Loc, diag::err_undeclared_use)
@@ -970,18 +814,18 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
return ExprError(Diag(Loc, diag::err_undeclared_var_use) << Name);
}
}
-
+
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
// Warn about constructs like:
// if (void *X = foo()) { ... } else { X }.
// In the else block, the pointer is always false.
-
+
// FIXME: In a template instantiation, we don't have scope
// information to check this property.
if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
Scope *CheckS = S;
while (CheckS) {
- if (CheckS->isWithinElse() &&
+ if (CheckS->isWithinElse() &&
CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
if (Var->getType()->isBooleanType())
ExprError(Diag(Loc, diag::warn_value_always_false)
@@ -991,7 +835,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
<< Var->getDeclName());
break;
}
-
+
// Move up one more control parent to check again.
CheckS = CheckS->getControlParent();
if (CheckS)
@@ -1010,24 +854,66 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
QualType T = Func->getType();
QualType NoProtoType = T;
- if (const FunctionProtoType *Proto = T->getAsFunctionProtoType())
+ if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>())
NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
return BuildDeclRefExpr(Func, NoProtoType, Loc, false, false, SS);
}
}
-
+
return BuildDeclarationNameExpr(Loc, D, HasTrailingLParen, SS, isAddressOfOperand);
}
+/// \brief Cast member's object to its own class if necessary.
+bool
+Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) {
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(Member))
+ if (CXXRecordDecl *RD =
+ dyn_cast<CXXRecordDecl>(FD->getDeclContext())) {
+ QualType DestType =
+ Context.getCanonicalType(Context.getTypeDeclType(RD));
+ if (DestType->isDependentType() || From->getType()->isDependentType())
+ return false;
+ QualType FromRecordType = From->getType();
+ QualType DestRecordType = DestType;
+ if (FromRecordType->getAs<PointerType>()) {
+ DestType = Context.getPointerType(DestType);
+ FromRecordType = FromRecordType->getPointeeType();
+ }
+ if (!Context.hasSameUnqualifiedType(FromRecordType, DestRecordType) &&
+ CheckDerivedToBaseConversion(FromRecordType,
+ DestRecordType,
+ From->getSourceRange().getBegin(),
+ From->getSourceRange()))
+ return true;
+ ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
+ /*isLvalue=*/true);
+ }
+ return false;
+}
+
+/// \brief Build a MemberExpr AST node.
+static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
+ const CXXScopeSpec *SS, NamedDecl *Member,
+ SourceLocation Loc, QualType Ty) {
+ if (SS && SS->isSet())
+ return MemberExpr::Create(C, Base, isArrow,
+ (NestedNameSpecifier *)SS->getScopeRep(),
+ SS->getRange(), Member, Loc,
+ // FIXME: Explicit template argument lists
+ false, SourceLocation(), 0, 0, SourceLocation(),
+ Ty);
+
+ return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty);
+}
/// \brief Complete semantic analysis for a reference to the given declaration.
Sema::OwningExprResult
Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
bool HasTrailingLParen,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec *SS,
bool isAddressOfOperand) {
assert(D && "Cannot refer to a NULL declaration");
DeclarationName Name = D->getDeclName();
-
+
// If this is an expression of the form &Class::member, don't build an
// implicit member ref, because we want a pointer to the member in general,
// not any specific instance's member.
@@ -1060,7 +946,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
if (!MD->isStatic()) {
- // C++ [class.mfct.nonstatic]p2:
+ // C++ [class.mfct.nonstatic]p2:
// [...] if name lookup (3.4.1) resolves the name in the
// id-expression to a nonstatic nontype member of class X or of
// a base class of X, the id-expression is transformed into a
@@ -1072,45 +958,74 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
Ctx = FD->getDeclContext();
MemberType = FD->getType();
- if (const ReferenceType *RefType = MemberType->getAsReferenceType())
+ if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>())
MemberType = RefType->getPointeeType();
- else if (!FD->isMutable()) {
- unsigned combinedQualifiers
- = MemberType.getCVRQualifiers() | MD->getTypeQualifiers();
- MemberType = MemberType.getQualifiedType(combinedQualifiers);
- }
+ else if (!FD->isMutable())
+ MemberType
+ = Context.getQualifiedType(MemberType,
+ Qualifiers::fromCVRMask(MD->getTypeQualifiers()));
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (!Method->isStatic()) {
Ctx = Method->getParent();
MemberType = Method->getType();
}
- } else if (OverloadedFunctionDecl *Ovl
+ } else if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(D)) {
+ if (CXXMethodDecl *Method
+ = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())) {
+ if (!Method->isStatic()) {
+ Ctx = Method->getParent();
+ MemberType = Context.OverloadTy;
+ }
+ }
+ } else if (OverloadedFunctionDecl *Ovl
= dyn_cast<OverloadedFunctionDecl>(D)) {
- for (OverloadedFunctionDecl::function_iterator
+ // FIXME: We need an abstraction for iterating over one or more function
+ // templates or functions. This code is far too repetitive!
+ for (OverloadedFunctionDecl::function_iterator
Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
Func != FuncEnd; ++Func) {
- if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(*Func))
- if (!DMethod->isStatic()) {
- Ctx = Ovl->getDeclContext();
- MemberType = Context.OverloadTy;
- break;
- }
+ CXXMethodDecl *DMethod = 0;
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(*Func))
+ DMethod = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ DMethod = dyn_cast<CXXMethodDecl>(*Func);
+
+ if (DMethod && !DMethod->isStatic()) {
+ Ctx = DMethod->getDeclContext();
+ MemberType = Context.OverloadTy;
+ break;
+ }
}
}
if (Ctx && Ctx->isRecord()) {
QualType CtxType = Context.getTagDeclType(cast<CXXRecordDecl>(Ctx));
QualType ThisType = Context.getTagDeclType(MD->getParent());
- if ((Context.getCanonicalType(CtxType)
+ if ((Context.getCanonicalType(CtxType)
== Context.getCanonicalType(ThisType)) ||
IsDerivedFrom(ThisType, CtxType)) {
// Build the implicit member access expression.
Expr *This = new (Context) CXXThisExpr(SourceLocation(),
MD->getThisType(Context));
MarkDeclarationReferenced(Loc, D);
- return Owned(new (Context) MemberExpr(This, true, D,
- Loc, MemberType));
+ if (PerformObjectMemberConversion(This, D))
+ return ExprError();
+
+ bool ShouldCheckUse = true;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ // Don't diagnose the use of a virtual member function unless it's
+ // explicitly qualified.
+ if (MD->isVirtual() && (!SS || !SS->isSet()))
+ ShouldCheckUse = false;
+ }
+
+ if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc))
+ return ExprError();
+ return Owned(BuildMemberExpr(Context, This, true, SS, D,
+ Loc, MemberType));
}
}
}
@@ -1145,13 +1060,18 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
return BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
false, false, SS);
+ else if (UnresolvedUsingDecl *UD = dyn_cast<UnresolvedUsingDecl>(D))
+ return BuildDeclRefExpr(UD, Context.DependentTy, Loc,
+ /*TypeDependent=*/true,
+ /*ValueDependent=*/true, SS);
+
ValueDecl *VD = cast<ValueDecl>(D);
// Check whether this declaration can be used. Note that we suppress
// this check when we're going to perform argument-dependent lookup
// on this function name, because this might not be the function
// that overload resolution actually selects.
- bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
+ bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
HasTrailingLParen;
if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc))
return ExprError();
@@ -1177,9 +1097,9 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
// This is to record that a 'const' was actually synthesize and added.
bool constAdded = !ExprTy.isConstQualified();
// Variable will be bound by-copy, make it const within the closure.
-
+
ExprTy.addConst();
- return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false,
+ return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false,
constAdded));
}
// If this reference is not in a block or if the referenced variable is
@@ -1189,7 +1109,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
bool ValueDependent = false;
if (getLangOptions().CPlusPlus) {
// C++ [temp.dep.expr]p3:
- // An id-expression is type-dependent if it contains:
+ // An id-expression is type-dependent if it contains:
// - an identifier that was declared with a dependent type,
if (VD->getType()->isDependentType())
TypeDependent = true;
@@ -1226,7 +1146,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
// - a constant with integral or enumeration type and is
// initialized with an expression that is value-dependent
else if (const VarDecl *Dcl = dyn_cast<VarDecl>(VD)) {
- if (Dcl->getType().getCVRQualifiers() == QualType::Const &&
+ if (Dcl->getType().getCVRQualifiers() == Qualifiers::Const &&
Dcl->getInit()) {
ValueDependent = Dcl->getInit()->isValueDependent();
}
@@ -1250,21 +1170,24 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
// Pre-defined identifiers are of type char[x], where x is the length of the
// string.
- unsigned Length;
- if (FunctionDecl *FD = getCurFunctionDecl())
- Length = FD->getIdentifier()->getLength();
- else if (ObjCMethodDecl *MD = getCurMethodDecl())
- Length = MD->getSynthesizedMethodSize();
- else {
+
+ Decl *currentDecl = getCurFunctionOrMethodDecl();
+ if (!currentDecl) {
Diag(Loc, diag::ext_predef_outside_function);
- // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string.
- Length = IT == PredefinedExpr::PrettyFunction ? strlen("top level") : 0;
+ currentDecl = Context.getTranslationUnitDecl();
}
+ QualType ResTy;
+ if (cast<DeclContext>(currentDecl)->isDependentContext()) {
+ ResTy = Context.DependentTy;
+ } else {
+ unsigned Length =
+ PredefinedExpr::ComputeName(Context, IT, currentDecl).length();
- llvm::APInt LengthI(32, Length + 1);
- QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const);
- ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
+ llvm::APInt LengthI(32, Length + 1);
+ ResTy = Context.CharTy.withConst();
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
+ }
return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
}
@@ -1304,7 +1227,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// Get the spelling of the token, which eliminates trigraphs, etc.
unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
- NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
+ NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
Tok.getLocation(), PP);
if (Literal.hadError)
return ExprError();
@@ -1417,7 +1340,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// If this is an imaginary literal, create the ImaginaryLiteral wrapper.
if (Literal.isImaginary)
- Res = new (Context) ImaginaryLiteral(Res,
+ Res = new (Context) ImaginaryLiteral(Res,
Context.getComplexType(Res->getType()));
return Owned(Res);
@@ -1446,27 +1369,27 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange;
return false;
}
-
+
// Allow sizeof(void)/alignof(void) as an extension.
if (exprType->isVoidType()) {
Diag(OpLoc, diag::ext_sizeof_void_type)
<< (isSizeof ? "sizeof" : "__alignof") << ExprRange;
return false;
}
-
+
if (RequireCompleteType(OpLoc, exprType,
- isSizeof ? diag::err_sizeof_incomplete_type :
- diag::err_alignof_incomplete_type,
- ExprRange))
+ isSizeof ? diag::err_sizeof_incomplete_type :
+ PDiag(diag::err_alignof_incomplete_type)
+ << ExprRange))
return true;
-
+
// Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
if (LangOpts.ObjCNonFragileABI && exprType->isObjCInterfaceType()) {
Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
<< exprType << isSizeof << ExprRange;
return true;
}
-
+
return false;
}
@@ -1474,7 +1397,7 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
const SourceRange &ExprRange) {
E = E->IgnoreParens();
- // alignof decl is always ok.
+ // alignof decl is always ok.
if (isa<DeclRefExpr>(E))
return false;
@@ -1490,15 +1413,15 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
// Alignment of a field access is always okay, so long as it isn't a
// bit-field.
if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
- if (dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (isa<FieldDecl>(ME->getMemberDecl()))
return false;
return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false);
}
/// \brief Build a sizeof or alignof expression given a type operand.
-Action::OwningExprResult
-Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
+Action::OwningExprResult
+Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
bool isSizeOf, SourceRange R) {
if (T.isNull())
return ExprError();
@@ -1515,8 +1438,8 @@ Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
/// \brief Build a sizeof or alignof expression given an expression
/// operand.
-Action::OwningExprResult
-Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
+Action::OwningExprResult
+Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
bool isSizeOf, SourceRange R) {
// Verify that the operand is valid.
bool isInvalid = false;
@@ -1550,9 +1473,10 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
if (TyOrEx == 0) return ExprError();
if (isType) {
- QualType ArgTy = QualType::getFromOpaquePtr(TyOrEx);
+ // FIXME: Preserve type source info.
+ QualType ArgTy = GetTypeFromParser(TyOrEx);
return CreateSizeOfAlignOfExpr(ArgTy, OpLoc, isSizeof, ArgRange);
- }
+ }
// Get the end location.
Expr *ArgEx = (Expr *)TyOrEx;
@@ -1568,15 +1492,15 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
if (V->isTypeDependent())
return Context.DependentTy;
-
+
// These operators return the element type of a complex type.
- if (const ComplexType *CT = V->getType()->getAsComplexType())
+ if (const ComplexType *CT = V->getType()->getAs<ComplexType>())
return CT->getElementType();
-
+
// Otherwise they pass through real integer and floating point types here.
if (V->getType()->isArithmeticType())
return V->getType();
-
+
// Reject anything else.
Diag(Loc, diag::err_realimag_invalid_type) << V->getType()
<< (isReal ? "__real" : "__imag");
@@ -1588,6 +1512,8 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
Action::OwningExprResult
Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind, ExprArg Input) {
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Input = MaybeConvertParenListExprToParenExpr(S, move(Input));
Expr *Arg = (Expr *)Input.get();
UnaryOperator::Opcode Opc;
@@ -1612,9 +1538,9 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
// for objects of that type. When the postfix increment is
// called as a result of using the ++ operator, the int
// argument will have value zero.
- Expr *Args[2] = {
- Arg,
- new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0,
+ Expr *Args[2] = {
+ Arg,
+ new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0,
/*isSigned=*/true), Context.IntTy, SourceLocation())
};
@@ -1646,9 +1572,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
}
// Determine the result type
- QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
- ResultTy = ResultTy.getNonReferenceType();
+ QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
@@ -1657,9 +1581,17 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
Input.release();
Args[0] = Arg;
- return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
- Args, 2, ResultTy,
- OpLoc));
+
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OverOp,
+ FnExpr, Args, 2,
+ ResultTy, OpLoc));
+
+ if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
+ FnDecl))
+ return ExprError();
+ return Owned(TheCall.release());
+
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -1672,11 +1604,19 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
}
}
- case OR_No_Viable_Function:
- // No viable function; fall through to handling this as a
- // built-in operator, which will produce an error message for us.
- break;
-
+ case OR_No_Viable_Function: {
+ // No viable function; try checking this as a built-in operator, which
+ // will fail and provide a diagnostic. Then, print the overload
+ // candidates.
+ OwningExprResult Result = CreateBuiltinUnaryOp(OpLoc, Opc, move(Input));
+ assert(Result.isInvalid() &&
+ "C++ postfix-unary operator overloading is missing candidates!");
+ if (Result.isInvalid())
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+
+ return move(Result);
+ }
+
case OR_Ambiguous:
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< UnaryOperator::getOpcodeStr(Opc)
@@ -1698,17 +1638,17 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
// build a built-in operation.
}
- QualType result = CheckIncrementDecrementOperand(Arg, OpLoc,
- Opc == UnaryOperator::PostInc);
- if (result.isNull())
- return ExprError();
Input.release();
- return Owned(new (Context) UnaryOperator(Arg, Opc, result, OpLoc));
+ Input = Arg;
+ return CreateBuiltinUnaryOp(OpLoc, Opc, move(Input));
}
Action::OwningExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
ExprArg Idx, SourceLocation RLoc) {
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+
Expr *LHSExp = static_cast<Expr*>(Base.get()),
*RHSExp = static_cast<Expr*>(Idx.get());
@@ -1720,12 +1660,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
Context.DependentTy, RLoc));
}
- if (getLangOptions().CPlusPlus &&
+ if (getLangOptions().CPlusPlus &&
(LHSExp->getType()->isRecordType() ||
LHSExp->getType()->isEnumeralType() ||
RHSExp->getType()->isRecordType() ||
RHSExp->getType()->isEnumeralType())) {
- // Add the appropriate overloaded operators (C++ [over.match.oper])
+ // Add the appropriate overloaded operators (C++ [over.match.oper])
// to the candidate set.
OverloadCandidateSet CandidateSet;
Expr *Args[2] = { LHSExp, RHSExp };
@@ -1746,7 +1686,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
if (PerformObjectArgumentInitialization(LHSExp, Method) ||
- PerformCopyInitialization(RHSExp,
+ PerformCopyInitialization(RHSExp,
FnDecl->getParamDecl(0)->getType(),
"passing"))
return ExprError();
@@ -1762,9 +1702,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
}
// Determine the result type
- QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
- ResultTy = ResultTy.getNonReferenceType();
+ QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
@@ -1775,9 +1713,16 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
Idx.release();
Args[0] = LHSExp;
Args[1] = RHSExp;
- return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
- FnExpr, Args, 2,
- ResultTy, LLoc));
+
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
+ FnExpr, Args, 2,
+ ResultTy, RLoc));
+ if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall.get(),
+ FnDecl))
+ return ExprError();
+
+ return Owned(TheCall.release());
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -1834,16 +1779,27 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
BaseExpr = LHSExp;
IndexExpr = RHSExp;
ResultType = Context.DependentTy;
- } else if (const PointerType *PTy = LHSTy->getAsPointerType()) {
+ } else if (const PointerType *PTy = LHSTy->getAs<PointerType>()) {
+ BaseExpr = LHSExp;
+ IndexExpr = RHSExp;
+ ResultType = PTy->getPointeeType();
+ } else if (const PointerType *PTy = RHSTy->getAs<PointerType>()) {
+ // Handle the uncommon case of "123[Ptr]".
+ BaseExpr = RHSExp;
+ IndexExpr = LHSExp;
+ ResultType = PTy->getPointeeType();
+ } else if (const ObjCObjectPointerType *PTy =
+ LHSTy->getAs<ObjCObjectPointerType>()) {
BaseExpr = LHSExp;
IndexExpr = RHSExp;
ResultType = PTy->getPointeeType();
- } else if (const PointerType *PTy = RHSTy->getAsPointerType()) {
+ } else if (const ObjCObjectPointerType *PTy =
+ RHSTy->getAs<ObjCObjectPointerType>()) {
// Handle the uncommon case of "123[Ptr]".
BaseExpr = RHSExp;
IndexExpr = LHSExp;
ResultType = PTy->getPointeeType();
- } else if (const VectorType *VTy = LHSTy->getAsVectorType()) {
+ } else if (const VectorType *VTy = LHSTy->getAs<VectorType>()) {
BaseExpr = LHSExp; // vectors: V[123]
IndexExpr = RHSExp;
@@ -1862,7 +1818,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
BaseExpr = LHSExp;
IndexExpr = RHSExp;
- ResultType = LHSTy->getAsPointerType()->getPointeeType();
+ ResultType = LHSTy->getAs<PointerType>()->getPointeeType();
} else if (RHSTy->isArrayType()) {
// Same as previous, except for 123[f().a] case
Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
@@ -1872,38 +1828,45 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
BaseExpr = RHSExp;
IndexExpr = LHSExp;
- ResultType = RHSTy->getAsPointerType()->getPointeeType();
+ ResultType = RHSTy->getAs<PointerType>()->getPointeeType();
} else {
return ExprError(Diag(LLoc, diag::err_typecheck_subscript_value)
<< LHSExp->getSourceRange() << RHSExp->getSourceRange());
}
// C99 6.5.2.1p1
- if (!IndexExpr->getType()->isIntegerType() && !IndexExpr->isTypeDependent())
+ if (!(IndexExpr->getType()->isIntegerType() &&
+ IndexExpr->getType()->isScalarType()) && !IndexExpr->isTypeDependent())
return ExprError(Diag(LLoc, diag::err_typecheck_subscript_not_integer)
<< IndexExpr->getSourceRange());
+ if ((IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_S) ||
+ IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_U))
+ && !IndexExpr->isTypeDependent())
+ Diag(LLoc, diag::warn_subscript_is_char) << IndexExpr->getSourceRange();
+
// C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly,
- // C++ [expr.sub]p1: The type "T" shall be a completely-defined object
- // type. Note that Functions are not objects, and that (in C99 parlance)
+ // C++ [expr.sub]p1: The type "T" shall be a completely-defined object
+ // type. Note that Functions are not objects, and that (in C99 parlance)
// incomplete types are not object types.
if (ResultType->isFunctionType()) {
Diag(BaseExpr->getLocStart(), diag::err_subscript_function_type)
<< ResultType << BaseExpr->getSourceRange();
return ExprError();
}
-
+
if (!ResultType->isDependentType() &&
- RequireCompleteType(LLoc, ResultType, diag::err_subscript_incomplete_type,
- BaseExpr->getSourceRange()))
+ RequireCompleteType(LLoc, ResultType,
+ PDiag(diag::err_subscript_incomplete_type)
+ << BaseExpr->getSourceRange()))
return ExprError();
-
+
// Diagnose bad cases where we step over interface counts.
if (ResultType->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
Diag(LLoc, diag::err_subscript_nonfragile_interface)
<< ResultType << BaseExpr->getSourceRange();
return ExprError();
}
-
+
Base.release();
Idx.release();
return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
@@ -1912,11 +1875,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
QualType Sema::
CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
- IdentifierInfo &CompName, SourceLocation CompLoc) {
- const ExtVectorType *vecType = baseType->getAsExtVectorType();
+ const IdentifierInfo *CompName,
+ SourceLocation CompLoc) {
+ const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
// The vector accessor can't exceed the number of elements.
- const char *compStr = CompName.getName();
+ const char *compStr = CompName->getName();
// This flag determines whether or not the component is one of the four
// special names that indicate a subset of exactly half the elements are
@@ -1953,7 +1917,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
// Ensure no component accessor exceeds the width of the vector type it
// operates on.
if (!HalvingSwizzle) {
- compStr = CompName.getName();
+ compStr = CompName->getName();
if (HexSwizzle)
compStr++;
@@ -1981,7 +1945,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
// vec4.s0 is a float, vec4.s23 is a vec3, etc.
// vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
unsigned CompSize = HalvingSwizzle ? vecType->getNumElements() / 2
- : CompName.getLength();
+ : CompName->getLength();
if (HexSwizzle)
CompSize--;
@@ -1999,18 +1963,18 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
}
static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
- IdentifierInfo &Member,
+ IdentifierInfo *Member,
const Selector &Sel,
ASTContext &Context) {
-
- if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(&Member))
+
+ if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
return PD;
if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
return OMD;
-
+
for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
E = PDecl->protocol_end(); I != E; ++I) {
- if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel,
+ if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel,
Context))
return D;
}
@@ -2018,14 +1982,14 @@ static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
}
static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy,
- IdentifierInfo &Member,
+ IdentifierInfo *Member,
const Selector &Sel,
ASTContext &Context) {
// Check protocols on qualified interfaces.
Decl *GDecl = 0;
for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
E = QIdTy->qual_end(); I != E; ++I) {
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
GDecl = PD;
break;
}
@@ -2047,101 +2011,213 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy,
return GDecl;
}
-/// FindMethodInNestedImplementations - Look up a method in current and
-/// all base class implementations.
-///
-ObjCMethodDecl *Sema::FindMethodInNestedImplementations(
- const ObjCInterfaceDecl *IFace,
- const Selector &Sel) {
- ObjCMethodDecl *Method = 0;
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(IFace->getIdentifier()))
- Method = ImpDecl->getInstanceMethod(Sel);
-
- if (!Method && IFace->getSuperClass())
- return FindMethodInNestedImplementations(IFace->getSuperClass(), Sel);
- return Method;
-}
-
Action::OwningExprResult
-Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
+Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
tok::TokenKind OpKind, SourceLocation MemberLoc,
- IdentifierInfo &Member,
- DeclPtrTy ObjCImpDecl) {
+ DeclarationName MemberName,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ SourceLocation RAngleLoc,
+ DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS,
+ NamedDecl *FirstQualifierInScope) {
+ if (SS && SS->isInvalid())
+ return ExprError();
+
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+
Expr *BaseExpr = Base.takeAs<Expr>();
- assert(BaseExpr && "no record expression");
+ assert(BaseExpr && "no base expression");
// Perform default conversions.
DefaultFunctionArrayConversion(BaseExpr);
QualType BaseType = BaseExpr->getType();
+ // If this is an Objective-C pseudo-builtin and a definition is provided then
+ // use that.
+ if (BaseType->isObjCIdType()) {
+ // We have an 'id' type. Rather than fall through, we check if this
+ // is a reference to 'isa'.
+ if (BaseType != Context.ObjCIdRedefinitionType) {
+ BaseType = Context.ObjCIdRedefinitionType;
+ ImpCastExprToType(BaseExpr, BaseType);
+ }
+ }
assert(!BaseType.isNull() && "no type for member expression");
+ // Handle properties on ObjC 'Class' types.
+ if (OpKind == tok::period && BaseType->isObjCClassType()) {
+ // Also must look for a getter name which uses property syntax.
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ if (ObjCMethodDecl *MD = getCurMethodDecl()) {
+ ObjCInterfaceDecl *IFace = MD->getClassInterface();
+ ObjCMethodDecl *Getter;
+ // FIXME: need to also look locally in the implementation.
+ if ((Getter = IFace->lookupClassMethod(Sel))) {
+ // Check the use of this method.
+ if (DiagnoseUseOfDecl(Getter, MemberLoc))
+ return ExprError();
+ }
+ // If we found a getter then this may be a valid dot-reference, we
+ // will look for the matching setter, in case it is needed.
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
+ ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
+ if (!Setter) {
+ // If this reference is in an @implementation, also check for 'private'
+ // methods.
+ Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
+ }
+ // Look through local category implementations associated with the class.
+ if (!Setter)
+ Setter = IFace->getCategoryClassMethod(SetterSel);
+
+ if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
+ return ExprError();
+
+ if (Getter || Setter) {
+ QualType PType;
+
+ if (Getter)
+ PType = Getter->getResultType();
+ else
+ // Get the expression type from Setter's incoming parameter.
+ PType = (*(Setter->param_end() -1))->getType();
+ // FIXME: we must check that the setter has property type.
+ return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter,
+ PType,
+ Setter, MemberLoc, BaseExpr));
+ }
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType);
+ }
+ }
+
+ if (BaseType->isObjCClassType() &&
+ BaseType != Context.ObjCClassRedefinitionType) {
+ BaseType = Context.ObjCClassRedefinitionType;
+ ImpCastExprToType(BaseExpr, BaseType);
+ }
+
// Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
// must have pointer type, and the accessed type is the pointee.
if (OpKind == tok::arrow) {
- if (BaseType->isDependentType())
- return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
- BaseExpr, true,
- OpLoc,
- DeclarationName(&Member),
- MemberLoc));
- else if (const PointerType *PT = BaseType->getAsPointerType())
+ if (BaseType->isDependentType()) {
+ NestedNameSpecifier *Qualifier = 0;
+ if (SS) {
+ Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ if (!FirstQualifierInScope)
+ FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
+ }
+
+ return Owned(CXXUnresolvedMemberExpr::Create(Context, BaseExpr, true,
+ OpLoc, Qualifier,
+ SS? SS->getRange() : SourceRange(),
+ FirstQualifierInScope,
+ MemberName,
+ MemberLoc,
+ HasExplicitTemplateArgs,
+ LAngleLoc,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ RAngleLoc));
+ }
+ else if (const PointerType *PT = BaseType->getAs<PointerType>())
BaseType = PT->getPointeeType();
- else if (getLangOptions().CPlusPlus && BaseType->isRecordType())
- return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc,
- MemberLoc, Member));
+ else if (BaseType->isObjCObjectPointerType())
+ ;
else
return ExprError(Diag(MemberLoc,
diag::err_typecheck_member_reference_arrow)
<< BaseType << BaseExpr->getSourceRange());
- } else {
- if (BaseType->isDependentType()) {
- // Require that the base type isn't a pointer type
+ } else if (BaseType->isDependentType()) {
+ // Require that the base type isn't a pointer type
// (so we'll report an error for)
// T* t;
// t.f;
- //
+ //
// In Obj-C++, however, the above expression is valid, since it could be
// accessing the 'f' property if T is an Obj-C interface. The extra check
// allows this, while still reporting an error if T is a struct pointer.
- const PointerType *PT = BaseType->getAsPointerType();
+ const PointerType *PT = BaseType->getAs<PointerType>();
+
+ if (!PT || (getLangOptions().ObjC1 &&
+ !PT->getPointeeType()->isRecordType())) {
+ NestedNameSpecifier *Qualifier = 0;
+ if (SS) {
+ Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ if (!FirstQualifierInScope)
+ FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
+ }
- if (!PT || (getLangOptions().ObjC1 &&
- !PT->getPointeeType()->isRecordType()))
- return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
- BaseExpr, false,
- OpLoc,
- DeclarationName(&Member),
- MemberLoc));
+ return Owned(CXXUnresolvedMemberExpr::Create(Context,
+ BaseExpr, false,
+ OpLoc,
+ Qualifier,
+ SS? SS->getRange() : SourceRange(),
+ FirstQualifierInScope,
+ MemberName,
+ MemberLoc,
+ HasExplicitTemplateArgs,
+ LAngleLoc,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ RAngleLoc));
+ }
}
- }
// Handle field access to simple records. This also handles access to fields
// of the ObjC 'id' struct.
- if (const RecordType *RTy = BaseType->getAsRecordType()) {
+ if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
RecordDecl *RDecl = RTy->getDecl();
if (RequireCompleteType(OpLoc, BaseType,
- diag::err_typecheck_incomplete_tag,
- BaseExpr->getSourceRange()))
+ PDiag(diag::err_typecheck_incomplete_tag)
+ << BaseExpr->getSourceRange()))
return ExprError();
+ DeclContext *DC = RDecl;
+ if (SS && SS->isSet()) {
+ // If the member name was a qualified-id, look into the
+ // nested-name-specifier.
+ DC = computeDeclContext(*SS, false);
+
+ // FIXME: If DC is not computable, we should build a
+ // CXXUnresolvedMemberExpr.
+ assert(DC && "Cannot handle non-computable dependent contexts in lookup");
+ }
+
// The record definition is complete, now make sure the member is valid.
- // FIXME: Qualified name lookup for C++ is a bit more complicated than this.
- LookupResult Result
- = LookupQualifiedName(RDecl, DeclarationName(&Member),
- LookupMemberName, false);
-
- if (!Result)
- return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member)
- << &Member << BaseExpr->getSourceRange());
+ LookupResult Result;
+ LookupQualifiedName(Result, DC, MemberName, LookupMemberName, false);
+
+ if (Result.empty())
+ return ExprError(Diag(MemberLoc, diag::err_no_member)
+ << MemberName << DC << BaseExpr->getSourceRange());
if (Result.isAmbiguous()) {
- DiagnoseAmbiguousLookup(Result, DeclarationName(&Member),
- MemberLoc, BaseExpr->getSourceRange());
+ DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc,
+ BaseExpr->getSourceRange());
return ExprError();
}
-
- NamedDecl *MemberDecl = Result;
+
+ NamedDecl *MemberDecl = Result.getAsSingleDecl(Context);
+
+ if (SS && SS->isSet()) {
+ TypeDecl* TyD = cast<TypeDecl>(MemberDecl->getDeclContext());
+ QualType BaseTypeCanon
+ = Context.getCanonicalType(BaseType).getUnqualifiedType();
+ QualType MemberTypeCanon
+ = Context.getCanonicalType(Context.getTypeDeclType(TyD));
+
+ if (BaseTypeCanon != MemberTypeCanon &&
+ !IsDerivedFrom(BaseTypeCanon, MemberTypeCanon))
+ return ExprError(Diag(SS->getBeginLoc(),
+ diag::err_not_direct_base_or_virtual)
+ << MemberTypeCanon << BaseTypeCanon);
+ }
// If the decl being referenced had an error, return an error for this
// sub-expr without emitting another error, in order to avoid cascading
@@ -2149,8 +2225,16 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
if (MemberDecl->isInvalidDecl())
return ExprError();
+ bool ShouldCheckUse = true;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ // Don't diagnose the use of a virtual member function unless it's
+ // explicitly qualified.
+ if (MD->isVirtual() && (!SS || !SS->isSet()))
+ ShouldCheckUse = false;
+ }
+
// Check the use of this field
- if (DiagnoseUseOfDecl(MemberDecl, MemberLoc))
+ if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc))
return ExprError();
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
@@ -2161,137 +2245,253 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
BaseExpr, OpLoc);
// Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
- // FIXME: Handle address space modifiers
QualType MemberType = FD->getType();
- if (const ReferenceType *Ref = MemberType->getAsReferenceType())
+ if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>())
MemberType = Ref->getPointeeType();
else {
- unsigned combinedQualifiers =
- MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
- if (FD->isMutable())
- combinedQualifiers &= ~QualType::Const;
- MemberType = MemberType.getQualifiedType(combinedQualifiers);
+ Qualifiers BaseQuals = BaseType.getQualifiers();
+ BaseQuals.removeObjCGCAttr();
+ if (FD->isMutable()) BaseQuals.removeConst();
+
+ Qualifiers MemberQuals
+ = Context.getCanonicalType(MemberType).getQualifiers();
+
+ Qualifiers Combined = BaseQuals + MemberQuals;
+ if (Combined != MemberQuals)
+ MemberType = Context.getQualifiedType(MemberType, Combined);
}
MarkDeclarationReferenced(MemberLoc, FD);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD,
- MemberLoc, MemberType));
+ if (PerformObjectMemberConversion(BaseExpr, FD))
+ return ExprError();
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ FD, MemberLoc, MemberType));
}
-
+
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
- Var, MemberLoc,
- Var->getType().getNonReferenceType()));
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ Var, MemberLoc,
+ Var->getType().getNonReferenceType()));
}
if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
- MemberFn, MemberLoc,
- MemberFn->getType()));
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ MemberFn, MemberLoc,
+ MemberFn->getType()));
+ }
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+
+ if (HasExplicitTemplateArgs)
+ return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
+ (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+ SS? SS->getRange() : SourceRange(),
+ FunTmpl, MemberLoc, true,
+ LAngleLoc, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs, RAngleLoc,
+ Context.OverloadTy));
+
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ FunTmpl, MemberLoc,
+ Context.OverloadTy));
}
if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(MemberDecl))
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl,
- MemberLoc, Context.OverloadTy));
+ = dyn_cast<OverloadedFunctionDecl>(MemberDecl)) {
+ if (HasExplicitTemplateArgs)
+ return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
+ (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+ SS? SS->getRange() : SourceRange(),
+ Ovl, MemberLoc, true,
+ LAngleLoc, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs, RAngleLoc,
+ Context.OverloadTy));
+
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ Ovl, MemberLoc, Context.OverloadTy));
+ }
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
- Enum, MemberLoc, Enum->getType()));
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ Enum, MemberLoc, Enum->getType()));
}
if (isa<TypeDecl>(MemberDecl))
return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
- << DeclarationName(&Member) << int(OpKind == tok::arrow));
+ << MemberName << int(OpKind == tok::arrow));
// We found a declaration kind that we didn't expect. This is a
// generic error message that tells the user that she can't refer
// to this member with '.' or '->'.
return ExprError(Diag(MemberLoc,
diag::err_typecheck_member_reference_unknown)
- << DeclarationName(&Member) << int(OpKind == tok::arrow));
+ << MemberName << int(OpKind == tok::arrow));
+ }
+
+ // Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring
+ // into a record type was handled above, any destructor we see here is a
+ // pseudo-destructor.
+ if (MemberName.getNameKind() == DeclarationName::CXXDestructorName) {
+ // C++ [expr.pseudo]p2:
+ // The left hand side of the dot operator shall be of scalar type. The
+ // left hand side of the arrow operator shall be of pointer to scalar
+ // type.
+ if (!BaseType->isScalarType())
+ return Owned(Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
+ << BaseType << BaseExpr->getSourceRange());
+
+ // [...] The type designated by the pseudo-destructor-name shall be the
+ // same as the object type.
+ if (!MemberName.getCXXNameType()->isDependentType() &&
+ !Context.hasSameUnqualifiedType(BaseType, MemberName.getCXXNameType()))
+ return Owned(Diag(OpLoc, diag::err_pseudo_dtor_type_mismatch)
+ << BaseType << MemberName.getCXXNameType()
+ << BaseExpr->getSourceRange() << SourceRange(MemberLoc));
+
+ // [...] Furthermore, the two type-names in a pseudo-destructor-name of
+ // the form
+ //
+ // ::[opt] nested-name-specifier[opt] type-name :: ̃ type-name
+ //
+ // shall designate the same scalar type.
+ //
+ // FIXME: DPG can't see any way to trigger this particular clause, so it
+ // isn't checked here.
+
+ // FIXME: We've lost the precise spelling of the type by going through
+ // DeclarationName. Can we do better?
+ return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr,
+ OpKind == tok::arrow,
+ OpLoc,
+ (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+ SS? SS->getRange() : SourceRange(),
+ MemberName.getCXXNameType(),
+ MemberLoc));
}
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
// (*Obj).ivar.
- if (const ObjCInterfaceType *IFTy = BaseType->getAsObjCInterfaceType()) {
- ObjCInterfaceDecl *ClassDeclared;
- if (ObjCIvarDecl *IV = IFTy->getDecl()->lookupInstanceVariable(&Member,
- ClassDeclared)) {
- // If the decl being referenced had an error, return an error for this
- // sub-expr without emitting another error, in order to avoid cascading
- // error cases.
- if (IV->isInvalidDecl())
- return ExprError();
+ if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) ||
+ (OpKind == tok::period && BaseType->isObjCInterfaceType())) {
+ const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>();
+ const ObjCInterfaceType *IFaceT =
+ OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>();
+ if (IFaceT) {
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+
+ ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
+ ObjCInterfaceDecl *ClassDeclared;
+ ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
- // Check whether we can reference this field.
- if (DiagnoseUseOfDecl(IV, MemberLoc))
- return ExprError();
- if (IV->getAccessControl() != ObjCIvarDecl::Public &&
- IV->getAccessControl() != ObjCIvarDecl::Package) {
- ObjCInterfaceDecl *ClassOfMethodDecl = 0;
- if (ObjCMethodDecl *MD = getCurMethodDecl())
- ClassOfMethodDecl = MD->getClassInterface();
- else if (ObjCImpDecl && getCurFunctionDecl()) {
- // Case of a c-function declared inside an objc implementation.
- // FIXME: For a c-style function nested inside an objc implementation
- // class, there is no implementation context available, so we pass
- // down the context as argument to this routine. Ideally, this context
- // need be passed down in the AST node and somehow calculated from the
- // AST for a function decl.
- Decl *ImplDecl = ObjCImpDecl.getAs<Decl>();
- if (ObjCImplementationDecl *IMPD =
- dyn_cast<ObjCImplementationDecl>(ImplDecl))
- ClassOfMethodDecl = IMPD->getClassInterface();
- else if (ObjCCategoryImplDecl* CatImplClass =
- dyn_cast<ObjCCategoryImplDecl>(ImplDecl))
- ClassOfMethodDecl = CatImplClass->getClassInterface();
- }
-
- if (IV->getAccessControl() == ObjCIvarDecl::Private) {
- if (ClassDeclared != IFTy->getDecl() ||
- ClassOfMethodDecl != ClassDeclared)
- Diag(MemberLoc, diag::error_private_ivar_access) << IV->getDeclName();
+ if (IV) {
+ // If the decl being referenced had an error, return an error for this
+ // sub-expr without emitting another error, in order to avoid cascading
+ // error cases.
+ if (IV->isInvalidDecl())
+ return ExprError();
+
+ // Check whether we can reference this field.
+ if (DiagnoseUseOfDecl(IV, MemberLoc))
+ return ExprError();
+ if (IV->getAccessControl() != ObjCIvarDecl::Public &&
+ IV->getAccessControl() != ObjCIvarDecl::Package) {
+ ObjCInterfaceDecl *ClassOfMethodDecl = 0;
+ if (ObjCMethodDecl *MD = getCurMethodDecl())
+ ClassOfMethodDecl = MD->getClassInterface();
+ else if (ObjCImpDecl && getCurFunctionDecl()) {
+ // Case of a c-function declared inside an objc implementation.
+ // FIXME: For a c-style function nested inside an objc implementation
+ // class, there is no implementation context available, so we pass
+ // down the context as argument to this routine. Ideally, this context
+ // need be passed down in the AST node and somehow calculated from the
+ // AST for a function decl.
+ Decl *ImplDecl = ObjCImpDecl.getAs<Decl>();
+ if (ObjCImplementationDecl *IMPD =
+ dyn_cast<ObjCImplementationDecl>(ImplDecl))
+ ClassOfMethodDecl = IMPD->getClassInterface();
+ else if (ObjCCategoryImplDecl* CatImplClass =
+ dyn_cast<ObjCCategoryImplDecl>(ImplDecl))
+ ClassOfMethodDecl = CatImplClass->getClassInterface();
+ }
+
+ if (IV->getAccessControl() == ObjCIvarDecl::Private) {
+ if (ClassDeclared != IDecl ||
+ ClassOfMethodDecl != ClassDeclared)
+ Diag(MemberLoc, diag::error_private_ivar_access)
+ << IV->getDeclName();
+ } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
+ // @protected
+ Diag(MemberLoc, diag::error_protected_ivar_access)
+ << IV->getDeclName();
}
- // @protected
- else if (!IFTy->getDecl()->isSuperClassOf(ClassOfMethodDecl))
- Diag(MemberLoc, diag::error_protected_ivar_access) << IV->getDeclName();
- }
- return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc, BaseExpr,
- OpKind == tok::arrow));
+ return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ MemberLoc, BaseExpr,
+ OpKind == tok::arrow));
+ }
+ return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
+ << IDecl->getDeclName() << MemberName
+ << BaseExpr->getSourceRange());
}
- return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
- << IFTy->getDecl()->getDeclName() << &Member
- << BaseExpr->getSourceRange());
}
+ // Handle properties on 'id' and qualified "id".
+ if (OpKind == tok::period && (BaseType->isObjCIdType() ||
+ BaseType->isObjCQualifiedIdType())) {
+ const ObjCObjectPointerType *QIdTy = BaseType->getAs<ObjCObjectPointerType>();
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+ // Check protocols on qualified interfaces.
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) {
+ if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
+ // Check the use of this declaration
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ MemberLoc, BaseExpr));
+ }
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
+ // Check the use of this method.
+ if (DiagnoseUseOfDecl(OMD, MemberLoc))
+ return ExprError();
+
+ return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
+ OMD->getResultType(),
+ OMD, OpLoc, MemberLoc,
+ NULL, 0));
+ }
+ }
+
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType);
+ }
// Handle Objective-C property access, which is "Obj.property" where Obj is a
// pointer to a (potentially qualified) interface type.
- const PointerType *PTy;
- const ObjCInterfaceType *IFTy;
- if (OpKind == tok::period && (PTy = BaseType->getAsPointerType()) &&
- (IFTy = PTy->getPointeeType()->getAsObjCInterfaceType())) {
- ObjCInterfaceDecl *IFace = IFTy->getDecl();
+ const ObjCObjectPointerType *OPT;
+ if (OpKind == tok::period &&
+ (OPT = BaseType->getAsObjCInterfacePointerType())) {
+ const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
+ ObjCInterfaceDecl *IFace = IFaceT->getDecl();
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
// Search for a declared property first.
- if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(&Member)) {
+ if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
QualType ResTy = PD->getType();
- Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
ResTy = Getter->getResultType();
return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
MemberLoc, BaseExpr));
}
-
// Check protocols on qualified interfaces.
- for (ObjCInterfaceType::qual_iterator I = IFTy->qual_begin(),
- E = IFTy->qual_end(); I != E; ++I)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
@@ -2299,27 +2499,32 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
MemberLoc, BaseExpr));
}
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
+ // Check whether we can reference this property.
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ MemberLoc, BaseExpr));
+ }
// If that failed, look for an "implicit" property by seeing if the nullary
// selector is implemented.
// FIXME: The logic for looking up nullary and unary selectors should be
// shared with the code in ActOnInstanceMessage.
- Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
// If this reference is in an @implementation, check for 'private' methods.
if (!Getter)
- Getter = FindMethodInNestedImplementations(IFace, Sel);
+ Getter = IFace->lookupPrivateInstanceMethod(Sel);
// Look through local category implementations associated with the class.
- if (!Getter) {
- for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Getter; i++) {
- if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
- Getter = ObjCCategoryImpls[i]->getInstanceMethod(Sel);
- }
- }
+ if (!Getter)
+ Getter = IFace->getCategoryInstanceMethod(Sel);
if (Getter) {
// Check if we can reference this property.
if (DiagnoseUseOfDecl(Getter, MemberLoc))
@@ -2327,22 +2532,18 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
}
// If we found a getter then this may be a valid dot-reference, we
// will look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), &Member);
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
if (!Setter) {
// If this reference is in an @implementation, also check for 'private'
// methods.
- Setter = FindMethodInNestedImplementations(IFace, SetterSel);
+ Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
}
// Look through local category implementations associated with the class.
- if (!Setter) {
- for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
- if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
- Setter = ObjCCategoryImpls[i]->getInstanceMethod(SetterSel);
- }
- }
+ if (!Setter)
+ Setter = IFace->getCategoryInstanceMethod(SetterSel);
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
@@ -2352,107 +2553,31 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
if (Getter)
PType = Getter->getResultType();
- else {
- for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
- E = Setter->param_end(); PI != E; ++PI)
- PType = (*PI)->getType();
- }
+ else
+ // Get the expression type from Setter's incoming parameter.
+ PType = (*(Setter->param_end() -1))->getType();
// FIXME: we must check that the setter has property type.
- return Owned(new (Context) ObjCKVCRefExpr(Getter, PType,
+ return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
Setter, MemberLoc, BaseExpr));
}
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << &Member << BaseType);
- }
- // Handle properties on qualified "id" protocols.
- const ObjCObjectPointerType *QIdTy;
- if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) {
- // Check protocols on qualified interfaces.
- Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
- if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) {
- if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
- // Check the use of this declaration
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
-
- return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
- MemberLoc, BaseExpr));
- }
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
- // Check the use of this method.
- if (DiagnoseUseOfDecl(OMD, MemberLoc))
- return ExprError();
-
- return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
- OMD->getResultType(),
- OMD, OpLoc, MemberLoc,
- NULL, 0));
- }
- }
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << &Member << BaseType);
+ << MemberName << BaseType);
}
- // Handle properties on ObjC 'Class' types.
- if (OpKind == tok::period && (BaseType == Context.getObjCClassType())) {
- // Also must look for a getter name which uses property syntax.
- Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
- if (ObjCMethodDecl *MD = getCurMethodDecl()) {
- ObjCInterfaceDecl *IFace = MD->getClassInterface();
- ObjCMethodDecl *Getter;
- // FIXME: need to also look locally in the implementation.
- if ((Getter = IFace->lookupClassMethod(Sel))) {
- // Check the use of this method.
- if (DiagnoseUseOfDecl(Getter, MemberLoc))
- return ExprError();
- }
- // If we found a getter then this may be a valid dot-reference, we
- // will look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), &Member);
- ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
- if (!Setter) {
- // If this reference is in an @implementation, also check for 'private'
- // methods.
- Setter = FindMethodInNestedImplementations(IFace, SetterSel);
- }
- // Look through local category implementations associated with the class.
- if (!Setter) {
- for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
- if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
- Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel);
- }
- }
- if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
- return ExprError();
+ // Handle the following exceptional case (*Obj).isa.
+ if (OpKind == tok::period &&
+ BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) &&
+ MemberName.getAsIdentifierInfo()->isStr("isa"))
+ return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc,
+ Context.getObjCIdType()));
- if (Getter || Setter) {
- QualType PType;
-
- if (Getter)
- PType = Getter->getResultType();
- else {
- for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
- E = Setter->param_end(); PI != E; ++PI)
- PType = (*PI)->getType();
- }
- // FIXME: we must check that the setter has property type.
- return Owned(new (Context) ObjCKVCRefExpr(Getter, PType,
- Setter, MemberLoc, BaseExpr));
- }
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << &Member << BaseType);
- }
- }
-
// Handle 'field access' to vectors, such as 'V.xx'.
if (BaseType->isExtVectorType()) {
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc);
if (ret.isNull())
return ExprError();
- return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, Member,
+ return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, *Member,
MemberLoc));
}
@@ -2462,10 +2587,10 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
// If the user is trying to apply -> or . to a function or function
// pointer, it's probably because they forgot parentheses to call
// the function. Suggest the addition of those parentheses.
- if (BaseType == Context.OverloadTy ||
+ if (BaseType == Context.OverloadTy ||
BaseType->isFunctionType() ||
- (BaseType->isPointerType() &&
- BaseType->getAsPointerType()->isFunctionType())) {
+ (BaseType->isPointerType() &&
+ BaseType->getAs<PointerType>()->isFunctionType())) {
SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
Diag(Loc, diag::note_member_reference_needs_call)
<< CodeModificationHint::CreateInsertion(Loc, "()");
@@ -2474,6 +2599,63 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return ExprError();
}
+Action::OwningExprResult
+Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
+ tok::TokenKind OpKind, SourceLocation MemberLoc,
+ IdentifierInfo &Member,
+ DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) {
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
+ DeclarationName(&Member), ObjCImpDecl, SS);
+}
+
+Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
+ FunctionDecl *FD,
+ ParmVarDecl *Param) {
+ if (Param->hasUnparsedDefaultArg()) {
+ Diag (CallLoc,
+ diag::err_use_of_default_argument_to_function_declared_later) <<
+ FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName();
+ Diag(UnparsedDefaultArgLocs[Param],
+ diag::note_default_argument_declared_here);
+ } else {
+ if (Param->hasUninstantiatedDefaultArg()) {
+ Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
+
+ // Instantiate the expression.
+ MultiLevelTemplateArgumentList ArgList = getTemplateInstantiationArgs(FD);
+
+ InstantiatingTemplate Inst(*this, CallLoc, Param,
+ ArgList.getInnermost().getFlatArgumentList(),
+ ArgList.getInnermost().flat_size());
+
+ OwningExprResult Result = SubstExpr(UninstExpr, ArgList);
+ if (Result.isInvalid())
+ return ExprError();
+
+ if (SetParamDefaultArgument(Param, move(Result),
+ /*FIXME:EqualLoc*/
+ UninstExpr->getSourceRange().getBegin()))
+ return ExprError();
+ }
+
+ Expr *DefaultExpr = Param->getDefaultArg();
+
+ // If the default expression creates temporaries, we need to
+ // push them to the current stack of expression temporaries so they'll
+ // be properly destroyed.
+ if (CXXExprWithTemporaries *E
+ = dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) {
+ assert(!E->shouldDestroyTemporaries() &&
+ "Can't destroy temporaries in a default argument expr!");
+ for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I)
+ ExprTemporaries.push_back(E->getTemporary(I));
+ }
+ }
+
+ // We already type-checked the argument, so we know it works.
+ return Owned(CXXDefaultArgExpr::Create(Context, Param));
+}
+
/// ConvertArgumentsForCall - Converts the arguments specified in
/// Args/NumArgs to the parameter types of the function FDecl with
/// function prototype Proto. Call is the call expression itself, and
@@ -2529,40 +2711,24 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
ProtoArgType,
- diag::err_call_incomplete_argument,
- Arg->getSourceRange()))
+ PDiag(diag::err_call_incomplete_argument)
+ << Arg->getSourceRange()))
return true;
// Pass the argument.
if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
return true;
} else {
- if (FDecl->getParamDecl(i)->hasUnparsedDefaultArg()) {
- Diag (Call->getSourceRange().getBegin(),
- diag::err_use_of_default_argument_to_function_declared_later) <<
- FDecl << cast<CXXRecordDecl>(FDecl->getDeclContext())->getDeclName();
- Diag(UnparsedDefaultArgLocs[FDecl->getParamDecl(i)],
- diag::note_default_argument_declared_here);
- } else {
- Expr *DefaultExpr = FDecl->getParamDecl(i)->getDefaultArg();
-
- // If the default expression creates temporaries, we need to
- // push them to the current stack of expression temporaries so they'll
- // be properly destroyed.
- if (CXXExprWithTemporaries *E
- = dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) {
- assert(!E->shouldDestroyTemporaries() &&
- "Can't destroy temporaries in a default argument expr!");
- for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I)
- ExprTemporaries.push_back(E->getTemporary(I));
- }
- }
-
- // We already type-checked the argument, so we know it works.
- Arg = new (Context) CXXDefaultArgExpr(FDecl->getParamDecl(i));
+ ParmVarDecl *Param = FDecl->getParamDecl(i);
+
+ OwningExprResult ArgExpr =
+ BuildCXXDefaultArgExpr(Call->getSourceRange().getBegin(),
+ FDecl, Param);
+ if (ArgExpr.isInvalid())
+ return true;
+
+ Arg = ArgExpr.takeAs<Expr>();
}
-
- QualType ArgType = Arg->getType();
Call->setArg(i, Arg);
}
@@ -2586,6 +2752,96 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
return Invalid;
}
+/// \brief "Deconstruct" the function argument of a call expression to find
+/// the underlying declaration (if any), the name of the called function,
+/// whether argument-dependent lookup is available, whether it has explicit
+/// template arguments, etc.
+void Sema::DeconstructCallFunction(Expr *FnExpr,
+ NamedDecl *&Function,
+ DeclarationName &Name,
+ NestedNameSpecifier *&Qualifier,
+ SourceRange &QualifierRange,
+ bool &ArgumentDependentLookup,
+ bool &HasExplicitTemplateArguments,
+ const TemplateArgument *&ExplicitTemplateArgs,
+ unsigned &NumExplicitTemplateArgs) {
+ // Set defaults for all of the output parameters.
+ Function = 0;
+ Name = DeclarationName();
+ Qualifier = 0;
+ QualifierRange = SourceRange();
+ ArgumentDependentLookup = getLangOptions().CPlusPlus;
+ HasExplicitTemplateArguments = false;
+
+ // If we're directly calling a function, get the appropriate declaration.
+ // Also, in C++, keep track of whether we should perform argument-dependent
+ // lookup and whether there were any explicitly-specified template arguments.
+ while (true) {
+ if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
+ FnExpr = IcExpr->getSubExpr();
+ else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
+ // Parentheses around a function disable ADL
+ // (C++0x [basic.lookup.argdep]p1).
+ ArgumentDependentLookup = false;
+ FnExpr = PExpr->getSubExpr();
+ } else if (isa<UnaryOperator>(FnExpr) &&
+ cast<UnaryOperator>(FnExpr)->getOpcode()
+ == UnaryOperator::AddrOf) {
+ FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
+ } else if (QualifiedDeclRefExpr *QDRExpr
+ = dyn_cast<QualifiedDeclRefExpr>(FnExpr)) {
+ // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
+ ArgumentDependentLookup = false;
+ Qualifier = QDRExpr->getQualifier();
+ QualifierRange = QDRExpr->getQualifierRange();
+ Function = dyn_cast<NamedDecl>(QDRExpr->getDecl());
+ break;
+ } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
+ Function = dyn_cast<NamedDecl>(DRExpr->getDecl());
+ break;
+ } else if (UnresolvedFunctionNameExpr *DepName
+ = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
+ Name = DepName->getName();
+ break;
+ } else if (TemplateIdRefExpr *TemplateIdRef
+ = dyn_cast<TemplateIdRefExpr>(FnExpr)) {
+ Function = TemplateIdRef->getTemplateName().getAsTemplateDecl();
+ if (!Function)
+ Function = TemplateIdRef->getTemplateName().getAsOverloadedFunctionDecl();
+ HasExplicitTemplateArguments = true;
+ ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs();
+ NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs();
+
+ // C++ [temp.arg.explicit]p6:
+ // [Note: For simple function names, argument dependent lookup (3.4.2)
+ // applies even when the function name is not visible within the
+ // scope of the call. This is because the call still has the syntactic
+ // form of a function call (3.4.1). But when a function template with
+ // explicit template arguments is used, the call does not have the
+ // correct syntactic form unless there is a function template with
+ // that name visible at the point of the call. If no such name is
+ // visible, the call is not syntactically well-formed and
+ // argument-dependent lookup does not apply. If some such name is
+ // visible, argument dependent lookup applies and additional function
+ // templates may be found in other namespaces.
+ //
+ // The summary of this paragraph is that, if we get to this point and the
+ // template-id was not a qualified name, then argument-dependent lookup
+ // is still possible.
+ if ((Qualifier = TemplateIdRef->getQualifier())) {
+ ArgumentDependentLookup = false;
+ QualifierRange = TemplateIdRef->getQualifierRange();
+ }
+ break;
+ } else {
+ // Any kind of name that does not refer to a declaration (or
+ // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3).
+ ArgumentDependentLookup = false;
+ break;
+ }
+ }
+}
+
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
@@ -2594,6 +2850,10 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
MultiExprArg args,
SourceLocation *CommaLocs, SourceLocation RParenLoc) {
unsigned NumArgs = args.size();
+
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ fn = MaybeConvertParenListExprToParenExpr(S, move(fn));
+
Expr *Fn = fn.takeAs<Expr>();
Expr **Args = reinterpret_cast<Expr**>(args.release());
assert(Fn && "no function call expression");
@@ -2602,6 +2862,25 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
DeclarationName UnqualifiedName;
if (getLangOptions().CPlusPlus) {
+ // If this is a pseudo-destructor expression, build the call immediately.
+ if (isa<CXXPseudoDestructorExpr>(Fn)) {
+ if (NumArgs > 0) {
+ // Pseudo-destructor calls should not have any arguments.
+ Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args)
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(Args[0]->getLocStart(),
+ Args[NumArgs-1]->getLocEnd()));
+
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Destroy(Context);
+
+ NumArgs = 0;
+ }
+
+ return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy,
+ RParenLoc));
+ }
+
// Determine whether this is a dependent call inside a C++ template,
// in which case we won't do any semantic analysis now.
// FIXME: Will need to cache the results of name lookup (including ADL) in
@@ -2632,70 +2911,42 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc));
}
+
+ // Determine whether this is a call to a pointer-to-member function.
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Fn->IgnoreParens())) {
+ if (BO->getOpcode() == BinaryOperator::PtrMemD ||
+ BO->getOpcode() == BinaryOperator::PtrMemI) {
+ const FunctionProtoType *FPT = cast<FunctionProtoType>(BO->getType());
+ QualType ReturnTy = FPT->getResultType();
+
+ CXXMemberCallExpr *CE =
+ new (Context) CXXMemberCallExpr(Context, BO, Args, NumArgs,
+ ReturnTy.getNonReferenceType(),
+ RParenLoc);
+
+ ExprOwningPtr<CXXMemberCallExpr> TheCall(this, CE);
+
+ if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs,
+ RParenLoc))
+ return ExprError();
+
+ return Owned(MaybeBindToTemporary(TheCall.release()).release());
+ }
+ }
}
// If we're directly calling a function, get the appropriate declaration.
- // Also, in C++, keep track of whether we should perform argument-dependent
+ // Also, in C++, keep track of whether we should perform argument-dependent
// lookup and whether there were any explicitly-specified template arguments.
- Expr *FnExpr = Fn;
bool ADL = true;
bool HasExplicitTemplateArgs = 0;
const TemplateArgument *ExplicitTemplateArgs = 0;
unsigned NumExplicitTemplateArgs = 0;
- while (true) {
- if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
- FnExpr = IcExpr->getSubExpr();
- else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
- // Parentheses around a function disable ADL
- // (C++0x [basic.lookup.argdep]p1).
- ADL = false;
- FnExpr = PExpr->getSubExpr();
- } else if (isa<UnaryOperator>(FnExpr) &&
- cast<UnaryOperator>(FnExpr)->getOpcode()
- == UnaryOperator::AddrOf) {
- FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
- } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
- // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
- ADL &= !isa<QualifiedDeclRefExpr>(DRExpr);
- NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
- break;
- } else if (UnresolvedFunctionNameExpr *DepName
- = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
- UnqualifiedName = DepName->getName();
- break;
- } else if (TemplateIdRefExpr *TemplateIdRef
- = dyn_cast<TemplateIdRefExpr>(FnExpr)) {
- NDecl = TemplateIdRef->getTemplateName().getAsTemplateDecl();
- HasExplicitTemplateArgs = true;
- ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs();
- NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs();
-
- // C++ [temp.arg.explicit]p6:
- // [Note: For simple function names, argument dependent lookup (3.4.2)
- // applies even when the function name is not visible within the
- // scope of the call. This is because the call still has the syntactic
- // form of a function call (3.4.1). But when a function template with
- // explicit template arguments is used, the call does not have the
- // correct syntactic form unless there is a function template with
- // that name visible at the point of the call. If no such name is
- // visible, the call is not syntactically well-formed and
- // argument-dependent lookup does not apply. If some such name is
- // visible, argument dependent lookup applies and additional function
- // templates may be found in other namespaces.
- //
- // The summary of this paragraph is that, if we get to this point and the
- // template-id was not a qualified name, then argument-dependent lookup
- // is still possible.
- if (TemplateIdRef->getQualifier())
- ADL = false;
- break;
- } else {
- // Any kind of name that does not refer to a declaration (or
- // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3).
- ADL = false;
- break;
- }
- }
+ NestedNameSpecifier *Qualifier = 0;
+ SourceRange QualifierRange;
+ DeconstructCallFunction(Fn, NDecl, UnqualifiedName, Qualifier, QualifierRange,
+ ADL,HasExplicitTemplateArgs, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs);
OverloadedFunctionDecl *Ovl = 0;
FunctionTemplateDecl *FunctionTemplate = 0;
@@ -2708,10 +2959,10 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
Ovl = dyn_cast<OverloadedFunctionDecl>(NDecl);
}
- if (Ovl || FunctionTemplate ||
+ if (Ovl || FunctionTemplate ||
(getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
// We don't perform ADL for implicit declarations of builtins.
- if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit())
+ if (FDecl && FDecl->getBuiltinID() && FDecl->isImplicit())
ADL = false;
// We don't perform ADL in C.
@@ -2719,27 +2970,26 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
ADL = false;
if (Ovl || FunctionTemplate || ADL) {
- FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName,
+ FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName,
HasExplicitTemplateArgs,
ExplicitTemplateArgs,
NumExplicitTemplateArgs,
- LParenLoc, Args, NumArgs, CommaLocs,
+ LParenLoc, Args, NumArgs, CommaLocs,
RParenLoc, ADL);
if (!FDecl)
return ExprError();
// Update Fn to refer to the actual function selected.
Expr *NewFn = 0;
- if (QualifiedDeclRefExpr *QDRExpr
- = dyn_cast<QualifiedDeclRefExpr>(FnExpr))
+ if (Qualifier)
NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
- QDRExpr->getLocation(),
+ Fn->getLocStart(),
false, false,
- QDRExpr->getQualifierRange(),
- QDRExpr->getQualifier());
+ QualifierRange,
+ Qualifier);
else
NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(),
- Fn->getSourceRange().getBegin());
+ Fn->getLocStart());
Fn->Destroy(Context);
Fn = NewFn;
}
@@ -2759,25 +3009,23 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
if (!Fn->getType()->isBlockPointerType()) {
// C99 6.5.2.2p1 - "The expression that denotes the called function shall
// have type pointer to function".
- const PointerType *PT = Fn->getType()->getAsPointerType();
+ const PointerType *PT = Fn->getType()->getAs<PointerType>();
if (PT == 0)
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
<< Fn->getType() << Fn->getSourceRange());
- FuncT = PT->getPointeeType()->getAsFunctionType();
+ FuncT = PT->getPointeeType()->getAs<FunctionType>();
} else { // This is a block call.
- FuncT = Fn->getType()->getAsBlockPointerType()->getPointeeType()->
- getAsFunctionType();
+ FuncT = Fn->getType()->getAs<BlockPointerType>()->getPointeeType()->
+ getAs<FunctionType>();
}
if (FuncT == 0)
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
<< Fn->getType() << Fn->getSourceRange());
// Check for a valid return type
- if (!FuncT->getResultType()->isVoidType() &&
- RequireCompleteType(Fn->getSourceRange().getBegin(),
- FuncT->getResultType(),
- diag::err_call_incomplete_return,
- TheCall->getSourceRange()))
+ if (CheckCallReturnType(FuncT->getResultType(),
+ Fn->getSourceRange().getBegin(), TheCall.get(),
+ FDecl))
return ExprError();
// We know the result type of the call, set it.
@@ -2796,7 +3044,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
const FunctionDecl *Def = 0;
if (FDecl->getBody(Def) && NumArgs != Def->param_size()) {
const FunctionProtoType *Proto =
- Def->getType()->getAsFunctionProtoType();
+ Def->getType()->getAs<FunctionProtoType>();
if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size())) {
Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
<< (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
@@ -2810,8 +3058,8 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
DefaultArgumentPromotion(Arg);
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
Arg->getType(),
- diag::err_call_incomplete_argument,
- Arg->getSourceRange()))
+ PDiag(diag::err_call_incomplete_argument)
+ << Arg->getSourceRange()))
return ExprError();
TheCall->setArg(i, Arg);
}
@@ -2825,20 +3073,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
// Check for sentinels
if (NDecl)
DiagnoseSentinelCalls(NDecl, LParenLoc, Args, NumArgs);
+
// Do special checking on direct calls to functions.
- if (FDecl)
- return CheckFunctionCall(FDecl, TheCall.take());
- if (NDecl)
- return CheckBlockCall(NDecl, TheCall.take());
+ if (FDecl) {
+ if (CheckFunctionCall(FDecl, TheCall.get()))
+ return ExprError();
- return Owned(TheCall.take());
+ if (unsigned BuiltinID = FDecl->getBuiltinID())
+ return CheckBuiltinFunctionCall(BuiltinID, TheCall.take());
+ } else if (NDecl) {
+ if (CheckBlockCall(NDecl, TheCall.get()))
+ return ExprError();
+ }
+
+ return MaybeBindToTemporary(TheCall.take());
}
Action::OwningExprResult
Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg InitExpr) {
assert((Ty != 0) && "ActOnCompoundLiteral(): missing type");
- QualType literalType = QualType::getFromOpaquePtr(Ty);
+ //FIXME: Preserve type source info.
+ QualType literalType = GetTypeFromParser(Ty);
// FIXME: put back this assert when initializers are worked out.
//assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
Expr *literalExpr = static_cast<Expr*>(InitExpr.get());
@@ -2849,8 +3105,9 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
<< SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()));
} else if (!literalType->isDependentType() &&
RequireCompleteType(LParenLoc, literalType,
- diag::err_typecheck_decl_incomplete_type,
- SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd())))
+ PDiag(diag::err_typecheck_decl_incomplete_type)
+ << SourceRange(LParenLoc,
+ literalExpr->getSourceRange().getEnd())))
return ExprError();
if (CheckInitializerTypes(literalExpr, literalType, LParenLoc,
@@ -2883,15 +3140,20 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
}
/// CheckCastTypes - Check type constraints for casting between types.
-bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
- UsualUnaryConversions(castExpr);
+bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
+ CastExpr::CastKind& Kind,
+ CXXMethodDecl *& ConversionDecl,
+ bool FunctionalStyle) {
+ if (getLangOptions().CPlusPlus)
+ return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle,
+ ConversionDecl);
+
+ DefaultFunctionArrayConversion(castExpr);
// C99 6.5.4p2: the cast type needs to be void or scalar and the expression
// type needs to be scalar.
if (castType->isVoidType()) {
// Cast to void allows any expr type.
- } else if (castType->isDependentType() || castExpr->isTypeDependent()) {
- // We can't check any more until template instantiation time.
} else if (!castType->isScalarType() && !castType->isVectorType()) {
if (Context.getCanonicalType(castType).getUnqualifiedType() ==
Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) &&
@@ -2900,9 +3162,10 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
// FIXME: Check that the cast destination type is complete.
Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar)
<< castType << castExpr->getSourceRange();
+ Kind = CastExpr::CK_NoOp;
} else if (castType->isUnionType()) {
// GCC cast to union extension
- RecordDecl *RD = castType->getAsRecordType()->getDecl();
+ RecordDecl *RD = castType->getAs<RecordType>()->getDecl();
RecordDecl::field_iterator Field, FieldEnd;
for (Field = RD->field_begin(), FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
@@ -2916,6 +3179,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
if (Field == FieldEnd)
return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type)
<< castExpr->getType() << castExpr->getSourceRange();
+ Kind = CastExpr::CK_ToUnion;
} else {
// Reject any other conversions to non-scalar types.
return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar)
@@ -2974,7 +3238,7 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) {
bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) {
assert(DestTy->isExtVectorType() && "Not an extended vector type!");
-
+
// If SrcTy is a VectorType, the total size must match to explicitly cast to
// an ExtVectorType.
if (SrcTy->isVectorType()) {
@@ -2995,20 +3259,104 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) {
}
Action::OwningExprResult
-Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg Op) {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+
assert((Ty != 0) && (Op.get() != 0) &&
"ActOnCastExpr(): missing type or expr");
- Expr *castExpr = Op.takeAs<Expr>();
- QualType castType = QualType::getFromOpaquePtr(Ty);
+ Expr *castExpr = (Expr *)Op.get();
+ //FIXME: Preserve type source info.
+ QualType castType = GetTypeFromParser(Ty);
- if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr))
+ // If the Expr being casted is a ParenListExpr, handle it specially.
+ if (isa<ParenListExpr>(castExpr))
+ return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),castType);
+ CXXMethodDecl *Method = 0;
+ if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr,
+ Kind, Method))
return ExprError();
- return Owned(new (Context) CStyleCastExpr(castType, castExpr, castType,
+
+ if (Method) {
+ OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, castType, Kind,
+ Method, move(Op));
+
+ if (CastArg.isInvalid())
+ return ExprError();
+
+ castExpr = CastArg.takeAs<Expr>();
+ } else {
+ Op.release();
+ }
+
+ return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(),
+ Kind, castExpr, castType,
LParenLoc, RParenLoc));
}
+/// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence
+/// of comma binary operators.
+Action::OwningExprResult
+Sema::MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg EA) {
+ Expr *expr = EA.takeAs<Expr>();
+ ParenListExpr *E = dyn_cast<ParenListExpr>(expr);
+ if (!E)
+ return Owned(expr);
+
+ OwningExprResult Result(*this, E->getExpr(0));
+
+ for (unsigned i = 1, e = E->getNumExprs(); i != e && !Result.isInvalid(); ++i)
+ Result = ActOnBinOp(S, E->getExprLoc(), tok::comma, move(Result),
+ Owned(E->getExpr(i)));
+
+ return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), move(Result));
+}
+
+Action::OwningExprResult
+Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
+ SourceLocation RParenLoc, ExprArg Op,
+ QualType Ty) {
+ ParenListExpr *PE = (ParenListExpr *)Op.get();
+
+ // If this is an altivec initializer, '(' type ')' '(' init, ..., init ')'
+ // then handle it as such.
+ if (getLangOptions().AltiVec && Ty->isVectorType()) {
+ if (PE->getNumExprs() == 0) {
+ Diag(PE->getExprLoc(), diag::err_altivec_empty_initializer);
+ return ExprError();
+ }
+
+ llvm::SmallVector<Expr *, 8> initExprs;
+ for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
+ initExprs.push_back(PE->getExpr(i));
+
+ // FIXME: This means that pretty-printing the final AST will produce curly
+ // braces instead of the original commas.
+ Op.release();
+ InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0],
+ initExprs.size(), RParenLoc);
+ E->setType(Ty);
+ return ActOnCompoundLiteral(LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,
+ Owned(E));
+ } else {
+ // This is not an AltiVec-style cast, so turn the ParenListExpr into a
+ // sequence of BinOp comma operators.
+ Op = MaybeConvertParenListExprToParenExpr(S, move(Op));
+ return ActOnCastExpr(S, LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,move(Op));
+ }
+}
+
+Action::OwningExprResult Sema::ActOnParenListExpr(SourceLocation L,
+ SourceLocation R,
+ MultiExprArg Val) {
+ unsigned nexprs = Val.size();
+ Expr **exprs = reinterpret_cast<Expr**>(Val.release());
+ assert((exprs != 0) && "ActOnParenListExpr() missing expr list");
+ Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
+ return Owned(expr);
+}
+
/// Note that lhs is not null here, even if this is the gnu "x ?: y" extension.
/// In that case, lhs = cond.
/// C99 6.5.15
@@ -3033,6 +3381,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
}
// Now check the two expressions.
+ if (LHSTy->isVectorType() || RHSTy->isVectorType())
+ return CheckVectorOperands(QuestionLoc, LHS, RHS);
// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
@@ -3043,8 +3393,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// If both operands are the same structure or union type, the result is that
// type.
- if (const RecordType *LHSRT = LHSTy->getAsRecordType()) { // C99 6.5.15p3
- if (const RecordType *RHSRT = RHSTy->getAsRecordType())
+ if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3
+ if (const RecordType *RHSRT = RHSTy->getAs<RecordType>())
if (LHSRT->getDecl() == RHSRT->getDecl())
// "If both the operands have structure or union type, the result has
// that type." This implies that CV qualifiers are dropped.
@@ -3067,24 +3417,46 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
}
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
// the type of the other operand."
- if ((LHSTy->isPointerType() || LHSTy->isBlockPointerType() ||
- Context.isObjCObjectPointerType(LHSTy)) &&
- RHS->isNullPointerConstant(Context)) {
+ if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) &&
+ RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer.
return LHSTy;
}
- if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() ||
- Context.isObjCObjectPointerType(RHSTy)) &&
- LHS->isNullPointerConstant(Context)) {
+ if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) &&
+ LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
return RHSTy;
}
+ // Handle things like Class and struct objc_class*. Here we case the result
+ // to the pseudo-builtin, because that will be implicitly cast back to the
+ // redefinition type if an attempt is made to access its fields.
+ if (LHSTy->isObjCClassType() &&
+ (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+ ImpCastExprToType(RHS, LHSTy);
+ return LHSTy;
+ }
+ if (RHSTy->isObjCClassType() &&
+ (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy);
+ return RHSTy;
+ }
+ // And the same for struct objc_object* / id
+ if (LHSTy->isObjCIdType() &&
+ (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+ ImpCastExprToType(RHS, LHSTy);
+ return LHSTy;
+ }
+ if (RHSTy->isObjCIdType() &&
+ (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy);
+ return RHSTy;
+ }
// Handle block pointer types.
if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) {
QualType destType = Context.getPointerType(Context.VoidTy);
- ImpCastExprToType(LHS, destType);
+ ImpCastExprToType(LHS, destType);
ImpCastExprToType(RHS, destType);
return destType;
}
@@ -3098,8 +3470,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
return LHSTy;
}
// The block pointer types aren't identical, continue checking.
- QualType lhptee = LHSTy->getAsBlockPointerType()->getPointeeType();
- QualType rhptee = RHSTy->getAsBlockPointerType()->getPointeeType();
+ QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType();
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType())) {
@@ -3118,48 +3490,17 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, LHSTy);
return LHSTy;
}
- // Need to handle "id<xx>" explicitly. Unlike "id", whose canonical type
- // evaluates to "struct objc_object *" (and is handled above when comparing
- // id with statically typed objects).
- if (LHSTy->isObjCQualifiedIdType() || RHSTy->isObjCQualifiedIdType()) {
- // GCC allows qualified id and any Objective-C type to devolve to
- // id. Currently localizing to here until clear this should be
- // part of ObjCQualifiedIdTypesAreCompatible.
- if (ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true) ||
- (LHSTy->isObjCQualifiedIdType() &&
- Context.isObjCObjectPointerType(RHSTy)) ||
- (RHSTy->isObjCQualifiedIdType() &&
- Context.isObjCObjectPointerType(LHSTy))) {
- // FIXME: This is not the correct composite type. This only happens to
- // work because id can more or less be used anywhere, however this may
- // change the type of method sends.
-
- // FIXME: gcc adds some type-checking of the arguments and emits
- // (confusing) incompatible comparison warnings in some
- // cases. Investigate.
- QualType compositeType = Context.getObjCIdType();
- ImpCastExprToType(LHS, compositeType);
- ImpCastExprToType(RHS, compositeType);
- return compositeType;
- }
- }
// Check constraints for Objective-C object pointers types.
- if (Context.isObjCObjectPointerType(LHSTy) &&
- Context.isObjCObjectPointerType(RHSTy)) {
-
+ if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) {
+
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
// Two identical object pointer types are always compatible.
return LHSTy;
}
- // No need to check for block pointer types or qualified id types (they
- // were handled above).
- assert((LHSTy->isPointerType() && RHSTy->isPointerType()) &&
- "Sema::CheckConditionalOperands(): Unexpected type");
- QualType lhptee = LHSTy->getAsPointerType()->getPointeeType();
- QualType rhptee = RHSTy->getAsPointerType()->getPointeeType();
-
+ const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>();
QualType compositeType = LHSTy;
-
+
// If both operands are interfaces and either operand can be
// assigned to the other, use that type as the composite
// type. This allows
@@ -3173,16 +3514,19 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
// It could return the composite type.
- const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
- const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
- if (LHSIface && RHSIface &&
- Context.canAssignObjCInterfaces(LHSIface, RHSIface)) {
- compositeType = LHSTy;
- } else if (LHSIface && RHSIface &&
- Context.canAssignObjCInterfaces(RHSIface, LHSIface)) {
- compositeType = RHSTy;
- } else if (Context.isObjCIdStructType(lhptee) ||
- Context.isObjCIdStructType(rhptee)) {
+ if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) {
+ compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy;
+ } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
+ compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy;
+ } else if ((LHSTy->isObjCQualifiedIdType() ||
+ RHSTy->isObjCQualifiedIdType()) &&
+ Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
+ // Need to handle "id<xx>" explicitly.
+ // GCC allows qualified id and any Objective-C type to devolve to
+ // id. Currently localizing to here until clear this should be
+ // part of ObjCQualifiedIdTypesAreCompatible.
+ compositeType = Context.getObjCIdType();
+ } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) {
compositeType = Context.getObjCIdType();
} else {
Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
@@ -3198,23 +3542,46 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, compositeType);
return compositeType;
}
+ // Check Objective-C object pointer types and 'void *'
+ if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) {
+ QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType destPointee
+ = Context.getQualifiedType(lhptee, rhptee.getQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ ImpCastExprToType(LHS, destType); // add qualifiers if necessary
+ ImpCastExprToType(RHS, destType); // promote to void*
+ return destType;
+ }
+ if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) {
+ QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+ QualType destPointee
+ = Context.getQualifiedType(rhptee, lhptee.getQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ ImpCastExprToType(RHS, destType); // add qualifiers if necessary
+ ImpCastExprToType(LHS, destType); // promote to void*
+ return destType;
+ }
// Check constraints for C object pointers types (C99 6.5.15p3,6).
if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
// get the "pointed to" types
- QualType lhptee = LHSTy->getAsPointerType()->getPointeeType();
- QualType rhptee = RHSTy->getAsPointerType()->getPointeeType();
+ QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
// ignore qualifiers on void (C99 6.5.15p3, clause 6)
if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
// Figure out necessary qualifiers (C99 6.5.15p6)
- QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers());
+ QualType destPointee
+ = Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
ImpCastExprToType(LHS, destType); // add qualifiers if necessary
ImpCastExprToType(RHS, destType); // promote to void*
return destType;
}
if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
- QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers());
+ QualType destPointee
+ = Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
ImpCastExprToType(LHS, destType); // add qualifiers if necessary
ImpCastExprToType(RHS, destType); // promote to void*
@@ -3248,7 +3615,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, LHSTy);
return LHSTy;
}
-
+
// GCC compatibility: soften pointer/integer mismatch.
if (RHSTy->isPointerType() && LHSTy->isIntegerType()) {
Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
@@ -3292,12 +3659,11 @@ Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
Cond.release();
LHS.release();
RHS.release();
- return Owned(new (Context) ConditionalOperator(CondExpr,
+ return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc,
isLHSNull ? 0 : LHSExpr,
- RHSExpr, result));
+ ColonLoc, RHSExpr, result));
}
-
// CheckPointerTypesForAssignment - This is a very tricky routine (despite
// being closely modeled after the C99 spec:-). The odd characteristic of this
// routine is it effectively iqnores the qualifiers on the top level pointee.
@@ -3307,9 +3673,16 @@ Sema::AssignConvertType
Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
QualType lhptee, rhptee;
+ if ((lhsType->isObjCClassType() &&
+ (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
+ (rhsType->isObjCClassType() &&
+ (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
+ return Compatible;
+ }
+
// get the "pointed to" type (ignoring qualifiers at the top level)
- lhptee = lhsType->getAsPointerType()->getPointeeType();
- rhptee = rhsType->getAsPointerType()->getPointeeType();
+ lhptee = lhsType->getAs<PointerType>()->getPointeeType();
+ rhptee = rhsType->getAs<PointerType>()->getPointeeType();
// make sure we operate on the canonical type
lhptee = Context.getCanonicalType(lhptee);
@@ -3371,7 +3744,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
return IncompatiblePointerSign;
}
// General pointer incompatibility takes priority over qualifiers.
- return IncompatiblePointer;
+ return IncompatiblePointer;
}
return ConvTy;
}
@@ -3386,8 +3759,8 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
QualType lhptee, rhptee;
// get the "pointed to" type (ignoring qualifiers at the top level)
- lhptee = lhsType->getAsBlockPointerType()->getPointeeType();
- rhptee = rhsType->getAsBlockPointerType()->getPointeeType();
+ lhptee = lhsType->getAs<BlockPointerType>()->getPointeeType();
+ rhptee = rhsType->getAs<BlockPointerType>()->getPointeeType();
// make sure we operate on the canonical type
lhptee = Context.getCanonicalType(lhptee);
@@ -3430,6 +3803,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
if (lhsType == rhsType)
return Compatible; // Common case: fast path an exact match.
+ if ((lhsType->isObjCClassType() &&
+ (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
+ (rhsType->isObjCClassType() &&
+ (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
+ return Compatible;
+ }
+
// If the left-hand side is a reference type, then we are in a
// (rare!) case where we've allowed the use of references in C,
// e.g., as a parameter type in a built-in function. In this case,
@@ -3437,23 +3817,11 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
// right-hand side type. The caller is responsible for adjusting
// lhsType so that the resulting expression does not have reference
// type.
- if (const ReferenceType *lhsTypeRef = lhsType->getAsReferenceType()) {
+ if (const ReferenceType *lhsTypeRef = lhsType->getAs<ReferenceType>()) {
if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType))
return Compatible;
return Incompatible;
}
-
- if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) {
- if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false))
- return Compatible;
- // Relax integer conversions like we do for pointers below.
- if (rhsType->isIntegerType())
- return IntToPointer;
- if (lhsType->isIntegerType())
- return PointerToInt;
- return IncompatibleObjCQualifiedId;
- }
-
// Allow scalar to ExtVector assignments, and assignments of an ExtVector type
// to the same ExtVector type.
if (lhsType->isExtVectorType()) {
@@ -3462,7 +3830,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
if (!rhsType->isVectorType() && rhsType->isArithmeticType())
return Compatible;
}
-
+
if (lhsType->isVectorType() || rhsType->isVectorType()) {
// If we are allowing lax vector conversions, and LHS and RHS are both
// vectors, the total size only needs to be the same. This is a bitcast;
@@ -3485,13 +3853,18 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
if (isa<PointerType>(rhsType))
return CheckPointerTypesForAssignment(lhsType, rhsType);
- if (rhsType->getAsBlockPointerType()) {
- if (lhsType->getAsPointerType()->getPointeeType()->isVoidType())
+ // In general, C pointers are not compatible with ObjC object pointers.
+ if (isa<ObjCObjectPointerType>(rhsType)) {
+ if (lhsType->isVoidPointerType()) // an exception to the rule.
+ return Compatible;
+ return IncompatiblePointer;
+ }
+ if (rhsType->getAs<BlockPointerType>()) {
+ if (lhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
return Compatible;
// Treat block pointers as objects.
- if (getLangOptions().ObjC1 &&
- lhsType == Context.getCanonicalType(Context.getObjCIdType()))
+ if (getLangOptions().ObjC1 && lhsType->isObjCIdType())
return Compatible;
}
return Incompatible;
@@ -3502,20 +3875,47 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
return IntToBlockPointer;
// Treat block pointers as objects.
- if (getLangOptions().ObjC1 &&
- rhsType == Context.getCanonicalType(Context.getObjCIdType()))
+ if (getLangOptions().ObjC1 && rhsType->isObjCIdType())
return Compatible;
if (rhsType->isBlockPointerType())
return CheckBlockPointerTypesForAssignment(lhsType, rhsType);
- if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
+ if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) {
if (RHSPT->getPointeeType()->isVoidType())
return Compatible;
}
return Incompatible;
}
+ if (isa<ObjCObjectPointerType>(lhsType)) {
+ if (rhsType->isIntegerType())
+ return IntToPointer;
+
+ // In general, C pointers are not compatible with ObjC object pointers.
+ if (isa<PointerType>(rhsType)) {
+ if (rhsType->isVoidPointerType()) // an exception to the rule.
+ return Compatible;
+ return IncompatiblePointer;
+ }
+ if (rhsType->isObjCObjectPointerType()) {
+ if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType())
+ return Compatible;
+ if (Context.typesAreCompatible(lhsType, rhsType))
+ return Compatible;
+ if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType())
+ return IncompatibleObjCQualifiedId;
+ return IncompatiblePointer;
+ }
+ if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) {
+ if (RHSPT->getPointeeType()->isVoidType())
+ return Compatible;
+ }
+ // Treat block pointers as objects.
+ if (rhsType->isBlockPointerType())
+ return Compatible;
+ return Incompatible;
+ }
if (isa<PointerType>(rhsType)) {
// C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
if (lhsType == Context.BoolTy)
@@ -3528,7 +3928,26 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
return CheckPointerTypesForAssignment(lhsType, rhsType);
if (isa<BlockPointerType>(lhsType) &&
- rhsType->getAsPointerType()->getPointeeType()->isVoidType())
+ rhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
+ return Compatible;
+ return Incompatible;
+ }
+ if (isa<ObjCObjectPointerType>(rhsType)) {
+ // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
+ if (lhsType == Context.BoolTy)
+ return Compatible;
+
+ if (lhsType->isIntegerType())
+ return PointerToInt;
+
+ // In general, C pointers are not compatible with ObjC object pointers.
+ if (isa<PointerType>(lhsType)) {
+ if (lhsType->isVoidPointerType()) // an exception to the rule.
+ return Compatible;
+ return IncompatiblePointer;
+ }
+ if (isa<BlockPointerType>(lhsType) &&
+ rhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
return Compatible;
return Incompatible;
}
@@ -3542,7 +3961,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
/// \brief Constructs a transparent union from an expression that is
/// used to initialize the transparent union.
-static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
+static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
QualType UnionType, FieldDecl *Field) {
// Build an initializer list that designates the appropriate member
// of the transparent union.
@@ -3562,7 +3981,7 @@ Sema::AssignConvertType
Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
QualType FromType = rExpr->getType();
- // If the ArgType is a Union type, we want to handle a potential
+ // If the ArgType is a Union type, we want to handle a potential
// transparent_union GCC extension.
const RecordType *UT = ArgType->getAsUnionType();
if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
@@ -3580,13 +3999,14 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
// 1) void pointer
// 2) null pointer constant
if (FromType->isPointerType())
- if (FromType->getAsPointerType()->getPointeeType()->isVoidType()) {
+ if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) {
ImpCastExprToType(rExpr, it->getType());
InitField = *it;
break;
}
-
- if (rExpr->isNullPointerConstant(Context)) {
+
+ if (rExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(rExpr, it->getType());
InitField = *it;
break;
@@ -3626,10 +4046,11 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
// C99 6.5.16.1p1: the left operand is a pointer and the right is
// a null pointer constant.
- if ((lhsType->isPointerType() ||
- lhsType->isObjCQualifiedIdType() ||
+ if ((lhsType->isPointerType() ||
+ lhsType->isObjCObjectPointerType() ||
lhsType->isBlockPointerType())
- && rExpr->isNullPointerConstant(Context)) {
+ && rExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(rExpr, lhsType);
return Compatible;
}
@@ -3681,8 +4102,8 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
// type. It would be nice if we only had one vector type someday.
if (getLangOptions().LaxVectorConversions) {
// FIXME: Should we warn here?
- if (const VectorType *LV = lhsType->getAsVectorType()) {
- if (const VectorType *RV = rhsType->getAsVectorType())
+ if (const VectorType *LV = lhsType->getAs<VectorType>()) {
+ if (const VectorType *RV = rhsType->getAs<VectorType>())
if (LV->getElementType() == RV->getElementType() &&
LV->getNumElements() == RV->getNumElements()) {
return lhsType->isExtVectorType() ? lhsType : rhsType;
@@ -3698,9 +4119,9 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
std::swap(rex, lex);
std::swap(rhsType, lhsType);
}
-
+
// Handle the case of an ext vector and scalar.
- if (const ExtVectorType *LV = lhsType->getAsExtVectorType()) {
+ if (const ExtVectorType *LV = lhsType->getAs<ExtVectorType>()) {
QualType EltTy = LV->getElementType();
if (EltTy->isIntegralType() && rhsType->isIntegralType()) {
if (Context.getIntegerTypeOrder(EltTy, rhsType) >= 0) {
@@ -3718,7 +4139,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
}
}
}
-
+
// Vectors of different size or scalar and non-ext-vector are errors.
Diag(Loc, diag::err_typecheck_vector_not_convertable)
<< lex->getType() << rex->getType()
@@ -3727,8 +4148,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
}
inline QualType Sema::CheckMultiplyDivideOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorOperands(Loc, lex, rex);
@@ -3740,8 +4160,7 @@ inline QualType Sema::CheckMultiplyDivideOperands(
}
inline QualType Sema::CheckRemainderOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
return CheckVectorOperands(Loc, lex, rex);
@@ -3756,8 +4175,7 @@ inline QualType Sema::CheckRemainderOperands(
}
inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
- Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
QualType compType = CheckVectorOperands(Loc, lex, rex);
if (CompLHSTy) *CompLHSTy = compType;
@@ -3775,12 +4193,14 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
// Put any potential pointer into PExp
Expr* PExp = lex, *IExp = rex;
- if (IExp->getType()->isPointerType())
+ if (IExp->getType()->isAnyPointerType())
std::swap(PExp, IExp);
- if (const PointerType *PTy = PExp->getType()->getAsPointerType()) {
+ if (PExp->getType()->isAnyPointerType()) {
+
if (IExp->getType()->isIntegerType()) {
- QualType PointeeTy = PTy->getPointeeType();
+ QualType PointeeTy = PExp->getType()->getPointeeType();
+
// Check for arithmetic on pointers to incomplete types.
if (PointeeTy->isVoidType()) {
if (getLangOptions().CPlusPlus) {
@@ -3802,30 +4222,31 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
// GNU extension: arithmetic on pointer to function
Diag(Loc, diag::ext_gnu_ptr_func_arith)
<< lex->getType() << lex->getSourceRange();
- } else if (!PTy->isDependentType() &&
- RequireCompleteType(Loc, PointeeTy,
- diag::err_typecheck_arithmetic_incomplete_type,
- PExp->getSourceRange(), SourceRange(),
- PExp->getType()))
- return QualType();
-
+ } else {
+ // Check if we require a complete type.
+ if (((PExp->getType()->isPointerType() &&
+ !PExp->getType()->isDependentType()) ||
+ PExp->getType()->isObjCObjectPointerType()) &&
+ RequireCompleteType(Loc, PointeeTy,
+ PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << PExp->getSourceRange()
+ << PExp->getType()))
+ return QualType();
+ }
// Diagnose bad cases where we step over interface counts.
if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
<< PointeeTy << PExp->getSourceRange();
return QualType();
}
-
+
if (CompLHSTy) {
- QualType LHSTy = lex->getType();
- if (LHSTy->isPromotableIntegerType())
- LHSTy = Context.IntTy;
- else {
- QualType T = isPromotableBitField(lex, Context);
- if (!T.isNull())
- LHSTy = T;
+ QualType LHSTy = Context.isPromotableBitField(lex);
+ if (LHSTy.isNull()) {
+ LHSTy = lex->getType();
+ if (LHSTy->isPromotableIntegerType())
+ LHSTy = Context.getPromotedIntegerType(LHSTy);
}
-
*CompLHSTy = LHSTy;
}
return PExp->getType();
@@ -3856,8 +4277,8 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
}
// Either ptr - int or ptr - ptr.
- if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) {
- QualType lpointee = LHSPTy->getPointeeType();
+ if (lex->getType()->isAnyPointerType()) {
+ QualType lpointee = lex->getType()->getPointeeType();
// The LHS must be an completely-defined object type.
@@ -3882,11 +4303,10 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
// GNU C extension: arithmetic on pointer to function
ComplainAboutFunc = lex;
} else if (!lpointee->isDependentType() &&
- RequireCompleteType(Loc, lpointee,
- diag::err_typecheck_sub_ptr_object,
- lex->getSourceRange(),
- SourceRange(),
- lex->getType()))
+ RequireCompleteType(Loc, lpointee,
+ PDiag(diag::err_typecheck_sub_ptr_object)
+ << lex->getSourceRange()
+ << lex->getType()))
return QualType();
// Diagnose bad cases where we step over interface counts.
@@ -3895,7 +4315,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
<< lpointee << lex->getSourceRange();
return QualType();
}
-
+
// The result type of a pointer-int computation is the pointer type.
if (rex->getType()->isIntegerType()) {
if (ComplainAboutVoid)
@@ -3903,7 +4323,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
<< lex->getSourceRange() << rex->getSourceRange();
if (ComplainAboutFunc)
Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
+ << ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
if (CompLHSTy) *CompLHSTy = lex->getType();
@@ -3911,7 +4331,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
}
// Handle pointer-pointer subtractions.
- if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) {
+ if (const PointerType *RHSPTy = rex->getType()->getAs<PointerType>()) {
QualType rpointee = RHSPTy->getPointeeType();
// RHS must be a completely-type object type.
@@ -3936,10 +4356,9 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
ComplainAboutFunc = rex;
} else if (!rpointee->isDependentType() &&
RequireCompleteType(Loc, rpointee,
- diag::err_typecheck_sub_ptr_object,
- rex->getSourceRange(),
- SourceRange(),
- rex->getType()))
+ PDiag(diag::err_typecheck_sub_ptr_object)
+ << rex->getSourceRange()
+ << rex->getType()))
return QualType();
if (getLangOptions().CPlusPlus) {
@@ -3967,7 +4386,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
<< lex->getSourceRange() << rex->getSourceRange();
if (ComplainAboutFunc)
Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
+ << ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
if (CompLHSTy) *CompLHSTy = lex->getType();
@@ -3987,19 +4406,32 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// Shifts don't perform usual arithmetic conversions, they just do integer
// promotions on each operand. C99 6.5.7p3
- QualType LHSTy;
- if (lex->getType()->isPromotableIntegerType())
- LHSTy = Context.IntTy;
- else {
- LHSTy = isPromotableBitField(lex, Context);
- if (LHSTy.isNull())
- LHSTy = lex->getType();
+ QualType LHSTy = Context.isPromotableBitField(lex);
+ if (LHSTy.isNull()) {
+ LHSTy = lex->getType();
+ if (LHSTy->isPromotableIntegerType())
+ LHSTy = Context.getPromotedIntegerType(LHSTy);
}
if (!isCompAssign)
ImpCastExprToType(lex, LHSTy);
UsualUnaryConversions(rex);
+ // Sanity-check shift operands
+ llvm::APSInt Right;
+ // Check right/shifter operand
+ if (!rex->isValueDependent() &&
+ rex->isIntegerConstantExpr(Right, Context)) {
+ if (Right.isNegative())
+ Diag(Loc, diag::warn_shift_negative) << rex->getSourceRange();
+ else {
+ llvm::APInt LeftBits(Right.getBitWidth(),
+ Context.getTypeSize(lex->getType()));
+ if (Right.uge(LeftBits))
+ Diag(Loc, diag::warn_shift_gt_typewidth) << rex->getSourceRange();
+ }
+ }
+
// "The type of the result is that of the promoted left operand."
return LHSTy;
}
@@ -4027,7 +4459,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
- // NOTE: Don't warn about comparisons of enum constants. These can arise
+ // NOTE: Don't warn about comparisons of enum constants. These can arise
// from macro expansions, and are usually quite deliberate.
Expr *LHSStripped = lex->IgnoreParens();
Expr *RHSStripped = rex->IgnoreParens();
@@ -4036,24 +4468,25 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (DRL->getDecl() == DRR->getDecl() &&
!isa<EnumConstantDecl>(DRL->getDecl()))
Diag(Loc, diag::warn_selfcomparison);
-
+
if (isa<CastExpr>(LHSStripped))
LHSStripped = LHSStripped->IgnoreParenCasts();
if (isa<CastExpr>(RHSStripped))
RHSStripped = RHSStripped->IgnoreParenCasts();
-
+
// Warn about comparisons against a string constant (unless the other
// operand is null), the user probably wants strcmp.
Expr *literalString = 0;
Expr *literalStringStripped = 0;
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
- !RHSStripped->isNullPointerConstant(Context)) {
+ !RHSStripped->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
literalString = lex;
literalStringStripped = LHSStripped;
- }
- else if ((isa<StringLiteral>(RHSStripped) ||
- isa<ObjCEncodeExpr>(RHSStripped)) &&
- !LHSStripped->isNullPointerConstant(Context)) {
+ } else if ((isa<StringLiteral>(RHSStripped) ||
+ isa<ObjCEncodeExpr>(RHSStripped)) &&
+ !LHSStripped->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
literalString = rex;
literalStringStripped = RHSStripped;
}
@@ -4098,41 +4531,31 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return ResultTy;
}
- bool LHSIsNull = lex->isNullPointerConstant(Context);
- bool RHSIsNull = rex->isNullPointerConstant(Context);
+ bool LHSIsNull = lex->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull);
+ bool RHSIsNull = rex->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull);
// All of the following pointer related warnings are GCC extensions, except
// when handling null pointer constants. One day, we can consider making them
// errors (when -pedantic-errors is enabled).
if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2
QualType LCanPointeeTy =
- Context.getCanonicalType(lType->getAsPointerType()->getPointeeType());
+ Context.getCanonicalType(lType->getAs<PointerType>()->getPointeeType());
QualType RCanPointeeTy =
- Context.getCanonicalType(rType->getAsPointerType()->getPointeeType());
-
- if (rType->isFunctionPointerType() || lType->isFunctionPointerType()) {
- if (isRelational) {
- Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- }
- }
- if (((!LHSIsNull || isRelational) && LCanPointeeTy->isVoidType()) !=
- ((!RHSIsNull || isRelational) && RCanPointeeTy->isVoidType())) {
- Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- }
- // Simple check: if the pointee types are identical, we're done.
- if (LCanPointeeTy == RCanPointeeTy)
- return ResultTy;
+ Context.getCanonicalType(rType->getAs<PointerType>()->getPointeeType());
if (getLangOptions().CPlusPlus) {
+ if (LCanPointeeTy == RCanPointeeTy)
+ return ResultTy;
+
// C++ [expr.rel]p2:
// [...] Pointer conversions (4.10) and qualification
// conversions (4.4) are performed on pointer operands (or on
// a pointer operand and a null pointer constant) to bring
// them to their composite pointer type. [...]
//
- // C++ [expr.eq]p2 uses the same notion for (in)equality
+ // C++ [expr.eq]p1 uses the same notion for (in)equality
// comparisons of pointers.
QualType T = FindCompositePointerType(lex, rex);
if (T.isNull()) {
@@ -4145,36 +4568,82 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
ImpCastExprToType(rex, T);
return ResultTy;
}
-
- if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2
- !LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() &&
- !Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
- RCanPointeeTy.getUnqualifiedType()) &&
- !Context.areComparableObjCPointerTypes(lType, rType)) {
+ // C99 6.5.9p2 and C99 6.5.8p2
+ if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
+ RCanPointeeTy.getUnqualifiedType())) {
+ // Valid unless a relational comparison of function pointers
+ if (isRelational && LCanPointeeTy->isFunctionType()) {
+ Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
+ } else if (!isRelational &&
+ (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
+ // Valid unless comparison between non-null pointer and function pointer
+ if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
+ && !LHSIsNull && !RHSIsNull) {
+ Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
+ } else {
+ // Invalid
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
}
- ImpCastExprToType(rex, lType); // promote the pointer to pointer
+ if (LCanPointeeTy != RCanPointeeTy)
+ ImpCastExprToType(rex, lType); // promote the pointer to pointer
return ResultTy;
}
- // C++ allows comparison of pointers with null pointer constants.
+
if (getLangOptions().CPlusPlus) {
- if (lType->isPointerType() && RHSIsNull) {
- ImpCastExprToType(rex, lType);
+ // Comparison of pointers with null pointer constants and equality
+ // comparisons of member pointers to null pointer constants.
+ if (RHSIsNull &&
+ (lType->isPointerType() ||
+ (!isRelational && lType->isMemberPointerType()))) {
+ ImpCastExprToType(rex, lType, CastExpr::CK_NullToMemberPointer);
+ return ResultTy;
+ }
+ if (LHSIsNull &&
+ (rType->isPointerType() ||
+ (!isRelational && rType->isMemberPointerType()))) {
+ ImpCastExprToType(lex, rType, CastExpr::CK_NullToMemberPointer);
return ResultTy;
}
- if (rType->isPointerType() && LHSIsNull) {
- ImpCastExprToType(lex, rType);
+
+ // Comparison of member pointers.
+ if (!isRelational &&
+ lType->isMemberPointerType() && rType->isMemberPointerType()) {
+ // C++ [expr.eq]p2:
+ // In addition, pointers to members can be compared, or a pointer to
+ // member and a null pointer constant. Pointer to member conversions
+ // (4.11) and qualification conversions (4.4) are performed to bring
+ // them to a common type. If one operand is a null pointer constant,
+ // the common type is the type of the other operand. Otherwise, the
+ // common type is a pointer to member type similar (4.4) to the type
+ // of one of the operands, with a cv-qualification signature (4.4)
+ // that is the union of the cv-qualification signatures of the operand
+ // types.
+ QualType T = FindCompositePointerType(lex, rex);
+ if (T.isNull()) {
+ Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ return QualType();
+ }
+
+ ImpCastExprToType(lex, T);
+ ImpCastExprToType(rex, T);
return ResultTy;
}
- // And comparison of nullptr_t with itself.
+
+ // Comparison of nullptr_t with itself.
if (lType->isNullPtrType() && rType->isNullPtrType())
return ResultTy;
}
+
// Handle block pointer types.
if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) {
- QualType lpointee = lType->getAsBlockPointerType()->getPointeeType();
- QualType rpointee = rType->getAsBlockPointerType()->getPointeeType();
+ QualType lpointee = lType->getAs<BlockPointerType>()->getPointeeType();
+ QualType rpointee = rType->getAs<BlockPointerType>()->getPointeeType();
if (!LHSIsNull && !RHSIsNull &&
!Context.typesAreCompatible(lpointee, rpointee)) {
@@ -4189,9 +4658,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
&& ((lType->isBlockPointerType() && rType->isPointerType())
|| (lType->isPointerType() && rType->isBlockPointerType()))) {
if (!LHSIsNull && !RHSIsNull) {
- if (!((rType->isPointerType() && rType->getAsPointerType()
+ if (!((rType->isPointerType() && rType->getAs<PointerType>()
->getPointeeType()->isVoidType())
- || (lType->isPointerType() && lType->getAsPointerType()
+ || (lType->isPointerType() && lType->getAs<PointerType>()
->getPointeeType()->isVoidType())))
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
@@ -4200,10 +4669,10 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return ResultTy;
}
- if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
+ if ((lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType())) {
if (lType->isPointerType() || rType->isPointerType()) {
- const PointerType *LPT = lType->getAsPointerType();
- const PointerType *RPT = rType->getAsPointerType();
+ const PointerType *LPT = lType->getAs<PointerType>();
+ const PointerType *RPT = rType->getAs<PointerType>();
bool LPtrToVoid = LPT ?
Context.getCanonicalType(LPT->getPointeeType())->isVoidType() : false;
bool RPtrToVoid = RPT ?
@@ -4213,43 +4682,49 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
!Context.typesAreCompatible(lType, rType)) {
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
- ImpCastExprToType(rex, lType);
- return ResultTy;
}
ImpCastExprToType(rex, lType);
return ResultTy;
}
- if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
+ if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) {
+ if (!Context.areComparableObjCPointerTypes(lType, rType))
+ Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
ImpCastExprToType(rex, lType);
return ResultTy;
- } else {
- if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) {
- Diag(Loc, diag::warn_incompatible_qualified_id_operands)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- ImpCastExprToType(rex, lType);
- return ResultTy;
- }
}
}
- if ((lType->isPointerType() || lType->isObjCQualifiedIdType()) &&
- rType->isIntegerType()) {
- if (isRelational)
- Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- else if (!RHSIsNull)
- Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
+ if (lType->isAnyPointerType() && rType->isIntegerType()) {
+ unsigned DiagID = 0;
+ if (RHSIsNull) {
+ if (isRelational)
+ DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
+ } else if (isRelational)
+ DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
+ else
+ DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
+
+ if (DiagID) {
+ Diag(Loc, DiagID)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
ImpCastExprToType(rex, lType); // promote the integer to pointer
return ResultTy;
}
- if (lType->isIntegerType() &&
- (rType->isPointerType() || rType->isObjCQualifiedIdType())) {
- if (isRelational)
- Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- else if (!LHSIsNull)
- Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
+ if (lType->isIntegerType() && rType->isAnyPointerType()) {
+ unsigned DiagID = 0;
+ if (LHSIsNull) {
+ if (isRelational)
+ DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
+ } else if (isRelational)
+ DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
+ else
+ DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
+
+ if (DiagID) {
+ Diag(Loc, DiagID)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
ImpCastExprToType(lex, rType); // promote the integer to pointer
return ResultTy;
}
@@ -4299,21 +4774,13 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
CheckFloatComparison(Loc,lex,rex);
}
- // FIXME: Vector compare support in the LLVM backend is not fully reliable,
- // just reject all vector comparisons for now.
- if (1) {
- Diag(Loc, diag::err_typecheck_vector_comparison)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- return QualType();
- }
-
// Return the type for the comparison, which is the same as vector type for
// integer vectors, or an integer type of identical size and number of
// elements for floating point vectors.
if (lType->isIntegerType())
return lType;
- const VectorType *VTy = lType->getAsVectorType();
+ const VectorType *VTy = lType->getAs<VectorType>();
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
if (TypeSize == Context.getTypeSize(Context.IntTy))
return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
@@ -4326,8 +4793,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
}
inline QualType Sema::CheckBitwiseOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorOperands(Loc, lex, rex);
@@ -4339,8 +4805,7 @@ inline QualType Sema::CheckBitwiseOperands(
}
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
- Expr *&lex, Expr *&rex, SourceLocation Loc)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc) {
UsualUnaryConversions(lex);
UsualUnaryConversions(rex);
@@ -4353,18 +4818,16 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
/// is a read-only property; return true if so. A readonly property expression
/// depends on various declarations and thus must be treated specially.
///
-static bool IsReadonlyProperty(Expr *E, Sema &S)
-{
+static bool IsReadonlyProperty(Expr *E, Sema &S) {
if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) {
QualType BaseType = PropExpr->getBase()->getType();
- if (const PointerType *PTy = BaseType->getAsPointerType())
- if (const ObjCInterfaceType *IFTy =
- PTy->getPointeeType()->getAsObjCInterfaceType())
- if (ObjCInterfaceDecl *IFace = IFTy->getDecl())
- if (S.isPropertyReadonly(PDecl, IFace))
- return true;
+ if (const ObjCObjectPointerType *OPT =
+ BaseType->getAsObjCInterfacePointerType())
+ if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
+ if (S.isPropertyReadonly(PDecl, IFace))
+ return true;
}
}
return false;
@@ -4374,7 +4837,7 @@ static bool IsReadonlyProperty(Expr *E, Sema &S)
/// emit an error and return true. If so, return false.
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
SourceLocation OrigLoc = Loc;
- Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context,
+ Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context,
&Loc);
if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S))
IsLV = Expr::MLV_ReadonlyProperty;
@@ -4403,8 +4866,8 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_IncompleteType:
case Expr::MLV_IncompleteVoidType:
return S.RequireCompleteType(Loc, E->getType(),
- diag::err_typecheck_incomplete_type_not_modifiable_lvalue,
- E->getSourceRange());
+ PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue)
+ << E->getSourceRange());
case Expr::MLV_DuplicateVectorComponents:
Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
break;
@@ -4425,7 +4888,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
if (NeedType)
S.Diag(Loc, Diag) << E->getType() << E->getSourceRange() << Assign;
else
- S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
+ S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
return true;
}
@@ -4449,9 +4912,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
// Special case of NSObject attributes on c-style pointer types.
if (ConvTy == IncompatiblePointer &&
((Context.isObjCNSObjectType(LHSType) &&
- Context.isObjCObjectPointerType(RHSType)) ||
+ RHSType->isObjCObjectPointerType()) ||
(Context.isObjCNSObjectType(RHSType) &&
- Context.isObjCObjectPointerType(LHSType))))
+ LHSType->isObjCObjectPointerType())))
ConvTy = Compatible;
// If the RHS is a unary plus or minus, check to see if they = and + are
@@ -4525,9 +4988,11 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
} else if (ResType->isRealType()) {
// OK!
- } else if (const PointerType *PT = ResType->getAsPointerType()) {
+ } else if (ResType->isAnyPointerType()) {
+ QualType PointeeTy = ResType->getPointeeType();
+
// C99 6.5.2.4p2, 6.5.6p2
- if (PT->getPointeeType()->isVoidType()) {
+ if (PointeeTy->isVoidType()) {
if (getLangOptions().CPlusPlus) {
Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
<< Op->getSourceRange();
@@ -4536,7 +5001,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
// Pointer to void is a GNU extension in C.
Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
- } else if (PT->getPointeeType()->isFunctionType()) {
+ } else if (PointeeTy->isFunctionType()) {
if (getLangOptions().CPlusPlus) {
Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
<< Op->getType() << Op->getSourceRange();
@@ -4545,11 +5010,17 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
<< ResType << Op->getSourceRange();
- } else if (RequireCompleteType(OpLoc, PT->getPointeeType(),
- diag::err_typecheck_arithmetic_incomplete_type,
- Op->getSourceRange(), SourceRange(),
- ResType))
+ } else if (RequireCompleteType(OpLoc, PointeeTy,
+ PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << Op->getSourceRange()
+ << ResType))
return QualType();
+ // Diagnose bad cases where we step over interface counts.
+ else if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
+ << PointeeTy << Op->getSourceRange();
+ return QualType();
+ }
} else if (ResType->isComplexType()) {
// C99 does not support ++/-- on complex types, we allow as an extension.
Diag(OpLoc, diag::ext_integer_increment_complex)
@@ -4672,6 +5143,15 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
Diag(OpLoc, diag::err_typecheck_address_of)
<< "vector element" << op->getSourceRange();
return QualType();
+ } else if (isa<ObjCPropertyRefExpr>(op)) {
+ // cannot take address of a property expression.
+ Diag(OpLoc, diag::err_typecheck_address_of)
+ << "property expression" << op->getSourceRange();
+ return QualType();
+ } else if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(op)) {
+ // FIXME: Can LHS ever be null here?
+ if (!CheckAddressOfOperand(CO->getTrueExpr(), OpLoc).isNull())
+ return CheckAddressOfOperand(CO->getFalseExpr(), OpLoc);
} else if (dcl) { // C99 6.5.3.2p1
// We have an lvalue with a decl. Make sure the decl is not declared
// with the register storage-class specifier.
@@ -4681,17 +5161,26 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
<< "register variable" << op->getSourceRange();
return QualType();
}
- } else if (isa<OverloadedFunctionDecl>(dcl)) {
+ } else if (isa<OverloadedFunctionDecl>(dcl) ||
+ isa<FunctionTemplateDecl>(dcl)) {
return Context.OverloadTy;
- } else if (isa<FieldDecl>(dcl)) {
+ } else if (FieldDecl *FD = dyn_cast<FieldDecl>(dcl)) {
// Okay: we can take the address of a field.
// Could be a pointer to member, though, if there is an explicit
// scope qualifier for the class.
if (isa<QualifiedDeclRefExpr>(op)) {
DeclContext *Ctx = dcl->getDeclContext();
- if (Ctx && Ctx->isRecord())
+ if (Ctx && Ctx->isRecord()) {
+ if (FD->getType()->isReferenceType()) {
+ Diag(OpLoc,
+ diag::err_cannot_form_pointer_to_member_of_reference_type)
+ << FD->getDeclName() << FD->getType();
+ return QualType();
+ }
+
return Context.getMemberPointerType(op->getType(),
Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
+ }
}
} else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(dcl)) {
// Okay: we can take the address of a function.
@@ -4725,9 +5214,12 @@ QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) {
// incomplete type or void. It would be possible to warn about dereferencing
// a void pointer, but it's completely well-defined, and such a warning is
// unlikely to catch any mistakes.
- if (const PointerType *PT = Ty->getAsPointerType())
+ if (const PointerType *PT = Ty->getAs<PointerType>())
return PT->getPointeeType();
+ if (const ObjCObjectPointerType *OPT = Ty->getAs<ObjCObjectPointerType>())
+ return OPT->getPointeeType();
+
Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer)
<< Ty << Op->getSourceRange();
return QualType();
@@ -4914,7 +5406,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
assert((rhs != 0) && "ActOnBinOp(): missing right expression");
if (getLangOptions().CPlusPlus &&
- (lhs->getType()->isOverloadableType() ||
+ (lhs->getType()->isOverloadableType() ||
rhs->getType()->isOverloadableType())) {
// Find all of the overloaded operators visible from this
// point. We perform both an operator-name lookup from the local
@@ -4926,7 +5418,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
Functions);
Expr *Args[2] = { lhs, rhs };
- DeclarationName OpName
+ DeclarationName OpName
= Context.DeclarationNames.getCXXOperatorName(OverOp);
ArgumentDependentLookup(OpName, Args, 2, Functions);
}
@@ -4941,7 +5433,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
}
Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
- unsigned OpcIn,
+ unsigned OpcIn,
ExprArg InputArg) {
UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
@@ -4949,16 +5441,17 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Expr *Input = (Expr *)InputArg.get();
QualType resultType;
switch (Opc) {
- case UnaryOperator::PostInc:
- case UnaryOperator::PostDec:
case UnaryOperator::OffsetOf:
assert(false && "Invalid unary operator");
break;
case UnaryOperator::PreInc:
case UnaryOperator::PreDec:
+ case UnaryOperator::PostInc:
+ case UnaryOperator::PostDec:
resultType = CheckIncrementDecrementOperand(Input, OpLoc,
- Opc == UnaryOperator::PreInc);
+ Opc == UnaryOperator::PreInc ||
+ Opc == UnaryOperator::PostInc);
break;
case UnaryOperator::AddrOf:
resultType = CheckAddressOfOperand(Input, OpLoc);
@@ -5043,7 +5536,7 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
if (OverOp != OO_None) {
LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
Functions);
- DeclarationName OpName
+ DeclarationName OpName
= Context.DeclarationNames.getCXXOperatorName(OverOp);
ArgumentDependentLookup(OpName, &Input, 1, Functions);
}
@@ -5116,7 +5609,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
SourceLocation RPLoc) {
// FIXME: This function leaks all expressions in the offset components on
// error.
- QualType ArgTy = QualType::getFromOpaquePtr(argty);
+ // FIXME: Preserve type source info.
+ QualType ArgTy = GetTypeFromParser(argty);
assert(!ArgTy.isNull() && "Missing type argument!");
bool Dependent = ArgTy->isDependentType();
@@ -5147,7 +5641,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
if (!Dependent) {
bool DidWarnAboutNonPOD = false;
-
+
// FIXME: Dependent case loses a lot of information here. And probably
// leaks like a sieve.
for (unsigned i = 0; i != NumComponents; ++i) {
@@ -5180,7 +5674,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
continue;
}
- const RecordType *RC = Res->getType()->getAsRecordType();
+ const RecordType *RC = Res->getType()->getAs<RecordType>();
if (!RC) {
Res->Destroy(Context);
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
@@ -5197,15 +5691,16 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
DidWarnAboutNonPOD = true;
}
}
-
+
+ LookupResult R;
+ LookupQualifiedName(R, RD, OC.U.IdentInfo, LookupMemberName);
+
FieldDecl *MemberDecl
- = dyn_cast_or_null<FieldDecl>(LookupQualifiedName(RD, OC.U.IdentInfo,
- LookupMemberName)
- .getAsDecl());
+ = dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context));
// FIXME: Leaks Res
if (!MemberDecl)
- return ExprError(Diag(BuiltinLoc, diag::err_typecheck_no_member)
- << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd));
+ return ExprError(Diag(BuiltinLoc, diag::err_no_member)
+ << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
// FIXME: C++: Verify that MemberDecl isn't a static field.
// FIXME: Verify that MemberDecl isn't a bitfield.
@@ -5229,8 +5724,9 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
Sema::OwningExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
TypeTy *arg1,TypeTy *arg2,
SourceLocation RPLoc) {
- QualType argT1 = QualType::getFromOpaquePtr(arg1);
- QualType argT2 = QualType::getFromOpaquePtr(arg2);
+ // FIXME: Preserve type source info.
+ QualType argT1 = GetTypeFromParser(arg1);
+ QualType argT2 = GetTypeFromParser(arg2);
assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)");
@@ -5255,8 +5751,10 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)");
QualType resType;
+ bool ValueDependent = false;
if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
resType = Context.DependentTy;
+ ValueDependent = true;
} else {
// The conditional expression is required to be a constant expression.
llvm::APSInt condEval(32);
@@ -5268,11 +5766,15 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
// If the condition is > zero, then the AST type is the same as the LSHExpr.
resType = condEval.getZExtValue() ? LHSExpr->getType() : RHSExpr->getType();
+ ValueDependent = condEval.getZExtValue() ? LHSExpr->isValueDependent()
+ : RHSExpr->isValueDependent();
}
cond.release(); expr1.release(); expr2.release();
return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
- resType, RPLoc));
+ resType, RPLoc,
+ resType->isDependentType(),
+ ValueDependent));
}
//===----------------------------------------------------------------------===//
@@ -5291,6 +5793,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
BSI->ReturnType = QualType();
BSI->TheScope = BlockScope;
BSI->hasBlockDeclRefExprs = false;
+ BSI->hasPrototype = false;
BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking;
CurFunctionNeedsScopeChecking = false;
@@ -5320,12 +5823,12 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
CurBlock->isVariadic = false;
// Check for a valid sentinel attribute on this block.
if (CurBlock->TheDecl->getAttr<SentinelAttr>()) {
- Diag(ParamInfo.getAttributes()->getLoc(),
+ Diag(ParamInfo.getAttributes()->getLoc(),
diag::warn_attribute_sentinel_not_variadic) << 1;
// FIXME: remove the attribute.
}
- QualType RetTy = T.getTypePtr()->getAsFunctionType()->getResultType();
-
+ QualType RetTy = T.getTypePtr()->getAs<FunctionType>()->getResultType();
+
// Do not allow returning a objc interface by-value.
if (RetTy->isObjCInterfaceType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
@@ -5367,17 +5870,17 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
PushOnScopeChains(*AI, CurBlock->TheScope);
// Check for a valid sentinel attribute on this block.
- if (!CurBlock->isVariadic &&
+ if (!CurBlock->isVariadic &&
CurBlock->TheDecl->getAttr<SentinelAttr>()) {
- Diag(ParamInfo.getAttributes()->getLoc(),
+ Diag(ParamInfo.getAttributes()->getLoc(),
diag::warn_attribute_sentinel_not_variadic) << 1;
// FIXME: remove the attribute.
}
-
+
// Analyze the return type.
QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
- QualType RetTy = T->getAsFunctionType()->getResultType();
-
+ QualType RetTy = T->getAs<FunctionType>()->getResultType();
+
// Do not allow returning a objc interface by-value.
if (RetTy->isObjCInterfaceType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
@@ -5407,7 +5910,7 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// If blocks are disabled, emit an error.
if (!LangOpts.Blocks)
Diag(CaretLoc, diag::err_blocks_disable);
-
+
// Ensure that CurBlock is deleted.
llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
@@ -5424,12 +5927,15 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
ArgTypes.push_back(BSI->Params[i]->getType());
+ bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>();
QualType BlockTy;
if (!BSI->hasPrototype)
- BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0);
+ BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0,
+ NoReturn);
else
BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
- BSI->isVariadic, 0);
+ BSI->isVariadic, 0, false, false, 0, 0,
+ NoReturn);
// FIXME: Check that return/parameter types are complete/non-abstract
DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
@@ -5439,8 +5945,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (CurFunctionNeedsScopeChecking)
DiagnoseInvalidJumps(static_cast<CompoundStmt*>(body.get()));
CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
-
+
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
+ CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody());
return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs));
}
@@ -5448,10 +5955,10 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
ExprArg expr, TypeTy *type,
SourceLocation RPLoc) {
- QualType T = QualType::getFromOpaquePtr(type);
+ QualType T = GetTypeFromParser(type);
Expr *E = static_cast<Expr*>(expr.get());
Expr *OrigExpr = E;
-
+
InitBuiltinVaListType();
// Get the va_list type
@@ -5466,7 +5973,7 @@ Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
} else {
// Otherwise, the va_list argument must be an l-value because
// it is modified by va_arg.
- if (!E->isTypeDependent() &&
+ if (!E->isTypeDependent() &&
CheckForModifiableLvalue(E, BuiltinLoc, *this))
return ExprError();
}
@@ -5600,17 +6107,17 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
return false;
}
-Sema::ExpressionEvaluationContext
-Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
+Sema::ExpressionEvaluationContext
+Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
// Introduce a new set of potentially referenced declarations to the stack.
if (NewContext == PotentiallyPotentiallyEvaluated)
PotentiallyReferencedDeclStack.push_back(PotentiallyReferencedDecls());
-
+
std::swap(ExprEvalContext, NewContext);
return NewContext;
}
-void
+void
Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
ExpressionEvaluationContext NewContext) {
ExprEvalContext = NewContext;
@@ -5622,7 +6129,7 @@ Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
PotentiallyReferencedDecls RemainingDecls;
RemainingDecls.swap(PotentiallyReferencedDeclStack.back());
PotentiallyReferencedDeclStack.pop_back();
-
+
for (PotentiallyReferencedDecls::iterator I = RemainingDecls.begin(),
IEnd = RemainingDecls.end();
I != IEnd; ++I)
@@ -5642,30 +6149,33 @@ Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
/// \param D the declaration that has been referenced by the source code.
void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
assert(D && "No declaration?");
-
+
if (D->isUsed())
return;
-
- // Mark a parameter declaration "used", regardless of whether we're in a
- // template or not.
- if (isa<ParmVarDecl>(D))
+
+ // Mark a parameter or variable declaration "used", regardless of whether we're in a
+ // template or not. The reason for this is that unevaluated expressions
+ // (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and
+ // -Wunused-parameters)
+ if (isa<ParmVarDecl>(D) ||
+ (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod()))
D->setUsed(true);
-
+
// Do not mark anything as "used" within a dependent context; wait for
// an instantiation.
if (CurContext->isDependentContext())
return;
-
+
switch (ExprEvalContext) {
case Unevaluated:
// We are in an expression that is not potentially evaluated; do nothing.
return;
-
+
case PotentiallyEvaluated:
// We are in a potentially-evaluated expression, so this declaration is
// "used"; handle this below.
break;
-
+
case PotentiallyPotentiallyEvaluated:
// We are in an expression that may be potentially evaluated; queue this
// declaration reference until we know whether the expression is
@@ -5673,23 +6183,22 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
PotentiallyReferencedDeclStack.back().push_back(std::make_pair(Loc, D));
return;
}
-
+
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
unsigned TypeQuals;
if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) {
if (!Constructor->isUsed())
DefineImplicitDefaultConstructor(Loc, Constructor);
- }
- else if (Constructor->isImplicit() &&
- Constructor->isCopyConstructor(Context, TypeQuals)) {
+ } else if (Constructor->isImplicit() &&
+ Constructor->isCopyConstructor(Context, TypeQuals)) {
if (!Constructor->isUsed())
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
}
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
if (Destructor->isImplicit() && !Destructor->isUsed())
DefineImplicitDestructor(Loc, Destructor);
-
+
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
@@ -5698,28 +6207,125 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
}
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- // Implicit instantiation of function templates and member functions of
+ // Implicit instantiation of function templates and member functions of
// class templates.
- if (!Function->getBody()) {
- // FIXME: distinguish between implicit instantiations of function
- // templates and explicit specializations (the latter don't get
- // instantiated, naturally).
- if (Function->getInstantiatedFromMemberFunction() ||
- Function->getPrimaryTemplate())
+ if (!Function->getBody() &&
+ Function->getTemplateSpecializationKind()
+ == TSK_ImplicitInstantiation) {
+ bool AlreadyInstantiated = false;
+ if (FunctionTemplateSpecializationInfo *SpecInfo
+ = Function->getTemplateSpecializationInfo()) {
+ if (SpecInfo->getPointOfInstantiation().isInvalid())
+ SpecInfo->setPointOfInstantiation(Loc);
+ else
+ AlreadyInstantiated = true;
+ } else if (MemberSpecializationInfo *MSInfo
+ = Function->getMemberSpecializationInfo()) {
+ if (MSInfo->getPointOfInstantiation().isInvalid())
+ MSInfo->setPointOfInstantiation(Loc);
+ else
+ AlreadyInstantiated = true;
+ }
+
+ if (!AlreadyInstantiated)
PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc));
}
-
// FIXME: keep track of references to static functions
Function->setUsed(true);
return;
}
-
+
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
- (void)Var;
- // FIXME: implicit template instantiation
+ // Implicit instantiation of static data members of class templates.
+ if (Var->isStaticDataMember() &&
+ Var->getInstantiatedFromStaticDataMember()) {
+ MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
+ assert(MSInfo && "Missing member specialization information?");
+ if (MSInfo->getPointOfInstantiation().isInvalid() &&
+ MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) {
+ MSInfo->setPointOfInstantiation(Loc);
+ PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc));
+ }
+ }
+
// FIXME: keep track of references to static data?
+
D->setUsed(true);
+ return;
+ }
+}
+
+bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
+ CallExpr *CE, FunctionDecl *FD) {
+ if (ReturnType->isVoidType() || !ReturnType->isIncompleteType())
+ return false;
+
+ PartialDiagnostic Note =
+ FD ? PDiag(diag::note_function_with_incomplete_return_type_declared_here)
+ << FD->getDeclName() : PDiag();
+ SourceLocation NoteLoc = FD ? FD->getLocation() : SourceLocation();
+
+ if (RequireCompleteType(Loc, ReturnType,
+ FD ?
+ PDiag(diag::err_call_function_incomplete_return)
+ << CE->getSourceRange() << FD->getDeclName() :
+ PDiag(diag::err_call_incomplete_return)
+ << CE->getSourceRange(),
+ std::make_pair(NoteLoc, Note)))
+ return true;
+
+ return false;
+}
+
+// Diagnose the common s/=/==/ typo. Note that adding parentheses
+// will prevent this condition from triggering, which is what we want.
+void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
+ SourceLocation Loc;
+
+ if (isa<BinaryOperator>(E)) {
+ BinaryOperator *Op = cast<BinaryOperator>(E);
+ if (Op->getOpcode() != BinaryOperator::Assign)
+ return;
+
+ Loc = Op->getOperatorLoc();
+ } else if (isa<CXXOperatorCallExpr>(E)) {
+ CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(E);
+ if (Op->getOperator() != OO_Equal)
+ return;
+
+ Loc = Op->getOperatorLoc();
+ } else {
+ // Not an assignment.
+ return;
}
+
+ SourceLocation Open = E->getSourceRange().getBegin();
+ SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
+
+ Diag(Loc, diag::warn_condition_is_assignment)
+ << E->getSourceRange()
+ << CodeModificationHint::CreateInsertion(Open, "(")
+ << CodeModificationHint::CreateInsertion(Close, ")");
}
+bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
+ DiagnoseAssignmentAsCondition(E);
+
+ if (!E->isTypeDependent()) {
+ DefaultFunctionArrayConversion(E);
+
+ QualType T = E->getType();
+
+ if (getLangOptions().CPlusPlus) {
+ if (CheckCXXBooleanCondition(E)) // C++ 6.4p4
+ return true;
+ } else if (!T->isScalarType()) { // C99 6.8.4.1p1
+ Diag(Loc, diag::err_typecheck_statement_requires_scalar)
+ << T << E->getSourceRange();
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 7afa5941dad90..5f111c8a60e7a 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -11,13 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#include "SemaInherit.h"
#include "Sema.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/ASTContext.h"
-#include "clang/Parse/DeclSpec.h"
-#include "clang/Lex/Preprocessor.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
@@ -31,9 +32,10 @@ Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc,
TypeTy *Ty, bool HasTrailingLParen,
const CXXScopeSpec &SS,
bool isAddressOfOperand) {
- QualType ConvType = QualType::getFromOpaquePtr(Ty);
- QualType ConvTypeCanon = Context.getCanonicalType(ConvType);
- DeclarationName ConvName
+ //FIXME: Preserve type source info.
+ QualType ConvType = GetTypeFromParser(Ty);
+ CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType);
+ DeclarationName ConvName
= Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen,
&SS, isAddressOfOperand);
@@ -59,12 +61,17 @@ Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc,
Action::OwningExprResult
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
- NamespaceDecl *StdNs = GetStdNamespace();
- if (!StdNs)
+ if (!StdNamespace)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
-
+
+ if (isType)
+ // FIXME: Preserve type source info.
+ TyOrExpr = GetTypeFromParser(TyOrExpr).getAsOpaquePtr();
+
IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
- Decl *TypeInfoDecl = LookupQualifiedName(StdNs, TypeInfoII, LookupTagName);
+ LookupResult R;
+ LookupQualifiedName(R, StdNamespace, TypeInfoII, LookupTagName);
+ Decl *TypeInfoDecl = R.getAsSingleDecl(Context);
RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl);
if (!TypeInfoRecordDecl)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
@@ -73,29 +80,29 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
if (!isType) {
// C++0x [expr.typeid]p3:
- // When typeid is applied to an expression other than an lvalue of a
- // polymorphic class type [...] [the] expression is an unevaluated
+ // When typeid is applied to an expression other than an lvalue of a
+ // polymorphic class type [...] [the] expression is an unevaluated
// operand.
-
+
// FIXME: if the type of the expression is a class type, the class
// shall be completely defined.
bool isUnevaluatedOperand = true;
Expr *E = static_cast<Expr *>(TyOrExpr);
if (E && !E->isTypeDependent() && E->isLvalue(Context) == Expr::LV_Valid) {
QualType T = E->getType();
- if (const RecordType *RecordT = T->getAsRecordType()) {
+ if (const RecordType *RecordT = T->getAs<RecordType>()) {
CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
if (RecordD->isPolymorphic())
isUnevaluatedOperand = false;
}
}
-
+
// If this is an unevaluated operand, clear out the set of declaration
// references we have been computing.
if (isUnevaluatedOperand)
PotentiallyReferencedDeclStack.back().clear();
}
-
+
return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr,
TypeInfoType.withConst(),
SourceRange(OpLoc, RParenLoc)));
@@ -136,15 +143,15 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
// to an incomplete type other than (cv) void the program is ill-formed.
QualType Ty = E->getType();
int isPointer = 0;
- if (const PointerType* Ptr = Ty->getAsPointerType()) {
+ if (const PointerType* Ptr = Ty->getAs<PointerType>()) {
Ty = Ptr->getPointeeType();
isPointer = 1;
}
if (!isPointer || !Ty->isVoidType()) {
if (RequireCompleteType(ThrowLoc, Ty,
- isPointer ? diag::err_throw_incomplete_ptr
- : diag::err_throw_incomplete,
- E->getSourceRange(), SourceRange(), QualType()))
+ PDiag(isPointer ? diag::err_throw_incomplete_ptr
+ : diag::err_throw_incomplete)
+ << E->getSourceRange()))
return true;
}
@@ -179,7 +186,8 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
assert(TypeRep && "Missing type!");
- QualType Ty = QualType::getFromOpaquePtr(TypeRep);
+ // FIXME: Preserve type source info.
+ QualType Ty = GetTypeFromParser(TypeRep);
unsigned NumExprs = exprs.size();
Expr **Exprs = (Expr**)exprs.get();
SourceLocation TyBeginLoc = TypeRange.getBegin();
@@ -188,14 +196,27 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
if (Ty->isDependentType() ||
CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) {
exprs.release();
-
- return Owned(CXXUnresolvedConstructExpr::Create(Context,
- TypeRange.getBegin(), Ty,
+
+ return Owned(CXXUnresolvedConstructExpr::Create(Context,
+ TypeRange.getBegin(), Ty,
LParenLoc,
Exprs, NumExprs,
RParenLoc));
}
+ if (Ty->isArrayType())
+ return ExprError(Diag(TyBeginLoc,
+ diag::err_value_init_for_array_type) << FullRange);
+ if (!Ty->isVoidType() &&
+ RequireCompleteType(TyBeginLoc, Ty,
+ PDiag(diag::err_invalid_incomplete_type_use)
+ << FullRange))
+ return ExprError();
+
+ if (RequireNonAbstractType(TyBeginLoc, Ty,
+ diag::err_allocation_of_abstract_type))
+ return ExprError();
+
// C++ [expr.type.conv]p1:
// If the expression list is a single expression, the type conversion
@@ -203,36 +224,54 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
// corresponding cast expression.
//
if (NumExprs == 1) {
- if (CheckCastTypes(TypeRange, Ty, Exprs[0]))
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ CXXMethodDecl *Method = 0;
+ if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, Method,
+ /*FunctionalStyle=*/true))
return ExprError();
+
exprs.release();
+ if (Method) {
+ OwningExprResult CastArg
+ = BuildCXXCastArgument(TypeRange.getBegin(), Ty.getNonReferenceType(),
+ Kind, Method, Owned(Exprs[0]));
+ if (CastArg.isInvalid())
+ return ExprError();
+
+ Exprs[0] = CastArg.takeAs<Expr>();
+ }
+
return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
- Ty, TyBeginLoc, Exprs[0],
- RParenLoc));
+ Ty, TyBeginLoc, Kind,
+ Exprs[0], RParenLoc));
}
- if (const RecordType *RT = Ty->getAsRecordType()) {
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
- // FIXME: We should always create a CXXTemporaryObjectExpr here unless
- // both the ctor and dtor are trivial.
- if (NumExprs > 1 || Record->hasUserDeclaredConstructor()) {
+ if (NumExprs > 1 || !Record->hasTrivialConstructor() ||
+ !Record->hasTrivialDestructor()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(Ty, Exprs, NumExprs,
+ = PerformInitializationByConstructor(Ty, move(exprs),
TypeRange.getBegin(),
SourceRange(TypeRange.getBegin(),
RParenLoc),
DeclarationName(),
- IK_Direct);
+ IK_Direct,
+ ConstructorArgs);
if (!Constructor)
return ExprError();
- exprs.release();
- Expr *E = new (Context) CXXTemporaryObjectExpr(Context, Constructor,
- Ty, TyBeginLoc, Exprs,
- NumExprs, RParenLoc);
- return MaybeBindToTemporary(E);
+ OwningExprResult Result =
+ BuildCXXTemporaryObjectExpr(Constructor, Ty, TyBeginLoc,
+ move_arg(ConstructorArgs), RParenLoc);
+ if (Result.isInvalid())
+ return ExprError();
+
+ return MaybeBindToTemporary(Result.takeAs<Expr>());
}
// Fall through to value-initialize an object of class type that
@@ -255,18 +294,6 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
// complete object type or the (possibly cv-qualified) void type, creates an
// rvalue of the specified type, which is value-initialized.
//
- if (Ty->isArrayType())
- return ExprError(Diag(TyBeginLoc,
- diag::err_value_init_for_array_type) << FullRange);
- if (!Ty->isDependentType() && !Ty->isVoidType() &&
- RequireCompleteType(TyBeginLoc, Ty,
- diag::err_invalid_incomplete_type_use, FullRange))
- return ExprError();
-
- if (RequireNonAbstractType(TyBeginLoc, Ty,
- diag::err_allocation_of_abstract_type))
- return ExprError();
-
exprs.release();
return Owned(new (Context) CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc));
}
@@ -283,8 +310,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementRParen, bool ParenTypeId,
Declarator &D, SourceLocation ConstructorLParen,
MultiExprArg ConstructorArgs,
- SourceLocation ConstructorRParen)
-{
+ SourceLocation ConstructorRParen) {
Expr *ArraySize = 0;
unsigned Skip = 0;
// If the specified type is an array, unwrap it and save the expression.
@@ -301,29 +327,37 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
Skip = 1;
}
- QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip);
- if (D.isInvalidType())
- return ExprError();
-
// Every dimension shall be of constant size.
- unsigned i = 1;
- QualType ElementType = AllocType;
- while (const ArrayType *Array = Context.getAsArrayType(ElementType)) {
- if (!Array->isConstantArrayType()) {
- Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst)
- << static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange();
- return ExprError();
+ if (D.getNumTypeObjects() > 0 &&
+ D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
+ for (unsigned I = 1, N = D.getNumTypeObjects(); I < N; ++I) {
+ if (D.getTypeObject(I).Kind != DeclaratorChunk::Array)
+ break;
+
+ DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr;
+ if (Expr *NumElts = (Expr *)Array.NumElts) {
+ if (!NumElts->isTypeDependent() && !NumElts->isValueDependent() &&
+ !NumElts->isIntegerConstantExpr(Context)) {
+ Diag(D.getTypeObject(I).Loc, diag::err_new_array_nonconst)
+ << NumElts->getSourceRange();
+ return ExprError();
+ }
+ }
}
- ElementType = Array->getElementType();
- ++i;
}
+
+ //FIXME: Store DeclaratorInfo in CXXNew expression.
+ DeclaratorInfo *DInfo = 0;
+ QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo, Skip);
+ if (D.isInvalidType())
+ return ExprError();
- return BuildCXXNew(StartLoc, UseGlobal,
+ return BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
- move(PlacementArgs),
+ move(PlacementArgs),
PlacementRParen,
ParenTypeId,
- AllocType,
+ AllocType,
D.getSourceRange().getBegin(),
D.getSourceRange(),
Owned(ArraySize),
@@ -332,12 +366,12 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
ConstructorRParen);
}
-Sema::OwningExprResult
+Sema::OwningExprResult
Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
- bool ParenTypeId,
+ bool ParenTypeId,
QualType AllocType,
SourceLocation TypeLoc,
SourceRange TypeRange,
@@ -369,12 +403,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
llvm::APSInt Value;
if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) {
if (Value < llvm::APSInt(
- llvm::APInt::getNullValue(Value.getBitWidth()), false))
+ llvm::APInt::getNullValue(Value.getBitWidth()),
+ Value.isUnsigned()))
return ExprError(Diag(ArraySize->getSourceRange().getBegin(),
diag::err_typecheck_negative_array_size)
<< ArraySize->getSourceRange());
}
}
+
+ ImpCastExprToType(ArraySize, Context.getSizeType());
}
FunctionDecl *OperatorNew = 0;
@@ -413,17 +450,24 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
unsigned NumConsArgs = ConstructorArgs.size();
if (AllocType->isDependentType()) {
// Skip all the checks.
- }
- else if ((RT = AllocType->getAsRecordType()) &&
- !AllocType->isAggregateType()) {
+ } else if ((RT = AllocType->getAs<RecordType>()) &&
+ !AllocType->isAggregateType()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
+
Constructor = PerformInitializationByConstructor(
- AllocType, ConsArgs, NumConsArgs,
+ AllocType, move(ConstructorArgs),
TypeLoc,
SourceRange(TypeLoc, ConstructorRParen),
RT->getDecl()->getDeclName(),
- NumConsArgs != 0 ? IK_Direct : IK_Default);
+ NumConsArgs != 0 ? IK_Direct : IK_Default,
+ ConvertedConstructorArgs);
if (!Constructor)
return ExprError();
+
+ // Take the converted constructor arguments and use them for the new
+ // expression.
+ NumConsArgs = ConvertedConstructorArgs.size();
+ ConsArgs = (Expr **)ConvertedConstructorArgs.take();
} else {
if (!Init) {
// FIXME: Check that no subpart is const.
@@ -454,15 +498,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs,
NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init,
ConsArgs, NumConsArgs, OperatorDelete, ResultType,
- StartLoc, Init ? ConstructorRParen : SourceLocation()));
+ StartLoc, Init ? ConstructorRParen : SourceLocation()));
}
/// CheckAllocatedType - Checks that a type is suitable as the allocated type
/// in a new-expression.
/// dimension off and stores the size expression in ArraySize.
bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
- SourceRange R)
-{
+ SourceRange R) {
// C++ 5.3.4p1: "[The] type shall be a complete object type, but not an
// abstract class type or array thereof.
if (AllocType->isFunctionType())
@@ -473,8 +516,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
<< AllocType << 1 << R;
else if (!AllocType->isDependentType() &&
RequireCompleteType(Loc, AllocType,
- diag::err_new_incomplete_type,
- R))
+ PDiag(diag::err_new_incomplete_type)
+ << R))
return true;
else if (RequireNonAbstractType(Loc, AllocType,
diag::err_allocation_of_abstract_type))
@@ -490,8 +533,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool IsArray, Expr **PlaceArgs,
unsigned NumPlaceArgs,
FunctionDecl *&OperatorNew,
- FunctionDecl *&OperatorDelete)
-{
+ FunctionDecl *&OperatorDelete) {
// --- Choosing an allocation function ---
// C++ 5.3.4p8 - 14 & 18
// 1) If UseGlobal is true, only look in the global scope. Else, also look
@@ -506,17 +548,18 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// We don't care about the actual value of this argument.
// FIXME: Should the Sema create the expression and embed it in the syntax
// tree? Or should the consumer just recalculate the value?
- AllocArgs[0] = new (Context) IntegerLiteral(llvm::APInt::getNullValue(
- Context.Target.getPointerWidth(0)),
- Context.getSizeType(),
- SourceLocation());
+ IntegerLiteral Size(llvm::APInt::getNullValue(
+ Context.Target.getPointerWidth(0)),
+ Context.getSizeType(),
+ SourceLocation());
+ AllocArgs[0] = &Size;
std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1);
DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName(
IsArray ? OO_Array_New : OO_New);
if (AllocType->isRecordType() && !UseGlobal) {
- CXXRecordDecl *Record
- = cast<CXXRecordDecl>(AllocType->getAsRecordType()->getDecl());
+ CXXRecordDecl *Record
+ = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl());
// FIXME: We fail to find inherited overloads.
if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0],
AllocArgs.size(), Record, /*AllowMissing=*/true,
@@ -537,10 +580,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// copy them back.
if (NumPlaceArgs > 0)
std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs);
-
- // FIXME: This is leaked on error. But so much is currently in Sema that it's
- // easier to clean it in one go.
- AllocArgs[0]->Destroy(Context);
+
return false;
}
@@ -549,24 +589,30 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
DeclarationName Name, Expr** Args,
unsigned NumArgs, DeclContext *Ctx,
- bool AllowMissing, FunctionDecl *&Operator)
-{
- DeclContext::lookup_iterator Alloc, AllocEnd;
- llvm::tie(Alloc, AllocEnd) = Ctx->lookup(Name);
- if (Alloc == AllocEnd) {
+ bool AllowMissing, FunctionDecl *&Operator) {
+ LookupResult R;
+ LookupQualifiedName(R, Ctx, Name, LookupOrdinaryName);
+ if (R.empty()) {
if (AllowMissing)
return false;
return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
<< Name << Range;
}
+ // FIXME: handle ambiguity
+
OverloadCandidateSet Candidates;
- for (; Alloc != AllocEnd; ++Alloc) {
+ for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
+ Alloc != AllocEnd; ++Alloc) {
// Even member operator new/delete are implicitly treated as
// static, so don't use AddMemberCandidate.
- if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc))
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc)) {
AddOverloadCandidate(Fn, Args, NumArgs, Candidates,
/*SuppressUserConversions=*/false);
+ continue;
+ }
+
+ // FIXME: Handle function templates
}
// Do the resolution.
@@ -578,7 +624,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// The first argument is size_t, and the first parameter must be size_t,
// too. This is checked on declaration and can be assumed. (It can't be
// asserted on, though, since invalid decls are left in there.)
- for (unsigned i = 1; i < NumArgs; ++i) {
+ for (unsigned i = 0; i < NumArgs; ++i) {
// FIXME: Passing word to diagnostic.
if (PerformCopyInitialization(Args[i],
FnDecl->getParamDecl(i)->getType(),
@@ -623,16 +669,52 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
/// @endcode
/// Note that the placement and nothrow forms of new are *not* implicitly
/// declared. Their use requires including \<new\>.
-void Sema::DeclareGlobalNewDelete()
-{
+void Sema::DeclareGlobalNewDelete() {
if (GlobalNewDeleteDeclared)
return;
+
+ // C++ [basic.std.dynamic]p2:
+ // [...] The following allocation and deallocation functions (18.4) are
+ // implicitly declared in global scope in each translation unit of a
+ // program
+ //
+ // void* operator new(std::size_t) throw(std::bad_alloc);
+ // void* operator new[](std::size_t) throw(std::bad_alloc);
+ // void operator delete(void*) throw();
+ // void operator delete[](void*) throw();
+ //
+ // These implicit declarations introduce only the function names operator
+ // new, operator new[], operator delete, operator delete[].
+ //
+ // Here, we need to refer to std::bad_alloc, so we will implicitly declare
+ // "std" or "bad_alloc" as necessary to form the exception specification.
+ // However, we do not make these implicit declarations visible to name
+ // lookup.
+ if (!StdNamespace) {
+ // The "std" namespace has not yet been defined, so build one implicitly.
+ StdNamespace = NamespaceDecl::Create(Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(),
+ &PP.getIdentifierTable().get("std"));
+ StdNamespace->setImplicit(true);
+ }
+
+ if (!StdBadAlloc) {
+ // The "std::bad_alloc" class has not yet been declared, so build it
+ // implicitly.
+ StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class,
+ StdNamespace,
+ SourceLocation(),
+ &PP.getIdentifierTable().get("bad_alloc"),
+ SourceLocation(), 0);
+ StdBadAlloc->setImplicit(true);
+ }
+
GlobalNewDeleteDeclared = true;
QualType VoidPtr = Context.getPointerType(Context.VoidTy);
QualType SizeT = Context.getSizeType();
- // FIXME: Exception specifications are not added.
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_New),
VoidPtr, SizeT);
@@ -650,8 +732,7 @@ void Sema::DeclareGlobalNewDelete()
/// DeclareGlobalAllocationFunction - Declares a single implicit global
/// allocation function if it doesn't already exist.
void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
- QualType Return, QualType Argument)
-{
+ QualType Return, QualType Argument) {
DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
// Check if this function is already declared.
@@ -667,14 +748,26 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
}
}
- QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0);
+ QualType BadAllocType;
+ bool HasBadAllocExceptionSpec
+ = (Name.getCXXOverloadedOperator() == OO_New ||
+ Name.getCXXOverloadedOperator() == OO_Array_New);
+ if (HasBadAllocExceptionSpec) {
+ assert(StdBadAlloc && "Must have std::bad_alloc declared");
+ BadAllocType = Context.getTypeDeclType(StdBadAlloc);
+ }
+
+ QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0,
+ true, false,
+ HasBadAllocExceptionSpec? 1 : 0,
+ &BadAllocType);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
- FnType, FunctionDecl::None, false, true,
- SourceLocation());
+ FnType, /*DInfo=*/0, FunctionDecl::None, false, true);
Alloc->setImplicit();
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
- 0, Argument, VarDecl::None, 0);
+ 0, Argument, /*DInfo=*/0,
+ VarDecl::None, 0);
Alloc->setParams(Context, &Param, 1);
// FIXME: Also add this declaration to the IdentifierResolver, but
@@ -689,43 +782,131 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
/// @code delete [] ptr; @endcode
Action::OwningExprResult
Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
- bool ArrayForm, ExprArg Operand)
-{
- // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type
- // having a single conversion function to a pointer type. The result has
- // type void."
+ bool ArrayForm, ExprArg Operand) {
+ // C++ [expr.delete]p1:
+ // The operand shall have a pointer type, or a class type having a single
+ // conversion function to a pointer type. The result has type void.
+ //
// DR599 amends "pointer type" to "pointer to object type" in both cases.
+ FunctionDecl *OperatorDelete = 0;
+
Expr *Ex = (Expr *)Operand.get();
if (!Ex->isTypeDependent()) {
QualType Type = Ex->getType();
- if (Type->isRecordType()) {
- // FIXME: Find that one conversion function and amend the type.
+ if (const RecordType *Record = Type->getAs<RecordType>()) {
+ llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions;
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ OverloadedFunctionDecl *Conversions =
+ RD->getVisibleConversionFunctions();
+
+ for (OverloadedFunctionDecl::function_iterator
+ Func = Conversions->function_begin(),
+ FuncEnd = Conversions->function_end();
+ Func != FuncEnd; ++Func) {
+ // Skip over templated conversion functions; they aren't considered.
+ if (isa<FunctionTemplateDecl>(*Func))
+ continue;
+
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+
+ QualType ConvType = Conv->getConversionType().getNonReferenceType();
+ if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
+ if (ConvPtrType->getPointeeType()->isObjectType())
+ ObjectPtrConversions.push_back(Conv);
+ }
+ if (ObjectPtrConversions.size() == 1) {
+ // We have a single conversion to a pointer-to-object type. Perform
+ // that conversion.
+ Operand.release();
+ if (!PerformImplicitConversion(Ex,
+ ObjectPtrConversions.front()->getConversionType(),
+ "converting")) {
+ Operand = Owned(Ex);
+ Type = Ex->getType();
+ }
+ }
+ else if (ObjectPtrConversions.size() > 1) {
+ Diag(StartLoc, diag::err_ambiguous_delete_operand)
+ << Type << Ex->getSourceRange();
+ for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) {
+ CXXConversionDecl *Conv = ObjectPtrConversions[i];
+ Diag(Conv->getLocation(), diag::err_ovl_candidate);
+ }
+ return ExprError();
+ }
}
if (!Type->isPointerType())
return ExprError(Diag(StartLoc, diag::err_delete_operand)
<< Type << Ex->getSourceRange());
- QualType Pointee = Type->getAsPointerType()->getPointeeType();
+ QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
if (Pointee->isFunctionType() || Pointee->isVoidType())
return ExprError(Diag(StartLoc, diag::err_delete_operand)
<< Type << Ex->getSourceRange());
else if (!Pointee->isDependentType() &&
- RequireCompleteType(StartLoc, Pointee,
- diag::warn_delete_incomplete,
- Ex->getSourceRange()))
+ RequireCompleteType(StartLoc, Pointee,
+ PDiag(diag::warn_delete_incomplete)
+ << Ex->getSourceRange()))
return ExprError();
- // FIXME: Look up the correct operator delete overload and pass a pointer
- // along.
+ // C++ [expr.delete]p2:
+ // [Note: a pointer to a const type can be the operand of a
+ // delete-expression; it is not necessary to cast away the constness
+ // (5.2.11) of the pointer expression before it is used as the operand
+ // of the delete-expression. ]
+ ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy),
+ CastExpr::CK_NoOp);
+
+ // Update the operand.
+ Operand.take();
+ Operand = ExprArg(*this, Ex);
+
+ DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
+ ArrayForm ? OO_Array_Delete : OO_Delete);
+
+ if (Pointee->isRecordType() && !UseGlobal) {
+ CXXRecordDecl *Record
+ = cast<CXXRecordDecl>(Pointee->getAs<RecordType>()->getDecl());
+
+ // Try to find operator delete/operator delete[] in class scope.
+ LookupResult Found;
+ LookupQualifiedName(Found, Record, DeleteName, LookupOrdinaryName);
+ // FIXME: Diagnose ambiguity properly
+ assert(!Found.isAmbiguous() && "Ambiguous delete/delete[] not handled");
+ for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
+ F != FEnd; ++F) {
+ if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F))
+ if (Delete->isUsualDeallocationFunction()) {
+ OperatorDelete = Delete;
+ break;
+ }
+ }
+
+ if (!Record->hasTrivialDestructor())
+ if (const CXXDestructorDecl *Dtor = Record->getDestructor(Context))
+ MarkDeclarationReferenced(StartLoc,
+ const_cast<CXXDestructorDecl*>(Dtor));
+ }
+
+ if (!OperatorDelete) {
+ // Didn't find a member overload. Look for a global one.
+ DeclareGlobalNewDelete();
+ DeclContext *TUDecl = Context.getTranslationUnitDecl();
+ if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName,
+ &Ex, 1, TUDecl, /*AllowMissing=*/false,
+ OperatorDelete))
+ return ExprError();
+ }
+
// FIXME: Check access and ambiguity of operator delete and destructor.
}
Operand.release();
return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm,
- 0, Ex, StartLoc));
+ OperatorDelete, Ex, StartLoc));
}
@@ -747,8 +928,11 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class of condition decl.");
- QualType Ty = GetTypeForDeclarator(D, S);
-
+ // FIXME: Store DeclaratorInfo in the expression.
+ DeclaratorInfo *DInfo = 0;
+ TagDecl *OwnedTag = 0;
+ QualType Ty = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag);
+
if (Ty->isFunctionType()) { // The declarator shall not specify a function...
// We exit without creating a CXXConditionDeclExpr because a FunctionDecl
// would be created and CXXConditionDeclExpr wants a VarDecl.
@@ -757,18 +941,9 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
} else if (Ty->isArrayType()) { // ...or an array.
Diag(StartLoc, diag::err_invalid_use_of_array_type)
<< SourceRange(StartLoc, EqualLoc);
- } else if (const RecordType *RT = Ty->getAsRecordType()) {
- RecordDecl *RD = RT->getDecl();
- // The type-specifier-seq shall not declare a new class...
- if (RD->isDefinition() &&
- (RD->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(RD))))
- Diag(RD->getLocation(), diag::err_type_defined_in_condition);
- } else if (const EnumType *ET = Ty->getAsEnumType()) {
- EnumDecl *ED = ET->getDecl();
- // ...or enumeration.
- if (ED->isDefinition() &&
- (ED->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(ED))))
- Diag(ED->getLocation(), diag::err_type_defined_in_condition);
+ } else if (OwnedTag && OwnedTag->isDefinition()) {
+ // The type-specifier-seq shall not declare a new class or enumeration.
+ Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition);
}
DeclPtrTy Dcl = ActOnDeclarator(S, D);
@@ -801,7 +976,7 @@ bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) {
/// conversion from a string literal to a pointer to non-const char or
/// non-const wchar_t (for narrow and wide string literals,
/// respectively).
-bool
+bool
Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
// Look inside the implicit cast, if it exists.
if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(From))
@@ -812,12 +987,12 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
// string literal can be converted to an rvalue of type "pointer
// to wchar_t" (C++ 4.2p2).
if (StringLiteral *StrLit = dyn_cast<StringLiteral>(From))
- if (const PointerType *ToPtrType = ToType->getAsPointerType())
- if (const BuiltinType *ToPointeeType
- = ToPtrType->getPointeeType()->getAsBuiltinType()) {
+ if (const PointerType *ToPtrType = ToType->getAs<PointerType>())
+ if (const BuiltinType *ToPointeeType
+ = ToPtrType->getPointeeType()->getAs<BuiltinType>()) {
// This conversion is considered only when there is an
// explicit appropriate pointer target type (C++ 4.2p2).
- if (ToPtrType->getPointeeType().getCVRQualifiers() == 0 &&
+ if (!ToPtrType->getPointeeType().hasQualifiers() &&
((StrLit->isWide() && ToPointeeType->isWideCharType()) ||
(!StrLit->isWide() &&
(ToPointeeType->getKind() == BuiltinType::Char_U ||
@@ -839,16 +1014,31 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const char *Flavor, bool AllowExplicit,
- bool Elidable)
-{
+ bool Elidable) {
ImplicitConversionSequence ICS;
+ return PerformImplicitConversion(From, ToType, Flavor, AllowExplicit,
+ Elidable, ICS);
+}
+
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ const char *Flavor, bool AllowExplicit,
+ bool Elidable,
+ ImplicitConversionSequence& ICS) {
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
if (Elidable && getLangOptions().CPlusPlus0x) {
- ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions*/false,
- AllowExplicit, /*ForceRValue*/true);
+ ICS = TryImplicitConversion(From, ToType,
+ /*SuppressUserConversions=*/false,
+ AllowExplicit,
+ /*ForceRValue=*/true,
+ /*InOverloadResolution=*/false);
}
if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
- ICS = TryImplicitConversion(From, ToType, false, AllowExplicit);
+ ICS = TryImplicitConversion(From, ToType,
+ /*SuppressUserConversions=*/false,
+ AllowExplicit,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
return PerformImplicitConversion(From, ToType, ICS, Flavor);
}
@@ -869,13 +1059,48 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
return true;
break;
- case ImplicitConversionSequence::UserDefinedConversion:
- // FIXME: This is, of course, wrong. We'll need to actually call the
- // constructor or conversion operator, and then cope with the standard
- // conversions.
- ImpCastExprToType(From, ToType.getNonReferenceType(),
- ToType->isLValueReferenceType());
- return false;
+ case ImplicitConversionSequence::UserDefinedConversion: {
+
+ FunctionDecl *FD = ICS.UserDefined.ConversionFunction;
+ CastExpr::CastKind CastKind = CastExpr::CK_Unknown;
+ QualType BeforeToType;
+ if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(FD)) {
+ CastKind = CastExpr::CK_UserDefinedConversion;
+
+ // If the user-defined conversion is specified by a conversion function,
+ // the initial standard conversion sequence converts the source type to
+ // the implicit object parameter of the conversion function.
+ BeforeToType = Context.getTagDeclType(Conv->getParent());
+ } else if (const CXXConstructorDecl *Ctor =
+ dyn_cast<CXXConstructorDecl>(FD)) {
+ CastKind = CastExpr::CK_ConstructorConversion;
+
+ // If the user-defined conversion is specified by a constructor, the
+ // initial standard conversion sequence converts the source type to the
+ // type required by the argument of the constructor
+ BeforeToType = Ctor->getParamDecl(0)->getType();
+ }
+ else
+ assert(0 && "Unknown conversion function kind!");
+
+ if (PerformImplicitConversion(From, BeforeToType,
+ ICS.UserDefined.Before, "converting"))
+ return true;
+
+ OwningExprResult CastArg
+ = BuildCXXCastArgument(From->getLocStart(),
+ ToType.getNonReferenceType(),
+ CastKind, cast<CXXMethodDecl>(FD),
+ Owned(From));
+
+ if (CastArg.isInvalid())
+ return true;
+
+ From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(),
+ CastKind, CastArg.takeAs<Expr>(),
+ ToType->isLValueReferenceType());
+ return false;
+ }
case ImplicitConversionSequence::EllipsisConversion:
assert(false && "Cannot perform an ellipsis conversion");
@@ -895,7 +1120,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
/// otherwise. The expression From is replaced with the converted
/// expression. Flavor is the context in which we're performing this
/// conversion, for use in error messages.
-bool
+bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
const char *Flavor) {
@@ -908,10 +1133,31 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
if (SCS.CopyConstructor) {
// FIXME: When can ToType be a reference type?
assert(!ToType->isReferenceType());
-
- // FIXME: Keep track of whether the copy constructor is elidable or not.
- From = CXXConstructExpr::Create(Context, ToType,
- SCS.CopyConstructor, false, &From, 1);
+ if (SCS.Second == ICK_Derived_To_Base) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+ if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor),
+ MultiExprArg(*this, (void **)&From, 1),
+ /*FIXME:ConstructLoc*/SourceLocation(),
+ ConstructorArgs))
+ return true;
+ OwningExprResult FromResult =
+ BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
+ ToType, SCS.CopyConstructor,
+ move_arg(ConstructorArgs));
+ if (FromResult.isInvalid())
+ return true;
+ From = FromResult.takeAs<Expr>();
+ return false;
+ }
+ OwningExprResult FromResult =
+ BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
+ ToType, SCS.CopyConstructor,
+ MultiExprArg(*this, (void**)&From, 1));
+
+ if (FromResult.isInvalid())
+ return true;
+
+ From = FromResult.takeAs<Expr>();
return false;
}
@@ -924,7 +1170,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Array_To_Pointer:
FromType = Context.getArrayDecayedType(FromType);
- ImpCastExprToType(From, FromType);
+ ImpCastExprToType(From, FromType, CastExpr::CK_ArrayToPointerDecay);
break;
case ICK_Function_To_Pointer:
@@ -940,7 +1186,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
FromType = From->getType();
}
FromType = Context.getPointerType(FromType);
- ImpCastExprToType(From, FromType);
+ ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay);
break;
default:
@@ -951,7 +1197,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// Perform the second implicit conversion
switch (SCS.Second) {
case ICK_Identity:
- // Nothing to do.
+ // If both sides are functions (or pointers/references to them), there could
+ // be incompatible exception declarations.
+ if (CheckExceptionSpecCompatibility(From, ToType))
+ return true;
+ // Nothing else to do.
break;
case ICK_Integral_Promotion:
@@ -968,26 +1218,32 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
ImpCastExprToType(From, FromType);
break;
- case ICK_Pointer_Conversion:
+ case ICK_Pointer_Conversion: {
if (SCS.IncompatibleObjC) {
// Diagnose incompatible Objective-C conversions
- Diag(From->getSourceRange().getBegin(),
+ Diag(From->getSourceRange().getBegin(),
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Flavor
<< From->getSourceRange();
}
- if (CheckPointerConversion(From, ToType))
+
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (CheckPointerConversion(From, ToType, Kind))
return true;
- ImpCastExprToType(From, ToType);
+ ImpCastExprToType(From, ToType, Kind);
break;
-
- case ICK_Pointer_Member:
- if (CheckMemberPointerConversion(From, ToType))
+ }
+
+ case ICK_Pointer_Member: {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (CheckMemberPointerConversion(From, ToType, Kind))
return true;
- ImpCastExprToType(From, ToType);
+ if (CheckExceptionSpecCompatibility(From, ToType))
+ return true;
+ ImpCastExprToType(From, ToType, Kind);
break;
-
+ }
case ICK_Boolean_Conversion:
FromType = Context.BoolTy;
ImpCastExprToType(From, FromType);
@@ -1006,7 +1262,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Qualification:
// FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue
// references.
- ImpCastExprToType(From, ToType.getNonReferenceType(),
+ ImpCastExprToType(From, ToType.getNonReferenceType(),
+ CastExpr::CK_Unknown,
ToType->isLValueReferenceType());
break;
@@ -1023,34 +1280,38 @@ Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
SourceLocation LParen,
TypeTy *Ty,
SourceLocation RParen) {
- // FIXME: Some of the type traits have requirements. Interestingly, only the
- // __is_base_of requirement is explicitly stated to be diagnosed. Indeed, G++
- // accepts __is_pod(Incomplete) without complaints, and claims that the type
- // is indeed a POD.
+ QualType T = GetTypeFromParser(Ty);
+
+ // According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
+ // all traits except __is_class, __is_enum and __is_union require a the type
+ // to be complete.
+ if (OTT != UTT_IsClass && OTT != UTT_IsEnum && OTT != UTT_IsUnion) {
+ if (RequireCompleteType(KWLoc, T,
+ diag::err_incomplete_type_used_in_type_trait_expr))
+ return ExprError();
+ }
// There is no point in eagerly computing the value. The traits are designed
// to be used from type trait templates, so Ty will be a template parameter
// 99% of the time.
- return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT,
- QualType::getFromOpaquePtr(Ty),
- RParen, Context.BoolTy));
+ return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT, T,
+ RParen, Context.BoolTy));
}
QualType Sema::CheckPointerToMemberOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) {
const char *OpSpelling = isIndirect ? "->*" : ".*";
// C++ 5.5p2
// The binary operator .* [p3: ->*] binds its second operand, which shall
// be of type "pointer to member of T" (where T is a completely-defined
// class type) [...]
QualType RType = rex->getType();
- const MemberPointerType *MemPtr = RType->getAsMemberPointerType();
+ const MemberPointerType *MemPtr = RType->getAs<MemberPointerType>();
if (!MemPtr) {
Diag(Loc, diag::err_bad_memptr_rhs)
<< OpSpelling << RType << rex->getSourceRange();
return QualType();
- }
+ }
QualType Class(MemPtr->getClass(), 0);
@@ -1060,7 +1321,7 @@ QualType Sema::CheckPointerToMemberOperands(
// such a class]
QualType LType = lex->getType();
if (isIndirect) {
- if (const PointerType *Ptr = LType->getAsPointerType())
+ if (const PointerType *Ptr = LType->getAs<PointerType>())
LType = Ptr->getPointeeType().getNonReferenceType();
else {
Diag(Loc, diag::err_bad_memptr_lhs)
@@ -1071,8 +1332,8 @@ QualType Sema::CheckPointerToMemberOperands(
if (Context.getCanonicalType(Class).getUnqualifiedType() !=
Context.getCanonicalType(LType).getUnqualifiedType()) {
- BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
- /*DetectVirtual=*/false);
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ /*DetectVirtual=*/false);
// FIXME: Would it be useful to print full ambiguity paths, or is that
// overkill?
if (!IsDerivedFrom(LType, Class, Paths) ||
@@ -1096,10 +1357,7 @@ QualType Sema::CheckPointerToMemberOperands(
// argument.
// We probably need a "MemberFunctionClosureType" or something like that.
QualType Result = MemPtr->getPointeeType();
- if (LType.isConstQualified())
- Result.addConst();
- if (LType.isVolatileQualified())
- Result.addVolatile();
+ Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers());
return Result;
}
@@ -1124,8 +1382,7 @@ static QualType TargetType(const ImplicitConversionSequence &ICS) {
/// conversion.
static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
SourceLocation QuestionLoc,
- ImplicitConversionSequence &ICS)
-{
+ ImplicitConversionSequence &ICS) {
// C++0x 5.16p3
// The process for determining whether an operand expression E1 of type T1
// can be converted to match an operand expression E2 of type T2 is defined
@@ -1137,7 +1394,11 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// conversion the reference must bind directly to E1.
if (!Self.CheckReferenceInit(From,
Self.Context.getLValueReferenceType(To->getType()),
- &ICS))
+ To->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ &ICS))
{
assert((ICS.ConversionKind ==
ImplicitConversionSequence::StandardConversion ||
@@ -1157,8 +1418,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// the same or one is a base class of the other:
QualType FTy = From->getType();
QualType TTy = To->getType();
- const RecordType *FRec = FTy->getAsRecordType();
- const RecordType *TRec = TTy->getAsRecordType();
+ const RecordType *FRec = FTy->getAs<RecordType>();
+ const RecordType *TRec = TTy->getAs<RecordType>();
bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy);
if (FRec && TRec && (FRec == TRec ||
FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
@@ -1169,7 +1430,10 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// Could still fail if there's no copy constructor.
// FIXME: Is this a hard error then, or just a conversion failure? The
// standard doesn't say.
- ICS = Self.TryCopyInitialization(From, TTy);
+ ICS = Self.TryCopyInitialization(From, TTy,
+ /*SuppressUserConversions=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
} else {
// -- Otherwise: E1 can be converted to match E2 if E1 can be
@@ -1178,12 +1442,16 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// First find the decayed type.
if (TTy->isFunctionType())
TTy = Self.Context.getPointerType(TTy);
- else if(TTy->isArrayType())
+ else if (TTy->isArrayType())
TTy = Self.Context.getArrayDecayedType(TTy);
// Now try the implicit conversion.
// FIXME: This doesn't detect ambiguities.
- ICS = Self.TryImplicitConversion(From, TTy);
+ ICS = Self.TryImplicitConversion(From, TTy,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
return false;
}
@@ -1239,8 +1507,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
/// second part of a standard conversion is ICK_DerivedToBase. This function
/// handles the reference binding specially.
static bool ConvertForConditional(Sema &Self, Expr *&E,
- const ImplicitConversionSequence &ICS)
-{
+ const ImplicitConversionSequence &ICS) {
if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion &&
ICS.Standard.ReferenceBinding) {
assert(ICS.Standard.DirectBinding &&
@@ -1248,14 +1515,22 @@ static bool ConvertForConditional(Sema &Self, Expr *&E,
// FIXME: CheckReferenceInit should be able to reuse the ICS instead of
// redoing all the work.
return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
- TargetType(ICS)));
+ TargetType(ICS)),
+ /*FIXME:*/E->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false);
}
if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion &&
ICS.UserDefined.After.ReferenceBinding) {
assert(ICS.UserDefined.After.DirectBinding &&
"TryClassUnification should never generate indirect ref bindings");
return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
- TargetType(ICS)));
+ TargetType(ICS)),
+ /*FIXME:*/E->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false);
}
if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting"))
return true;
@@ -1412,27 +1687,48 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// containing class, and second-level cv-ness.
// cv-ness is not a union, but must match one of the two operands. (Which,
// frankly, is stupid.)
- const MemberPointerType *LMemPtr = LTy->getAsMemberPointerType();
- const MemberPointerType *RMemPtr = RTy->getAsMemberPointerType();
- if (LMemPtr && RHS->isNullPointerConstant(Context)) {
+ const MemberPointerType *LMemPtr = LTy->getAs<MemberPointerType>();
+ const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>();
+ if (LMemPtr &&
+ RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(RHS, LTy);
return LTy;
}
- if (RMemPtr && LHS->isNullPointerConstant(Context)) {
+ if (RMemPtr &&
+ LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(LHS, RTy);
return RTy;
}
if (LMemPtr && RMemPtr) {
QualType LPointee = LMemPtr->getPointeeType();
QualType RPointee = RMemPtr->getPointeeType();
+
+ QualifierCollector LPQuals, RPQuals;
+ const Type *LPCan = LPQuals.strip(Context.getCanonicalType(LPointee));
+ const Type *RPCan = RPQuals.strip(Context.getCanonicalType(RPointee));
+
// First, we check that the unqualified pointee type is the same. If it's
// not, there's no conversion that will unify the two pointers.
- if (Context.getCanonicalType(LPointee).getUnqualifiedType() ==
- Context.getCanonicalType(RPointee).getUnqualifiedType()) {
- // Second, we take the greater of the two cv qualifications. If neither
+ if (LPCan == RPCan) {
+
+ // Second, we take the greater of the two qualifications. If neither
// is greater than the other, the conversion is not possible.
- unsigned Q = LPointee.getCVRQualifiers() | RPointee.getCVRQualifiers();
- if (Q == LPointee.getCVRQualifiers() || Q == RPointee.getCVRQualifiers()){
+
+ Qualifiers MergedQuals = LPQuals + RPQuals;
+
+ bool CompatibleQuals = true;
+ if (MergedQuals.getCVRQualifiers() != LPQuals.getCVRQualifiers() &&
+ MergedQuals.getCVRQualifiers() != RPQuals.getCVRQualifiers())
+ CompatibleQuals = false;
+ else if (LPQuals.getAddressSpace() != RPQuals.getAddressSpace())
+ // FIXME:
+ // C99 6.5.15 as modified by TR 18037:
+ // If the second and third operands are pointers into different
+ // address spaces, the address spaces must overlap.
+ CompatibleQuals = false;
+ // FIXME: GC qualifiers?
+
+ if (CompatibleQuals) {
// Third, we check if either of the container classes is derived from
// the other.
QualType LContainer(LMemPtr->getClass(), 0);
@@ -1450,8 +1746,9 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// The type 'Q Pointee (MoreDerived::*)' is the common type.
// We don't use ImpCastExprToType here because this could still fail
// for ambiguous or inaccessible conversions.
- QualType Common = Context.getMemberPointerType(
- LPointee.getQualifiedType(Q), MoreDerived.getTypePtr());
+ LPointee = Context.getQualifiedType(LPointee, MergedQuals);
+ QualType Common
+ = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr());
if (PerformImplicitConversion(LHS, Common, "converting"))
return QualType();
if (PerformImplicitConversion(RHS, Common, "converting"))
@@ -1470,30 +1767,37 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
/// \brief Find a merged pointer type and convert the two expressions to it.
///
-/// This finds the composite pointer type for @p E1 and @p E2 according to
-/// C++0x 5.9p2. It converts both expressions to this type and returns it.
+/// This finds the composite pointer type (or member pointer type) for @p E1
+/// and @p E2 according to C++0x 5.9p2. It converts both expressions to this
+/// type and returns it.
/// It does not emit diagnostics.
QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
assert(getLangOptions().CPlusPlus && "This function assumes C++");
QualType T1 = E1->getType(), T2 = E2->getType();
- if(!T1->isPointerType() && !T2->isPointerType())
- return QualType();
+
+ if (!T1->isPointerType() && !T1->isMemberPointerType() &&
+ !T2->isPointerType() && !T2->isMemberPointerType())
+ return QualType();
+
+ // FIXME: Do we need to work on the canonical types?
// C++0x 5.9p2
// Pointer conversions and qualification conversions are performed on
// pointer operands to bring them to their composite pointer type. If
// one operand is a null pointer constant, the composite pointer type is
// the type of the other operand.
- if (E1->isNullPointerConstant(Context)) {
+ if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(E1, T2);
return T2;
}
- if (E2->isNullPointerConstant(Context)) {
+ if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(E2, T1);
return T1;
}
- // Now both have to be pointers.
- if(!T1->isPointerType() || !T2->isPointerType())
+
+ // Now both have to be pointers or member pointers.
+ if (!T1->isPointerType() && !T1->isMemberPointerType() &&
+ !T2->isPointerType() && !T2->isMemberPointerType())
return QualType();
// Otherwise, of one of the operands has type "pointer to cv1 void," then
@@ -1506,32 +1810,93 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
// What we do here is, we build the two possible composite types, and try the
// conversions in both directions. If only one works, or if the two composite
// types are the same, we have succeeded.
+ // FIXME: extended qualifiers?
llvm::SmallVector<unsigned, 4> QualifierUnion;
+ llvm::SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
QualType Composite1 = T1, Composite2 = T2;
- const PointerType *Ptr1, *Ptr2;
- while ((Ptr1 = Composite1->getAsPointerType()) &&
- (Ptr2 = Composite2->getAsPointerType())) {
- Composite1 = Ptr1->getPointeeType();
- Composite2 = Ptr2->getPointeeType();
- QualifierUnion.push_back(
- Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
- }
- // Rewrap the composites as pointers with the union CVRs.
- for (llvm::SmallVector<unsigned, 4>::iterator I = QualifierUnion.begin(),
- E = QualifierUnion.end(); I != E; ++I) {
- Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I));
- Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I));
+ do {
+ const PointerType *Ptr1, *Ptr2;
+ if ((Ptr1 = Composite1->getAs<PointerType>()) &&
+ (Ptr2 = Composite2->getAs<PointerType>())) {
+ Composite1 = Ptr1->getPointeeType();
+ Composite2 = Ptr2->getPointeeType();
+ QualifierUnion.push_back(
+ Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
+ MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0));
+ continue;
+ }
+
+ const MemberPointerType *MemPtr1, *MemPtr2;
+ if ((MemPtr1 = Composite1->getAs<MemberPointerType>()) &&
+ (MemPtr2 = Composite2->getAs<MemberPointerType>())) {
+ Composite1 = MemPtr1->getPointeeType();
+ Composite2 = MemPtr2->getPointeeType();
+ QualifierUnion.push_back(
+ Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
+ MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(),
+ MemPtr2->getClass()));
+ continue;
+ }
+
+ // FIXME: block pointer types?
+
+ // Cannot unwrap any more types.
+ break;
+ } while (true);
+
+ // Rewrap the composites as pointers or member pointers with the union CVRs.
+ llvm::SmallVector<std::pair<const Type *, const Type *>, 4>::iterator MOC
+ = MemberOfClass.begin();
+ for (llvm::SmallVector<unsigned, 4>::iterator
+ I = QualifierUnion.begin(),
+ E = QualifierUnion.end();
+ I != E; (void)++I, ++MOC) {
+ Qualifiers Quals = Qualifiers::fromCVRMask(*I);
+ if (MOC->first && MOC->second) {
+ // Rebuild member pointer type
+ Composite1 = Context.getMemberPointerType(
+ Context.getQualifiedType(Composite1, Quals),
+ MOC->first);
+ Composite2 = Context.getMemberPointerType(
+ Context.getQualifiedType(Composite2, Quals),
+ MOC->second);
+ } else {
+ // Rebuild pointer type
+ Composite1
+ = Context.getPointerType(Context.getQualifiedType(Composite1, Quals));
+ Composite2
+ = Context.getPointerType(Context.getQualifiedType(Composite2, Quals));
+ }
}
- ImplicitConversionSequence E1ToC1 = TryImplicitConversion(E1, Composite1);
- ImplicitConversionSequence E2ToC1 = TryImplicitConversion(E2, Composite1);
+ ImplicitConversionSequence E1ToC1 =
+ TryImplicitConversion(E1, Composite1,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+ ImplicitConversionSequence E2ToC1 =
+ TryImplicitConversion(E2, Composite1,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+
ImplicitConversionSequence E1ToC2, E2ToC2;
E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
if (Context.getCanonicalType(Composite1) !=
Context.getCanonicalType(Composite2)) {
- E1ToC2 = TryImplicitConversion(E1, Composite2);
- E2ToC2 = TryImplicitConversion(E2, Composite2);
+ E1ToC2 = TryImplicitConversion(E1, Composite2,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+ E2ToC2 = TryImplicitConversion(E2, Composite2,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
bool ToC1Viable = E1ToC1.ConversionKind !=
@@ -1556,84 +1921,264 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
}
Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
- const RecordType *RT = E->getType()->getAsRecordType();
+ if (!Context.getLangOptions().CPlusPlus)
+ return Owned(E);
+
+ const RecordType *RT = E->getType()->getAs<RecordType>();
if (!RT)
return Owned(E);
-
+
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialDestructor())
return Owned(E);
-
- CXXTemporary *Temp = CXXTemporary::Create(Context,
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ QualType Ty = CE->getCallee()->getType();
+ if (const PointerType *PT = Ty->getAs<PointerType>())
+ Ty = PT->getPointeeType();
+
+ const FunctionType *FTy = Ty->getAs<FunctionType>();
+ if (FTy->getResultType()->isReferenceType())
+ return Owned(E);
+ }
+ CXXTemporary *Temp = CXXTemporary::Create(Context,
RD->getDestructor(Context));
ExprTemporaries.push_back(Temp);
- MarkDestructorReferenced(E->getExprLoc(), E->getType());
+ if (CXXDestructorDecl *Destructor =
+ const_cast<CXXDestructorDecl*>(RD->getDestructor(Context)))
+ MarkDeclarationReferenced(E->getExprLoc(), Destructor);
// FIXME: Add the temporary to the temporaries vector.
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
}
-// FIXME: This doesn't handle casts yet.
-Expr *Sema::RemoveOutermostTemporaryBinding(Expr *E) {
- const RecordType *RT = E->getType()->getAsRecordType();
- if (!RT)
- return E;
-
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialDestructor())
- return E;
-
- /// The expr passed in must be a CXXExprWithTemporaries.
- CXXExprWithTemporaries *TempExpr = dyn_cast<CXXExprWithTemporaries>(E);
- if (!TempExpr)
- return E;
-
- Expr *SubExpr = TempExpr->getSubExpr();
- if (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(SubExpr)) {
- assert(BE->getTemporary() ==
- TempExpr->getTemporary(TempExpr->getNumTemporaries() - 1) &&
- "Found temporary is not last in list!");
-
- Expr *BindSubExpr = BE->getSubExpr();
- BE->setSubExpr(0);
-
- if (TempExpr->getNumTemporaries() == 1) {
- // There's just one temporary left, so we don't need the TempExpr node.
- TempExpr->Destroy(Context);
- return BindSubExpr;
- } else {
- TempExpr->removeLastTemporary();
- TempExpr->setSubExpr(BindSubExpr);
- BE->Destroy(Context);
- }
-
- return E;
- }
-
- // FIXME: We might need to handle other expressions here.
- return E;
-}
-
-Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
+Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
bool ShouldDestroyTemps) {
assert(SubExpr && "sub expression can't be null!");
-
+
if (ExprTemporaries.empty())
return SubExpr;
-
+
Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr,
- &ExprTemporaries[0],
+ &ExprTemporaries[0],
ExprTemporaries.size(),
ShouldDestroyTemps);
ExprTemporaries.clear();
-
+
return E;
}
+Sema::OwningExprResult
+Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
+ tok::TokenKind OpKind, TypeTy *&ObjectType) {
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+
+ Expr *BaseExpr = (Expr*)Base.get();
+ assert(BaseExpr && "no record expansion");
+
+ QualType BaseType = BaseExpr->getType();
+ if (BaseType->isDependentType()) {
+ // FIXME: member of the current instantiation
+ ObjectType = BaseType.getAsOpaquePtr();
+ return move(Base);
+ }
+
+ // C++ [over.match.oper]p8:
+ // [...] When operator->returns, the operator-> is applied to the value
+ // returned, with the original second operand.
+ if (OpKind == tok::arrow) {
+ // The set of types we've considered so far.
+ llvm::SmallPtrSet<CanQualType,8> CTypes;
+ llvm::SmallVector<SourceLocation, 8> Locations;
+ CTypes.insert(Context.getCanonicalType(BaseType));
+
+ while (BaseType->isRecordType()) {
+ Base = BuildOverloadedArrowExpr(S, move(Base), OpLoc);
+ BaseExpr = (Expr*)Base.get();
+ if (BaseExpr == NULL)
+ return ExprError();
+ if (CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(BaseExpr))
+ Locations.push_back(OpCall->getDirectCallee()->getLocation());
+ BaseType = BaseExpr->getType();
+ CanQualType CBaseType = Context.getCanonicalType(BaseType);
+ if (!CTypes.insert(CBaseType)) {
+ Diag(OpLoc, diag::err_operator_arrow_circular);
+ for (unsigned i = 0; i < Locations.size(); i++)
+ Diag(Locations[i], diag::note_declared_at);
+ return ExprError();
+ }
+ }
+ }
+
+ if (BaseType->isPointerType())
+ BaseType = BaseType->getPointeeType();
+
+ // We could end up with various non-record types here, such as extended
+ // vector types or Objective-C interfaces. Just return early and let
+ // ActOnMemberReferenceExpr do the work.
+ if (!BaseType->isRecordType()) {
+ // C++ [basic.lookup.classref]p2:
+ // [...] If the type of the object expression is of pointer to scalar
+ // type, the unqualified-id is looked up in the context of the complete
+ // postfix-expression.
+ ObjectType = 0;
+ return move(Base);
+ }
+
+ // C++ [basic.lookup.classref]p2:
+ // If the id-expression in a class member access (5.2.5) is an
+ // unqualified-id, and the type of the object expres- sion is of a class
+ // type C (or of pointer to a class type C), the unqualified-id is looked
+ // up in the scope of class C. [...]
+ ObjectType = BaseType.getAsOpaquePtr();
+ return move(Base);
+}
+
+Sema::OwningExprResult
+Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ IdentifierInfo *ClassName,
+ const CXXScopeSpec &SS,
+ bool HasTrailingLParen) {
+ if (SS.isInvalid())
+ return ExprError();
+
+ QualType BaseType;
+ if (isUnknownSpecialization(SS))
+ BaseType = Context.getTypenameType((NestedNameSpecifier *)SS.getScopeRep(),
+ ClassName);
+ else {
+ TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS);
+ if (!BaseTy) {
+ Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
+ << ClassName;
+ return ExprError();
+ }
+
+ BaseType = GetTypeFromParser(BaseTy);
+ }
+
+ CanQualType CanBaseType = Context.getCanonicalType(BaseType);
+ DeclarationName DtorName =
+ Context.DeclarationNames.getCXXDestructorName(CanBaseType);
+
+ OwningExprResult Result
+ = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+ DtorName, DeclPtrTy(), &SS);
+ if (Result.isInvalid() || HasTrailingLParen)
+ return move(Result);
+
+ // The only way a reference to a destructor can be used is to
+ // immediately call them. Since the next token is not a '(', produce a
+ // diagnostic and build the call now.
+ Expr *E = (Expr *)Result.get();
+ SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(E->getLocEnd());
+ Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
+ << isa<CXXPseudoDestructorExpr>(E)
+ << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
+
+ return ActOnCallExpr(0, move(Result), ExpectedLParenLoc,
+ MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc);
+}
+
+Sema::OwningExprResult
+Sema::ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ OverloadedOperatorKind OverOpKind,
+ const CXXScopeSpec *SS) {
+ if (SS && SS->isInvalid())
+ return ExprError();
+
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXOperatorName(OverOpKind);
+
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+ Name, DeclPtrTy(), SS);
+}
+
+Sema::OwningExprResult
+Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ TypeTy *Ty,
+ const CXXScopeSpec *SS) {
+ if (SS && SS->isInvalid())
+ return ExprError();
+
+ //FIXME: Preserve type source info.
+ QualType ConvType = GetTypeFromParser(Ty);
+ CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType);
+ DeclarationName ConvName =
+ Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
+
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+ ConvName, DeclPtrTy(), SS);
+}
+
+CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
+ CXXMethodDecl *Method) {
+ MemberExpr *ME =
+ new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method,
+ SourceLocation(), Method->getType());
+ QualType ResultType;
+ if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(Method))
+ ResultType = Conv->getConversionType().getNonReferenceType();
+ else
+ ResultType = Method->getResultType().getNonReferenceType();
+
+ CXXMemberCallExpr *CE =
+ new (Context) CXXMemberCallExpr(Context, ME, 0, 0,
+ ResultType,
+ SourceLocation());
+ return CE;
+}
+
+Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc,
+ QualType Ty,
+ CastExpr::CastKind Kind,
+ CXXMethodDecl *Method,
+ ExprArg Arg) {
+ Expr *From = Arg.takeAs<Expr>();
+
+ switch (Kind) {
+ default: assert(0 && "Unhandled cast kind!");
+ case CastExpr::CK_ConstructorConversion: {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ if (CompleteConstructorCall(cast<CXXConstructorDecl>(Method),
+ MultiExprArg(*this, (void **)&From, 1),
+ CastLoc, ConstructorArgs))
+ return ExprError();
+
+ return BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
+ move_arg(ConstructorArgs));
+ }
+
+ case CastExpr::CK_UserDefinedConversion: {
+ assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
+
+ // Cast to base if needed.
+ if (PerformObjectArgumentInitialization(From, Method))
+ return ExprError();
+
+ // Create an implicit call expr that calls it.
+ CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method);
+ return Owned(CE);
+ }
+ }
+}
+
Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
Expr *FullExpr = Arg.takeAs<Expr>();
if (FullExpr)
- FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr,
+ FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr,
/*ShouldDestroyTemps=*/true);
+
return Owned(FullExpr);
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 7bb6b44c39cf9..d7e4e4a67fe96 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -20,7 +20,7 @@
using namespace clang;
-Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
+Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
ExprTy **strings,
unsigned NumStrings) {
StringLiteral **Strings = reinterpret_cast<StringLiteral**>(strings);
@@ -30,40 +30,40 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
// each one, e.g. @"foo" "bar" @"baz" "qux" which need to be turned into one
// StringLiteral for ObjCStringLiteral to hold onto.
StringLiteral *S = Strings[0];
-
+
// If we have a multi-part string, merge it all together.
if (NumStrings != 1) {
// Concatenate objc strings.
llvm::SmallString<128> StrBuf;
llvm::SmallVector<SourceLocation, 8> StrLocs;
-
+
for (unsigned i = 0; i != NumStrings; ++i) {
S = Strings[i];
-
+
// ObjC strings can't be wide.
if (S->isWide()) {
Diag(S->getLocStart(), diag::err_cfstring_literal_not_string_constant)
<< S->getSourceRange();
return true;
}
-
+
// Get the string data.
StrBuf.append(S->getStrData(), S->getStrData()+S->getByteLength());
-
+
// Get the locations of the string tokens.
StrLocs.append(S->tokloc_begin(), S->tokloc_end());
-
+
// Free the temporary string.
S->Destroy(Context);
}
-
+
// Create the aggregate string with the appropriate content and location
// information.
S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(), false,
Context.getPointerType(Context.CharTy),
&StrLocs[0], StrLocs.size());
}
-
+
// Verify that this composite string is acceptable for ObjC strings.
if (CheckObjCString(S))
return true;
@@ -74,29 +74,29 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
// interface private (even though it appears in the header files).
QualType Ty = Context.getObjCConstantStringInterface();
if (!Ty.isNull()) {
- Ty = Context.getPointerType(Ty);
+ Ty = Context.getObjCObjectPointerType(Ty);
} else {
IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
- NamedDecl *IF = LookupName(TUScope, NSIdent, LookupOrdinaryName);
+ NamedDecl *IF = LookupSingleName(TUScope, NSIdent, LookupOrdinaryName);
if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
Context.setObjCConstantStringInterface(StrIF);
Ty = Context.getObjCConstantStringInterface();
- Ty = Context.getPointerType(Ty);
+ Ty = Context.getObjCObjectPointerType(Ty);
} else {
// If there is no NSString interface defined then treat constant
// strings as untyped objects and let the runtime figure it out later.
Ty = Context.getObjCIdType();
}
}
-
+
return new (Context) ObjCStringLiteral(S, Ty, AtLocs[0]);
}
-Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
+Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
QualType EncodedType,
SourceLocation RParenLoc) {
QualType StrTy;
- if (EncodedType->isDependentType())
+ if (EncodedType->isDependentType())
StrTy = Context.DependentTy;
else {
std::string Str;
@@ -111,7 +111,7 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1),
ArrayType::Normal, 0);
}
-
+
return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc);
}
@@ -120,7 +120,8 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
SourceLocation LParenLoc,
TypeTy *ty,
SourceLocation RParenLoc) {
- QualType EncodedType = QualType::getFromOpaquePtr(ty);
+ // FIXME: Preserve type source info ?
+ QualType EncodedType = GetTypeFromParser(ty);
return BuildObjCEncodeExpression(AtLoc, EncodedType, RParenLoc);
}
@@ -130,8 +131,8 @@ Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
SourceLocation SelLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
- ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LParenLoc, RParenLoc));
+ ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
+ SourceRange(LParenLoc, RParenLoc), false);
if (!Method)
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LParenLoc, RParenLoc));
@@ -152,19 +153,19 @@ Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId;
return true;
}
-
+
QualType Ty = Context.getObjCProtoType();
if (Ty.isNull())
return true;
- Ty = Context.getPointerType(Ty);
+ Ty = Context.getObjCObjectPointerType(Ty);
return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc);
}
-bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
- Selector Sel, ObjCMethodDecl *Method,
+bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+ Selector Sel, ObjCMethodDecl *Method,
bool isClassMessage,
SourceLocation lbrac, SourceLocation rbrac,
- QualType &ReturnType) {
+ QualType &ReturnType) {
if (!Method) {
// Apply default argument promotion as for (C99 6.5.2.2p6).
for (unsigned i = 0; i != NumArgs; i++)
@@ -177,9 +178,9 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
ReturnType = Context.getObjCIdType();
return false;
}
-
+
ReturnType = Method->getResultType();
-
+
unsigned NumNamedArgs = Sel.getNumArgs();
assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!");
@@ -187,22 +188,22 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
for (unsigned i = 0; i < NumNamedArgs; i++) {
Expr *argExpr = Args[i];
assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
-
+
QualType lhsType = Method->param_begin()[i]->getType();
QualType rhsType = argExpr->getType();
- // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8].
+ // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8].
if (lhsType->isArrayType())
lhsType = Context.getArrayDecayedType(lhsType);
else if (lhsType->isFunctionType())
lhsType = Context.getPointerType(lhsType);
- AssignConvertType Result =
+ AssignConvertType Result =
CheckSingleAssignmentConstraints(lhsType, argExpr);
if (Args[i] != argExpr) // The expression was converted.
Args[i] = argExpr; // Make sure we store the converted expression.
-
- IsError |=
+
+ IsError |=
DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType,
argExpr, "sending");
}
@@ -214,7 +215,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
} else {
// Check for extra arguments to non-variadic methods.
if (NumArgs != NumNamedArgs) {
- Diag(Args[NumNamedArgs]->getLocStart(),
+ Diag(Args[NumNamedArgs]->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 2 /*method*/ << Method->getSourceRange()
<< SourceRange(Args[NumNamedArgs]->getLocStart(),
@@ -241,29 +242,24 @@ ObjCMethodDecl *Sema::LookupPrivateClassMethod(Selector Sel,
ObjCMethodDecl *Method = 0;
// lookup in class and all superclasses
while (ClassDecl && !Method) {
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
Method = ImpDecl->getClassMethod(Sel);
-
+
// Look through local category implementations associated with the class.
- if (!Method) {
- for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) {
- if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl)
- Method = ObjCCategoryImpls[i]->getClassMethod(Sel);
- }
- }
-
+ if (!Method)
+ Method = ClassDecl->getCategoryClassMethod(Sel);
+
// Before we give up, check if the selector is an instance method.
// But only in the root. This matches gcc's behaviour and what the
// runtime expects.
if (!Method && !ClassDecl->getSuperClass()) {
Method = ClassDecl->lookupInstanceMethod(Sel);
- // Look through local category implementations associated
+ // Look through local category implementations associated
// with the root class.
- if (!Method)
+ if (!Method)
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
}
-
+
ClassDecl = ClassDecl->getSuperClass();
}
return Method;
@@ -274,17 +270,12 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
ObjCMethodDecl *Method = 0;
while (ClassDecl && !Method) {
// If we have implementations in scope, check "private" methods.
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
Method = ImpDecl->getInstanceMethod(Sel);
-
+
// Look through local category implementations associated with the class.
- if (!Method) {
- for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) {
- if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl)
- Method = ObjCCategoryImpls[i]->getInstanceMethod(Sel);
- }
- }
+ if (!Method)
+ Method = ClassDecl->getCategoryInstanceMethod(Sel);
ClassDecl = ClassDecl->getSuperClass();
}
return Method;
@@ -295,11 +286,11 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
IdentifierInfo &propertyName,
SourceLocation &receiverNameLoc,
SourceLocation &propertyNameLoc) {
-
+
ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(&receiverName);
-
+
// Search for a declared property first.
-
+
Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName);
ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel);
@@ -307,8 +298,7 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
if (!Getter)
if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
Getter = ImpDecl->getClassMethod(Sel);
if (Getter) {
@@ -317,29 +307,24 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
if (DiagnoseUseOfDecl(Getter, propertyNameLoc))
return ExprError();
}
-
+
// Look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
PP.getSelectorTable(), &propertyName);
-
+
ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
if (!Setter) {
// If this reference is in an @implementation, also check for 'private'
// methods.
if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
Setter = ImpDecl->getClassMethod(SetterSel);
}
// Look through local category implementations associated with the class.
- if (!Setter) {
- for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
- if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
- Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel);
- }
- }
+ if (!Setter)
+ Setter = IFace->getCategoryClassMethod(SetterSel);
if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc))
return ExprError();
@@ -354,7 +339,8 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
E = Setter->param_end(); PI != E; ++PI)
PType = (*PI)->getType();
}
- return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, Setter,
+ return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(
+ Getter, PType, Setter,
propertyNameLoc, IFace, receiverNameLoc));
}
return ExprError(Diag(propertyNameLoc, diag::err_property_not_found)
@@ -369,32 +355,31 @@ Sema::ExprResult Sema::ActOnClassMessage(
Scope *S,
IdentifierInfo *receiverName, Selector Sel,
SourceLocation lbrac, SourceLocation receiverLoc,
- SourceLocation selectorLoc, SourceLocation rbrac,
- ExprTy **Args, unsigned NumArgs)
-{
+ SourceLocation selectorLoc, SourceLocation rbrac,
+ ExprTy **Args, unsigned NumArgs) {
assert(receiverName && "missing receiver class name");
Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
ObjCInterfaceDecl* ClassDecl = 0;
bool isSuper = false;
-
+
if (receiverName->isStr("super")) {
if (getCurMethodDecl()) {
isSuper = true;
ObjCInterfaceDecl *OID = getCurMethodDecl()->getClassInterface();
if (!OID)
- return Diag(lbrac, diag::error_no_super_class_message)
+ return Diag(lbrac, diag::error_no_super_class_message)
<< getCurMethodDecl()->getDeclName();
ClassDecl = OID->getSuperClass();
if (!ClassDecl)
return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName();
if (getCurMethodDecl()->isInstanceMethod()) {
QualType superTy = Context.getObjCInterfaceType(ClassDecl);
- superTy = Context.getPointerType(superTy);
+ superTy = Context.getObjCObjectPointerType(superTy);
ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(),
superTy);
// We are really in an instance method, redirect.
- return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
+ return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
selectorLoc, rbrac, Args, NumArgs);
}
// We are sending a message to 'super' within a class method. Do nothing,
@@ -402,20 +387,21 @@ Sema::ExprResult Sema::ActOnClassMessage(
} else {
// 'super' has been used outside a method context. If a variable named
// 'super' has been declared, redirect. If not, produce a diagnostic.
- NamedDecl *SuperDecl = LookupName(S, receiverName, LookupOrdinaryName);
+ NamedDecl *SuperDecl
+ = LookupSingleName(S, receiverName, LookupOrdinaryName);
ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl);
if (VD) {
- ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(),
+ ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(),
receiverLoc);
// We are really in an instance method, redirect.
- return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
+ return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
selectorLoc, rbrac, Args, NumArgs);
}
return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
- }
+ }
} else
ClassDecl = getObjCInterfaceDecl(receiverName);
-
+
// The following code allows for the following GCC-ism:
//
// typedef XCElementDisplayRect XCElementGraphicsRect;
@@ -427,10 +413,11 @@ Sema::ExprResult Sema::ActOnClassMessage(
//
// If necessary, the following lookup could move to getObjCInterfaceDecl().
if (!ClassDecl) {
- NamedDecl *IDecl = LookupName(TUScope, receiverName, LookupOrdinaryName);
+ NamedDecl *IDecl
+ = LookupSingleName(TUScope, receiverName, LookupOrdinaryName);
if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) {
const ObjCInterfaceType *OCIT;
- OCIT = OCTD->getUnderlyingType()->getAsObjCInterfaceType();
+ OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>();
if (!OCIT) {
Diag(receiverLoc, diag::err_invalid_receiver_to_message);
return true;
@@ -446,25 +433,25 @@ Sema::ExprResult Sema::ActOnClassMessage(
Diag(lbrac, diag::warn_receiver_forward_class) << ClassDecl->getDeclName();
Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac));
if (Method)
- Diag(Method->getLocation(), diag::note_method_sent_forward_class)
+ Diag(Method->getLocation(), diag::note_method_sent_forward_class)
<< Method->getDeclName();
}
if (!Method)
Method = ClassDecl->lookupClassMethod(Sel);
-
+
// If we have an implementation in scope, check "private" methods.
if (!Method)
Method = LookupPrivateClassMethod(Sel, ClassDecl);
if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
return true;
-
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true,
+
+ if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
-
+
// If we have the ObjCInterfaceDecl* for the class that is receiving the
// message, use that to construct the ObjCMessageExpr. Otherwise pass on the
// IdentifierInfo* for the class.
@@ -483,19 +470,19 @@ Sema::ExprResult Sema::ActOnClassMessage(
// ArgExprs is optional - if it is present, the number of expressions
// is obtained from Sel.getNumArgs().
Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
- SourceLocation lbrac,
+ SourceLocation lbrac,
SourceLocation receiverLoc,
SourceLocation rbrac,
ExprTy **Args, unsigned NumArgs) {
assert(receiver && "missing receiver expression");
-
+
Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
Expr *RExpr = static_cast<Expr *>(receiver);
-
+
// If necessary, apply function/array conversion to the receiver.
// C99 6.7.5.3p[7,8].
DefaultFunctionArrayConversion(RExpr);
-
+
QualType returnType;
QualType ReceiverCType =
Context.getCanonicalType(RExpr->getType()).getUnqualifiedType();
@@ -508,8 +495,8 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) {
Method = SuperDecl->lookupInstanceMethod(Sel);
-
- if (!Method)
+
+ if (!Method)
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, SuperDecl);
}
@@ -521,39 +508,42 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
lbrac, rbrac, returnType))
return true;
-
+
returnType = returnType.getNonReferenceType();
return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
rbrac, ArgExprs, NumArgs);
}
// Handle messages to id.
- if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) ||
- ReceiverCType->isBlockPointerType() ||
+ if (ReceiverCType->isObjCIdType() || ReceiverCType->isBlockPointerType() ||
Context.isObjCNSObjectType(RExpr->getType())) {
ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(
Sel, SourceRange(lbrac,rbrac));
if (!Method)
Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac));
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
+ if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
rbrac, ArgExprs, NumArgs);
}
-
+
// Handle messages to Class.
- if (ReceiverCType == Context.getCanonicalType(Context.getObjCClassType())) {
+ if (ReceiverCType->isObjCClassType() ||
+ ReceiverCType->isObjCQualifiedClassType()) {
ObjCMethodDecl *Method = 0;
-
+
if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
// First check the public methods in the class interface.
Method = ClassDecl->lookupClassMethod(Sel);
-
+
if (!Method)
Method = LookupPrivateClassMethod(Sel, ClassDecl);
+
+ // FIXME: if we still haven't found a method, we need to look in
+ // protocols (if we have qualifiers).
}
if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
return true;
@@ -584,13 +574,13 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
rbrac, ArgExprs, NumArgs);
}
-
+
ObjCMethodDecl *Method = 0;
ObjCInterfaceDecl* ClassDecl = 0;
-
- // We allow sending a message to a qualified ID ("id<foo>"), which is ok as
+
+ // We allow sending a message to a qualified ID ("id<foo>"), which is ok as
// long as one of the protocols implements the selector (if not, warn).
- if (const ObjCObjectPointerType *QIdTy =
+ if (const ObjCObjectPointerType *QIdTy =
ReceiverCType->getAsObjCQualifiedIdType()) {
// Search protocols for instance methods.
for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
@@ -602,19 +592,19 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
break;
}
- } else if (const ObjCInterfaceType *OCIType =
- ReceiverCType->getAsPointerToObjCInterfaceType()) {
+ } else if (const ObjCObjectPointerType *OCIType =
+ ReceiverCType->getAsObjCInterfacePointerType()) {
// We allow sending a message to a pointer to an interface (an object).
-
- ClassDecl = OCIType->getDecl();
+
+ ClassDecl = OCIType->getInterfaceDecl();
// FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
// faster than the following method (which can do *many* linear searches).
// The idea is to add class info to InstanceMethodPool.
Method = ClassDecl->lookupInstanceMethod(Sel);
-
+
if (!Method) {
// Search protocol qualifiers.
- for (ObjCQualifiedInterfaceType::qual_iterator QI = OCIType->qual_begin(),
+ for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
E = OCIType->qual_end(); QI != E; ++QI) {
if ((Method = (*QI)->lookupInstanceMethod(Sel)))
break;
@@ -623,7 +613,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
if (!Method) {
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
-
+
if (!Method && !isSelfExpr(RExpr)) {
// If we still haven't found a method, look in the global pool. This
// behavior isn't very desirable, however we need it for GCC
@@ -631,9 +621,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
if (OCIType->qual_empty()) {
Method = LookupInstanceMethodInGlobalPool(
Sel, SourceRange(lbrac,rbrac));
- if (Method && !OCIType->getDecl()->isForwardDecl())
- Diag(lbrac, diag::warn_maynot_respond)
- << OCIType->getDecl()->getIdentifier()->getName() << Sel;
+ if (Method && !OCIType->getInterfaceDecl()->isForwardDecl())
+ Diag(lbrac, diag::warn_maynot_respond)
+ << OCIType->getInterfaceDecl()->getIdentifier()->getName() << Sel;
}
}
}
@@ -641,7 +631,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
return true;
} else if (!Context.getObjCIdType().isNull() &&
(ReceiverCType->isPointerType() ||
- (ReceiverCType->isIntegerType() &&
+ (ReceiverCType->isIntegerType() &&
ReceiverCType->isScalarType()))) {
// Implicitly convert integers and pointers to 'id' but emit a warning.
Diag(lbrac, diag::warn_bad_receiver_type)
@@ -653,7 +643,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
<< RExpr->getType() << RExpr->getSourceRange();
return true;
}
-
+
if (Method)
DiagnoseSentinelCalls(Method, receiverLoc, ArgExprs, NumArgs);
if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
@@ -664,217 +654,3 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
rbrac, ArgExprs, NumArgs);
}
-//===----------------------------------------------------------------------===//
-// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's.
-//===----------------------------------------------------------------------===//
-
-/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the
-/// inheritance hierarchy of 'rProto'.
-static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
- ObjCProtocolDecl *rProto) {
- if (lProto == rProto)
- return true;
- for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(),
- E = rProto->protocol_end(); PI != E; ++PI)
- if (ProtocolCompatibleWithProtocol(lProto, *PI))
- return true;
- return false;
-}
-
-/// ClassImplementsProtocol - Checks that 'lProto' protocol
-/// has been implemented in IDecl class, its super class or categories (if
-/// lookupCategory is true).
-static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto,
- ObjCInterfaceDecl *IDecl,
- bool lookupCategory,
- bool RHSIsQualifiedID = false) {
-
- // 1st, look up the class.
- const ObjCList<ObjCProtocolDecl> &Protocols =
- IDecl->getReferencedProtocols();
-
- for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(),
- E = Protocols.end(); PI != E; ++PI) {
- if (ProtocolCompatibleWithProtocol(lProto, *PI))
- return true;
- // This is dubious and is added to be compatible with gcc. In gcc, it is
- // also allowed assigning a protocol-qualified 'id' type to a LHS object
- // when protocol in qualified LHS is in list of protocols in the rhs 'id'
- // object. This IMO, should be a bug.
- // FIXME: Treat this as an extension, and flag this as an error when GCC
- // extensions are not enabled.
- if (RHSIsQualifiedID && ProtocolCompatibleWithProtocol(*PI, lProto))
- return true;
- }
-
- // 2nd, look up the category.
- if (lookupCategory)
- for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory()) {
- for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(),
- E = CDecl->protocol_end(); PI != E; ++PI)
- if (ProtocolCompatibleWithProtocol(lProto, *PI))
- return true;
- }
-
- // 3rd, look up the super class(s)
- if (IDecl->getSuperClass())
- return
- ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory,
- RHSIsQualifiedID);
-
- return false;
-}
-
-/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...>
-/// return true if lhs's protocols conform to rhs's protocol; false
-/// otherwise.
-bool Sema::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
- if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType())
- return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false);
- return false;
-}
-
-/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an
-/// ObjCQualifiedIDType.
-/// FIXME: Move to ASTContext::typesAreCompatible() and friends.
-bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
- bool compare) {
- // Allow id<P..> and an 'id' or void* type in all cases.
- if (const PointerType *PT = lhs->getAsPointerType()) {
- QualType PointeeTy = PT->getPointeeType();
- if (PointeeTy->isVoidType() ||
- Context.isObjCIdStructType(PointeeTy) ||
- Context.isObjCClassStructType(PointeeTy))
- return true;
- } else if (const PointerType *PT = rhs->getAsPointerType()) {
- QualType PointeeTy = PT->getPointeeType();
- if (PointeeTy->isVoidType() ||
- Context.isObjCIdStructType(PointeeTy) ||
- Context.isObjCClassStructType(PointeeTy))
- return true;
- }
-
- if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
- const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
- const ObjCQualifiedInterfaceType *rhsQI = 0;
- QualType rtype;
-
- if (!rhsQID) {
- // Not comparing two ObjCQualifiedIdType's?
- if (!rhs->isPointerType()) return false;
-
- rtype = rhs->getAsPointerType()->getPointeeType();
- rhsQI = rtype->getAsObjCQualifiedInterfaceType();
- if (rhsQI == 0) {
- // If the RHS is a unqualified interface pointer "NSString*",
- // make sure we check the class hierarchy.
- if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) {
- ObjCInterfaceDecl *rhsID = IT->getDecl();
- for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
- E = lhsQID->qual_end(); I != E; ++I) {
- // when comparing an id<P> on lhs with a static type on rhs,
- // see if static class implements all of id's protocols, directly or
- // through its super class and categories.
- if (!ClassImplementsProtocol(*I, rhsID, true))
- return false;
- }
- return true;
- }
- }
- }
-
- ObjCObjectPointerType::qual_iterator RHSProtoI, RHSProtoE;
- if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *").
- RHSProtoI = rhsQI->qual_begin();
- RHSProtoE = rhsQI->qual_end();
- } else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *").
- RHSProtoI = rhsQID->qual_begin();
- RHSProtoE = rhsQID->qual_end();
- } else {
- return false;
- }
-
- for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
- E = lhsQID->qual_end(); I != E; ++I) {
- ObjCProtocolDecl *lhsProto = *I;
- bool match = false;
-
- // when comparing an id<P> on lhs with a static type on rhs,
- // see if static class implements all of id's protocols, directly or
- // through its super class and categories.
- for (; RHSProtoI != RHSProtoE; ++RHSProtoI) {
- ObjCProtocolDecl *rhsProto = *RHSProtoI;
- if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
- (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
- match = true;
- break;
- }
- }
- if (rhsQI) {
- // If the RHS is a qualified interface pointer "NSString<P>*",
- // make sure we check the class hierarchy.
- if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) {
- ObjCInterfaceDecl *rhsID = IT->getDecl();
- for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
- E = lhsQID->qual_end(); I != E; ++I) {
- // when comparing an id<P> on lhs with a static type on rhs,
- // see if static class implements all of id's protocols, directly or
- // through its super class and categories.
- if (ClassImplementsProtocol(*I, rhsID, true)) {
- match = true;
- break;
- }
- }
- }
- }
- if (!match)
- return false;
- }
-
- return true;
- }
-
- const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
- assert(rhsQID && "One of the LHS/RHS should be id<x>");
-
- if (!lhs->isPointerType())
- return false;
-
- QualType ltype = lhs->getAsPointerType()->getPointeeType();
- if (const ObjCQualifiedInterfaceType *lhsQI =
- ltype->getAsObjCQualifiedInterfaceType()) {
- ObjCObjectPointerType::qual_iterator LHSProtoI = lhsQI->qual_begin();
- ObjCObjectPointerType::qual_iterator LHSProtoE = lhsQI->qual_end();
- for (; LHSProtoI != LHSProtoE; ++LHSProtoI) {
- bool match = false;
- ObjCProtocolDecl *lhsProto = *LHSProtoI;
- for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
- E = rhsQID->qual_end(); I != E; ++I) {
- ObjCProtocolDecl *rhsProto = *I;
- if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
- (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
- match = true;
- break;
- }
- }
- if (!match)
- return false;
- }
- return true;
- }
-
- if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) {
- // for static type vs. qualified 'id' type, check that class implements
- // all of 'id's protocols.
- ObjCInterfaceDecl *lhsID = IT->getDecl();
- for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
- E = rhsQID->qual_end(); I != E; ++I) {
- if (!ClassImplementsProtocol(*I, lhsID, compare, true))
- return false;
- }
- return true;
- }
- return false;
-}
-
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index ecfdfd7ba0b64..27f0896807633 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -36,7 +36,7 @@ static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) {
// See if this is a string literal or @encode.
Init = Init->IgnoreParens();
-
+
// Handle @encode, which is a narrow string.
if (isa<ObjCEncodeExpr>(Init) && AT->getElementType()->isCharType())
return Init;
@@ -58,26 +58,38 @@ static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) {
if (Context.typesAreCompatible(Context.getWCharType(),
ElemTy.getUnqualifiedType()))
return Init;
-
+
return 0;
}
-static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
+static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
bool DirectInit, Sema &S) {
// Get the type before calling CheckSingleAssignmentConstraints(), since
// it can promote the expression.
- QualType InitType = Init->getType();
-
+ QualType InitType = Init->getType();
+
if (S.getLangOptions().CPlusPlus) {
// FIXME: I dislike this error message. A lot.
- if (S.PerformImplicitConversion(Init, DeclType, "initializing", DirectInit))
- return S.Diag(Init->getSourceRange().getBegin(),
- diag::err_typecheck_convert_incompatible)
- << DeclType << Init->getType() << "initializing"
- << Init->getSourceRange();
+ if (S.PerformImplicitConversion(Init, DeclType,
+ "initializing", DirectInit)) {
+ ImplicitConversionSequence ICS;
+ OverloadCandidateSet CandidateSet;
+ if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined,
+ CandidateSet,
+ true, false, false) != S.OR_Ambiguous)
+ return S.Diag(Init->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_incompatible)
+ << DeclType << Init->getType() << "initializing"
+ << Init->getSourceRange();
+ S.Diag(Init->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_ambiguous)
+ << DeclType << Init->getType() << Init->getSourceRange();
+ S.PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ return true;
+ }
return false;
}
-
+
Sema::AssignConvertType ConvTy =
S.CheckSingleAssignmentConstraints(DeclType, Init);
return S.DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
@@ -89,21 +101,22 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
uint64_t StrLength =
cast<ConstantArrayType>(Str->getType())->getSize().getZExtValue();
-
+
const ArrayType *AT = S.Context.getAsArrayType(DeclT);
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) {
- // C99 6.7.8p14. We have an array of character type with unknown size
+ // C99 6.7.8p14. We have an array of character type with unknown size
// being initialized to a string literal.
llvm::APSInt ConstVal(32);
ConstVal = StrLength;
// Return a new array type (C99 6.7.8p22).
- DeclT = S.Context.getConstantArrayType(IAT->getElementType(), ConstVal,
- ArrayType::Normal, 0);
+ DeclT = S.Context.getConstantArrayWithoutExprType(IAT->getElementType(),
+ ConstVal,
+ ArrayType::Normal, 0);
return;
}
-
+
const ConstantArrayType *CAT = cast<ConstantArrayType>(AT);
-
+
// C99 6.7.8p14. We have an array of character type with known size. However,
// the size may be smaller or larger than the string we are initializing.
// FIXME: Avoid truncation for 64-bit length strings.
@@ -111,7 +124,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
S.Diag(Str->getSourceRange().getBegin(),
diag::warn_initializer_string_for_char_array_too_long)
<< Str->getSourceRange();
-
+
// Set the type to the actual size that we are initializing. If we have
// something like:
// char x[1] = "foo";
@@ -122,23 +135,26 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
SourceLocation InitLoc,
DeclarationName InitEntity, bool DirectInit) {
- if (DeclType->isDependentType() ||
+ if (DeclType->isDependentType() ||
Init->isTypeDependent() || Init->isValueDependent())
return false;
-
+
// C++ [dcl.init.ref]p1:
// A variable declared to be a T& or T&&, that is "reference to type T"
// (8.3.2), shall be initialized by an object, or function, of
// type T or by an object that can be converted into a T.
if (DeclType->isReferenceType())
- return CheckReferenceInit(Init, DeclType, 0, false, DirectInit);
-
+ return CheckReferenceInit(Init, DeclType, InitLoc,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/DirectInit,
+ /*ForceRValue=*/false);
+
// C99 6.7.8p3: The type of the entity to be initialized shall be an array
// of unknown size ("[]") or an object type that is not a variable array type.
if (const VariableArrayType *VAT = Context.getAsVariableArrayType(DeclType))
return Diag(InitLoc, diag::err_variable_object_no_init)
<< VAT->getSizeExpr()->getSourceRange();
-
+
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
if (!InitList) {
// FIXME: Handle wide strings
@@ -146,41 +162,52 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
CheckStringInit(Str, DeclType, *this);
return false;
}
-
+
// C++ [dcl.init]p14:
// -- If the destination type is a (possibly cv-qualified) class
// type:
if (getLangOptions().CPlusPlus && DeclType->isRecordType()) {
QualType DeclTypeC = Context.getCanonicalType(DeclType);
QualType InitTypeC = Context.getCanonicalType(Init->getType());
-
+
// -- If the initialization is direct-initialization, or if it is
// copy-initialization where the cv-unqualified version of the
// source type is the same class as, or a derived class of, the
// class of the destination, constructors are considered.
if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) ||
IsDerivedFrom(InitTypeC, DeclTypeC)) {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(DeclType->getAsRecordType()->getDecl());
-
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(DeclType->getAs<RecordType>()->getDecl());
+
// No need to make a CXXConstructExpr if both the ctor and dtor are
// trivial.
if (RD->hasTrivialConstructor() && RD->hasTrivialDestructor())
return false;
-
- CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(DeclType, &Init, 1,
- InitLoc, Init->getSourceRange(),
- InitEntity,
- DirectInit? IK_Direct : IK_Copy);
+
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(DeclType,
+ MultiExprArg(*this,
+ (void **)&Init, 1),
+ InitLoc, Init->getSourceRange(),
+ InitEntity,
+ DirectInit? IK_Direct : IK_Copy,
+ ConstructorArgs);
if (!Constructor)
return true;
-
- Init = CXXConstructExpr::Create(Context, DeclType, Constructor, false,
- &Init, 1);
+
+ OwningExprResult InitResult =
+ BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
+ DeclType, Constructor,
+ move_arg(ConstructorArgs));
+ if (InitResult.isInvalid())
+ return true;
+
+ Init = InitResult.takeAs<Expr>();
return false;
}
-
+
// -- Otherwise (i.e., for the remaining copy-initialization
// cases), user-defined conversion sequences that can
// convert from the source type to the destination type or
@@ -197,7 +224,7 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
// have ASTs for such things.
if (!PerformImplicitConversion(Init, DeclType, "initializing"))
return false;
-
+
if (InitEntity)
return Diag(InitLoc, diag::err_cannot_initialize_decl)
<< InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
@@ -206,15 +233,15 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
<< DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
<< Init->getType() << Init->getSourceRange();
}
-
+
// C99 6.7.8p16.
if (DeclType->isArrayType())
return Diag(Init->getLocStart(), diag::err_array_init_list_required)
<< Init->getSourceRange();
-
+
return CheckSingleInitializer(Init, DeclType, DirectInit, *this);
- }
-
+ }
+
bool hadError = CheckInitList(InitList, DeclType);
Init = InitList;
return hadError;
@@ -257,8 +284,8 @@ class InitListChecker {
bool hadError;
std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
InitListExpr *FullyStructuredList;
-
- void CheckImplicitInitList(InitListExpr *ParentIList, QualType T,
+
+ void CheckImplicitInitList(InitListExpr *ParentIList, QualType T,
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
@@ -266,41 +293,41 @@ class InitListChecker {
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
- bool SubobjectIsDesignatorContext,
+ void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
+ bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckSubElementType(InitListExpr *IList, QualType ElemType,
+ void CheckSubElementType(InitListExpr *IList, QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckScalarType(InitListExpr *IList, QualType DeclType,
+ void CheckScalarType(InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckReferenceType(InitListExpr *IList, QualType DeclType,
+ void CheckReferenceType(InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType,
- RecordDecl::field_iterator Field,
+ void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType,
+ RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckArrayType(InitListExpr *IList, QualType &DeclType,
- llvm::APSInt elementIndex,
+ void CheckArrayType(InitListExpr *IList, QualType &DeclType,
+ llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE,
+ bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE,
unsigned DesigIdx,
- QualType &CurrentObjectType,
+ QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
llvm::APSInt *NextElementIndex,
unsigned &Index,
@@ -334,15 +361,15 @@ public:
/// with expressions that perform value-initialization of the
/// appropriate type.
void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
- assert((ILE->getType() != SemaRef.Context.VoidTy) &&
+ assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
SourceLocation Loc = ILE->getSourceRange().getBegin();
if (ILE->getSyntacticForm())
Loc = ILE->getSyntacticForm()->getSourceRange().getBegin();
-
- if (const RecordType *RType = ILE->getType()->getAsRecordType()) {
+
+ if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
unsigned Init = 0, NumInits = ILE->getNumInits();
- for (RecordDecl::field_iterator
+ for (RecordDecl::field_iterator
Field = RType->getDecl()->field_begin(),
FieldEnd = RType->getDecl()->field_end();
Field != FieldEnd; ++Field) {
@@ -354,11 +381,11 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
// C++ [dcl.init.aggr]p9:
// If an incomplete or empty initializer-list leaves a
// member of reference type uninitialized, the program is
- // ill-formed.
+ // ill-formed.
SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
<< Field->getType()
<< ILE->getSyntacticForm()->getSourceRange();
- SemaRef.Diag(Field->getLocation(),
+ SemaRef.Diag(Field->getLocation(),
diag::note_uninit_reference_member);
hadError = true;
return;
@@ -371,9 +398,9 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
// we make that call explicit in the representation (even when it means
// extending the initializer list)?
if (Init < NumInits && !hadError)
- ILE->setInit(Init,
+ ILE->setInit(Init,
new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()));
- } else if (InitListExpr *InnerILE
+ } else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init)))
FillInValueInitializations(InnerILE);
++Init;
@@ -384,22 +411,22 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
}
return;
- }
+ }
QualType ElementType;
-
+
unsigned NumInits = ILE->getNumInits();
unsigned NumElements = NumInits;
if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) {
ElementType = AType->getElementType();
if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType))
NumElements = CAType->getSize().getZExtValue();
- } else if (const VectorType *VType = ILE->getType()->getAsVectorType()) {
+ } else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) {
ElementType = VType->getElementType();
NumElements = VType->getNumElements();
- } else
+ } else
ElementType = ILE->getType();
-
+
for (unsigned Init = 0; Init != NumElements; ++Init) {
if (Init >= NumInits || !ILE->getInit(Init)) {
if (SemaRef.CheckValueInitialization(ElementType, Loc)) {
@@ -411,10 +438,10 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
// we make that call explicit in the representation (even when it means
// extending the initializer list)?
if (Init < NumInits && !hadError)
- ILE->setInit(Init,
+ ILE->setInit(Init,
new (SemaRef.Context) ImplicitValueInitExpr(ElementType));
- }
- else if (InitListExpr *InnerILE =dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ } else if (InitListExpr *InnerILE
+ = dyn_cast<InitListExpr>(ILE->getInit(Init)))
FillInValueInitializations(InnerILE);
}
}
@@ -426,7 +453,7 @@ InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T)
unsigned newIndex = 0;
unsigned newStructuredIndex = 0;
- FullyStructuredList
+ FullyStructuredList
= getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange());
CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex,
/*TopLevelObject=*/true);
@@ -446,9 +473,9 @@ int InitListChecker::numArrayElements(QualType DeclType) {
}
int InitListChecker::numStructUnionElements(QualType DeclType) {
- RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl();
+ RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
int InitializableMembers = 0;
- for (RecordDecl::field_iterator
+ for (RecordDecl::field_iterator
Field = structDecl->field_begin(),
FieldEnd = structDecl->field_end();
Field != FieldEnd; ++Field) {
@@ -460,19 +487,19 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
-void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
+void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
QualType T, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject) {
int maxElements = 0;
-
+
if (T->isArrayType())
maxElements = numArrayElements(T);
else if (T->isStructureType() || T->isUnionType())
maxElements = numStructUnionElements(T);
else if (T->isVectorType())
- maxElements = T->getAsVectorType()->getNumElements();
+ maxElements = T->getAs<VectorType>()->getNumElements();
else
assert(0 && "CheckImplicitInitList(): Illegal type");
@@ -486,8 +513,8 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
// Build a structured initializer list corresponding to this subobject.
InitListExpr *StructuredSubobjectInitList
- = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList,
- StructuredIndex,
+ = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList,
+ StructuredIndex,
SourceRange(ParentIList->getInit(Index)->getSourceRange().getBegin(),
ParentIList->getSourceRange().getEnd()));
unsigned StructuredSubobjectInitIndex = 0;
@@ -495,7 +522,7 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
// Check the element types and build the structural subobject.
unsigned StartIndex = Index;
CheckListElementTypes(ParentIList, T, false, Index,
- StructuredSubobjectInitList,
+ StructuredSubobjectInitList,
StructuredSubobjectInitIndex,
TopLevelObject);
unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
@@ -504,7 +531,7 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
// Update the structured sub-object initializer so that it's ending
// range corresponds with the end of the last initializer it used.
if (EndIndex < ParentIList->getNumInits()) {
- SourceLocation EndLoc
+ SourceLocation EndLoc
= ParentIList->getInit(EndIndex)->getSourceRange().getEnd();
StructuredSubobjectInitList->setRBraceLoc(EndLoc);
}
@@ -518,7 +545,7 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
SyntacticToSemantic[IList] = StructuredList;
StructuredList->setSyntacticForm(IList);
- CheckListElementTypes(IList, T, true, Index, StructuredList,
+ CheckListElementTypes(IList, T, true, Index, StructuredList,
StructuredIndex, TopLevelObject);
IList->setType(T);
StructuredList->setType(T);
@@ -541,7 +568,7 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
// Don't complain for incomplete types, since we'll get an error
// elsewhere
QualType CurrentObjectType = StructuredList->getType();
- int initKind =
+ int initKind =
CurrentObjectType->isArrayType()? 0 :
CurrentObjectType->isVectorType()? 1 :
CurrentObjectType->isScalarType()? 2 :
@@ -553,6 +580,10 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
DK = diag::err_excess_initializers;
hadError = true;
}
+ if (SemaRef.getLangOptions().OpenCL && initKind == 1) {
+ DK = diag::err_excess_initializers;
+ hadError = true;
+ }
SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK)
<< initKind << IList->getInit(Index)->getSourceRange();
@@ -567,7 +598,7 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
}
void InitListChecker::CheckListElementTypes(InitListExpr *IList,
- QualType &DeclType,
+ QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
@@ -579,8 +610,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex);
} else if (DeclType->isAggregateType()) {
if (DeclType->isRecordType()) {
- RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
- CheckStructUnionTypes(IList, DeclType, RD->field_begin(),
+ RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ CheckStructUnionTypes(IList, DeclType, RD->field_begin(),
SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex,
TopLevelObject);
@@ -590,8 +621,7 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
false);
CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex);
- }
- else
+ } else
assert(0 && "Aggregate that isn't a structure or array?!");
} else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
// This type is invalid, issue a diagnostic.
@@ -615,13 +645,13 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
CheckReferenceType(IList, DeclType, Index, StructuredList, StructuredIndex);
} else {
// In C, all types are either scalars or aggregates, but
- // additional handling is needed here for C++ (and possibly others?).
+ // additional handling is needed here for C++ (and possibly others?).
assert(0 && "Unsupported initializer type");
}
}
void InitListChecker::CheckSubElementType(InitListExpr *IList,
- QualType ElemType,
+ QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
@@ -629,11 +659,11 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
unsigned newIndex = 0;
unsigned newStructuredIndex = 0;
- InitListExpr *newStructuredList
+ InitListExpr *newStructuredList
= getStructuredSubobjectInit(IList, Index, ElemType,
StructuredList, StructuredIndex,
SubInitList->getSourceRange());
- CheckExplicitInitList(SubInitList, ElemType, newIndex,
+ CheckExplicitInitList(SubInitList, ElemType, newIndex,
newStructuredList, newStructuredIndex);
++StructuredIndex;
++Index;
@@ -652,10 +682,14 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
// initializing the aggregate member with an ini- tializer from
// an initializer-list. If the initializer can initialize a
// member, the member is initialized. [...]
- ImplicitConversionSequence ICS
- = SemaRef.TryCopyInitialization(expr, ElemType);
+ ImplicitConversionSequence ICS
+ = SemaRef.TryCopyInitialization(expr, ElemType,
+ /*SuppressUserConversions=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+
if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) {
- if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS,
+ if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS,
"initializing"))
hadError = true;
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
@@ -665,7 +699,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
// Fall through for subaggregate initialization
} else {
- // C99 6.7.8p13:
+ // C99 6.7.8p13:
//
// The initializer for a structure or union object that has
// automatic storage duration shall be either an initializer
@@ -684,13 +718,13 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
}
// C++ [dcl.init.aggr]p12:
- //
+ //
// [...] Otherwise, if the member is itself a non-empty
// subaggregate, brace elision is assumed and the initializer is
// considered for the initialization of the first member of
// the subaggregate.
if (ElemType->isAggregateType() || ElemType->isVectorType()) {
- CheckImplicitInitList(IList, ElemType, Index, StructuredList,
+ CheckImplicitInitList(IList, ElemType, Index, StructuredList,
StructuredIndex);
++StructuredIndex;
} else {
@@ -719,7 +753,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType,
++StructuredIndex;
return;
} else if (isa<DesignatedInitExpr>(expr)) {
- SemaRef.Diag(expr->getSourceRange().getBegin(),
+ SemaRef.Diag(expr->getSourceRange().getBegin(),
diag::err_designator_for_scalar_init)
<< DeclType << expr->getSourceRange();
hadError = true;
@@ -763,10 +797,14 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
++Index;
++StructuredIndex;
return;
- }
+ }
Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
- if (SemaRef.CheckReferenceInit(expr, DeclType))
+ if (SemaRef.CheckReferenceInit(expr, DeclType,
+ /*FIXME:*/expr->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false))
hadError = true;
else if (savExpr != expr) {
// The type was promoted, update initializer list.
@@ -782,7 +820,7 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
// general, it would be useful to pass location information down the stack,
// so that we know the location (or decl) of the "current object" being
// initialized.
- SemaRef.Diag(IList->getLocStart(),
+ SemaRef.Diag(IList->getLocStart(),
diag::err_init_reference_member_uninitialized)
<< DeclType
<< IList->getSourceRange();
@@ -793,28 +831,59 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
}
}
-void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
+void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (Index < IList->getNumInits()) {
- const VectorType *VT = DeclType->getAsVectorType();
- int maxElements = VT->getNumElements();
+ const VectorType *VT = DeclType->getAs<VectorType>();
+ unsigned maxElements = VT->getNumElements();
+ unsigned numEltsInit = 0;
QualType elementType = VT->getElementType();
-
- for (int i = 0; i < maxElements; ++i) {
- // Don't attempt to go past the end of the init list
- if (Index >= IList->getNumInits())
- break;
- CheckSubElementType(IList, elementType, Index,
- StructuredList, StructuredIndex);
+
+ if (!SemaRef.getLangOptions().OpenCL) {
+ for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) {
+ // Don't attempt to go past the end of the init list
+ if (Index >= IList->getNumInits())
+ break;
+ CheckSubElementType(IList, elementType, Index,
+ StructuredList, StructuredIndex);
+ }
+ } else {
+ // OpenCL initializers allows vectors to be constructed from vectors.
+ for (unsigned i = 0; i < maxElements; ++i) {
+ // Don't attempt to go past the end of the init list
+ if (Index >= IList->getNumInits())
+ break;
+ QualType IType = IList->getInit(Index)->getType();
+ if (!IType->isVectorType()) {
+ CheckSubElementType(IList, elementType, Index,
+ StructuredList, StructuredIndex);
+ ++numEltsInit;
+ } else {
+ const VectorType *IVT = IType->getAs<VectorType>();
+ unsigned numIElts = IVT->getNumElements();
+ QualType VecType = SemaRef.Context.getExtVectorType(elementType,
+ numIElts);
+ CheckSubElementType(IList, VecType, Index,
+ StructuredList, StructuredIndex);
+ numEltsInit += numIElts;
+ }
+ }
}
+
+ // OpenCL & AltiVec require all elements to be initialized.
+ if (numEltsInit != maxElements)
+ if (SemaRef.getLangOptions().OpenCL || SemaRef.getLangOptions().AltiVec)
+ SemaRef.Diag(IList->getSourceRange().getBegin(),
+ diag::err_vector_incorrect_num_initializers)
+ << (numEltsInit < maxElements) << maxElements << numEltsInit;
}
}
-void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
+void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
- bool SubobjectIsDesignatorContext,
+ bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
@@ -873,7 +942,7 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
// Handle this designated initializer. elementIndex will be
// updated to be the next array element we'll initialize.
- if (CheckDesignatedInitializer(IList, DIE, 0,
+ if (CheckDesignatedInitializer(IList, DIE, 0,
DeclType, 0, &elementIndex, Index,
StructuredList, StructuredIndex, true,
false)) {
@@ -921,31 +990,31 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
diag::ext_typecheck_zero_array_size);
}
- DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements,
+ DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements,
ArrayType::Normal, 0);
}
}
-void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
- QualType DeclType,
+void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
+ QualType DeclType,
RecordDecl::field_iterator Field,
- bool SubobjectIsDesignatorContext,
+ bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject) {
- RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
-
+ RecordDecl* structDecl = DeclType->getAs<RecordType>()->getDecl();
+
// If the record is invalid, some of it's members are invalid. To avoid
// confusion, we forgo checking the intializer for the entire record.
if (structDecl->isInvalidDecl()) {
hadError = true;
return;
- }
+ }
if (DeclType->isUnionType() && IList->getNumInits() == 0) {
// Value-initialize the first named member of the union.
- RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
+ RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
if (Field->getDeclName()) {
@@ -960,7 +1029,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
// anything except look at designated initializers; That's okay,
// because an error should get printed out elsewhere. It might be
// worthwhile to skip over the rest of the initializer, though.
- RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
+ RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
bool InitializedSomething = false;
while (Index < IList->getNumInits()) {
@@ -975,7 +1044,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
// Handle this designated initializer. Field will be updated to
// the next field that we'll be initializing.
- if (CheckDesignatedInitializer(IList, DIE, 0,
+ if (CheckDesignatedInitializer(IList, DIE, 0,
DeclType, &Field, 0, Index,
StructuredList, StructuredIndex,
true, TopLevelObject))
@@ -1016,15 +1085,15 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
++Field;
}
- if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() ||
+ if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() ||
Index >= IList->getNumInits())
return;
// Handle GNU flexible array initializers.
- if (!TopLevelObject &&
+ if (!TopLevelObject &&
(!isa<InitListExpr>(IList->getInit(Index)) ||
cast<InitListExpr>(IList->getInit(Index))->getNumInits() > 0)) {
- SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
+ SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
diag::err_flexible_array_init_nonempty)
<< IList->getInit(Index)->getSourceRange().getBegin();
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
@@ -1033,7 +1102,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
++Index;
return;
} else {
- SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
+ SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
diag::ext_flexible_array_init)
<< IList->getInit(Index)->getSourceRange().getBegin();
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
@@ -1055,8 +1124,8 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
/// Field/FieldIndex will be updated to point to the (new)
/// currently-designated field.
static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
- DesignatedInitExpr *DIE,
- unsigned DesigIdx,
+ DesignatedInitExpr *DIE,
+ unsigned DesigIdx,
FieldDecl *Field,
RecordDecl::field_iterator &FieldIter,
unsigned &FieldIndex) {
@@ -1066,14 +1135,14 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
// anonymous struct/union (backwards).
llvm::SmallVector<FieldDecl *, 4> Path;
SemaRef.BuildAnonymousStructUnionMemberPath(Field, Path);
-
+
// Build the replacement designators.
llvm::SmallVector<Designator, 4> Replacements;
for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
FI = Path.rbegin(), FIEnd = Path.rend();
FI != FIEnd; ++FI) {
if (FI + 1 == FIEnd)
- Replacements.push_back(Designator((IdentifierInfo *)0,
+ Replacements.push_back(Designator((IdentifierInfo *)0,
DIE->getDesignator(DesigIdx)->getDotLoc(),
DIE->getDesignator(DesigIdx)->getFieldLoc()));
else
@@ -1085,9 +1154,9 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
// Expand the current designator into the set of replacement
// designators, so we have a full subobject path down to where the
// member of the anonymous struct/union is actually stored.
- DIE->ExpandDesignator(DesigIdx, &Replacements[0],
+ DIE->ExpandDesignator(DesigIdx, &Replacements[0],
&Replacements[0] + Replacements.size());
-
+
// Update FieldIter/FieldIndex;
RecordDecl *Record = cast<RecordDecl>(Path.back()->getDeclContext());
FieldIter = Record->field_begin();
@@ -1112,7 +1181,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
/// resides at the given @p Index within the initializer list @p
/// IList, is well-formed for a current object of type @p DeclType
/// (C99 6.7.8). The actual subobject that this designator refers to
-/// within the current subobject is returned in either
+/// within the current subobject is returned in either
/// @p NextField or @p NextElementIndex (whichever is appropriate).
///
/// @param IList The initializer list in which this designated
@@ -1141,9 +1210,9 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
/// actually be initialized.
///
/// @returns true if there was an error, false otherwise.
-bool
+bool
InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
- DesignatedInitExpr *DIE,
+ DesignatedInitExpr *DIE,
unsigned DesigIdx,
QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
@@ -1176,14 +1245,14 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
}
bool IsFirstDesignator = (DesigIdx == 0);
- assert((IsFirstDesignator || StructuredList) &&
+ assert((IsFirstDesignator || StructuredList) &&
"Need a non-designated initializer list to start from");
DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx);
// Determine the structural initializer list that corresponds to the
// current subobject.
StructuredList = IsFirstDesignator? SyntacticToSemantic[IList]
- : getStructuredSubobjectInit(IList, Index, CurrentObjectType,
+ : getStructuredSubobjectInit(IList, Index, CurrentObjectType,
StructuredList, StructuredIndex,
SourceRange(D->getStartLocation(),
DIE->getSourceRange().getEnd()));
@@ -1198,8 +1267,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
//
// then the current object (defined below) shall have
// structure or union type and the identifier shall be the
- // name of a member of that type.
- const RecordType *RT = CurrentObjectType->getAsRecordType();
+ // name of a member of that type.
+ const RecordType *RT = CurrentObjectType->getAs<RecordType>();
if (!RT) {
SourceLocation Loc = D->getDotLoc();
if (Loc.isInvalid())
@@ -1216,7 +1285,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
FieldDecl *KnownField = D->getField();
IdentifierInfo *FieldName = D->getFieldName();
unsigned FieldIndex = 0;
- RecordDecl::field_iterator
+ RecordDecl::field_iterator
Field = RT->getDecl()->field_begin(),
FieldEnd = RT->getDecl()->field_end();
for (; Field != FieldEnd; ++Field) {
@@ -1234,7 +1303,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// name. Perform another lookup for this name, which may find
// something that we can't designate (e.g., a member function),
// may find nothing, or may find a member of an anonymous
- // struct/union.
+ // struct/union.
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
if (Lookup.first == Lookup.second) {
// Name lookup didn't find anything.
@@ -1247,7 +1316,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
->isAnonymousStructOrUnion()) {
// Handle an field designator that refers to a member of an
// anonymous struct or union.
- ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
+ ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
cast<FieldDecl>(*Lookup.first),
Field, FieldIndex);
D = DIE->getDesignator(DesigIdx);
@@ -1255,7 +1324,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Name lookup found something, but it wasn't a field.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
<< FieldName;
- SemaRef.Diag((*Lookup.first)->getLocation(),
+ SemaRef.Diag((*Lookup.first)->getLocation(),
diag::note_field_designator_found);
++Index;
return true;
@@ -1277,7 +1346,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Update the designator with the field declaration.
D->setField(*Field);
-
+
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this field.
if (FieldIndex >= StructuredList->getNumInits())
@@ -1289,11 +1358,11 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
if ((DesigIdx + 1) != DIE->size()) {
// We can't designate an object within the flexible array
// member (because GCC doesn't allow it).
- DesignatedInitExpr::Designator *NextD
+ DesignatedInitExpr::Designator *NextD
= DIE->getDesignator(DesigIdx + 1);
- SemaRef.Diag(NextD->getStartLocation(),
+ SemaRef.Diag(NextD->getStartLocation(),
diag::err_designator_into_flexible_array_member)
- << SourceRange(NextD->getStartLocation(),
+ << SourceRange(NextD->getStartLocation(),
DIE->getSourceRange().getEnd());
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
<< *Field;
@@ -1311,9 +1380,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
}
// Handle GNU flexible array initializers.
- if (!Invalid && !TopLevelObject &&
+ if (!Invalid && !TopLevelObject &&
cast<InitListExpr>(DIE->getInit())->getNumInits() > 0) {
- SemaRef.Diag(DIE->getSourceRange().getBegin(),
+ SemaRef.Diag(DIE->getSourceRange().getBegin(),
diag::err_flexible_array_init_nonempty)
<< DIE->getSourceRange().getBegin();
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
@@ -1331,7 +1400,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
unsigned newStructuredIndex = FieldIndex;
unsigned OldIndex = Index;
IList->setInit(Index, DIE->getInit());
- CheckSubElementType(IList, Field->getType(), Index,
+ CheckSubElementType(IList, Field->getType(), Index,
StructuredList, newStructuredIndex);
IList->setInit(OldIndex, DIE);
if (hadError && !prevHadError) {
@@ -1412,10 +1481,10 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
} else {
assert(D->isArrayRangeDesignator() && "Need array-range designator");
-
- DesignatedStartIndex =
+
+ DesignatedStartIndex =
DIE->getArrayRangeStart(*D)->EvaluateAsInt(SemaRef.Context);
- DesignatedEndIndex =
+ DesignatedEndIndex =
DIE->getArrayRangeEnd(*D)->EvaluateAsInt(SemaRef.Context);
IndexExpr = DIE->getArrayRangeEnd(*D);
@@ -1447,11 +1516,11 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
DesignatedStartIndex.setIsUnsigned(true);
DesignatedEndIndex.setIsUnsigned(true);
}
-
+
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this array element.
if (DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits())
- StructuredList->resizeInits(SemaRef.Context,
+ StructuredList->resizeInits(SemaRef.Context,
DesignatedEndIndex.getZExtValue() + 1);
// Repeatedly perform subobject initializations in the range
@@ -1483,7 +1552,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
StructuredIndex = ElementIndex;
return false;
}
-
+
if (!FinishSubobjectInit)
return false;
@@ -1491,7 +1560,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
bool prevHadError = hadError;
CheckArrayType(IList, CurrentObjectType, DesignatedStartIndex, false, Index,
StructuredList, ElementIndex);
- return hadError && !prevHadError;
+ return hadError && !prevHadError;
}
// Get the structured initializer list for a subobject of type
@@ -1507,7 +1576,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
ExistingInit = SyntacticToSemantic[IList];
else if (StructuredIndex < StructuredList->getNumInits())
ExistingInit = StructuredList->getInit(StructuredIndex);
-
+
if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
return Result;
@@ -1516,24 +1585,24 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
// subobjects of the current object, but there was already an
// initialization that completely initialized the current
// subobject, e.g., by a compound literal:
- //
+ //
// struct X { int a, b; };
// struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
- //
+ //
// Here, xs[0].a == 0 and xs[0].b == 3, since the second,
// designated initializer re-initializes the whole
// subobject [0], overwriting previous initializers.
- SemaRef.Diag(InitRange.getBegin(),
+ SemaRef.Diag(InitRange.getBegin(),
diag::warn_subobject_initializer_overrides)
<< InitRange;
- SemaRef.Diag(ExistingInit->getSourceRange().getBegin(),
+ SemaRef.Diag(ExistingInit->getSourceRange().getBegin(),
diag::note_previous_initializer)
<< /*FIXME:has side effects=*/0
<< ExistingInit->getSourceRange();
}
- InitListExpr *Result
- = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0,
+ InitListExpr *Result
+ = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0,
InitRange.getEnd());
Result->setType(CurrentObjectType);
@@ -1548,7 +1617,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
NumInits = SubList->getNumInits();
}
- if (const ArrayType *AType
+ if (const ArrayType *AType
= SemaRef.Context.getAsArrayType(CurrentObjectType)) {
if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) {
NumElements = CAType->getSize().getZExtValue();
@@ -1557,14 +1626,14 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
if (NumInits && NumElements > NumInits)
NumElements = 0;
}
- } else if (const VectorType *VType = CurrentObjectType->getAsVectorType())
+ } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>())
NumElements = VType->getNumElements();
- else if (const RecordType *RType = CurrentObjectType->getAsRecordType()) {
+ else if (const RecordType *RType = CurrentObjectType->getAs<RecordType>()) {
RecordDecl *RDecl = RType->getDecl();
if (RDecl->isUnion())
NumElements = 1;
else
- NumElements = std::distance(RDecl->field_begin(),
+ NumElements = std::distance(RDecl->field_begin(),
RDecl->field_end());
}
@@ -1596,15 +1665,15 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) {
// This initializer overwrites a previous initializer. Warn.
- SemaRef.Diag(expr->getSourceRange().getBegin(),
+ SemaRef.Diag(expr->getSourceRange().getBegin(),
diag::warn_initializer_overrides)
<< expr->getSourceRange();
- SemaRef.Diag(PrevInit->getSourceRange().getBegin(),
+ SemaRef.Diag(PrevInit->getSourceRange().getBegin(),
diag::note_previous_initializer)
<< /*FIXME:has side effects=*/0
<< PrevInit->getSourceRange();
}
-
+
++StructuredIndex;
}
@@ -1615,7 +1684,7 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
/// failure. Returns true if there was an error, false otherwise. If
/// everything went okay, Value will receive the value of the constant
/// expression.
-static bool
+static bool
CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) {
SourceLocation Loc = Index->getSourceRange().getBegin();
@@ -1646,7 +1715,7 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
const Designator &D = Desig.getDesignator(Idx);
switch (D.getKind()) {
case Designator::FieldDesignator:
- Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(),
+ Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(),
D.getFieldLoc()));
break;
@@ -1659,7 +1728,7 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
Invalid = true;
else {
Designators.push_back(ASTDesignator(InitExpressions.size(),
- D.getLBracketLoc(),
+ D.getLBracketLoc(),
D.getRBracketLoc()));
InitExpressions.push_back(Index);
}
@@ -1691,12 +1760,12 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
if (!StartDependent && !EndDependent && EndValue < StartValue) {
Diag(D.getEllipsisLoc(), diag::err_array_designator_empty_range)
- << StartValue.toString(10) << EndValue.toString(10)
+ << StartValue.toString(10) << EndValue.toString(10)
<< StartIndex->getSourceRange() << EndIndex->getSourceRange();
Invalid = true;
} else {
Designators.push_back(ASTDesignator(InitExpressions.size(),
- D.getLBracketLoc(),
+ D.getLBracketLoc(),
D.getEllipsisLoc(),
D.getRBracketLoc()));
InitExpressions.push_back(StartIndex);
@@ -1741,7 +1810,7 @@ bool Sema::CheckInitList(InitListExpr *&InitList, QualType &DeclType) {
/// accessible, non-deleted default constructor. In C, everything can
/// be value-initialized, which corresponds to C's notion of
/// initializing objects with static storage duration when no
-/// initializer is provided for that object.
+/// initializer is provided for that object.
///
/// \returns true if there was an error, false otherwise.
bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
@@ -1753,19 +1822,34 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
if (const ArrayType *AT = Context.getAsArrayType(Type))
return CheckValueInitialization(AT->getElementType(), Loc);
- if (const RecordType *RT = Type->getAsRecordType()) {
+ if (const RecordType *RT = Type->getAs<RecordType>()) {
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
// -- if T is a class type (clause 9) with a user-declared
// constructor (12.1), then the default constructor for T is
// called (and the initialization is ill-formed if T has no
// accessible default constructor);
- if (ClassDecl->hasUserDeclaredConstructor())
- // FIXME: Eventually, we'll need to put the constructor decl into the
- // AST.
- return PerformInitializationByConstructor(Type, 0, 0, Loc,
- SourceRange(Loc),
- DeclarationName(),
- IK_Direct);
+ if (ClassDecl->hasUserDeclaredConstructor()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(Type,
+ MultiExprArg(*this, 0, 0),
+ Loc, SourceRange(Loc),
+ DeclarationName(),
+ IK_Direct,
+ ConstructorArgs);
+ if (!Constructor)
+ return true;
+
+ OwningExprResult Init
+ = BuildCXXConstructExpr(Loc, Type, Constructor,
+ move_arg(ConstructorArgs));
+ if (Init.isInvalid())
+ return true;
+
+ // FIXME: Actually perform the value-initialization!
+ return false;
+ }
}
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 6f2fc5e0c434b..dd877c16fba79 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -12,18 +12,20 @@
//
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "SemaInherit.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/ErrorHandling.h"
#include <set>
#include <vector>
#include <iterator>
@@ -34,7 +36,6 @@ using namespace clang;
typedef llvm::SmallVector<UsingDirectiveDecl*, 4> UsingDirectivesTy;
typedef llvm::DenseSet<NamespaceDecl*> NamespaceSet;
-typedef llvm::SmallVector<Sema::LookupResult, 3> LookupResultsTy;
/// UsingDirAncestorCompare - Implements strict weak ordering of
/// UsingDirectives. It orders them by address of its common ancestor.
@@ -59,7 +60,7 @@ struct UsingDirAncestorCompare {
/// AddNamespaceUsingDirectives - Adds all UsingDirectiveDecl's to heap UDirs
/// (ordered by common ancestors), found in namespace NS,
/// including all found (recursively) in their nominated namespaces.
-void AddNamespaceUsingDirectives(ASTContext &Context,
+void AddNamespaceUsingDirectives(ASTContext &Context,
DeclContext *NS,
UsingDirectivesTy &UDirs,
NamespaceSet &Visited) {
@@ -76,7 +77,7 @@ void AddNamespaceUsingDirectives(ASTContext &Context,
/// AddScopeUsingDirectives - Adds all UsingDirectiveDecl's found in Scope S,
/// including all found in the namespaces they nominate.
-static void AddScopeUsingDirectives(ASTContext &Context, Scope *S,
+static void AddScopeUsingDirectives(ASTContext &Context, Scope *S,
UsingDirectivesTy &UDirs) {
NamespaceSet VisitedNS;
@@ -99,189 +100,17 @@ static void AddScopeUsingDirectives(ASTContext &Context, Scope *S,
NamespaceDecl *Nominated = UD->getNominatedNamespace();
if (!VisitedNS.count(Nominated)) {
VisitedNS.insert(Nominated);
- AddNamespaceUsingDirectives(Context, Nominated, UDirs,
+ AddNamespaceUsingDirectives(Context, Nominated, UDirs,
/*ref*/ VisitedNS);
}
}
}
}
-/// MaybeConstructOverloadSet - Name lookup has determined that the
-/// elements in [I, IEnd) have the name that we are looking for, and
-/// *I is a match for the namespace. This routine returns an
-/// appropriate Decl for name lookup, which may either be *I or an
-/// OverloadedFunctionDecl that represents the overloaded functions in
-/// [I, IEnd).
-///
-/// The existance of this routine is temporary; users of LookupResult
-/// should be able to handle multiple results, to deal with cases of
-/// ambiguity and overloaded functions without needing to create a
-/// Decl node.
-template<typename DeclIterator>
-static NamedDecl *
-MaybeConstructOverloadSet(ASTContext &Context,
- DeclIterator I, DeclIterator IEnd) {
- assert(I != IEnd && "Iterator range cannot be empty");
- assert(!isa<OverloadedFunctionDecl>(*I) &&
- "Cannot have an overloaded function");
-
- if ((*I)->isFunctionOrFunctionTemplate()) {
- // If we found a function, there might be more functions. If
- // so, collect them into an overload set.
- DeclIterator Last = I;
- OverloadedFunctionDecl *Ovl = 0;
- for (++Last;
- Last != IEnd && (*Last)->isFunctionOrFunctionTemplate();
- ++Last) {
- if (!Ovl) {
- // FIXME: We leak this overload set. Eventually, we want to stop
- // building the declarations for these overload sets, so there will be
- // nothing to leak.
- Ovl = OverloadedFunctionDecl::Create(Context, (*I)->getDeclContext(),
- (*I)->getDeclName());
- NamedDecl *ND = (*I)->getUnderlyingDecl();
- if (isa<FunctionDecl>(ND))
- Ovl->addOverload(cast<FunctionDecl>(ND));
- else
- Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
- }
-
- NamedDecl *ND = (*Last)->getUnderlyingDecl();
- if (isa<FunctionDecl>(ND))
- Ovl->addOverload(cast<FunctionDecl>(ND));
- else
- Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
- }
-
- // If we had more than one function, we built an overload
- // set. Return it.
- if (Ovl)
- return Ovl;
- }
-
- return *I;
-}
-
-/// Merges together multiple LookupResults dealing with duplicated Decl's.
-static Sema::LookupResult
-MergeLookupResults(ASTContext &Context, LookupResultsTy &Results) {
- typedef Sema::LookupResult LResult;
- typedef llvm::SmallPtrSet<NamedDecl*, 4> DeclsSetTy;
-
- // Remove duplicated Decl pointing at same Decl, by storing them in
- // associative collection. This might be case for code like:
- //
- // namespace A { int i; }
- // namespace B { using namespace A; }
- // namespace C { using namespace A; }
- //
- // void foo() {
- // using namespace B;
- // using namespace C;
- // ++i; // finds A::i, from both namespace B and C at global scope
- // }
- //
- // C++ [namespace.qual].p3:
- // The same declaration found more than once is not an ambiguity
- // (because it is still a unique declaration).
- DeclsSetTy FoundDecls;
-
- // Counter of tag names, and functions for resolving ambiguity
- // and name hiding.
- std::size_t TagNames = 0, Functions = 0, OrdinaryNonFunc = 0;
-
- LookupResultsTy::iterator I = Results.begin(), End = Results.end();
-
- // No name lookup results, return early.
- if (I == End) return LResult::CreateLookupResult(Context, 0);
-
- // Keep track of the tag declaration we found. We only use this if
- // we find a single tag declaration.
- TagDecl *TagFound = 0;
-
- for (; I != End; ++I) {
- switch (I->getKind()) {
- case LResult::NotFound:
- assert(false &&
- "Should be always successful name lookup result here.");
- break;
-
- case LResult::AmbiguousReference:
- case LResult::AmbiguousBaseSubobjectTypes:
- case LResult::AmbiguousBaseSubobjects:
- assert(false && "Shouldn't get ambiguous lookup here.");
- break;
-
- case LResult::Found: {
- NamedDecl *ND = I->getAsDecl()->getUnderlyingDecl();
-
- if (TagDecl *TD = dyn_cast<TagDecl>(ND)) {
- TagFound = Context.getCanonicalDecl(TD);
- TagNames += FoundDecls.insert(TagFound)? 1 : 0;
- } else if (ND->isFunctionOrFunctionTemplate())
- Functions += FoundDecls.insert(ND)? 1 : 0;
- else
- FoundDecls.insert(ND);
- break;
- }
-
- case LResult::FoundOverloaded:
- for (LResult::iterator FI = I->begin(), FEnd = I->end(); FI != FEnd; ++FI)
- Functions += FoundDecls.insert(*FI)? 1 : 0;
- break;
- }
- }
- OrdinaryNonFunc = FoundDecls.size() - TagNames - Functions;
- bool Ambiguous = false, NameHidesTags = false;
-
- if (FoundDecls.size() == 1) {
- // 1) Exactly one result.
- } else if (TagNames > 1) {
- // 2) Multiple tag names (even though they may be hidden by an
- // object name).
- Ambiguous = true;
- } else if (FoundDecls.size() - TagNames == 1) {
- // 3) Ordinary name hides (optional) tag.
- NameHidesTags = TagFound;
- } else if (Functions) {
- // C++ [basic.lookup].p1:
- // ... Name lookup may associate more than one declaration with
- // a name if it finds the name to be a function name; the declarations
- // are said to form a set of overloaded functions (13.1).
- // Overload resolution (13.3) takes place after name lookup has succeeded.
- //
- if (!OrdinaryNonFunc) {
- // 4) Functions hide tag names.
- NameHidesTags = TagFound;
- } else {
- // 5) Functions + ordinary names.
- Ambiguous = true;
- }
- } else {
- // 6) Multiple non-tag names
- Ambiguous = true;
- }
-
- if (Ambiguous)
- return LResult::CreateLookupResult(Context,
- FoundDecls.begin(), FoundDecls.size());
- if (NameHidesTags) {
- // There's only one tag, TagFound. Remove it.
- assert(TagFound && FoundDecls.count(TagFound) && "No tag name found?");
- FoundDecls.erase(TagFound);
- }
-
- // Return successful name lookup result.
- return LResult::CreateLookupResult(Context,
- MaybeConstructOverloadSet(Context,
- FoundDecls.begin(),
- FoundDecls.end()));
-}
-
// Retrieve the set of identifier namespaces that correspond to a
// specific kind of name lookup.
-inline unsigned
-getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
+inline unsigned
+getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
bool CPlusPlus) {
unsigned IDNS = 0;
switch (NameKind) {
@@ -300,7 +129,7 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
case Sema::LookupMemberName:
IDNS = Decl::IDNS_Member;
if (CPlusPlus)
- IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary;
break;
case Sema::LookupNestedNameSpecifierName:
@@ -323,97 +152,81 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
return IDNS;
}
-Sema::LookupResult
-Sema::LookupResult::CreateLookupResult(ASTContext &Context, NamedDecl *D) {
- if (D)
- D = D->getUnderlyingDecl();
-
- LookupResult Result;
- Result.StoredKind = (D && isa<OverloadedFunctionDecl>(D))?
- OverloadedDeclSingleDecl : SingleDecl;
- Result.First = reinterpret_cast<uintptr_t>(D);
- Result.Last = 0;
- Result.Context = &Context;
- return Result;
+// Necessary because CXXBasePaths is not complete in Sema.h
+void Sema::LookupResult::deletePaths(CXXBasePaths *Paths) {
+ delete Paths;
}
-/// @brief Moves the name-lookup results from Other to this LookupResult.
-Sema::LookupResult
-Sema::LookupResult::CreateLookupResult(ASTContext &Context,
- IdentifierResolver::iterator F,
- IdentifierResolver::iterator L) {
- LookupResult Result;
- Result.Context = &Context;
-
- if (F != L && (*F)->isFunctionOrFunctionTemplate()) {
- IdentifierResolver::iterator Next = F;
- ++Next;
- if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) {
- Result.StoredKind = OverloadedDeclFromIdResolver;
- Result.First = F.getAsOpaqueValue();
- Result.Last = L.getAsOpaqueValue();
- return Result;
- }
- }
-
- NamedDecl *D = *F;
- if (D)
- D = D->getUnderlyingDecl();
-
- Result.StoredKind = SingleDecl;
- Result.First = reinterpret_cast<uintptr_t>(D);
- Result.Last = 0;
- return Result;
-}
-
-Sema::LookupResult
-Sema::LookupResult::CreateLookupResult(ASTContext &Context,
- DeclContext::lookup_iterator F,
- DeclContext::lookup_iterator L) {
- LookupResult Result;
- Result.Context = &Context;
-
- if (F != L && (*F)->isFunctionOrFunctionTemplate()) {
- DeclContext::lookup_iterator Next = F;
- ++Next;
- if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) {
- Result.StoredKind = OverloadedDeclFromDeclContext;
- Result.First = reinterpret_cast<uintptr_t>(F);
- Result.Last = reinterpret_cast<uintptr_t>(L);
- return Result;
- }
- }
+void Sema::LookupResult::resolveKind() {
+ unsigned N = Decls.size();
- NamedDecl *D = *F;
- if (D)
- D = D->getUnderlyingDecl();
-
- Result.StoredKind = SingleDecl;
- Result.First = reinterpret_cast<uintptr_t>(D);
- Result.Last = 0;
- return Result;
-}
+ // Fast case: no possible ambiguity.
+ if (N <= 1) return;
-/// @brief Determine the result of name lookup.
-Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
- switch (StoredKind) {
- case SingleDecl:
- return (reinterpret_cast<Decl *>(First) != 0)? Found : NotFound;
+ // Don't do any extra resolution if we've already resolved as ambiguous.
+ if (Kind == Ambiguous) return;
- case OverloadedDeclSingleDecl:
- case OverloadedDeclFromIdResolver:
- case OverloadedDeclFromDeclContext:
- return FoundOverloaded;
+ llvm::SmallPtrSet<NamedDecl*, 16> Unique;
- case AmbiguousLookupStoresBasePaths:
- return Last? AmbiguousBaseSubobjectTypes : AmbiguousBaseSubobjects;
+ bool Ambiguous = false;
+ bool HasTag = false, HasFunction = false, HasNonFunction = false;
- case AmbiguousLookupStoresDecls:
- return AmbiguousReference;
+ unsigned UniqueTagIndex = 0;
+
+ unsigned I = 0;
+ while (I < N) {
+ NamedDecl *D = Decls[I];
+ assert(D == D->getUnderlyingDecl());
+
+ NamedDecl *CanonD = cast<NamedDecl>(D->getCanonicalDecl());
+ if (!Unique.insert(CanonD)) {
+ // If it's not unique, pull something off the back (and
+ // continue at this index).
+ Decls[I] = Decls[--N];
+ } else if (isa<UnresolvedUsingDecl>(D)) {
+ // FIXME: proper support for UnresolvedUsingDecls.
+ Decls[I] = Decls[--N];
+ } else {
+ // Otherwise, do some decl type analysis and then continue.
+ if (isa<TagDecl>(D)) {
+ if (HasTag)
+ Ambiguous = true;
+ UniqueTagIndex = I;
+ HasTag = true;
+ } else if (D->isFunctionOrFunctionTemplate()) {
+ HasFunction = true;
+ } else {
+ if (HasNonFunction)
+ Ambiguous = true;
+ HasNonFunction = true;
+ }
+ I++;
+ }
}
- // We can't ever get here.
- return NotFound;
+ // C++ [basic.scope.hiding]p2:
+ // A class name or enumeration name can be hidden by the name of
+ // an object, function, or enumerator declared in the same
+ // scope. If a class or enumeration name and an object, function,
+ // or enumerator are declared in the same scope (in any order)
+ // with the same name, the class or enumeration name is hidden
+ // wherever the object, function, or enumerator name is visible.
+ // But it's still an error if there are distinct tag types found,
+ // even if they're not visible. (ref?)
+ if (HasTag && !Ambiguous && (HasFunction || HasNonFunction))
+ Decls[UniqueTagIndex] = Decls[--N];
+
+ Decls.set_size(N);
+
+ if (HasFunction && HasNonFunction)
+ Ambiguous = true;
+
+ if (Ambiguous)
+ setAmbiguous(LookupResult::AmbiguousReference);
+ else if (N > 1)
+ Kind = LookupResult::FoundOverloaded;
+ else
+ Kind = LookupResult::Found;
}
/// @brief Converts the result of name lookup into a single (possible
@@ -423,197 +236,99 @@ Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
/// (if only a single declaration was found), an
/// OverloadedFunctionDecl (if an overloaded function was found), or
/// NULL (if no declaration was found). This conversion must not be
-/// used anywhere where name lookup could result in an ambiguity.
+/// used anywhere where name lookup could result in an ambiguity.
///
/// The OverloadedFunctionDecl conversion is meant as a stop-gap
/// solution, since it causes the OverloadedFunctionDecl to be
/// leaked. FIXME: Eventually, there will be a better way to iterate
/// over the set of overloaded functions returned by name lookup.
-NamedDecl *Sema::LookupResult::getAsDecl() const {
- switch (StoredKind) {
- case SingleDecl:
- return reinterpret_cast<NamedDecl *>(First);
-
- case OverloadedDeclFromIdResolver:
- return MaybeConstructOverloadSet(*Context,
- IdentifierResolver::iterator::getFromOpaqueValue(First),
- IdentifierResolver::iterator::getFromOpaqueValue(Last));
-
- case OverloadedDeclFromDeclContext:
- return MaybeConstructOverloadSet(*Context,
- reinterpret_cast<DeclContext::lookup_iterator>(First),
- reinterpret_cast<DeclContext::lookup_iterator>(Last));
-
- case OverloadedDeclSingleDecl:
- return reinterpret_cast<OverloadedFunctionDecl*>(First);
-
- case AmbiguousLookupStoresDecls:
- case AmbiguousLookupStoresBasePaths:
- assert(false &&
- "Name lookup returned an ambiguity that could not be handled");
- break;
+NamedDecl *Sema::LookupResult::getAsSingleDecl(ASTContext &C) const {
+ size_t size = Decls.size();
+ if (size == 0) return 0;
+ if (size == 1) return *begin();
+
+ if (isAmbiguous()) return 0;
+
+ iterator I = begin(), E = end();
+
+ OverloadedFunctionDecl *Ovl
+ = OverloadedFunctionDecl::Create(C, (*I)->getDeclContext(),
+ (*I)->getDeclName());
+ for (; I != E; ++I) {
+ NamedDecl *ND = *I;
+ assert(ND->getUnderlyingDecl() == ND
+ && "decls in lookup result should have redirections stripped");
+ assert(ND->isFunctionOrFunctionTemplate());
+ if (isa<FunctionDecl>(ND))
+ Ovl->addOverload(cast<FunctionDecl>(ND));
+ else
+ Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
+ // FIXME: UnresolvedUsingDecls.
}
-
- return 0;
+
+ return Ovl;
}
-/// @brief Retrieves the BasePaths structure describing an ambiguous
-/// name lookup, or null.
-BasePaths *Sema::LookupResult::getBasePaths() const {
- if (StoredKind == AmbiguousLookupStoresBasePaths)
- return reinterpret_cast<BasePaths *>(First);
- return 0;
+void Sema::LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
+ CXXBasePaths::paths_iterator I, E;
+ DeclContext::lookup_iterator DI, DE;
+ for (I = P.begin(), E = P.end(); I != E; ++I)
+ for (llvm::tie(DI,DE) = I->Decls; DI != DE; ++DI)
+ addDecl(*DI);
}
-Sema::LookupResult::iterator::reference
-Sema::LookupResult::iterator::operator*() const {
- switch (Result->StoredKind) {
- case SingleDecl:
- return reinterpret_cast<NamedDecl*>(Current);
-
- case OverloadedDeclSingleDecl:
- return *reinterpret_cast<NamedDecl**>(Current);
-
- case OverloadedDeclFromIdResolver:
- return *IdentifierResolver::iterator::getFromOpaqueValue(Current);
-
- case AmbiguousLookupStoresBasePaths:
- if (Result->Last)
- return *reinterpret_cast<NamedDecl**>(Current);
-
- // Fall through to handle the DeclContext::lookup_iterator we're
- // storing.
-
- case OverloadedDeclFromDeclContext:
- case AmbiguousLookupStoresDecls:
- return *reinterpret_cast<DeclContext::lookup_iterator>(Current);
- }
-
- return 0;
+void Sema::LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) {
+ Paths = new CXXBasePaths;
+ Paths->swap(P);
+ addDeclsFromBasePaths(*Paths);
+ resolveKind();
+ setAmbiguous(AmbiguousBaseSubobjects);
}
-Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() {
- switch (Result->StoredKind) {
- case SingleDecl:
- Current = reinterpret_cast<uintptr_t>((NamedDecl*)0);
- break;
-
- case OverloadedDeclSingleDecl: {
- NamedDecl ** I = reinterpret_cast<NamedDecl**>(Current);
- ++I;
- Current = reinterpret_cast<uintptr_t>(I);
- break;
- }
-
- case OverloadedDeclFromIdResolver: {
- IdentifierResolver::iterator I
- = IdentifierResolver::iterator::getFromOpaqueValue(Current);
- ++I;
- Current = I.getAsOpaqueValue();
- break;
- }
-
- case AmbiguousLookupStoresBasePaths:
- if (Result->Last) {
- NamedDecl ** I = reinterpret_cast<NamedDecl**>(Current);
- ++I;
- Current = reinterpret_cast<uintptr_t>(I);
- break;
- }
- // Fall through to handle the DeclContext::lookup_iterator we're
- // storing.
-
- case OverloadedDeclFromDeclContext:
- case AmbiguousLookupStoresDecls: {
- DeclContext::lookup_iterator I
- = reinterpret_cast<DeclContext::lookup_iterator>(Current);
- ++I;
- Current = reinterpret_cast<uintptr_t>(I);
- break;
- }
- }
-
- return *this;
+void Sema::LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) {
+ Paths = new CXXBasePaths;
+ Paths->swap(P);
+ addDeclsFromBasePaths(*Paths);
+ resolveKind();
+ setAmbiguous(AmbiguousBaseSubobjectTypes);
}
-Sema::LookupResult::iterator Sema::LookupResult::begin() {
- switch (StoredKind) {
- case SingleDecl:
- case OverloadedDeclFromIdResolver:
- case OverloadedDeclFromDeclContext:
- case AmbiguousLookupStoresDecls:
- return iterator(this, First);
-
- case OverloadedDeclSingleDecl: {
- OverloadedFunctionDecl * Ovl =
- reinterpret_cast<OverloadedFunctionDecl*>(First);
- return iterator(this,
- reinterpret_cast<uintptr_t>(&(*Ovl->function_begin())));
- }
-
- case AmbiguousLookupStoresBasePaths:
- if (Last)
- return iterator(this,
- reinterpret_cast<uintptr_t>(getBasePaths()->found_decls_begin()));
- else
- return iterator(this,
- reinterpret_cast<uintptr_t>(getBasePaths()->front().Decls.first));
+void Sema::LookupResult::print(llvm::raw_ostream &Out) {
+ Out << Decls.size() << " result(s)";
+ if (isAmbiguous()) Out << ", ambiguous";
+ if (Paths) Out << ", base paths present";
+
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ Out << "\n";
+ (*I)->print(Out, 2);
}
-
- // Required to suppress GCC warning.
- return iterator();
}
-Sema::LookupResult::iterator Sema::LookupResult::end() {
- switch (StoredKind) {
- case SingleDecl:
- case OverloadedDeclFromIdResolver:
- case OverloadedDeclFromDeclContext:
- case AmbiguousLookupStoresDecls:
- return iterator(this, Last);
-
- case OverloadedDeclSingleDecl: {
- OverloadedFunctionDecl * Ovl =
- reinterpret_cast<OverloadedFunctionDecl*>(First);
- return iterator(this,
- reinterpret_cast<uintptr_t>(&(*Ovl->function_end())));
- }
-
- case AmbiguousLookupStoresBasePaths:
- if (Last)
- return iterator(this,
- reinterpret_cast<uintptr_t>(getBasePaths()->found_decls_end()));
- else
- return iterator(this, reinterpret_cast<uintptr_t>(
- getBasePaths()->front().Decls.second));
- }
+// Adds all qualifying matches for a name within a decl context to the
+// given lookup result. Returns true if any matches were found.
+static bool LookupDirect(Sema::LookupResult &R, DeclContext *DC,
+ DeclarationName Name,
+ Sema::LookupNameKind NameKind,
+ unsigned IDNS) {
+ bool Found = false;
- // Required to suppress GCC warning.
- return iterator();
-}
+ DeclContext::lookup_iterator I, E;
+ for (llvm::tie(I, E) = DC->lookup(Name); I != E; ++I)
+ if (Sema::isAcceptableLookupResult(*I, NameKind, IDNS))
+ R.addDecl(*I), Found = true;
-void Sema::LookupResult::Destroy() {
- if (BasePaths *Paths = getBasePaths())
- delete Paths;
- else if (getKind() == AmbiguousReference)
- delete[] reinterpret_cast<NamedDecl **>(First);
+ return Found;
}
-static void
-CppNamespaceLookup(ASTContext &Context, DeclContext *NS,
+static bool
+CppNamespaceLookup(Sema::LookupResult &R, ASTContext &Context, DeclContext *NS,
DeclarationName Name, Sema::LookupNameKind NameKind,
- unsigned IDNS, LookupResultsTy &Results,
- UsingDirectivesTy *UDirs = 0) {
+ unsigned IDNS, UsingDirectivesTy *UDirs = 0) {
assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!");
// Perform qualified name lookup into the LookupCtx.
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = NS->lookup(Name); I != E; ++I)
- if (Sema::isAcceptableLookupResult(*I, NameKind, IDNS)) {
- Results.push_back(Sema::LookupResult::CreateLookupResult(Context, I, E));
- break;
- }
+ bool Found = LookupDirect(R, NS, Name, NameKind, IDNS);
if (UDirs) {
// For each UsingDirectiveDecl, which common ancestor is equal
@@ -622,11 +337,15 @@ CppNamespaceLookup(ASTContext &Context, DeclContext *NS,
llvm::tie(UI, UEnd) =
std::equal_range(UDirs->begin(), UDirs->end(), NS,
UsingDirAncestorCompare());
-
+
for (; UI != UEnd; ++UI)
- CppNamespaceLookup(Context, (*UI)->getNominatedNamespace(),
- Name, NameKind, IDNS, Results);
+ if (LookupDirect(R, (*UI)->getNominatedNamespace(), Name, NameKind, IDNS))
+ Found = true;
}
+
+ R.resolveKind();
+
+ return Found;
}
static bool isNamespaceOrTranslationUnitScope(Scope *S) {
@@ -635,16 +354,31 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
return false;
}
-std::pair<bool, Sema::LookupResult>
-Sema::CppLookupName(Scope *S, DeclarationName Name,
+// Find the next outer declaration context corresponding to this scope.
+static DeclContext *findOuterContext(Scope *S) {
+ for (S = S->getParent(); S; S = S->getParent())
+ if (S->getEntity())
+ return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
+
+ return 0;
+}
+
+bool
+Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name,
LookupNameKind NameKind, bool RedeclarationOnly) {
assert(getLangOptions().CPlusPlus &&
"Can perform only C++ lookup");
- unsigned IDNS
+ unsigned IDNS
= getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true);
+
+ // If we're testing for redeclarations, also look in the friend namespaces.
+ if (RedeclarationOnly) {
+ if (IDNS & Decl::IDNS_Tag) IDNS |= Decl::IDNS_TagFriend;
+ if (IDNS & Decl::IDNS_Ordinary) IDNS |= Decl::IDNS_OrdinaryFriend;
+ }
+
Scope *Initial = S;
- DeclContext *OutOfLineCtx = 0;
- IdentifierResolver::iterator
+ IdentifierResolver::iterator
I = IdResolver.begin(Name),
IEnd = IdResolver.end();
@@ -653,8 +387,8 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
// ...During unqualified name lookup (3.4.1), the names appear as if
// they were declared in the nearest enclosing namespace which contains
// both the using-directive and the nominated namespace.
- // [Note: in this context, “contains” means “contains directly or
- // indirectly”.
+ // [Note: in this context, "contains" means "contains directly or
+ // indirectly".
//
// For example:
// namespace A { int i; }
@@ -668,47 +402,33 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
//
for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
// Check whether the IdResolver has anything in this scope.
+ bool Found = false;
for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
if (isAcceptableLookupResult(*I, NameKind, IDNS)) {
- // We found something. Look for anything else in our scope
- // with this same name and in an acceptable identifier
- // namespace, so that we can construct an overload set if we
- // need to.
- IdentifierResolver::iterator LastI = I;
- for (++LastI; LastI != IEnd; ++LastI) {
- if (!S->isDeclScope(DeclPtrTy::make(*LastI)))
- break;
- }
- LookupResult Result =
- LookupResult::CreateLookupResult(Context, I, LastI);
- return std::make_pair(true, Result);
+ Found = true;
+ R.addDecl(*I);
}
}
+ if (Found) {
+ R.resolveKind();
+ return true;
+ }
+
if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
- LookupResult R;
- // Perform member lookup into struct.
- // FIXME: In some cases, we know that every name that could be found by
- // this qualified name lookup will also be on the identifier chain. For
- // example, inside a class without any base classes, we never need to
- // perform qualified lookup because all of the members are on top of the
- // identifier chain.
- if (isa<RecordDecl>(Ctx)) {
- R = LookupQualifiedName(Ctx, Name, NameKind, RedeclarationOnly);
- if (R)
- return std::make_pair(true, R);
- }
- if (Ctx->getParent() != Ctx->getLexicalParent()
- || isa<CXXMethodDecl>(Ctx)) {
- // It is out of line defined C++ method or struct, we continue
- // doing name lookup in parent context. Once we will find namespace
- // or translation-unit we save it for possible checking
- // using-directives later.
- for (OutOfLineCtx = Ctx; OutOfLineCtx && !OutOfLineCtx->isFileContext();
- OutOfLineCtx = OutOfLineCtx->getParent()) {
- R = LookupQualifiedName(OutOfLineCtx, Name, NameKind, RedeclarationOnly);
- if (R)
- return std::make_pair(true, R);
- }
+ DeclContext *OuterCtx = findOuterContext(S);
+ for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
+ Ctx = Ctx->getLookupParent()) {
+ if (Ctx->isFunctionOrMethod())
+ continue;
+
+ // Perform qualified name lookup into this context.
+ // FIXME: In some cases, we know that every name that could be found by
+ // this qualified name lookup will also be on the identifier chain. For
+ // example, inside a class without any base classes, we never need to
+ // perform qualified lookup because all of the members are on top of the
+ // identifier chain.
+ if (LookupQualifiedName(R, Ctx, Name, NameKind, RedeclarationOnly))
+ return true;
}
}
}
@@ -731,71 +451,41 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
// that aren't strictly lexical, and therefore we walk through the
// context as well as walking through the scopes.
- LookupResultsTy LookupResults;
- assert((!OutOfLineCtx || OutOfLineCtx->isFileContext()) &&
- "We should have been looking only at file context here already.");
- bool LookedInCtx = false;
- LookupResult Result;
- while (OutOfLineCtx &&
- OutOfLineCtx != S->getEntity() &&
- OutOfLineCtx->isNamespace()) {
- LookedInCtx = true;
-
- // Look into context considering using-directives.
- CppNamespaceLookup(Context, OutOfLineCtx, Name, NameKind, IDNS,
- LookupResults, &UDirs);
-
- if ((Result = MergeLookupResults(Context, LookupResults)) ||
- (RedeclarationOnly && !OutOfLineCtx->isTransparentContext()))
- return std::make_pair(true, Result);
-
- OutOfLineCtx = OutOfLineCtx->getParent();
- }
-
for (; S; S = S->getParent()) {
DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
+ if (Ctx->isTransparentContext())
+ continue;
+
assert(Ctx && Ctx->isFileContext() &&
"We should have been looking only at file context here already.");
// Check whether the IdResolver has anything in this scope.
+ bool Found = false;
for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
if (isAcceptableLookupResult(*I, NameKind, IDNS)) {
// We found something. Look for anything else in our scope
// with this same name and in an acceptable identifier
// namespace, so that we can construct an overload set if we
// need to.
- IdentifierResolver::iterator LastI = I;
- for (++LastI; LastI != IEnd; ++LastI) {
- if (!S->isDeclScope(DeclPtrTy::make(*LastI)))
- break;
- }
-
- // We store name lookup result, and continue trying to look into
- // associated context, and maybe namespaces nominated by
- // using-directives.
- LookupResults.push_back(
- LookupResult::CreateLookupResult(Context, I, LastI));
- break;
+ Found = true;
+ R.addDecl(*I);
}
}
- LookedInCtx = true;
// Look into context considering using-directives.
- CppNamespaceLookup(Context, Ctx, Name, NameKind, IDNS,
- LookupResults, &UDirs);
+ if (CppNamespaceLookup(R, Context, Ctx, Name, NameKind, IDNS, &UDirs))
+ Found = true;
- if ((Result = MergeLookupResults(Context, LookupResults)) ||
- (RedeclarationOnly && !Ctx->isTransparentContext()))
- return std::make_pair(true, Result);
- }
+ if (Found) {
+ R.resolveKind();
+ return true;
+ }
- if (!(LookedInCtx || LookupResults.empty())) {
- // We didn't Performed lookup in Scope entity, so we return
- // result form IdentifierResolver.
- assert((LookupResults.size() == 1) && "Wrong size!");
- return std::make_pair(true, LookupResults.front());
+ if (RedeclarationOnly && !Ctx->isTransparentContext())
+ return false;
}
- return std::make_pair(false, LookupResult());
+
+ return !R.empty();
}
/// @brief Perform unqualified name lookup starting from a given
@@ -823,17 +513,16 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
/// @param Name The name of the entity that we are searching for.
///
/// @param Loc If provided, the source location where we're performing
-/// name lookup. At present, this is only used to produce diagnostics when
+/// name lookup. At present, this is only used to produce diagnostics when
/// C library functions (like "malloc") are implicitly declared.
///
/// @returns The result of name lookup, which includes zero or more
/// declarations and possibly additional information used to diagnose
/// ambiguities.
-Sema::LookupResult
-Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
- bool RedeclarationOnly, bool AllowBuiltinCreation,
- SourceLocation Loc) {
- if (!Name) return LookupResult::CreateLookupResult(Context, 0);
+bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name,
+ LookupNameKind NameKind, bool RedeclarationOnly,
+ bool AllowBuiltinCreation, SourceLocation Loc) {
+ if (!Name) return false;
if (!getLangOptions().CPlusPlus) {
// Unqualified name lookup in C/Objective-C is purely lexical, so
@@ -861,7 +550,7 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
case Sema::LookupRedeclarationWithLinkage:
// Find the nearest non-transparent declaration scope.
while (!(S->getFlags() & Scope::DeclScope) ||
- (S->getEntity() &&
+ (S->getEntity() &&
static_cast<DeclContext *>(S->getEntity())
->isTransparentContext()))
S = S->getParent();
@@ -875,7 +564,7 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
case Sema::LookupObjCImplementationName:
IDNS = Decl::IDNS_ObjCImplementation;
break;
-
+
case Sema::LookupObjCCategoryImplName:
IDNS = Decl::IDNS_ObjCCategoryImpl;
break;
@@ -888,7 +577,7 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
bool LeftStartingScope = false;
for (IdentifierResolver::iterator I = IdResolver.begin(Name),
- IEnd = IdResolver.end();
+ IEnd = IdResolver.end();
I != IEnd; ++I)
if ((*I)->isInIdentifierNamespace(IDNS)) {
if (NameKind == LookupRedeclarationWithLinkage) {
@@ -903,6 +592,8 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
continue;
}
+ R.addDecl(*I);
+
if ((*I)->getAttr<OverloadableAttr>()) {
// If this declaration has the "overloadable" attribute, we
// might have a set of overloaded functions.
@@ -918,26 +609,24 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
for (++LastI; LastI != IEnd; ++LastI) {
if (!S->isDeclScope(DeclPtrTy::make(*LastI)))
break;
+ R.addDecl(*LastI);
}
-
- return LookupResult::CreateLookupResult(Context, I, LastI);
}
- // We have a single lookup result.
- return LookupResult::CreateLookupResult(Context, *I);
+ R.resolveKind();
+
+ return true;
}
} else {
// Perform C++ unqualified name lookup.
- std::pair<bool, LookupResult> MaybeResult =
- CppLookupName(S, Name, NameKind, RedeclarationOnly);
- if (MaybeResult.first)
- return MaybeResult.second;
+ if (CppLookupName(R, S, Name, NameKind, RedeclarationOnly))
+ return true;
}
// If we didn't find a use of this identifier, and if the identifier
// corresponds to a compiler builtin, create the decl object for the builtin
// now, injecting it into translation unit scope, and return it.
- if (NameKind == LookupOrdinaryName ||
+ if (NameKind == LookupOrdinaryName ||
NameKind == LookupRedeclarationWithLinkage) {
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (II && AllowBuiltinCreation) {
@@ -945,17 +634,132 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
if (unsigned BuiltinID = II->getBuiltinID()) {
// In C++, we don't have any predefined library functions like
// 'malloc'. Instead, we'll just error.
- if (getLangOptions().CPlusPlus &&
+ if (getLangOptions().CPlusPlus &&
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
- return LookupResult::CreateLookupResult(Context, 0);
+ return false;
+
+ NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
+ S, RedeclarationOnly, Loc);
+ if (D) R.addDecl(D);
+ return (D != NULL);
+ }
+ }
+ }
+ return false;
+}
+
+/// @brief Perform qualified name lookup in the namespaces nominated by
+/// using directives by the given context.
+///
+/// C++98 [namespace.qual]p2:
+/// Given X::m (where X is a user-declared namespace), or given ::m
+/// (where X is the global namespace), let S be the set of all
+/// declarations of m in X and in the transitive closure of all
+/// namespaces nominated by using-directives in X and its used
+/// namespaces, except that using-directives are ignored in any
+/// namespace, including X, directly containing one or more
+/// declarations of m. No namespace is searched more than once in
+/// the lookup of a name. If S is the empty set, the program is
+/// ill-formed. Otherwise, if S has exactly one member, or if the
+/// context of the reference is a using-declaration
+/// (namespace.udecl), S is the required set of declarations of
+/// m. Otherwise if the use of m is not one that allows a unique
+/// declaration to be chosen from S, the program is ill-formed.
+/// C++98 [namespace.qual]p5:
+/// During the lookup of a qualified namespace member name, if the
+/// lookup finds more than one declaration of the member, and if one
+/// declaration introduces a class name or enumeration name and the
+/// other declarations either introduce the same object, the same
+/// enumerator or a set of functions, the non-type name hides the
+/// class or enumeration name if and only if the declarations are
+/// from the same namespace; otherwise (the declarations are from
+/// different namespaces), the program is ill-formed.
+static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R,
+ DeclContext *StartDC,
+ DeclarationName Name,
+ Sema::LookupNameKind NameKind,
+ unsigned IDNS) {
+ assert(StartDC->isFileContext() && "start context is not a file context");
+
+ DeclContext::udir_iterator I = StartDC->using_directives_begin();
+ DeclContext::udir_iterator E = StartDC->using_directives_end();
+
+ if (I == E) return false;
+
+ // We have at least added all these contexts to the queue.
+ llvm::DenseSet<DeclContext*> Visited;
+ Visited.insert(StartDC);
+
+ // We have not yet looked into these namespaces, much less added
+ // their "using-children" to the queue.
+ llvm::SmallVector<NamespaceDecl*, 8> Queue;
+
+ // We have already looked into the initial namespace; seed the queue
+ // with its using-children.
+ for (; I != E; ++I) {
+ NamespaceDecl *ND = (*I)->getNominatedNamespace();
+ if (Visited.insert(ND).second)
+ Queue.push_back(ND);
+ }
+
+ // The easiest way to implement the restriction in [namespace.qual]p5
+ // is to check whether any of the individual results found a tag
+ // and, if so, to declare an ambiguity if the final result is not
+ // a tag.
+ bool FoundTag = false;
+ bool FoundNonTag = false;
+
+ Sema::LookupResult LocalR;
+
+ bool Found = false;
+ while (!Queue.empty()) {
+ NamespaceDecl *ND = Queue.back();
+ Queue.pop_back();
+
+ // We go through some convolutions here to avoid copying results
+ // between LookupResults.
+ bool UseLocal = !R.empty();
+ Sema::LookupResult &DirectR = UseLocal ? LocalR : R;
+ bool FoundDirect = LookupDirect(DirectR, ND, Name, NameKind, IDNS);
+
+ if (FoundDirect) {
+ // First do any local hiding.
+ DirectR.resolveKind();
+
+ // If the local result is a tag, remember that.
+ if (DirectR.isSingleTagDecl())
+ FoundTag = true;
+ else
+ FoundNonTag = true;
- return LookupResult::CreateLookupResult(Context,
- LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
- S, RedeclarationOnly, Loc));
+ // Append the local results to the total results if necessary.
+ if (UseLocal) {
+ R.addAllDecls(LocalR);
+ LocalR.clear();
}
}
+
+ // If we find names in this namespace, ignore its using directives.
+ if (FoundDirect) {
+ Found = true;
+ continue;
+ }
+
+ for (llvm::tie(I,E) = ND->getUsingDirectives(); I != E; ++I) {
+ NamespaceDecl *Nom = (*I)->getNominatedNamespace();
+ if (Visited.insert(Nom).second)
+ Queue.push_back(Nom);
+ }
}
- return LookupResult::CreateLookupResult(Context, 0);
+
+ if (Found) {
+ if (FoundTag && FoundNonTag)
+ R.setAmbiguousQualifiedTagHiding();
+ else
+ R.resolveKind();
+ }
+
+ return Found;
}
/// @brief Perform qualified name lookup into a given context.
@@ -988,40 +792,91 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
/// @returns The result of name lookup, which includes zero or more
/// declarations and possibly additional information used to diagnose
/// ambiguities.
-Sema::LookupResult
-Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
- LookupNameKind NameKind, bool RedeclarationOnly) {
+bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+ DeclarationName Name, LookupNameKind NameKind,
+ bool RedeclarationOnly) {
assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context");
-
- if (!Name) return LookupResult::CreateLookupResult(Context, 0);
+
+ if (!Name)
+ return false;
// If we're performing qualified name lookup (e.g., lookup into a
// struct), find fields as part of ordinary name lookup.
unsigned IDNS
- = getIdentifierNamespacesFromLookupNameKind(NameKind,
+ = getIdentifierNamespacesFromLookupNameKind(NameKind,
getLangOptions().CPlusPlus);
if (NameKind == LookupOrdinaryName)
IDNS |= Decl::IDNS_Member;
+ // Make sure that the declaration context is complete.
+ assert((!isa<TagDecl>(LookupCtx) ||
+ LookupCtx->isDependentContext() ||
+ cast<TagDecl>(LookupCtx)->isDefinition() ||
+ Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>()
+ ->isBeingDefined()) &&
+ "Declaration context must already be complete!");
+
// Perform qualified name lookup into the LookupCtx.
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I)
- if (isAcceptableLookupResult(*I, NameKind, IDNS))
- return LookupResult::CreateLookupResult(Context, I, E);
+ if (LookupDirect(R, LookupCtx, Name, NameKind, IDNS)) {
+ R.resolveKind();
+ return true;
+ }
+
+ // Don't descend into implied contexts for redeclarations.
+ // C++98 [namespace.qual]p6:
+ // In a declaration for a namespace member in which the
+ // declarator-id is a qualified-id, given that the qualified-id
+ // for the namespace member has the form
+ // nested-name-specifier unqualified-id
+ // the unqualified-id shall name a member of the namespace
+ // designated by the nested-name-specifier.
+ // See also [class.mfct]p5 and [class.static.data]p2.
+ if (RedeclarationOnly)
+ return false;
- // If this isn't a C++ class or we aren't allowed to look into base
+ // If this is a namespace, look it up in
+ if (LookupCtx->isFileContext())
+ return LookupQualifiedNameInUsingDirectives(R, LookupCtx, Name, NameKind,
+ IDNS);
+
+ // If this isn't a C++ class, we aren't allowed to look into base
// classes, we're done.
- if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx))
- return LookupResult::CreateLookupResult(Context, 0);
+ if (!isa<CXXRecordDecl>(LookupCtx))
+ return false;
// Perform lookup into our base classes.
- BasePaths Paths;
- Paths.setOrigin(Context.getTypeDeclType(cast<RecordDecl>(LookupCtx)));
+ CXXRecordDecl *LookupRec = cast<CXXRecordDecl>(LookupCtx);
+ CXXBasePaths Paths;
+ Paths.setOrigin(LookupRec);
// Look for this member in our base classes
- if (!LookupInBases(cast<CXXRecordDecl>(LookupCtx),
- MemberLookupCriteria(Name, NameKind, IDNS), Paths))
- return LookupResult::CreateLookupResult(Context, 0);
+ CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0;
+ switch (NameKind) {
+ case LookupOrdinaryName:
+ case LookupMemberName:
+ case LookupRedeclarationWithLinkage:
+ BaseCallback = &CXXRecordDecl::FindOrdinaryMember;
+ break;
+
+ case LookupTagName:
+ BaseCallback = &CXXRecordDecl::FindTagMember;
+ break;
+
+ case LookupOperatorName:
+ case LookupNamespaceName:
+ case LookupObjCProtocolName:
+ case LookupObjCImplementationName:
+ case LookupObjCCategoryImplName:
+ // These lookups will never find a member in a C++ class (or base class).
+ return false;
+
+ case LookupNestedNameSpecifierName:
+ BaseCallback = &CXXRecordDecl::FindNestedNameSpecifierMember;
+ break;
+ }
+
+ if (!LookupRec->lookupInBases(BaseCallback, Name.getAsOpaquePtr(), Paths))
+ return false;
// C++ [class.member.lookup]p2:
// [...] If the resulting set of declarations are not all from
@@ -1032,29 +887,28 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
// FIXME: support using declarations!
QualType SubobjectType;
int SubobjectNumber = 0;
- for (BasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
+ for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
Path != PathEnd; ++Path) {
- const BasePathElement &PathElement = Path->back();
+ const CXXBasePathElement &PathElement = Path->back();
// Determine whether we're looking at a distinct sub-object or not.
if (SubobjectType.isNull()) {
- // This is the first subobject we've looked at. Record it's type.
+ // This is the first subobject we've looked at. Record its type.
SubobjectType = Context.getCanonicalType(PathElement.Base->getType());
SubobjectNumber = PathElement.SubobjectNumber;
- } else if (SubobjectType
+ } else if (SubobjectType
!= Context.getCanonicalType(PathElement.Base->getType())) {
// We found members of the given name in two subobjects of
// different types. This lookup is ambiguous.
- BasePaths *PathsOnHeap = new BasePaths;
- PathsOnHeap->swap(Paths);
- return LookupResult::CreateLookupResult(Context, PathsOnHeap, true);
+ R.setAmbiguousBaseSubobjectTypes(Paths);
+ return true;
} else if (SubobjectNumber != PathElement.SubobjectNumber) {
// We have a different subobject of the same type.
// C++ [class.member.lookup]p5:
// A static member, a nested type or an enumerator defined in
// a base class T can unambiguously be found even if an object
- // has more than one base class subobject of type T.
+ // has more than one base class subobject of type T.
Decl *FirstDecl = *Path->Decls.first;
if (isa<VarDecl>(FirstDecl) ||
isa<TypeDecl>(FirstDecl) ||
@@ -1083,21 +937,18 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
// We have found a nonstatic member name in multiple, distinct
// subobjects. Name lookup is ambiguous.
- BasePaths *PathsOnHeap = new BasePaths;
- PathsOnHeap->swap(Paths);
- return LookupResult::CreateLookupResult(Context, PathsOnHeap, false);
+ R.setAmbiguousBaseSubobjects(Paths);
+ return true;
}
}
// Lookup in a base class succeeded; return these results.
- // If we found a function declaration, return an overload set.
- if ((*Paths.front().Decls.first)->isFunctionOrFunctionTemplate())
- return LookupResult::CreateLookupResult(Context,
- Paths.front().Decls.first, Paths.front().Decls.second);
-
- // We found a non-function declaration; return a single declaration.
- return LookupResult::CreateLookupResult(Context, *Paths.front().Decls.first);
+ DeclContext::lookup_iterator I, E;
+ for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I)
+ R.addDecl(*I);
+ R.resolveKind();
+ return true;
}
/// @brief Performs name lookup for a name that was parsed in the
@@ -1111,59 +962,50 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
///
/// @param S The scope from which unqualified name lookup will
/// begin.
-///
-/// @param SS An optional C++ scope-specified, e.g., "::N::M".
+///
+/// @param SS An optional C++ scope-specifier, e.g., "::N::M".
///
/// @param Name The name of the entity that name lookup will
/// search for.
///
/// @param Loc If provided, the source location where we're performing
-/// name lookup. At present, this is only used to produce diagnostics when
+/// name lookup. At present, this is only used to produce diagnostics when
/// C library functions (like "malloc") are implicitly declared.
///
-/// @returns The result of qualified or unqualified name lookup.
-Sema::LookupResult
-Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
- DeclarationName Name, LookupNameKind NameKind,
- bool RedeclarationOnly, bool AllowBuiltinCreation,
- SourceLocation Loc) {
- if (SS && (SS->isSet() || SS->isInvalid())) {
- // If the scope specifier is invalid, don't even look for
+/// @param EnteringContext Indicates whether we are going to enter the
+/// context of the scope-specifier SS (if present).
+///
+/// @returns True if any decls were found (but possibly ambiguous)
+bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
+ DeclarationName Name, LookupNameKind NameKind,
+ bool RedeclarationOnly, bool AllowBuiltinCreation,
+ SourceLocation Loc,
+ bool EnteringContext) {
+ if (SS && SS->isInvalid()) {
+ // When the scope specifier is invalid, don't even look for
// anything.
- if (SS->isInvalid())
- return LookupResult::CreateLookupResult(Context, 0);
-
- assert(!isUnknownSpecialization(*SS) && "Can't lookup dependent types");
-
- if (isDependentScopeSpecifier(*SS)) {
- // Determine whether we are looking into the current
- // instantiation.
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
- CXXRecordDecl *Current = getCurrentInstantiationOf(NNS);
- assert(Current && "Bad dependent scope specifier");
-
- // We nested name specifier refers to the current instantiation,
- // so now we will look for a member of the current instantiation
- // (C++0x [temp.dep.type]).
- unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind, true);
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = Current->lookup(Name); I != E; ++I)
- if (isAcceptableLookupResult(*I, NameKind, IDNS))
- return LookupResult::CreateLookupResult(Context, I, E);
- }
+ return false;
+ }
- if (RequireCompleteDeclContext(*SS))
- return LookupResult::CreateLookupResult(Context, 0);
+ if (SS && SS->isSet()) {
+ if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) {
+ // We have resolved the scope specifier to a particular declaration
+ // contex, and will perform name lookup in that context.
+ if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS))
+ return false;
- return LookupQualifiedName(computeDeclContext(*SS),
- Name, NameKind, RedeclarationOnly);
+ return LookupQualifiedName(R, DC, Name, NameKind, RedeclarationOnly);
+ }
+
+ // We could not resolve the scope specified to a specific declaration
+ // context, which means that SS refers to an unknown specialization.
+ // Name lookup can't find anything in this case.
+ return false;
}
- LookupResult result(LookupName(S, Name, NameKind, RedeclarationOnly,
- AllowBuiltinCreation, Loc));
-
- return(result);
+ // Perform unqualified name lookup starting in the given scope.
+ return LookupName(R, S, Name, NameKind, RedeclarationOnly,
+ AllowBuiltinCreation, Loc);
}
@@ -1171,7 +1013,7 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
/// from name lookup.
///
/// @param Result The ambiguous name lookup result.
-///
+///
/// @param Name The name of the entity that name lookup was
/// searching for.
///
@@ -1184,79 +1026,164 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
///
/// @returns true
bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
- SourceLocation NameLoc,
+ SourceLocation NameLoc,
SourceRange LookupRange) {
assert(Result.isAmbiguous() && "Lookup result must be ambiguous");
- if (BasePaths *Paths = Result.getBasePaths()) {
- if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) {
- QualType SubobjectType = Paths->front().back().Base->getType();
- Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects)
- << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths)
- << LookupRange;
-
- DeclContext::lookup_iterator Found = Paths->front().Decls.first;
- while (isa<CXXMethodDecl>(*Found) &&
- cast<CXXMethodDecl>(*Found)->isStatic())
- ++Found;
-
- Diag((*Found)->getLocation(), diag::note_ambiguous_member_found);
-
- Result.Destroy();
- return true;
- }
-
- assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes &&
- "Unhandled form of name lookup ambiguity");
+ switch (Result.getAmbiguityKind()) {
+ case LookupResult::AmbiguousBaseSubobjects: {
+ CXXBasePaths *Paths = Result.getBasePaths();
+ QualType SubobjectType = Paths->front().back().Base->getType();
+ Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects)
+ << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths)
+ << LookupRange;
+
+ DeclContext::lookup_iterator Found = Paths->front().Decls.first;
+ while (isa<CXXMethodDecl>(*Found) &&
+ cast<CXXMethodDecl>(*Found)->isStatic())
+ ++Found;
+
+ Diag((*Found)->getLocation(), diag::note_ambiguous_member_found);
+
+ return true;
+ }
+ case LookupResult::AmbiguousBaseSubobjectTypes: {
Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types)
<< Name << LookupRange;
-
+
+ CXXBasePaths *Paths = Result.getBasePaths();
std::set<Decl *> DeclsPrinted;
- for (BasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end();
+ for (CXXBasePaths::paths_iterator Path = Paths->begin(),
+ PathEnd = Paths->end();
Path != PathEnd; ++Path) {
Decl *D = *Path->Decls.first;
if (DeclsPrinted.insert(D).second)
Diag(D->getLocation(), diag::note_ambiguous_member_found);
}
- Result.Destroy();
return true;
- } else if (Result.getKind() == LookupResult::AmbiguousReference) {
- Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange;
+ }
- NamedDecl **DI = reinterpret_cast<NamedDecl **>(Result.First),
- **DEnd = reinterpret_cast<NamedDecl **>(Result.Last);
+ case LookupResult::AmbiguousTagHiding: {
+ Diag(NameLoc, diag::err_ambiguous_tag_hiding) << Name << LookupRange;
- for (; DI != DEnd; ++DI)
- Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI;
+ llvm::SmallPtrSet<NamedDecl*,8> TagDecls;
+
+ LookupResult::iterator DI, DE = Result.end();
+ for (DI = Result.begin(); DI != DE; ++DI)
+ if (TagDecl *TD = dyn_cast<TagDecl>(*DI)) {
+ TagDecls.insert(TD);
+ Diag(TD->getLocation(), diag::note_hidden_tag);
+ }
+
+ for (DI = Result.begin(); DI != DE; ++DI)
+ if (!isa<TagDecl>(*DI))
+ Diag((*DI)->getLocation(), diag::note_hiding_object);
+
+ // For recovery purposes, go ahead and implement the hiding.
+ Result.hideDecls(TagDecls);
- Result.Destroy();
return true;
}
- assert(false && "Unhandled form of name lookup ambiguity");
+ case LookupResult::AmbiguousReference: {
+ Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange;
+
+ LookupResult::iterator DI = Result.begin(), DE = Result.end();
+ for (; DI != DE; ++DI)
+ Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI;
+
+ return true;
+ }
+ }
- // We can't reach here.
+ llvm::llvm_unreachable("unknown ambiguity kind");
return true;
}
+static void
+addAssociatedClassesAndNamespaces(QualType T,
+ ASTContext &Context,
+ Sema::AssociatedNamespaceSet &AssociatedNamespaces,
+ Sema::AssociatedClassSet &AssociatedClasses);
+
+static void CollectNamespace(Sema::AssociatedNamespaceSet &Namespaces,
+ DeclContext *Ctx) {
+ if (Ctx->isFileContext())
+ Namespaces.insert(Ctx);
+}
+
+// \brief Add the associated classes and namespaces for argument-dependent
+// lookup that involves a template argument (C++ [basic.lookup.koenig]p2).
+static void
+addAssociatedClassesAndNamespaces(const TemplateArgument &Arg,
+ ASTContext &Context,
+ Sema::AssociatedNamespaceSet &AssociatedNamespaces,
+ Sema::AssociatedClassSet &AssociatedClasses) {
+ // C++ [basic.lookup.koenig]p2, last bullet:
+ // -- [...] ;
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ break;
+
+ case TemplateArgument::Type:
+ // [...] the namespaces and classes associated with the types of the
+ // template arguments provided for template type parameters (excluding
+ // template template parameters)
+ addAssociatedClassesAndNamespaces(Arg.getAsType(), Context,
+ AssociatedNamespaces,
+ AssociatedClasses);
+ break;
+
+ case TemplateArgument::Declaration:
+ // [...] the namespaces in which any template template arguments are
+ // defined; and the classes in which any member templates used as
+ // template template arguments are defined.
+ if (ClassTemplateDecl *ClassTemplate
+ = dyn_cast<ClassTemplateDecl>(Arg.getAsDecl())) {
+ DeclContext *Ctx = ClassTemplate->getDeclContext();
+ if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
+ AssociatedClasses.insert(EnclosingClass);
+ // Add the associated namespace for this class.
+ while (Ctx->isRecord())
+ Ctx = Ctx->getParent();
+ CollectNamespace(AssociatedNamespaces, Ctx);
+ }
+ break;
+
+ case TemplateArgument::Integral:
+ case TemplateArgument::Expression:
+ // [Note: non-type template arguments do not contribute to the set of
+ // associated namespaces. ]
+ break;
+
+ case TemplateArgument::Pack:
+ for (TemplateArgument::pack_iterator P = Arg.pack_begin(),
+ PEnd = Arg.pack_end();
+ P != PEnd; ++P)
+ addAssociatedClassesAndNamespaces(*P, Context,
+ AssociatedNamespaces,
+ AssociatedClasses);
+ break;
+ }
+}
+
// \brief Add the associated classes and namespaces for
-// argument-dependent lookup with an argument of class type
-// (C++ [basic.lookup.koenig]p2).
-static void
-addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
+// argument-dependent lookup with an argument of class type
+// (C++ [basic.lookup.koenig]p2).
+static void
+addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
ASTContext &Context,
Sema::AssociatedNamespaceSet &AssociatedNamespaces,
- Sema::AssociatedClassSet &AssociatedClasses,
- bool &GlobalScope) {
+ Sema::AssociatedClassSet &AssociatedClasses) {
// C++ [basic.lookup.koenig]p2:
// [...]
// -- If T is a class type (including unions), its associated
// classes are: the class itself; the class of which it is a
// member, if any; and its direct and indirect base
// classes. Its associated namespaces are the namespaces in
- // which its associated classes are defined.
+ // which its associated classes are defined.
// Add the class of which it is a member, if any.
DeclContext *Ctx = Class->getDeclContext();
@@ -1265,17 +1192,38 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
// Add the associated namespace for this class.
while (Ctx->isRecord())
Ctx = Ctx->getParent();
- if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
- AssociatedNamespaces.insert(EnclosingNamespace);
- else if (Ctx->isTranslationUnit())
- GlobalScope = true;
-
+ CollectNamespace(AssociatedNamespaces, Ctx);
+
// Add the class itself. If we've already seen this class, we don't
// need to visit base classes.
if (!AssociatedClasses.insert(Class))
return;
- // FIXME: Handle class template specializations
+ // -- If T is a template-id, its associated namespaces and classes are
+ // the namespace in which the template is defined; for member
+ // templates, the member template’s class; the namespaces and classes
+ // associated with the types of the template arguments provided for
+ // template type parameters (excluding template template parameters); the
+ // namespaces in which any template template arguments are defined; and
+ // the classes in which any member templates used as template template
+ // arguments are defined. [Note: non-type template arguments do not
+ // contribute to the set of associated namespaces. ]
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Class)) {
+ DeclContext *Ctx = Spec->getSpecializedTemplate()->getDeclContext();
+ if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
+ AssociatedClasses.insert(EnclosingClass);
+ // Add the associated namespace for this class.
+ while (Ctx->isRecord())
+ Ctx = Ctx->getParent();
+ CollectNamespace(AssociatedNamespaces, Ctx);
+
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+ addAssociatedClassesAndNamespaces(TemplateArgs[I], Context,
+ AssociatedNamespaces,
+ AssociatedClasses);
+ }
// Add direct and indirect base classes along with their associated
// namespaces.
@@ -1290,17 +1238,14 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
for (CXXRecordDecl::base_class_iterator Base = Class->bases_begin(),
BaseEnd = Class->bases_end();
Base != BaseEnd; ++Base) {
- const RecordType *BaseType = Base->getType()->getAsRecordType();
+ const RecordType *BaseType = Base->getType()->getAs<RecordType>();
CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl());
if (AssociatedClasses.insert(BaseDecl)) {
// Find the associated namespace for this base class.
DeclContext *BaseCtx = BaseDecl->getDeclContext();
while (BaseCtx->isRecord())
BaseCtx = BaseCtx->getParent();
- if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(BaseCtx))
- AssociatedNamespaces.insert(EnclosingNamespace);
- else if (BaseCtx->isTranslationUnit())
- GlobalScope = true;
+ CollectNamespace(AssociatedNamespaces, BaseCtx);
// Make sure we visit the bases of this base class.
if (BaseDecl->bases_begin() != BaseDecl->bases_end())
@@ -1312,13 +1257,12 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
// \brief Add the associated classes and namespaces for
// argument-dependent lookup with an argument of type T
-// (C++ [basic.lookup.koenig]p2).
-static void
-addAssociatedClassesAndNamespaces(QualType T,
+// (C++ [basic.lookup.koenig]p2).
+static void
+addAssociatedClassesAndNamespaces(QualType T,
ASTContext &Context,
Sema::AssociatedNamespaceSet &AssociatedNamespaces,
- Sema::AssociatedClassSet &AssociatedClasses,
- bool &GlobalScope) {
+ Sema::AssociatedClassSet &AssociatedClasses) {
// C++ [basic.lookup.koenig]p2:
//
// For each argument type T in the function call, there is a set
@@ -1332,44 +1276,43 @@ addAssociatedClassesAndNamespaces(QualType T,
T = Context.getCanonicalType(T).getUnqualifiedType();
// -- If T is a pointer to U or an array of U, its associated
- // namespaces and classes are those associated with U.
+ // namespaces and classes are those associated with U.
//
// We handle this by unwrapping pointer and array types immediately,
// to avoid unnecessary recursion.
while (true) {
- if (const PointerType *Ptr = T->getAsPointerType())
+ if (const PointerType *Ptr = T->getAs<PointerType>())
T = Ptr->getPointeeType();
else if (const ArrayType *Ptr = Context.getAsArrayType(T))
T = Ptr->getElementType();
- else
+ else
break;
}
// -- If T is a fundamental type, its associated sets of
// namespaces and classes are both empty.
- if (T->getAsBuiltinType())
+ if (T->getAs<BuiltinType>())
return;
// -- If T is a class type (including unions), its associated
// classes are: the class itself; the class of which it is a
// member, if any; and its direct and indirect base
// classes. Its associated namespaces are the namespaces in
- // which its associated classes are defined.
- if (const RecordType *ClassType = T->getAsRecordType())
- if (CXXRecordDecl *ClassDecl
+ // which its associated classes are defined.
+ if (const RecordType *ClassType = T->getAs<RecordType>())
+ if (CXXRecordDecl *ClassDecl
= dyn_cast<CXXRecordDecl>(ClassType->getDecl())) {
- addAssociatedClassesAndNamespaces(ClassDecl, Context,
- AssociatedNamespaces,
- AssociatedClasses,
- GlobalScope);
+ addAssociatedClassesAndNamespaces(ClassDecl, Context,
+ AssociatedNamespaces,
+ AssociatedClasses);
return;
}
// -- If T is an enumeration type, its associated namespace is
// the namespace in which it is defined. If it is class
// member, its associated class is the member’s class; else
- // it has no associated class.
- if (const EnumType *EnumT = T->getAsEnumType()) {
+ // it has no associated class.
+ if (const EnumType *EnumT = T->getAs<EnumType>()) {
EnumDecl *Enum = EnumT->getDecl();
DeclContext *Ctx = Enum->getDeclContext();
@@ -1379,10 +1322,7 @@ addAssociatedClassesAndNamespaces(QualType T,
// Add the associated namespace for this class.
while (Ctx->isRecord())
Ctx = Ctx->getParent();
- if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
- AssociatedNamespaces.insert(EnclosingNamespace);
- else if (Ctx->isTranslationUnit())
- GlobalScope = true;
+ CollectNamespace(AssociatedNamespaces, Ctx);
return;
}
@@ -1390,50 +1330,48 @@ addAssociatedClassesAndNamespaces(QualType T,
// -- If T is a function type, its associated namespaces and
// classes are those associated with the function parameter
// types and those associated with the return type.
- if (const FunctionType *FunctionType = T->getAsFunctionType()) {
+ if (const FunctionType *FnType = T->getAs<FunctionType>()) {
// Return type
- addAssociatedClassesAndNamespaces(FunctionType->getResultType(),
+ addAssociatedClassesAndNamespaces(FnType->getResultType(),
Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ AssociatedNamespaces, AssociatedClasses);
- const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FunctionType);
+ const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType);
if (!Proto)
return;
// Argument types
for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
+ ArgEnd = Proto->arg_type_end();
Arg != ArgEnd; ++Arg)
addAssociatedClassesAndNamespaces(*Arg, Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
-
+ AssociatedNamespaces, AssociatedClasses);
+
return;
}
// -- If T is a pointer to a member function of a class X, its
// associated namespaces and classes are those associated
// with the function parameter types and return type,
- // together with those associated with X.
+ // together with those associated with X.
//
// -- If T is a pointer to a data member of class X, its
// associated namespaces and classes are those associated
// with the member type together with those associated with
- // X.
- if (const MemberPointerType *MemberPtr = T->getAsMemberPointerType()) {
+ // X.
+ if (const MemberPointerType *MemberPtr = T->getAs<MemberPointerType>()) {
// Handle the type that the pointer to member points to.
addAssociatedClassesAndNamespaces(MemberPtr->getPointeeType(),
Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ AssociatedNamespaces,
+ AssociatedClasses);
// Handle the class type into which this points.
- if (const RecordType *Class = MemberPtr->getClass()->getAsRecordType())
+ if (const RecordType *Class = MemberPtr->getClass()->getAs<RecordType>())
addAssociatedClassesAndNamespaces(cast<CXXRecordDecl>(Class->getDecl()),
Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ AssociatedNamespaces,
+ AssociatedClasses);
return;
}
@@ -1447,13 +1385,12 @@ addAssociatedClassesAndNamespaces(QualType T,
/// arguments.
///
/// This routine computes the sets of associated classes and associated
-/// namespaces searched by argument-dependent lookup
+/// namespaces searched by argument-dependent lookup
/// (C++ [basic.lookup.argdep]) for a given set of arguments.
-void
+void
Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
AssociatedNamespaceSet &AssociatedNamespaces,
- AssociatedClassSet &AssociatedClasses,
- bool &GlobalScope) {
+ AssociatedClassSet &AssociatedClasses) {
AssociatedNamespaces.clear();
AssociatedClasses.clear();
@@ -1463,14 +1400,14 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
// associated classes to be considered. The sets of namespaces and
// classes is determined entirely by the types of the function
// arguments (and the namespace of any template template
- // argument).
+ // argument).
for (unsigned ArgIdx = 0; ArgIdx != NumArgs; ++ArgIdx) {
Expr *Arg = Args[ArgIdx];
if (Arg->getType() != Context.OverloadTy) {
addAssociatedClassesAndNamespaces(Arg->getType(), Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ AssociatedNamespaces,
+ AssociatedClasses);
continue;
}
@@ -1482,16 +1419,23 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
// classes and namespaces associated with its (non-dependent)
// parameter types and return type.
DeclRefExpr *DRE = 0;
+ TemplateIdRefExpr *TIRE = 0;
+ Arg = Arg->IgnoreParens();
if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg)) {
- if (unaryOp->getOpcode() == UnaryOperator::AddrOf)
+ if (unaryOp->getOpcode() == UnaryOperator::AddrOf) {
DRE = dyn_cast<DeclRefExpr>(unaryOp->getSubExpr());
- } else
+ TIRE = dyn_cast<TemplateIdRefExpr>(unaryOp->getSubExpr());
+ }
+ } else {
DRE = dyn_cast<DeclRefExpr>(Arg);
- if (!DRE)
- continue;
+ TIRE = dyn_cast<TemplateIdRefExpr>(Arg);
+ }
- OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
+ OverloadedFunctionDecl *Ovl = 0;
+ if (DRE)
+ Ovl = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
+ else if (TIRE)
+ Ovl = TIRE->getTemplateName().getAsOverloadedFunctionDecl();
if (!Ovl)
continue;
@@ -1506,16 +1450,13 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
// that, if this is a member function, we do *not* consider the
// enclosing namespace of its class.
DeclContext *Ctx = FDecl->getDeclContext();
- if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
- AssociatedNamespaces.insert(EnclosingNamespace);
- else if (Ctx->isTranslationUnit())
- GlobalScope = true;
+ CollectNamespace(AssociatedNamespaces, Ctx);
// Add the classes and namespaces associated with the parameter
// types and return type of this function.
addAssociatedClassesAndNamespaces(FDecl->getType(), Context,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ AssociatedNamespaces,
+ AssociatedClasses);
}
}
}
@@ -1525,7 +1466,7 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
/// arguments have types T1 (and, if non-empty, T2). This routine
/// implements the check in C++ [over.match.oper]p3b2 concerning
/// enumeration types.
-static bool
+static bool
IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
QualType T1, QualType T2,
ASTContext &Context) {
@@ -1535,7 +1476,7 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
return true;
- const FunctionProtoType *Proto = Fn->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>();
if (Proto->getNumArgs() < 1)
return false;
@@ -1561,26 +1502,19 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
/// \brief Find the protocol with the given name, if any.
ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) {
- Decl *D = LookupName(TUScope, II, LookupObjCProtocolName).getAsDecl();
+ Decl *D = LookupSingleName(TUScope, II, LookupObjCProtocolName);
return cast_or_null<ObjCProtocolDecl>(D);
}
-/// \brief Find the Objective-C implementation with the given name, if
-/// any.
-ObjCImplementationDecl *Sema::LookupObjCImplementation(IdentifierInfo *II) {
- Decl *D = LookupName(TUScope, II, LookupObjCImplementationName).getAsDecl();
- return cast_or_null<ObjCImplementationDecl>(D);
-}
-
/// \brief Find the Objective-C category implementation with the given
/// name, if any.
ObjCCategoryImplDecl *Sema::LookupObjCCategoryImpl(IdentifierInfo *II) {
- Decl *D = LookupName(TUScope, II, LookupObjCCategoryImplName).getAsDecl();
+ Decl *D = LookupSingleName(TUScope, II, LookupObjCCategoryImplName);
return cast_or_null<ObjCCategoryImplDecl>(D);
}
void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
- QualType T1, QualType T2,
+ QualType T1, QualType T2,
FunctionSet &Functions) {
// C++ [over.match.oper]p3:
// -- The set of non-member candidates is the result of the
@@ -1589,17 +1523,18 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
// unqualified function calls (3.4.2) except that all member
// functions are ignored. However, if no operand has a class
// type, only those non-member functions in the lookup set
- // that have a first parameter of type T1 or “reference to
- // (possibly cv-qualified) T1”, when T1 is an enumeration
+ // that have a first parameter of type T1 or "reference to
+ // (possibly cv-qualified) T1", when T1 is an enumeration
// type, or (if there is a right operand) a second parameter
- // of type T2 or “reference to (possibly cv-qualified) T2”,
+ // of type T2 or "reference to (possibly cv-qualified) T2",
// when T2 is an enumeration type, are candidate functions.
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
- LookupResult Operators = LookupName(S, OpName, LookupOperatorName);
-
+ LookupResult Operators;
+ LookupName(Operators, S, OpName, LookupOperatorName);
+
assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
- if (!Operators)
+ if (Operators.empty())
return;
for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end();
@@ -1607,10 +1542,10 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) {
if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
Functions.insert(FD); // FIXME: canonical FD
- } else if (FunctionTemplateDecl *FunTmpl
+ } else if (FunctionTemplateDecl *FunTmpl
= dyn_cast<FunctionTemplateDecl>(*Op)) {
// FIXME: friend operators?
- // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
+ // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
// later?
if (!FunTmpl->getDeclContext()->isRecord())
Functions.insert(FunTmpl);
@@ -1618,6 +1553,14 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
}
}
+static void CollectFunctionDecl(Sema::FunctionSet &Functions,
+ Decl *D) {
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
+ Functions.insert(Func);
+ else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
+ Functions.insert(FunTmpl);
+}
+
void Sema::ArgumentDependentLookup(DeclarationName Name,
Expr **Args, unsigned NumArgs,
FunctionSet &Functions) {
@@ -1625,10 +1568,9 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
AssociatedClassSet AssociatedClasses;
- bool GlobalScope = false;
- FindAssociatedClassesAndNamespaces(Args, NumArgs,
- AssociatedNamespaces, AssociatedClasses,
- GlobalScope);
+ FindAssociatedClassesAndNamespaces(Args, NumArgs,
+ AssociatedNamespaces,
+ AssociatedClasses);
// C++ [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
@@ -1642,8 +1584,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
// Here, we compute Y and add its members to the overloaded
// candidate set.
for (AssociatedNamespaceSet::iterator NS = AssociatedNamespaces.begin(),
- NSEnd = AssociatedNamespaces.end();
- NS != NSEnd; ++NS) {
+ NSEnd = AssociatedNamespaces.end();
+ NS != NSEnd; ++NS) {
// When considering an associated namespace, the lookup is the
// same as the lookup performed when the associated namespace is
// used as a qualifier (3.4.3.2) except that:
@@ -1651,28 +1593,22 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
// -- Any using-directives in the associated namespace are
// ignored.
//
- // -- FIXME: Any namespace-scope friend functions declared in
+ // -- Any namespace-scope friend functions declared in
// associated classes are visible within their respective
// namespaces even if they are not visible during an ordinary
// lookup (11.4).
DeclContext::lookup_iterator I, E;
for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
- if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*I))
- Functions.insert(Func);
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*I))
- Functions.insert(FunTmpl);
- }
- }
-
- if (GlobalScope) {
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E)
- = Context.getTranslationUnitDecl()->lookup(Name);
- I != E; ++I) {
- if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*I))
- Functions.insert(Func);
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*I))
- Functions.insert(FunTmpl);
+ Decl *D = *I;
+ // If the only declaration here is an ordinary friend, consider
+ // it only if it was declared in an associated classes.
+ if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) {
+ DeclContext *LexDC = D->getLexicalDeclContext();
+ if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)))
+ continue;
+ }
+
+ CollectFunctionDecl(Functions, D);
}
}
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 03ac2d9bb73a4..99e7b0811c91f 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -12,23 +12,25 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "SemaInherit.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeOrdering.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
+#include <cstdio>
namespace clang {
/// GetConversionCategory - Retrieve the implicit conversion
/// category corresponding to the given implicit conversion kind.
-ImplicitConversionCategory
+ImplicitConversionCategory
GetConversionCategory(ImplicitConversionKind Kind) {
static const ImplicitConversionCategory
Category[(int)ICK_Num_Conversion_Kinds] = {
@@ -136,10 +138,9 @@ ImplicitConversionRank StandardConversionSequence::getRank() const {
/// isPointerConversionToBool - Determines whether this conversion is
/// a conversion of a pointer or pointer-to-member to bool. This is
-/// used as part of the ranking of standard conversion sequences
+/// used as part of the ranking of standard conversion sequences
/// (C++ 13.3.3.2p4).
-bool StandardConversionSequence::isPointerConversionToBool() const
-{
+bool StandardConversionSequence::isPointerConversionToBool() const {
QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
@@ -159,10 +160,9 @@ bool StandardConversionSequence::isPointerConversionToBool() const
/// conversion is a conversion of a pointer to a void pointer. This is
/// used as part of the ranking of standard conversion sequences (C++
/// 13.3.3.2p4).
-bool
+bool
StandardConversionSequence::
-isPointerConversionToVoidPointer(ASTContext& Context) const
-{
+isPointerConversionToVoidPointer(ASTContext& Context) const {
QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
@@ -173,7 +173,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const
FromType = Context.getArrayDecayedType(FromType);
if (Second == ICK_Pointer_Conversion)
- if (const PointerType* ToPtrType = ToType->getAsPointerType())
+ if (const PointerType* ToPtrType = ToType->getAs<PointerType>())
return ToPtrType->getPointeeType()->isVoidType();
return false;
@@ -260,7 +260,7 @@ void ImplicitConversionSequence::DebugPrint() const {
// same signature (C++ 1.3.10) or if the Old declaration isn't a
// function (or overload set). When it does return false and Old is an
// OverloadedFunctionDecl, MatchedDecl will be set to point to the
-// FunctionDecl that New cannot be overloaded with.
+// FunctionDecl that New cannot be overloaded with.
//
// Example: Given the following input:
//
@@ -269,7 +269,7 @@ void ImplicitConversionSequence::DebugPrint() const {
// int f(int, int); // #3
//
// When we process #1, there is no previous declaration of "f",
-// so IsOverload will not be used.
+// so IsOverload will not be used.
//
// When we process #2, Old is a FunctionDecl for #1. By comparing the
// parameter types, we see that #1 and #2 are overloaded (since they
@@ -283,9 +283,8 @@ void ImplicitConversionSequence::DebugPrint() const {
// signature), IsOverload returns false and MatchedDecl will be set to
// point to the FunctionDecl for #2.
bool
-Sema::IsOverload(FunctionDecl *New, Decl* OldD,
- OverloadedFunctionDecl::function_iterator& MatchedDecl)
-{
+Sema::IsOverload(FunctionDecl *New, Decl* OldD,
+ OverloadedFunctionDecl::function_iterator& MatchedDecl) {
if (OverloadedFunctionDecl* Ovl = dyn_cast<OverloadedFunctionDecl>(OldD)) {
// Is this new function an overload of every function in the
// overload set?
@@ -304,8 +303,8 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
return IsOverload(New, Old->getTemplatedDecl(), MatchedDecl);
else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) {
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
- FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
-
+ FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
+
// C++ [temp.fct]p2:
// A function template can be overloaded with other function templates
// and with normal (non-template) functions.
@@ -340,21 +339,21 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
return true;
// C++ [temp.over.link]p4:
- // The signature of a function template consists of its function
+ // The signature of a function template consists of its function
// signature, its return type and its template parameter list. The names
// of the template parameters are significant only for establishing the
- // relationship between the template parameters and the rest of the
+ // relationship between the template parameters and the rest of the
// signature.
//
// We check the return type and template parameter lists for function
// templates first; the remaining checks follow.
if (NewTemplate &&
- (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
+ (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
false, false, SourceLocation()) ||
OldType->getResultType() != NewType->getResultType()))
return true;
-
+
// If the function is a class member, its signature includes the
// cv-qualifiers (if any) on the function itself.
//
@@ -365,7 +364,7 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
// can be overloaded.
CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
- if (OldMethod && NewMethod &&
+ if (OldMethod && NewMethod &&
!OldMethod->isStatic() && !NewMethod->isStatic() &&
OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers())
return true;
@@ -405,18 +404,25 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
/// permitted.
/// If @p ForceRValue, then overloading is performed as if From was an rvalue,
/// no matter its actual lvalueness.
+/// If @p UserCast, the implicit conversion is being done for a user-specified
+/// cast.
ImplicitConversionSequence
Sema::TryImplicitConversion(Expr* From, QualType ToType,
bool SuppressUserConversions,
- bool AllowExplicit, bool ForceRValue)
-{
+ bool AllowExplicit, bool ForceRValue,
+ bool InOverloadResolution,
+ bool UserCast) {
ImplicitConversionSequence ICS;
- if (IsStandardConversion(From, ToType, ICS.Standard))
+ OverloadCandidateSet Conversions;
+ OverloadingResult UserDefResult = OR_Success;
+ if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard))
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
else if (getLangOptions().CPlusPlus &&
- IsUserDefinedConversion(From, ToType, ICS.UserDefined,
+ (UserDefResult = IsUserDefinedConversion(From, ToType,
+ ICS.UserDefined,
+ Conversions,
!SuppressUserConversions, AllowExplicit,
- ForceRValue)) {
+ ForceRValue, UserCast)) == OR_Success) {
ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
// C++ [over.ics.user]p4:
// A conversion of an expression of class type to the same class
@@ -425,9 +431,9 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
// given Conversion rank, in spite of the fact that a copy
// constructor (i.e., a user-defined conversion function) is
// called for those cases.
- if (CXXConstructorDecl *Constructor
+ if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
- QualType FromCanon
+ QualType FromCanon
= Context.getCanonicalType(From->getType().getUnqualifiedType());
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
@@ -453,8 +459,15 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
if (SuppressUserConversions &&
ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion)
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
- } else
+ } else {
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ if (UserDefResult == OR_Ambiguous) {
+ for (OverloadCandidateSet::iterator Cand = Conversions.begin();
+ Cand != Conversions.end(); ++Cand)
+ if (Cand->Viable)
+ ICS.ConversionFunctionSet.push_back(Cand->Function);
+ }
+ }
return ICS;
}
@@ -467,10 +480,10 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
/// contain the standard conversion sequence required to perform this
/// conversion and this routine will return true. Otherwise, this
/// routine will return false and the value of SCS is unspecified.
-bool
-Sema::IsStandardConversion(Expr* From, QualType ToType,
- StandardConversionSequence &SCS)
-{
+bool
+Sema::IsStandardConversion(Expr* From, QualType ToType,
+ bool InOverloadResolution,
+ StandardConversionSequence &SCS) {
QualType FromType = From->getType();
// Standard conversions (C++ [conv])
@@ -481,23 +494,23 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
SCS.CopyConstructor = 0;
// There are no standard conversions for class types in C++, so
- // abort early. When overloading in C, however, we do permit
+ // abort early. When overloading in C, however, we do permit
if (FromType->isRecordType() || ToType->isRecordType()) {
if (getLangOptions().CPlusPlus)
return false;
- // When we're overloading in C, we allow, as standard conversions,
+ // When we're overloading in C, we allow, as standard conversions,
}
// The first conversion can be an lvalue-to-rvalue conversion,
// array-to-pointer conversion, or function-to-pointer conversion
// (C++ 4p1).
- // Lvalue-to-rvalue conversion (C++ 4.1):
+ // Lvalue-to-rvalue conversion (C++ 4.1):
// An lvalue (3.10) of a non-function, non-array type T can be
// converted to an rvalue.
Expr::isLvalueResult argIsLvalue = From->isLvalue(Context);
- if (argIsLvalue == Expr::LV_Valid &&
+ if (argIsLvalue == Expr::LV_Valid &&
!FromType->isFunctionType() && !FromType->isArrayType() &&
Context.getCanonicalType(FromType) != Context.OverloadTy) {
SCS.First = ICK_Lvalue_To_Rvalue;
@@ -509,9 +522,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// FIXME: Doesn't see through to qualifiers behind a typedef!
FromType = FromType.getUnqualifiedType();
- }
- // Array-to-pointer conversion (C++ 4.2)
- else if (FromType->isArrayType()) {
+ } else if (FromType->isArrayType()) {
+ // Array-to-pointer conversion (C++ 4.2)
SCS.First = ICK_Array_To_Pointer;
// An lvalue or rvalue of type "array of N T" or "array of unknown
@@ -532,19 +544,17 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
SCS.ToTypePtr = ToType.getAsOpaquePtr();
return true;
}
- }
- // Function-to-pointer conversion (C++ 4.3).
- else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) {
+ } else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) {
+ // Function-to-pointer conversion (C++ 4.3).
SCS.First = ICK_Function_To_Pointer;
// An lvalue of function type T can be converted to an rvalue of
// type "pointer to T." The result is a pointer to the
// function. (C++ 4.3p1).
FromType = Context.getPointerType(FromType);
- }
- // Address of overloaded function (C++ [over.over]).
- else if (FunctionDecl *Fn
+ } else if (FunctionDecl *Fn
= ResolveAddressOfOverloadedFunction(From, ToType, false)) {
+ // Address of overloaded function (C++ [over.over]).
SCS.First = ICK_Function_To_Pointer;
// We were able to resolve the address of the overloaded function,
@@ -566,9 +576,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
Context.getTypeDeclType(M->getParent()).getTypePtr());
} else
FromType = Context.getPointerType(FromType);
- }
- // We don't require any conversions for the first step.
- else {
+ } else {
+ // We don't require any conversions for the first step.
SCS.First = ICK_Identity;
}
@@ -583,79 +592,68 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// The unqualified versions of the types are the same: there's no
// conversion to do.
SCS.Second = ICK_Identity;
- }
- // Integral promotion (C++ 4.5).
- else if (IsIntegralPromotion(From, FromType, ToType)) {
+ } else if (IsIntegralPromotion(From, FromType, ToType)) {
+ // Integral promotion (C++ 4.5).
SCS.Second = ICK_Integral_Promotion;
FromType = ToType.getUnqualifiedType();
- }
- // Floating point promotion (C++ 4.6).
- else if (IsFloatingPointPromotion(FromType, ToType)) {
+ } else if (IsFloatingPointPromotion(FromType, ToType)) {
+ // Floating point promotion (C++ 4.6).
SCS.Second = ICK_Floating_Promotion;
FromType = ToType.getUnqualifiedType();
- }
- // Complex promotion (Clang extension)
- else if (IsComplexPromotion(FromType, ToType)) {
+ } else if (IsComplexPromotion(FromType, ToType)) {
+ // Complex promotion (Clang extension)
SCS.Second = ICK_Complex_Promotion;
FromType = ToType.getUnqualifiedType();
- }
- // Integral conversions (C++ 4.7).
- // FIXME: isIntegralType shouldn't be true for enums in C++.
- else if ((FromType->isIntegralType() || FromType->isEnumeralType()) &&
+ } else if ((FromType->isIntegralType() || FromType->isEnumeralType()) &&
(ToType->isIntegralType() && !ToType->isEnumeralType())) {
+ // Integral conversions (C++ 4.7).
+ // FIXME: isIntegralType shouldn't be true for enums in C++.
SCS.Second = ICK_Integral_Conversion;
FromType = ToType.getUnqualifiedType();
- }
- // Floating point conversions (C++ 4.8).
- else if (FromType->isFloatingType() && ToType->isFloatingType()) {
+ } else if (FromType->isFloatingType() && ToType->isFloatingType()) {
+ // Floating point conversions (C++ 4.8).
SCS.Second = ICK_Floating_Conversion;
FromType = ToType.getUnqualifiedType();
- }
- // Complex conversions (C99 6.3.1.6)
- else if (FromType->isComplexType() && ToType->isComplexType()) {
+ } else if (FromType->isComplexType() && ToType->isComplexType()) {
+ // Complex conversions (C99 6.3.1.6)
SCS.Second = ICK_Complex_Conversion;
FromType = ToType.getUnqualifiedType();
- }
- // Floating-integral conversions (C++ 4.9).
- // FIXME: isIntegralType shouldn't be true for enums in C++.
- else if ((FromType->isFloatingType() &&
- ToType->isIntegralType() && !ToType->isBooleanType() &&
- !ToType->isEnumeralType()) ||
- ((FromType->isIntegralType() || FromType->isEnumeralType()) &&
- ToType->isFloatingType())) {
+ } else if ((FromType->isFloatingType() &&
+ ToType->isIntegralType() && (!ToType->isBooleanType() &&
+ !ToType->isEnumeralType())) ||
+ ((FromType->isIntegralType() || FromType->isEnumeralType()) &&
+ ToType->isFloatingType())) {
+ // Floating-integral conversions (C++ 4.9).
+ // FIXME: isIntegralType shouldn't be true for enums in C++.
SCS.Second = ICK_Floating_Integral;
FromType = ToType.getUnqualifiedType();
- }
- // Complex-real conversions (C99 6.3.1.7)
- else if ((FromType->isComplexType() && ToType->isArithmeticType()) ||
- (ToType->isComplexType() && FromType->isArithmeticType())) {
+ } else if ((FromType->isComplexType() && ToType->isArithmeticType()) ||
+ (ToType->isComplexType() && FromType->isArithmeticType())) {
+ // Complex-real conversions (C99 6.3.1.7)
SCS.Second = ICK_Complex_Real;
FromType = ToType.getUnqualifiedType();
- }
- // Pointer conversions (C++ 4.10).
- else if (IsPointerConversion(From, FromType, ToType, FromType,
- IncompatibleObjC)) {
+ } else if (IsPointerConversion(From, FromType, ToType, InOverloadResolution,
+ FromType, IncompatibleObjC)) {
+ // Pointer conversions (C++ 4.10).
SCS.Second = ICK_Pointer_Conversion;
SCS.IncompatibleObjC = IncompatibleObjC;
- }
- // Pointer to member conversions (4.11).
- else if (IsMemberPointerConversion(From, FromType, ToType, FromType)) {
+ } else if (IsMemberPointerConversion(From, FromType, ToType,
+ InOverloadResolution, FromType)) {
+ // Pointer to member conversions (4.11).
SCS.Second = ICK_Pointer_Member;
- }
- // Boolean conversions (C++ 4.12).
- else if (ToType->isBooleanType() &&
- (FromType->isArithmeticType() ||
- FromType->isEnumeralType() ||
- FromType->isPointerType() ||
- FromType->isBlockPointerType() ||
- FromType->isMemberPointerType() ||
- FromType->isNullPtrType())) {
+ } else if (ToType->isBooleanType() &&
+ (FromType->isArithmeticType() ||
+ FromType->isEnumeralType() ||
+ FromType->isPointerType() ||
+ FromType->isBlockPointerType() ||
+ FromType->isMemberPointerType() ||
+ FromType->isNullPtrType())) {
+ // Boolean conversions (C++ 4.12).
SCS.Second = ICK_Boolean_Conversion;
FromType = Context.BoolTy;
- }
- // Compatible conversions (Clang extension for C function overloading)
- else if (!getLangOptions().CPlusPlus &&
- Context.typesAreCompatible(ToType, FromType)) {
+ } else if (!getLangOptions().CPlusPlus &&
+ Context.typesAreCompatible(ToType, FromType)) {
+ // Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
} else {
// No second conversion required.
@@ -674,12 +672,12 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// No conversion required
SCS.Third = ICK_Identity;
- // C++ [over.best.ics]p6:
+ // C++ [over.best.ics]p6:
// [...] Any difference in top-level cv-qualification is
// subsumed by the initialization itself and does not constitute
// a conversion. [...]
CanonFrom = Context.getCanonicalType(FromType);
- CanonTo = Context.getCanonicalType(ToType);
+ CanonTo = Context.getCanonicalType(ToType);
if (CanonFrom.getUnqualifiedType() == CanonTo.getUnqualifiedType() &&
CanonFrom.getCVRQualifiers() != CanonTo.getCVRQualifiers()) {
FromType = ToType;
@@ -700,9 +698,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
/// expression From (whose potentially-adjusted type is FromType) to
/// ToType is an integral promotion (C++ 4.5). If so, returns true and
/// sets PromotedType to the promoted type.
-bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
-{
- const BuiltinType *To = ToType->getAsBuiltinType();
+bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
+ const BuiltinType *To = ToType->getAs<BuiltinType>();
// All integers are built-in.
if (!To) {
return false;
@@ -718,7 +715,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
(FromType->isSignedIntegerType() ||
// We can promote any unsigned integer type whose size is
// less than int to an int.
- (!FromType->isSignedIntegerType() &&
+ (!FromType->isSignedIntegerType() &&
Context.getTypeSize(FromType) < Context.getTypeSize(ToType)))) {
return To->getKind() == BuiltinType::Int;
}
@@ -736,7 +733,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
// unsigned.
bool FromIsSigned;
uint64_t FromSize = Context.getTypeSize(FromType);
- if (const EnumType *FromEnumType = FromType->getAsEnumType()) {
+ if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) {
QualType UnderlyingType = FromEnumType->getDecl()->getIntegerType();
FromIsSigned = UnderlyingType->isSignedIntegerType();
} else {
@@ -746,15 +743,15 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
// The types we'll try to promote to, in the appropriate
// order. Try each of these types.
- QualType PromoteTypes[6] = {
- Context.IntTy, Context.UnsignedIntTy,
+ QualType PromoteTypes[6] = {
+ Context.IntTy, Context.UnsignedIntTy,
Context.LongTy, Context.UnsignedLongTy ,
Context.LongLongTy, Context.UnsignedLongLongTy
};
for (int Idx = 0; Idx < 6; ++Idx) {
uint64_t ToSize = Context.getTypeSize(PromoteTypes[Idx]);
if (FromSize < ToSize ||
- (FromSize == ToSize &&
+ (FromSize == ToSize &&
FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType())) {
// We found the type that we can promote to. If this is the
// type we wanted, we have a promotion. Otherwise, no
@@ -782,23 +779,23 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
MemberDecl->getBitWidth()->isIntegerConstantExpr(BitWidth, Context)) {
APSInt ToSize(BitWidth.getBitWidth(), BitWidth.isUnsigned());
ToSize = Context.getTypeSize(ToType);
-
+
// Are we promoting to an int from a bitfield that fits in an int?
if (BitWidth < ToSize ||
(FromType->isSignedIntegerType() && BitWidth <= ToSize)) {
return To->getKind() == BuiltinType::Int;
}
-
+
// Are we promoting to an unsigned int from an unsigned bitfield
// that fits into an unsigned int?
if (FromType->isUnsignedIntegerType() && BitWidth <= ToSize) {
return To->getKind() == BuiltinType::UInt;
}
-
+
return false;
}
}
-
+
// An rvalue of type bool can be converted to an rvalue of type int,
// with false becoming zero and true becoming one (C++ 4.5p4).
if (FromType->isBooleanType() && To->getKind() == BuiltinType::Int) {
@@ -811,12 +808,11 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
/// IsFloatingPointPromotion - Determines whether the conversion from
/// FromType to ToType is a floating point promotion (C++ 4.6). If so,
/// returns true and sets PromotedType to the promoted type.
-bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType)
-{
+bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) {
/// An rvalue of type float can be converted to an rvalue of type
/// double. (C++ 4.6p1).
- if (const BuiltinType *FromBuiltin = FromType->getAsBuiltinType())
- if (const BuiltinType *ToBuiltin = ToType->getAsBuiltinType()) {
+ if (const BuiltinType *FromBuiltin = FromType->getAs<BuiltinType>())
+ if (const BuiltinType *ToBuiltin = ToType->getAs<BuiltinType>()) {
if (FromBuiltin->getKind() == BuiltinType::Float &&
ToBuiltin->getKind() == BuiltinType::Double)
return true;
@@ -840,11 +836,11 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType)
/// where the conversion between the underlying real types is a
/// floating-point or integral promotion.
bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) {
- const ComplexType *FromComplex = FromType->getAsComplexType();
+ const ComplexType *FromComplex = FromType->getAs<ComplexType>();
if (!FromComplex)
return false;
- const ComplexType *ToComplex = ToType->getAsComplexType();
+ const ComplexType *ToComplex = ToType->getAs<ComplexType>();
if (!ToComplex)
return false;
@@ -859,18 +855,18 @@ bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) {
/// same type qualifiers as FromPtr has on its pointee type. ToType,
/// if non-empty, will be a pointer to ToType that may or may not have
/// the right set of qualifiers on its pointee.
-static QualType
-BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
+static QualType
+BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
QualType ToPointee, QualType ToType,
ASTContext &Context) {
QualType CanonFromPointee = Context.getCanonicalType(FromPtr->getPointeeType());
QualType CanonToPointee = Context.getCanonicalType(ToPointee);
- unsigned Quals = CanonFromPointee.getCVRQualifiers();
-
- // Exact qualifier match -> return the pointer type we're converting to.
- if (CanonToPointee.getCVRQualifiers() == Quals) {
+ Qualifiers Quals = CanonFromPointee.getQualifiers();
+
+ // Exact qualifier match -> return the pointer type we're converting to.
+ if (CanonToPointee.getQualifiers() == Quals) {
// ToType is exactly what we need. Return it.
- if (ToType.getTypePtr())
+ if (!ToType.isNull())
return ToType;
// Build a pointer to ToPointee. It has the right qualifiers
@@ -879,7 +875,22 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
}
// Just build a canonical type that has the right qualifiers.
- return Context.getPointerType(CanonToPointee.getQualifiedType(Quals));
+ return Context.getPointerType(
+ Context.getQualifiedType(CanonToPointee.getUnqualifiedType(), Quals));
+}
+
+static bool isNullPointerConstantForConversion(Expr *Expr,
+ bool InOverloadResolution,
+ ASTContext &Context) {
+ // Handle value-dependent integral null pointer constants correctly.
+ // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#903
+ if (Expr->isValueDependent() && !Expr->isTypeDependent() &&
+ Expr->getType()->isIntegralType())
+ return !InOverloadResolution;
+
+ return Expr->isNullPointerConstant(Context,
+ InOverloadResolution? Expr::NPC_ValueDependentIsNotNull
+ : Expr::NPC_ValueDependentIsNull);
}
/// IsPointerConversion - Determines whether the conversion of the
@@ -899,52 +910,54 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
/// set if the conversion is an allowed Objective-C conversion that
/// should result in a warning.
bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
+ bool InOverloadResolution,
QualType& ConvertedType,
- bool &IncompatibleObjC)
-{
+ bool &IncompatibleObjC) {
IncompatibleObjC = false;
if (isObjCPointerConversion(FromType, ToType, ConvertedType, IncompatibleObjC))
return true;
- // Conversion from a null pointer constant to any Objective-C pointer type.
- if (Context.isObjCObjectPointerType(ToType) &&
- From->isNullPointerConstant(Context)) {
+ // Conversion from a null pointer constant to any Objective-C pointer type.
+ if (ToType->isObjCObjectPointerType() &&
+ isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
// Blocks: Block pointers can be converted to void*.
if (FromType->isBlockPointerType() && ToType->isPointerType() &&
- ToType->getAsPointerType()->getPointeeType()->isVoidType()) {
+ ToType->getAs<PointerType>()->getPointeeType()->isVoidType()) {
ConvertedType = ToType;
return true;
}
// Blocks: A null pointer constant can be converted to a block
// pointer type.
- if (ToType->isBlockPointerType() && From->isNullPointerConstant(Context)) {
+ if (ToType->isBlockPointerType() &&
+ isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
// If the left-hand-side is nullptr_t, the right side can be a null
// pointer constant.
- if (ToType->isNullPtrType() && From->isNullPointerConstant(Context)) {
+ if (ToType->isNullPtrType() &&
+ isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
- const PointerType* ToTypePtr = ToType->getAsPointerType();
+ const PointerType* ToTypePtr = ToType->getAs<PointerType>();
if (!ToTypePtr)
return false;
// A null pointer constant can be converted to a pointer type (C++ 4.10p1).
- if (From->isNullPointerConstant(Context)) {
+ if (isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
// Beyond this point, both types need to be pointers.
- const PointerType *FromTypePtr = FromType->getAsPointerType();
+ const PointerType *FromTypePtr = FromType->getAs<PointerType>();
if (!FromTypePtr)
return false;
@@ -955,7 +968,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// can be converted to an rvalue of type "pointer to cv void" (C++
// 4.10p2).
if (FromPointeeType->isObjectType() && ToPointeeType->isVoidType()) {
- ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
ToType, Context);
return true;
@@ -963,16 +976,16 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// When we're overloading in C, we allow a special kind of pointer
// conversion for compatible-but-not-identical pointee types.
- if (!getLangOptions().CPlusPlus &&
+ if (!getLangOptions().CPlusPlus &&
Context.typesAreCompatible(FromPointeeType, ToPointeeType)) {
- ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
- ToType, Context);
+ ToType, Context);
return true;
}
// C++ [conv.ptr]p3:
- //
+ //
// An rvalue of type "pointer to cv D," where D is a class type,
// can be converted to an rvalue of type "pointer to cv B," where
// B is a base class (clause 10) of D. If B is an inaccessible
@@ -987,7 +1000,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
if (getLangOptions().CPlusPlus &&
FromPointeeType->isRecordType() && ToPointeeType->isRecordType() &&
IsDerivedFrom(FromPointeeType, ToPointeeType)) {
- ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
ToType, Context);
return true;
@@ -999,83 +1012,65 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
/// isObjCPointerConversion - Determines whether this is an
/// Objective-C pointer conversion. Subroutine of IsPointerConversion,
/// with the same arguments and return values.
-bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
+bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType,
bool &IncompatibleObjC) {
if (!getLangOptions().ObjC1)
return false;
- // Conversions with Objective-C's id<...>.
- if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) &&
- ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
- ConvertedType = ToType;
- return true;
- }
+ // First, we handle all conversions on ObjC object pointer types.
+ const ObjCObjectPointerType* ToObjCPtr = ToType->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *FromObjCPtr =
+ FromType->getAs<ObjCObjectPointerType>();
+
+ if (ToObjCPtr && FromObjCPtr) {
+ // Objective C++: We're able to convert between "id" or "Class" and a
+ // pointer to any interface (in both directions).
+ if (ToObjCPtr->isObjCBuiltinType() && FromObjCPtr->isObjCBuiltinType()) {
+ ConvertedType = ToType;
+ return true;
+ }
+ // Conversions with Objective-C's id<...>.
+ if ((FromObjCPtr->isObjCQualifiedIdType() ||
+ ToObjCPtr->isObjCQualifiedIdType()) &&
+ Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType,
+ /*compare=*/false)) {
+ ConvertedType = ToType;
+ return true;
+ }
+ // Objective C++: We're able to convert from a pointer to an
+ // interface to a pointer to a different interface.
+ if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) {
+ ConvertedType = ToType;
+ return true;
+ }
- // Beyond this point, both types need to be pointers or block pointers.
+ if (Context.canAssignObjCInterfaces(FromObjCPtr, ToObjCPtr)) {
+ // Okay: this is some kind of implicit downcast of Objective-C
+ // interfaces, which is permitted. However, we're going to
+ // complain about it.
+ IncompatibleObjC = true;
+ ConvertedType = FromType;
+ return true;
+ }
+ }
+ // Beyond this point, both types need to be C pointers or block pointers.
QualType ToPointeeType;
- const PointerType* ToTypePtr = ToType->getAsPointerType();
- if (ToTypePtr)
- ToPointeeType = ToTypePtr->getPointeeType();
- else if (const BlockPointerType *ToBlockPtr = ToType->getAsBlockPointerType())
+ if (const PointerType *ToCPtr = ToType->getAs<PointerType>())
+ ToPointeeType = ToCPtr->getPointeeType();
+ else if (const BlockPointerType *ToBlockPtr = ToType->getAs<BlockPointerType>())
ToPointeeType = ToBlockPtr->getPointeeType();
else
return false;
QualType FromPointeeType;
- const PointerType *FromTypePtr = FromType->getAsPointerType();
- if (FromTypePtr)
- FromPointeeType = FromTypePtr->getPointeeType();
- else if (const BlockPointerType *FromBlockPtr
- = FromType->getAsBlockPointerType())
+ if (const PointerType *FromCPtr = FromType->getAs<PointerType>())
+ FromPointeeType = FromCPtr->getPointeeType();
+ else if (const BlockPointerType *FromBlockPtr = FromType->getAs<BlockPointerType>())
FromPointeeType = FromBlockPtr->getPointeeType();
else
return false;
- // Objective C++: We're able to convert from a pointer to an
- // interface to a pointer to a different interface.
- const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType();
- const ObjCInterfaceType* ToIface = ToPointeeType->getAsObjCInterfaceType();
- if (FromIface && ToIface &&
- Context.canAssignObjCInterfaces(ToIface, FromIface)) {
- ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
- ToPointeeType,
- ToType, Context);
- return true;
- }
-
- if (FromIface && ToIface &&
- Context.canAssignObjCInterfaces(FromIface, ToIface)) {
- // Okay: this is some kind of implicit downcast of Objective-C
- // interfaces, which is permitted. However, we're going to
- // complain about it.
- IncompatibleObjC = true;
- ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
- ToPointeeType,
- ToType, Context);
- return true;
- }
-
- // Objective C++: We're able to convert between "id" and a pointer
- // to any interface (in both directions).
- if ((FromIface && Context.isObjCIdStructType(ToPointeeType))
- || (ToIface && Context.isObjCIdStructType(FromPointeeType))) {
- ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
- ToPointeeType,
- ToType, Context);
- return true;
- }
-
- // Objective C++: Allow conversions between the Objective-C "id" and
- // "Class", in either direction.
- if ((Context.isObjCIdStructType(FromPointeeType) &&
- Context.isObjCClassStructType(ToPointeeType)) ||
- (Context.isObjCClassStructType(FromPointeeType) &&
- Context.isObjCIdStructType(ToPointeeType))) {
- ConvertedType = ToType;
- return true;
- }
-
// If we have pointers to pointers, recursively check whether this
// is an Objective-C conversion.
if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() &&
@@ -1086,15 +1081,14 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ConvertedType = ToType;
return true;
}
-
// If we have pointers to functions or blocks, check whether the only
// differences in the argument and result types are in Objective-C
// pointer conversions. If so, we permit the conversion (but
// complain about it).
- const FunctionProtoType *FromFunctionType
- = FromPointeeType->getAsFunctionProtoType();
+ const FunctionProtoType *FromFunctionType
+ = FromPointeeType->getAs<FunctionProtoType>();
const FunctionProtoType *ToFunctionType
- = ToPointeeType->getAsFunctionProtoType();
+ = ToPointeeType->getAs<FunctionProtoType>();
if (FromFunctionType && ToFunctionType) {
// If the function types are exactly the same, this isn't an
// Objective-C pointer conversion.
@@ -1122,7 +1116,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
// Function types are too different. Abort.
return false;
}
-
+
// Check argument types.
for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
ArgIdx != NumArgs; ++ArgIdx) {
@@ -1155,37 +1149,43 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
/// CheckPointerConversion - Check the pointer conversion from the
/// expression From to the type ToType. This routine checks for
-/// ambiguous (FIXME: or inaccessible) derived-to-base pointer
+/// ambiguous or inaccessible derived-to-base pointer
/// conversions for which IsPointerConversion has already returned
/// true. It returns true and produces a diagnostic if there was an
/// error, or returns false otherwise.
-bool Sema::CheckPointerConversion(Expr *From, QualType ToType) {
+bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
+ CastExpr::CastKind &Kind) {
QualType FromType = From->getType();
- if (const PointerType *FromPtrType = FromType->getAsPointerType())
- if (const PointerType *ToPtrType = ToType->getAsPointerType()) {
+ if (const PointerType *FromPtrType = FromType->getAs<PointerType>())
+ if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) {
QualType FromPointeeType = FromPtrType->getPointeeType(),
ToPointeeType = ToPtrType->getPointeeType();
- // Objective-C++ conversions are always okay.
- // FIXME: We should have a different class of conversions for the
- // Objective-C++ implicit conversions.
- if (Context.isObjCIdStructType(FromPointeeType) ||
- Context.isObjCIdStructType(ToPointeeType) ||
- Context.isObjCClassStructType(FromPointeeType) ||
- Context.isObjCClassStructType(ToPointeeType))
- return false;
-
if (FromPointeeType->isRecordType() &&
ToPointeeType->isRecordType()) {
// We must have a derived-to-base conversion. Check an
// ambiguous or inaccessible conversion.
- return CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
- From->getExprLoc(),
- From->getSourceRange());
+ if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
+ From->getExprLoc(),
+ From->getSourceRange()))
+ return true;
+
+ // The conversion was successful.
+ Kind = CastExpr::CK_DerivedToBase;
}
}
+ if (const ObjCObjectPointerType *FromPtrType =
+ FromType->getAs<ObjCObjectPointerType>())
+ if (const ObjCObjectPointerType *ToPtrType =
+ ToType->getAs<ObjCObjectPointerType>()) {
+ // Objective-C++ conversions are always okay.
+ // FIXME: We should have a different class of conversions for the
+ // Objective-C++ implicit conversions.
+ if (FromPtrType->isObjCBuiltinType() || ToPtrType->isObjCBuiltinType())
+ return false;
+ }
return false;
}
@@ -1195,20 +1195,23 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType) {
/// If so, returns true and places the converted type (that might differ from
/// ToType in its cv-qualifiers at some level) into ConvertedType.
bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
- QualType ToType, QualType &ConvertedType)
-{
- const MemberPointerType *ToTypePtr = ToType->getAsMemberPointerType();
+ QualType ToType,
+ bool InOverloadResolution,
+ QualType &ConvertedType) {
+ const MemberPointerType *ToTypePtr = ToType->getAs<MemberPointerType>();
if (!ToTypePtr)
return false;
// A null pointer constant can be converted to a member pointer (C++ 4.11p1)
- if (From->isNullPointerConstant(Context)) {
+ if (From->isNullPointerConstant(Context,
+ InOverloadResolution? Expr::NPC_ValueDependentIsNotNull
+ : Expr::NPC_ValueDependentIsNull)) {
ConvertedType = ToType;
return true;
}
// Otherwise, both types have to be member pointers.
- const MemberPointerType *FromTypePtr = FromType->getAsMemberPointerType();
+ const MemberPointerType *FromTypePtr = FromType->getAs<MemberPointerType>();
if (!FromTypePtr)
return false;
@@ -1233,13 +1236,20 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
/// for which IsMemberPointerConversion has already returned true. It returns
/// true and produces a diagnostic if there was an error, or returns false
/// otherwise.
-bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) {
+bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
+ CastExpr::CastKind &Kind) {
QualType FromType = From->getType();
- const MemberPointerType *FromPtrType = FromType->getAsMemberPointerType();
- if (!FromPtrType)
+ const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
+ if (!FromPtrType) {
+ // This must be a null pointer to member pointer conversion
+ assert(From->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull) &&
+ "Expr must be null pointer constant!");
+ Kind = CastExpr::CK_NullToMemberPointer;
return false;
+ }
- const MemberPointerType *ToPtrType = ToType->getAsMemberPointerType();
+ const MemberPointerType *ToPtrType = ToType->getAs<MemberPointerType>();
assert(ToPtrType && "No member pointer cast has a target type "
"that is not a member pointer.");
@@ -1250,8 +1260,8 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) {
assert(FromClass->isRecordType() && "Pointer into non-class.");
assert(ToClass->isRecordType() && "Pointer into non-class.");
- BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
- /*DetectVirtual=*/true);
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ /*DetectVirtual=*/true);
bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths);
assert(DerivationOkay &&
"Should not have been called if derivation isn't OK.");
@@ -1279,15 +1289,16 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) {
return true;
}
+ // Must be a base to derived member conversion.
+ Kind = CastExpr::CK_BaseToDerivedMemberPointer;
return false;
}
/// IsQualificationConversion - Determines whether the conversion from
/// an rvalue of type FromType to ToType is a qualification conversion
/// (C++ 4.4).
-bool
-Sema::IsQualificationConversion(QualType FromType, QualType ToType)
-{
+bool
+Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
FromType = Context.getCanonicalType(FromType);
ToType = Context.getCanonicalType(ToType);
@@ -1314,16 +1325,16 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
// 2,j, and similarly for volatile.
if (!ToType.isAtLeastAsQualifiedAs(FromType))
return false;
-
+
// -- if the cv 1,j and cv 2,j are different, then const is in
// every cv for 0 < k < j.
if (FromType.getCVRQualifiers() != ToType.getCVRQualifiers()
&& !PreviousToQualsIncludeConst)
return false;
-
+
// Keep track of whether all prior cv-qualifiers in the "to" type
// include const.
- PreviousToQualsIncludeConst
+ PreviousToQualsIncludeConst
= PreviousToQualsIncludeConst && ToType.isConstQualified();
}
@@ -1336,6 +1347,18 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
FromType.getUnqualifiedType() == ToType.getUnqualifiedType();
}
+/// \brief Given a function template or function, extract the function template
+/// declaration (if any) and the underlying function declaration.
+template<typename T>
+static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function,
+ FunctionTemplateDecl *&FunctionTemplate) {
+ FunctionTemplate = dyn_cast<FunctionTemplateDecl>(Orig);
+ if (FunctionTemplate)
+ Function = cast<T>(FunctionTemplate->getTemplatedDecl());
+ else
+ Function = cast<T>(Orig);
+}
+
/// Determines whether there is a user-defined conversion sequence
/// (C++ [over.ics.user]) that converts expression From to the type
/// ToType. If such a conversion exists, User will contain the
@@ -1353,14 +1376,17 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
///
/// \param ForceRValue true if the expression should be treated as an rvalue
/// for overload resolution.
-bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
+/// \param UserCast true if looking for user defined conversion for a static
+/// cast.
+Sema::OverloadingResult Sema::IsUserDefinedConversion(
+ Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
+ OverloadCandidateSet& CandidateSet,
bool AllowConversionFunctions,
- bool AllowExplicit, bool ForceRValue)
-{
- OverloadCandidateSet CandidateSet;
- if (const RecordType *ToRecordType = ToType->getAsRecordType()) {
- if (CXXRecordDecl *ToRecordDecl
+ bool AllowExplicit, bool ForceRValue,
+ bool UserCast) {
+ if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) {
+ if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
// C++ [over.match.ctor]p1:
// When objects of class type are direct-initialized (8.5), or
@@ -1370,37 +1396,72 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
// functions are all the converting constructors (12.3.1) of
// that class. The argument list is the expression-list within
// the parentheses of the initializer.
- DeclarationName ConstructorName
+ DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ToType).getUnqualifiedType());
DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd)
+ for (llvm::tie(Con, ConEnd)
= ToRecordDecl->lookup(ConstructorName);
Con != ConEnd; ++Con) {
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
- if (Constructor->isConvertingConstructor())
- AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
- /*SuppressUserConversions=*/true, ForceRValue);
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl
+ = dyn_cast<FunctionTemplateDecl>(*Con);
+ if (ConstructorTmpl)
+ Constructor
+ = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
+ else
+ Constructor = cast<CXXConstructorDecl>(*Con);
+
+ if (!Constructor->isInvalidDecl() &&
+ Constructor->isConvertingConstructor(AllowExplicit)) {
+ if (ConstructorTmpl)
+ AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From,
+ 1, CandidateSet,
+ /*SuppressUserConversions=*/!UserCast,
+ ForceRValue);
+ else
+ // Allow one user-defined conversion when user specifies a
+ // From->ToType conversion via an static cast (c-style, etc).
+ AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
+ /*SuppressUserConversions=*/!UserCast,
+ ForceRValue);
+ }
}
}
}
if (!AllowConversionFunctions) {
// Don't allow any conversion functions to enter the overload set.
- } else if (const RecordType *FromRecordType
- = From->getType()->getAsRecordType()) {
- if (CXXRecordDecl *FromRecordDecl
- = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
+ } else if (RequireCompleteType(From->getLocStart(), From->getType(),
+ PDiag(0)
+ << From->getSourceRange())) {
+ // No conversion functions from incomplete types.
+ } else if (const RecordType *FromRecordType
+ = From->getType()->getAs<RecordType>()) {
+ if (CXXRecordDecl *FromRecordDecl
+ = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
// Add all of the conversion functions as candidates.
- // FIXME: Look for conversions in base classes!
- OverloadedFunctionDecl *Conversions
- = FromRecordDecl->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator Func
+ OverloadedFunctionDecl *Conversions
+ = FromRecordDecl->getVisibleConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
- if (AllowExplicit || !Conv->isExplicit())
- AddConversionCandidate(Conv, From, ToType, CandidateSet);
+ CXXConversionDecl *Conv;
+ FunctionTemplateDecl *ConvTemplate;
+ GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+ if (ConvTemplate)
+ Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = dyn_cast<CXXConversionDecl>(*Func);
+
+ if (AllowExplicit || !Conv->isExplicit()) {
+ if (ConvTemplate)
+ AddTemplateConversionCandidate(ConvTemplate, From, ToType,
+ CandidateSet);
+ else
+ AddConversionCandidate(Conv, From, ToType, CandidateSet);
+ }
}
}
}
@@ -1409,7 +1470,7 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
switch (BestViableFunction(CandidateSet, From->getLocStart(), Best)) {
case OR_Success:
// Record the standard conversion we used and the conversion function.
- if (CXXConstructorDecl *Constructor
+ if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Best->Function)) {
// C++ [over.ics.user]p1:
// If the user-defined conversion is specified by a
@@ -1422,10 +1483,10 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
User.Before = Best->Conversions[0].Standard;
User.ConversionFunction = Constructor;
User.After.setAsIdentityConversion();
- User.After.FromTypePtr
- = ThisType->getAsPointerType()->getPointeeType().getAsOpaquePtr();
+ User.After.FromTypePtr
+ = ThisType->getAs<PointerType>()->getPointeeType().getAsOpaquePtr();
User.After.ToTypePtr = ToType.getAsOpaquePtr();
- return true;
+ return OR_Success;
} else if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
// C++ [over.ics.user]p1:
@@ -1436,8 +1497,8 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
// implicit object parameter of the conversion function.
User.Before = Best->Conversions[0].Standard;
User.ConversionFunction = Conversion;
-
- // C++ [over.ics.user]p2:
+
+ // C++ [over.ics.user]p2:
// The second standard conversion sequence converts the
// result of the user-defined conversion to the target type
// for the sequence. Since an implicit conversion sequence
@@ -1447,30 +1508,45 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
// user-defined conversion sequence (see 13.3.3 and
// 13.3.3.1).
User.After = Best->FinalConversion;
- return true;
+ return OR_Success;
} else {
assert(false && "Not a constructor or conversion function?");
- return false;
+ return OR_No_Viable_Function;
}
-
+
case OR_No_Viable_Function:
+ return OR_No_Viable_Function;
case OR_Deleted:
// No conversion here! We're done.
- return false;
+ return OR_Deleted;
case OR_Ambiguous:
- // FIXME: See C++ [over.best.ics]p10 for the handling of
- // ambiguous conversion sequences.
- return false;
+ return OR_Ambiguous;
}
- return false;
+ return OR_No_Viable_Function;
+}
+
+bool
+Sema::DiagnoseAmbiguousUserDefinedConversion(Expr *From, QualType ToType) {
+ ImplicitConversionSequence ICS;
+ OverloadCandidateSet CandidateSet;
+ OverloadingResult OvResult =
+ IsUserDefinedConversion(From, ToType, ICS.UserDefined,
+ CandidateSet, true, false, false);
+ if (OvResult != OR_Ambiguous)
+ return false;
+ Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_ambiguous_condition)
+ << From->getType() << ToType << From->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ return true;
}
/// CompareImplicitConversionSequences - Compare two implicit
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2).
-ImplicitConversionSequence::CompareKind
+ImplicitConversionSequence::CompareKind
Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
const ImplicitConversionSequence& ICS2)
{
@@ -1482,7 +1558,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// -- a user-defined conversion sequence (13.3.3.1.2) is a better
// conversion sequence than an ellipsis conversion sequence
// (13.3.3.1.3).
- //
+ //
if (ICS1.ConversionKind < ICS2.ConversionKind)
return ImplicitConversionSequence::Better;
else if (ICS2.ConversionKind < ICS1.ConversionKind)
@@ -1493,7 +1569,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// following rules apply: (C++ 13.3.3.2p3):
if (ICS1.ConversionKind == ImplicitConversionSequence::StandardConversion)
return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard);
- else if (ICS1.ConversionKind ==
+ else if (ICS1.ConversionKind ==
ImplicitConversionSequence::UserDefinedConversion) {
// User-defined conversion sequence U1 is a better conversion
// sequence than another user-defined conversion sequence U2 if
@@ -1501,7 +1577,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// constructor and if the second standard conversion sequence of
// U1 is better than the second standard conversion sequence of
// U2 (C++ 13.3.3.2p3).
- if (ICS1.UserDefined.ConversionFunction ==
+ if (ICS1.UserDefined.ConversionFunction ==
ICS2.UserDefined.ConversionFunction)
return CompareStandardConversionSequences(ICS1.UserDefined.After,
ICS2.UserDefined.After);
@@ -1513,7 +1589,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
/// CompareStandardConversionSequences - Compare two standard
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2p3).
-ImplicitConversionSequence::CompareKind
+ImplicitConversionSequence::CompareKind
Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2)
{
@@ -1530,13 +1606,13 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
;
else if ((SCS1.Second == ICK_Identity && SCS1.Third == SCS2.Third) ||
(SCS1.Third == ICK_Identity && SCS1.Second == SCS2.Second) ||
- (SCS1.Second == ICK_Identity &&
+ (SCS1.Second == ICK_Identity &&
SCS1.Third == ICK_Identity))
// SCS1 is a proper subsequence of SCS2.
return ImplicitConversionSequence::Better;
else if ((SCS2.Second == ICK_Identity && SCS2.Third == SCS1.Third) ||
(SCS2.Third == ICK_Identity && SCS2.Second == SCS1.Second) ||
- (SCS2.Second == ICK_Identity &&
+ (SCS2.Second == ICK_Identity &&
SCS2.Third == ICK_Identity))
// SCS2 is a proper subsequence of SCS1.
return ImplicitConversionSequence::Worse;
@@ -1553,7 +1629,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// (C++ 13.3.3.2p4): Two conversion sequences with the same rank
// are indistinguishable unless one of the following rules
// applies:
-
+
// A conversion that is not a conversion of a pointer, or
// pointer to member, to bool is better than another conversion
// that is such a conversion.
@@ -1568,9 +1644,9 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// conversion of B* to A* is better than conversion of B* to
// void*, and conversion of A* to void* is better than conversion
// of B* to void*.
- bool SCS1ConvertsToVoid
+ bool SCS1ConvertsToVoid
= SCS1.isPointerConversionToVoidPointer(Context);
- bool SCS2ConvertsToVoid
+ bool SCS2ConvertsToVoid
= SCS2.isPointerConversionToVoidPointer(Context);
if (SCS1ConvertsToVoid != SCS2ConvertsToVoid) {
// Exactly one of the conversion sequences is a conversion to
@@ -1597,10 +1673,10 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
if (SCS2.First == ICK_Array_To_Pointer)
FromType2 = Context.getArrayDecayedType(FromType2);
- QualType FromPointee1
- = FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee1
+ = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
QualType FromPointee2
- = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
if (IsDerivedFrom(FromPointee2, FromPointee1))
return ImplicitConversionSequence::Better;
@@ -1609,8 +1685,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// Objective-C++: If one interface is more specific than the
// other, it is the better one.
- const ObjCInterfaceType* FromIface1 = FromPointee1->getAsObjCInterfaceType();
- const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType();
+ const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>();
+ const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>();
if (FromIface1 && FromIface1) {
if (Context.canAssignObjCInterfaces(FromIface2, FromIface1))
return ImplicitConversionSequence::Better;
@@ -1621,7 +1697,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// Compare based on qualification conversions (C++ 13.3.3.2p3,
// bullet 3).
- if (ImplicitConversionSequence::CompareKind QualCK
+ if (ImplicitConversionSequence::CompareKind QualCK
= CompareQualificationConversions(SCS1, SCS2))
return QualCK;
@@ -1661,11 +1737,10 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
/// CompareQualificationConversions - Compares two standard conversion
/// sequences to determine whether they can be ranked based on their
-/// qualification conversions (C++ 13.3.3.2p3 bullet 3).
-ImplicitConversionSequence::CompareKind
+/// qualification conversions (C++ 13.3.3.2p3 bullet 3).
+ImplicitConversionSequence::CompareKind
Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
- const StandardConversionSequence& SCS2)
-{
+ const StandardConversionSequence& SCS2) {
// C++ 13.3.3.2p3:
// -- S1 and S2 differ only in their qualification conversion and
// yield similar types T1 and T2 (C++ 4.4), respectively, and the
@@ -1688,7 +1763,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
if (T1.getUnqualifiedType() == T2.getUnqualifiedType())
return ImplicitConversionSequence::Indistinguishable;
- ImplicitConversionSequence::CompareKind Result
+ ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
while (UnwrapSimilarPointerTypes(T1, T2)) {
// Within each iteration of the loop, we check the qualifiers to
@@ -1709,7 +1784,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
// Neither has qualifiers that are a subset of the other's
// qualifiers.
return ImplicitConversionSequence::Indistinguishable;
-
+
Result = ImplicitConversionSequence::Better;
} else if (T1.isMoreQualifiedThan(T2)) {
// T2 has fewer qualifiers, so it could be the better sequence.
@@ -1717,7 +1792,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
// Neither has qualifiers that are a subset of the other's
// qualifiers.
return ImplicitConversionSequence::Indistinguishable;
-
+
Result = ImplicitConversionSequence::Worse;
} else {
// Qualifiers are disjoint.
@@ -1784,24 +1859,24 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
// interfaces.
// Compare based on pointer conversions.
- if (SCS1.Second == ICK_Pointer_Conversion &&
+ if (SCS1.Second == ICK_Pointer_Conversion &&
SCS2.Second == ICK_Pointer_Conversion &&
/*FIXME: Remove if Objective-C id conversions get their own rank*/
FromType1->isPointerType() && FromType2->isPointerType() &&
ToType1->isPointerType() && ToType2->isPointerType()) {
- QualType FromPointee1
- = FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType();
- QualType ToPointee1
- = ToType1->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee1
+ = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType ToPointee1
+ = ToType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
QualType FromPointee2
- = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
QualType ToPointee2
- = ToType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ = ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- const ObjCInterfaceType* FromIface1 = FromPointee1->getAsObjCInterfaceType();
- const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType();
- const ObjCInterfaceType* ToIface1 = ToPointee1->getAsObjCInterfaceType();
- const ObjCInterfaceType* ToIface2 = ToPointee2->getAsObjCInterfaceType();
+ const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>();
+ const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>();
+ const ObjCInterfaceType* ToIface1 = ToPointee1->getAs<ObjCInterfaceType>();
+ const ObjCInterfaceType* ToIface2 = ToPointee2->getAs<ObjCInterfaceType>();
// -- conversion of C* to B* is better than conversion of C* to A*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
@@ -1824,7 +1899,7 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
-
+
if (FromIface1 && FromIface2) {
if (Context.canAssignObjCInterfaces(FromIface1, FromIface2))
return ImplicitConversionSequence::Better;
@@ -1898,17 +1973,25 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
/// a parameter of this type). If @p SuppressUserConversions, then we
/// do not permit any user-defined conversion sequences. If @p ForceRValue,
/// then we treat @p From as an rvalue, even if it is an lvalue.
-ImplicitConversionSequence
-Sema::TryCopyInitialization(Expr *From, QualType ToType,
- bool SuppressUserConversions, bool ForceRValue) {
+ImplicitConversionSequence
+Sema::TryCopyInitialization(Expr *From, QualType ToType,
+ bool SuppressUserConversions, bool ForceRValue,
+ bool InOverloadResolution) {
if (ToType->isReferenceType()) {
ImplicitConversionSequence ICS;
- CheckReferenceInit(From, ToType, &ICS, SuppressUserConversions,
- /*AllowExplicit=*/false, ForceRValue);
+ CheckReferenceInit(From, ToType,
+ /*FIXME:*/From->getLocStart(),
+ SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ ForceRValue,
+ &ICS);
return ICS;
} else {
- return TryImplicitConversion(From, ToType, SuppressUserConversions,
- ForceRValue);
+ return TryImplicitConversion(From, ToType,
+ SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ ForceRValue,
+ InOverloadResolution);
}
}
@@ -1917,32 +2000,37 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType,
/// an error, returns false if the initialization succeeded. Elidable should
/// be true when the copy may be elided (C++ 12.8p15). Overload resolution works
/// differently in C++0x for this case.
-bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
+bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
const char* Flavor, bool Elidable) {
if (!getLangOptions().CPlusPlus) {
// In C, argument passing is the same as performing an assignment.
QualType FromType = From->getType();
-
+
AssignConvertType ConvTy =
CheckSingleAssignmentConstraints(ToType, From);
if (ConvTy != Compatible &&
CheckTransparentUnionArgumentConstraints(ToType, From) == Compatible)
ConvTy = Compatible;
-
+
return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType,
FromType, From, Flavor);
}
if (ToType->isReferenceType())
- return CheckReferenceInit(From, ToType);
+ return CheckReferenceInit(From, ToType,
+ /*FIXME:*/From->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false);
if (!PerformImplicitConversion(From, ToType, Flavor,
/*AllowExplicit=*/false, Elidable))
return false;
-
- return Diag(From->getSourceRange().getBegin(),
- diag::err_typecheck_convert_incompatible)
- << ToType << From->getType() << Flavor << From->getSourceRange();
+ if (!DiagnoseAmbiguousUserDefinedConversion(From, ToType))
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_incompatible)
+ << ToType << From->getType() << Flavor << From->getSourceRange();
+ return true;
}
/// TryObjectArgumentInitialization - Try to initialize the object
@@ -1951,8 +2039,8 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
ImplicitConversionSequence
Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
QualType ClassType = Context.getTypeDeclType(Method->getParent());
- unsigned MethodQuals = Method->getTypeQualifiers();
- QualType ImplicitParamType = ClassType.getQualifiedType(MethodQuals);
+ QualType ImplicitParamType
+ = Context.getCVRQualifiedType(ClassType, Method->getTypeQualifiers());
// Set up the conversion sequence as a "bad" conversion, to allow us
// to exit early.
@@ -1962,7 +2050,7 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
// We need to have an object of class type.
QualType FromType = From->getType();
- if (const PointerType *PT = FromType->getAsPointerType())
+ if (const PointerType *PT = FromType->getAs<PointerType>())
FromType = PT->getPointeeType();
assert(FromType->isRecordType());
@@ -1971,7 +2059,7 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
// where X is the class of which the function is a member
// (C++ [over.match.funcs]p4). However, when finding an implicit
// conversion sequence for the argument, we are not allowed to
- // create temporaries or perform user-defined conversions
+ // create temporaries or perform user-defined conversions
// (C++ [over.match.funcs]p5). We perform a simplified version of
// reference binding here, that allows class rvalues to bind to
// non-constant references.
@@ -2009,10 +2097,10 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
bool
Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
QualType FromRecordType, DestType;
- QualType ImplicitParamRecordType =
- Method->getThisType(Context)->getAsPointerType()->getPointeeType();
-
- if (const PointerType *PT = From->getType()->getAsPointerType()) {
+ QualType ImplicitParamRecordType =
+ Method->getThisType(Context)->getAs<PointerType>()->getPointeeType();
+
+ if (const PointerType *PT = From->getType()->getAs<PointerType>()) {
FromRecordType = PT->getPointeeType();
DestType = Method->getThisType(Context);
} else {
@@ -2020,13 +2108,13 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
DestType = ImplicitParamRecordType;
}
- ImplicitConversionSequence ICS
+ ImplicitConversionSequence ICS
= TryObjectArgumentInitialization(From, Method);
if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
return Diag(From->getSourceRange().getBegin(),
diag::err_implicit_object_parameter_init)
<< ImplicitParamRecordType << FromRecordType << From->getSourceRange();
-
+
if (ICS.Standard.Second == ICK_Derived_To_Base &&
CheckDerivedToBaseConversion(FromRecordType,
ImplicitParamRecordType,
@@ -2034,14 +2122,20 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
From->getSourceRange()))
return true;
- ImpCastExprToType(From, DestType, /*isLvalue=*/true);
+ ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
+ /*isLvalue=*/true);
return false;
}
/// TryContextuallyConvertToBool - Attempt to contextually convert the
/// expression From to bool (C++0x [conv]p3).
ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
- return TryImplicitConversion(From, Context.BoolTy, false, true);
+ return TryImplicitConversion(From, Context.BoolTy,
+ // FIXME: Are these flags correct?
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/true,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
/// PerformContextuallyConvertToBool - Perform a contextual conversion
@@ -2050,10 +2144,12 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From);
if (!PerformImplicitConversion(From, Context.BoolTy, ICS, "converting"))
return false;
-
- return Diag(From->getSourceRange().getBegin(),
- diag::err_typecheck_bool_condition)
- << From->getType() << From->getSourceRange();
+
+ if (!DiagnoseAmbiguousUserDefinedConversion(From, Context.BoolTy))
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_bool_condition)
+ << From->getType() << From->getSourceRange();
+ return true;
}
/// AddOverloadCandidate - Adds the given function to the set of
@@ -2063,21 +2159,25 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
/// If @p ForceRValue, treat all arguments as rvalues. This is a slightly
/// hacky way to implement the overloading rules for elidable copy
/// initialization in C++0x (C++0x 12.8p15).
-void
-Sema::AddOverloadCandidate(FunctionDecl *Function,
+///
+/// \para PartialOverloading true if we are performing "partial" overloading
+/// based on an incomplete set of function arguments. This feature is used by
+/// code completion.
+void
+Sema::AddOverloadCandidate(FunctionDecl *Function,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
- bool ForceRValue)
-{
- const FunctionProtoType* Proto
- = dyn_cast<FunctionProtoType>(Function->getType()->getAsFunctionType());
+ bool ForceRValue,
+ bool PartialOverloading) {
+ const FunctionProtoType* Proto
+ = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
- assert(!isa<CXXConversionDecl>(Function) &&
+ assert(!isa<CXXConversionDecl>(Function) &&
"Use AddConversionCandidate for conversion functions");
- assert(!Function->getDescribedFunctionTemplate() &&
+ assert(!Function->getDescribedFunctionTemplate() &&
"Use AddTemplateOverloadCandidate for function templates");
-
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
if (!isa<CXXConstructorDecl>(Method)) {
// If we get here, it's because we're calling a member function
@@ -2086,7 +2186,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// implicitly. This can happen with a qualified call to a member
// function, e.g., X::f(). We use a NULL object as the implied
// object argument (C++ [over.call.func]p3).
- AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet,
+ AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
return;
}
@@ -2094,7 +2194,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// argument doesn't participate in overload resolution.
}
-
+ if (!CandidateSet.isNewCandidate(Function))
+ return;
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2108,7 +2210,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// (C++ 13.3.2p2): A candidate function having fewer than m
// parameters is viable only if it has an ellipsis in its parameter
// list (8.3.5).
- if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
+ if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto &&
+ !Proto->isVariadic()) {
Candidate.Viable = false;
return;
}
@@ -2119,7 +2222,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// parameter list is truncated on the right, so that there are
// exactly m parameters.
unsigned MinRequiredArgs = Function->getMinRequiredArguments();
- if (NumArgs < MinRequiredArgs) {
+ if (NumArgs < MinRequiredArgs && !PartialOverloading) {
// Not enough arguments.
Candidate.Viable = false;
return;
@@ -2135,19 +2238,38 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
QualType ParamType = Proto->getArgType(ArgIdx);
- Candidate.Conversions[ArgIdx]
- = TryCopyInitialization(Args[ArgIdx], ParamType,
- SuppressUserConversions, ForceRValue);
- if (Candidate.Conversions[ArgIdx].ConversionKind
+ Candidate.Conversions[ArgIdx]
+ = TryCopyInitialization(Args[ArgIdx], ParamType,
+ SuppressUserConversions, ForceRValue,
+ /*InOverloadResolution=*/true);
+ if (Candidate.Conversions[ArgIdx].ConversionKind
== ImplicitConversionSequence::BadConversion) {
- Candidate.Viable = false;
- break;
+ // 13.3.3.1-p10 If several different sequences of conversions exist that
+ // each convert the argument to the parameter type, the implicit conversion
+ // sequence associated with the parameter is defined to be the unique conversion
+ // sequence designated the ambiguous conversion sequence. For the purpose of
+ // ranking implicit conversion sequences as described in 13.3.3.2, the ambiguous
+ // conversion sequence is treated as a user-defined sequence that is
+ // indistinguishable from any other user-defined conversion sequence
+ if (!Candidate.Conversions[ArgIdx].ConversionFunctionSet.empty()) {
+ Candidate.Conversions[ArgIdx].ConversionKind =
+ ImplicitConversionSequence::UserDefinedConversion;
+ // Set the conversion function to one of them. As due to ambiguity,
+ // they carry the same weight and is needed for overload resolution
+ // later.
+ Candidate.Conversions[ArgIdx].UserDefined.ConversionFunction =
+ Candidate.Conversions[ArgIdx].ConversionFunctionSet[0];
+ }
+ else {
+ Candidate.Viable = false;
+ break;
+ }
}
} else {
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx].ConversionKind
+ Candidate.Conversions[ArgIdx].ConversionKind
= ImplicitConversionSequence::EllipsisConversion;
}
}
@@ -2159,17 +2281,32 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
- for (FunctionSet::const_iterator F = Functions.begin(),
+ for (FunctionSet::const_iterator F = Functions.begin(),
FEnd = Functions.end();
F != FEnd; ++F) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F))
- AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
- SuppressUserConversions);
- else
- AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*F),
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) {
+ if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
+ AddMethodCandidate(cast<CXXMethodDecl>(FD),
+ Args[0], Args + 1, NumArgs - 1,
+ CandidateSet, SuppressUserConversions);
+ else
+ AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
+ } else {
+ FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*F);
+ if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
+ !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
+ AddMethodTemplateCandidate(FunTmpl,
/*FIXME: explicit args */false, 0, 0,
- Args, NumArgs, CandidateSet,
+ Args[0], Args + 1, NumArgs - 1,
+ CandidateSet,
SuppressUserConversions);
+ else
+ AddTemplateOverloadCandidate(FunTmpl,
+ /*FIXME: explicit args */false, 0, 0,
+ Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
+ }
}
}
@@ -2182,20 +2319,22 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
/// operators. If @p ForceRValue, treat all arguments as rvalues. This is
/// a slightly hacky way to implement the overloading rules for elidable copy
/// initialization in C++0x (C++0x 12.8p15).
-void
+void
Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions, bool ForceRValue)
-{
- const FunctionProtoType* Proto
- = dyn_cast<FunctionProtoType>(Method->getType()->getAsFunctionType());
+ bool SuppressUserConversions, bool ForceRValue) {
+ const FunctionProtoType* Proto
+ = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
assert(!isa<CXXConversionDecl>(Method) &&
"Use AddConversionCandidate for conversion functions");
assert(!isa<CXXConstructorDecl>(Method) &&
"Use AddOverloadCandidate for constructors");
+ if (!CandidateSet.isNewCandidate(Method))
+ return;
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2235,7 +2374,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
// Determine the implicit conversion sequence for the object
// parameter.
Candidate.Conversions[0] = TryObjectArgumentInitialization(Object, Method);
- if (Candidate.Conversions[0].ConversionKind
+ if (Candidate.Conversions[0].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
return;
@@ -2251,10 +2390,11 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
QualType ParamType = Proto->getArgType(ArgIdx);
- Candidate.Conversions[ArgIdx + 1]
- = TryCopyInitialization(Args[ArgIdx], ParamType,
- SuppressUserConversions, ForceRValue);
- if (Candidate.Conversions[ArgIdx + 1].ConversionKind
+ Candidate.Conversions[ArgIdx + 1]
+ = TryCopyInitialization(Args[ArgIdx], ParamType,
+ SuppressUserConversions, ForceRValue,
+ /*InOverloadResolution=*/true);
+ if (Candidate.Conversions[ArgIdx + 1].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
break;
@@ -2263,16 +2403,61 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx + 1].ConversionKind
+ Candidate.Conversions[ArgIdx + 1].ConversionKind
= ImplicitConversionSequence::EllipsisConversion;
}
}
}
-/// \brief Add a C++ function template as a candidate in the candidate set,
-/// using template argument deduction to produce an appropriate function
-/// template specialization.
-void
+/// \brief Add a C++ member function template as a candidate to the candidate
+/// set, using template argument deduction to produce an appropriate member
+/// function template specialization.
+void
+Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ Expr *Object, Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions,
+ bool ForceRValue) {
+ if (!CandidateSet.isNewCandidate(MethodTmpl))
+ return;
+
+ // C++ [over.match.funcs]p7:
+ // In each case where a candidate is a function template, candidate
+ // function template specializations are generated using template argument
+ // deduction (14.8.3, 14.8.2). Those candidates are then handled as
+ // candidate functions in the usual way.113) A given name can refer to one
+ // or more function templates and also to a set of overloaded non-template
+ // functions. In such a case, the candidate functions generated from each
+ // function template are combined with the set of non-template candidate
+ // functions.
+ TemplateDeductionInfo Info(Context);
+ FunctionDecl *Specialization = 0;
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArguments(MethodTmpl, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ Args, NumArgs, Specialization, Info)) {
+ // FIXME: Record what happened with template argument deduction, so
+ // that we can give the user a beautiful diagnostic.
+ (void)Result;
+ return;
+ }
+
+ // Add the function template specialization produced by template argument
+ // deduction as a candidate.
+ assert(Specialization && "Missing member function template specialization?");
+ assert(isa<CXXMethodDecl>(Specialization) &&
+ "Specialization is not a member function?");
+ AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Object, Args, NumArgs,
+ CandidateSet, SuppressUserConversions, ForceRValue);
+}
+
+/// \brief Add a C++ function template specialization as a candidate
+/// in the candidate set, using template argument deduction to produce
+/// an appropriate function template specialization.
+void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
@@ -2281,10 +2466,13 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
bool ForceRValue) {
+ if (!CandidateSet.isNewCandidate(FunctionTemplate))
+ return;
+
// C++ [over.match.funcs]p7:
- // In each case where a candidate is a function template, candidate
+ // In each case where a candidate is a function template, candidate
// function template specializations are generated using template argument
- // deduction (14.8.3, 14.8.2). Those candidates are then handled as
+ // deduction (14.8.3, 14.8.2). Those candidates are then handled as
// candidate functions in the usual way.113) A given name can refer to one
// or more function templates and also to a set of overloaded non-template
// functions. In such a case, the candidate functions generated from each
@@ -2301,24 +2489,30 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
(void)Result;
return;
}
-
+
// Add the function template specialization produced by template argument
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
AddOverloadCandidate(Specialization, Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
}
-
+
/// AddConversionCandidate - Add a C++ conversion function as a
-/// candidate in the candidate set (C++ [over.match.conv],
+/// candidate in the candidate set (C++ [over.match.conv],
/// C++ [over.match.copy]). From is the expression we're converting from,
-/// and ToType is the type that we're eventually trying to convert to
+/// and ToType is the type that we're eventually trying to convert to
/// (which may or may not be the same type as the type that the
/// conversion function produces).
void
Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet) {
+ assert(!Conversion->getDescribedFunctionTemplate() &&
+ "Conversion function templates use AddTemplateConversionCandidate");
+
+ if (!CandidateSet.isNewCandidate(Conversion))
+ return;
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2326,7 +2520,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
- Candidate.FinalConversion.FromTypePtr
+ Candidate.FinalConversion.FromTypePtr
= Conversion->getConversionType().getAsOpaquePtr();
Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr();
@@ -2335,8 +2529,12 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.Viable = true;
Candidate.Conversions.resize(1);
Candidate.Conversions[0] = TryObjectArgumentInitialization(From, Conversion);
-
- if (Candidate.Conversions[0].ConversionKind
+ // Conversion functions to a different type in the base class is visible in
+ // the derived class. So, a derived to base conversion should not participate
+ // in overload resolution.
+ if (Candidate.Conversions[0].Standard.Second == ICK_Derived_To_Base)
+ Candidate.Conversions[0].Standard.Second = ICK_Identity;
+ if (Candidate.Conversions[0].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
return;
@@ -2350,18 +2548,24 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// lvalues/rvalues and the type. Fortunately, we can allocate this
// call on the stack and we don't need its arguments to be
// well-formed.
- DeclRefExpr ConversionRef(Conversion, Conversion->getType(),
+ DeclRefExpr ConversionRef(Conversion, Conversion->getType(),
SourceLocation());
ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()),
+ CastExpr::CK_Unknown,
&ConversionRef, false);
-
- // Note that it is safe to allocate CallExpr on the stack here because
+
+ // Note that it is safe to allocate CallExpr on the stack here because
// there are 0 arguments (i.e., nothing is allocated using ASTContext's
// allocator).
- CallExpr Call(Context, &ConversionFn, 0, 0,
+ CallExpr Call(Context, &ConversionFn, 0, 0,
Conversion->getConversionType().getNonReferenceType(),
SourceLocation());
- ImplicitConversionSequence ICS = TryCopyInitialization(&Call, ToType, true);
+ ImplicitConversionSequence ICS =
+ TryCopyInitialization(&Call, ToType,
+ /*SuppressUserConversions=*/true,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+
switch (ICS.ConversionKind) {
case ImplicitConversionSequence::StandardConversion:
Candidate.FinalConversion = ICS.Standard;
@@ -2372,11 +2576,43 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
break;
default:
- assert(false &&
+ assert(false &&
"Can only end up with a standard conversion sequence or failure");
}
}
+/// \brief Adds a conversion function template specialization
+/// candidate to the overload set, using template argument deduction
+/// to deduce the template arguments of the conversion function
+/// template from the type that we are converting to (C++
+/// [temp.deduct.conv]).
+void
+Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ Expr *From, QualType ToType,
+ OverloadCandidateSet &CandidateSet) {
+ assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
+ "Only conversion function templates permitted here");
+
+ if (!CandidateSet.isNewCandidate(FunctionTemplate))
+ return;
+
+ TemplateDeductionInfo Info(Context);
+ CXXConversionDecl *Specialization = 0;
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArguments(FunctionTemplate, ToType,
+ Specialization, Info)) {
+ // FIXME: Record what happened with template argument deduction, so
+ // that we can give the user a beautiful diagnostic.
+ (void)Result;
+ return;
+ }
+
+ // Add the conversion function template specialization produced by
+ // template argument deduction as a candidate.
+ assert(Specialization && "Missing function template specialization?");
+ AddConversionCandidate(Specialization, From, ToType, CandidateSet);
+}
+
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
/// converts the given @c Object to a function pointer via the
/// conversion function @c Conversion, and then attempts to call it
@@ -2386,6 +2622,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
const FunctionProtoType *Proto,
Expr *Object, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet) {
+ if (!CandidateSet.isNewCandidate(Conversion))
+ return;
+
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = 0;
@@ -2397,7 +2636,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// Determine the implicit conversion sequence for the implicit
// object parameter.
- ImplicitConversionSequence ObjectInit
+ ImplicitConversionSequence ObjectInit
= TryObjectArgumentInitialization(Object, Conversion);
if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
@@ -2407,15 +2646,15 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// The first conversion is actually a user-defined conversion whose
// first conversion is ObjectInit's standard conversion (which is
// effectively a reference binding). Record it as such.
- Candidate.Conversions[0].ConversionKind
+ Candidate.Conversions[0].ConversionKind
= ImplicitConversionSequence::UserDefinedConversion;
Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard;
Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion;
- Candidate.Conversions[0].UserDefined.After
+ Candidate.Conversions[0].UserDefined.After
= Candidate.Conversions[0].UserDefined.Before;
Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion();
- // Find the
+ // Find the
unsigned NumArgsInProto = Proto->getNumArgs();
// (C++ 13.3.2p2): A candidate function having fewer than m
@@ -2443,10 +2682,12 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
QualType ParamType = Proto->getArgType(ArgIdx);
- Candidate.Conversions[ArgIdx + 1]
- = TryCopyInitialization(Args[ArgIdx], ParamType,
- /*SuppressUserConversions=*/false);
- if (Candidate.Conversions[ArgIdx + 1].ConversionKind
+ Candidate.Conversions[ArgIdx + 1]
+ = TryCopyInitialization(Args[ArgIdx], ParamType,
+ /*SuppressUserConversions=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+ if (Candidate.Conversions[ArgIdx + 1].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
break;
@@ -2455,7 +2696,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx + 1].ConversionKind
+ Candidate.Conversions[ArgIdx + 1].ConversionKind
= ImplicitConversionSequence::EllipsisConversion;
}
}
@@ -2469,7 +2710,6 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange) {
-
FunctionSet Functions;
QualType T1 = Args[0]->getType();
@@ -2518,14 +2758,32 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
// result of the qualified lookup of T1::operator@
// (13.3.1.1.1); otherwise, the set of member candidates is
// empty.
- // FIXME: Lookup in base classes, too!
- if (const RecordType *T1Rec = T1->getAsRecordType()) {
- DeclContext::lookup_const_iterator Oper, OperEnd;
- for (llvm::tie(Oper, OperEnd) = T1Rec->getDecl()->lookup(OpName);
- Oper != OperEnd; ++Oper)
- AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Args[0],
- Args+1, NumArgs - 1, CandidateSet,
- /*SuppressUserConversions=*/false);
+ if (const RecordType *T1Rec = T1->getAs<RecordType>()) {
+ // Complete the type if it can be completed. Otherwise, we're done.
+ if (RequireCompleteType(OpLoc, T1, PDiag()))
+ return;
+
+ LookupResult Operators;
+ LookupQualifiedName(Operators, T1Rec->getDecl(), OpName,
+ LookupOrdinaryName, false);
+ for (LookupResult::iterator Oper = Operators.begin(),
+ OperEnd = Operators.end();
+ Oper != OperEnd;
+ ++Oper) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Oper)) {
+ AddMethodCandidate(Method, Args[0], Args+1, NumArgs - 1, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ continue;
+ }
+
+ assert(isa<FunctionTemplateDecl>(*Oper) &&
+ isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(*Oper)
+ ->getTemplatedDecl()) &&
+ "Expected a member function template");
+ AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Oper), false, 0, 0,
+ Args[0], Args+1, NumArgs - 1, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ }
}
}
@@ -2537,7 +2795,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
/// operator. NumContextualBoolArguments is the number of arguments
/// (at the beginning of the argument list) that will be contextually
/// converted to bool.
-void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
+void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool IsAssignmentOperator,
@@ -2563,22 +2821,24 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
// -- no temporaries are introduced to hold the left operand, and
// -- no user-defined conversions are applied to the left
// operand to achieve a type match with the left-most
- // parameter of a built-in candidate.
+ // parameter of a built-in candidate.
//
// We block these conversions by turning off user-defined
// conversions, since that is the only way that initialization of
// a reference to a non-class type can occur from something that
// is not of the same type.
if (ArgIdx < NumContextualBoolArguments) {
- assert(ParamTys[ArgIdx] == Context.BoolTy &&
+ assert(ParamTys[ArgIdx] == Context.BoolTy &&
"Contextual conversion to bool requires bool type");
Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]);
} else {
- Candidate.Conversions[ArgIdx]
- = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx],
- ArgIdx == 0 && IsAssignmentOperator);
+ Candidate.Conversions[ArgIdx]
+ = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx],
+ ArgIdx == 0 && IsAssignmentOperator,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
- if (Candidate.Conversions[ArgIdx].ConversionKind
+ if (Candidate.Conversions[ArgIdx].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
break;
@@ -2606,6 +2866,10 @@ class BuiltinCandidateTypeSet {
/// used in the built-in candidates.
TypeSet EnumerationTypes;
+ /// Sema - The semantic analysis instance where we are building the
+ /// candidate type set.
+ Sema &SemaRef;
+
/// Context - The AST context in which we will build the type sets.
ASTContext &Context;
@@ -2616,7 +2880,8 @@ public:
/// iterator - Iterates through the types that are part of the set.
typedef TypeSet::iterator iterator;
- BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { }
+ BuiltinCandidateTypeSet(Sema &SemaRef)
+ : SemaRef(SemaRef), Context(SemaRef.Context) { }
void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions,
bool AllowExplicitConversions);
@@ -2647,27 +2912,27 @@ public:
/// restrict *", and "int const volatile restrict *" to the set of
/// pointer types. Returns true if the add of @p Ty itself succeeded,
/// false otherwise.
+///
+/// FIXME: what to do about extended qualifiers?
bool
BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) {
+
// Insert this type.
if (!PointerTypes.insert(Ty))
return false;
- if (const PointerType *PointerTy = Ty->getAsPointerType()) {
- QualType PointeeTy = PointerTy->getPointeeType();
- // FIXME: Optimize this so that we don't keep trying to add the same types.
-
- // FIXME: Do we have to add CVR qualifiers at *all* levels to deal with all
- // pointer conversions that don't cast away constness?
- if (!PointeeTy.isConstQualified())
- AddPointerWithMoreQualifiedTypeVariants
- (Context.getPointerType(PointeeTy.withConst()));
- if (!PointeeTy.isVolatileQualified())
- AddPointerWithMoreQualifiedTypeVariants
- (Context.getPointerType(PointeeTy.withVolatile()));
- if (!PointeeTy.isRestrictQualified())
- AddPointerWithMoreQualifiedTypeVariants
- (Context.getPointerType(PointeeTy.withRestrict()));
+ const PointerType *PointerTy = Ty->getAs<PointerType>();
+ assert(PointerTy && "type was not a pointer type!");
+
+ QualType PointeeTy = PointerTy->getPointeeType();
+ unsigned BaseCVR = PointeeTy.getCVRQualifiers();
+
+ // Iterate through all strict supersets of BaseCVR.
+ for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) {
+ if ((CVR | BaseCVR) != CVR) continue;
+
+ QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR);
+ PointerTypes.insert(Context.getPointerType(QPointeeTy));
}
return true;
@@ -2680,6 +2945,8 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) {
/// restrict *", and "int const volatile restrict *" to the set of
/// pointer types. Returns true if the add of @p Ty itself succeeded,
/// false otherwise.
+///
+/// FIXME: what to do about extended qualifiers?
bool
BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants(
QualType Ty) {
@@ -2687,20 +2954,20 @@ BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants(
if (!MemberPointerTypes.insert(Ty))
return false;
- if (const MemberPointerType *PointerTy = Ty->getAsMemberPointerType()) {
- QualType PointeeTy = PointerTy->getPointeeType();
- const Type *ClassTy = PointerTy->getClass();
- // FIXME: Optimize this so that we don't keep trying to add the same types.
-
- if (!PointeeTy.isConstQualified())
- AddMemberPointerWithMoreQualifiedTypeVariants
- (Context.getMemberPointerType(PointeeTy.withConst(), ClassTy));
- if (!PointeeTy.isVolatileQualified())
- AddMemberPointerWithMoreQualifiedTypeVariants
- (Context.getMemberPointerType(PointeeTy.withVolatile(), ClassTy));
- if (!PointeeTy.isRestrictQualified())
- AddMemberPointerWithMoreQualifiedTypeVariants
- (Context.getMemberPointerType(PointeeTy.withRestrict(), ClassTy));
+ const MemberPointerType *PointerTy = Ty->getAs<MemberPointerType>();
+ assert(PointerTy && "type was not a member pointer type!");
+
+ QualType PointeeTy = PointerTy->getPointeeType();
+ const Type *ClassTy = PointerTy->getClass();
+
+ // Iterate through all strict supersets of the pointee type's CVR
+ // qualifiers.
+ unsigned BaseCVR = PointeeTy.getCVRQualifiers();
+ for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) {
+ if ((CVR | BaseCVR) != CVR) continue;
+
+ QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR);
+ MemberPointerTypes.insert(Context.getMemberPointerType(QPointeeTy, ClassTy));
}
return true;
@@ -2714,7 +2981,7 @@ BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants(
/// functions of a class type, and AllowExplicitConversions if we
/// should also include the explicit conversion functions of a class
/// type.
-void
+void
BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
bool AllowUserConversions,
bool AllowExplicitConversions) {
@@ -2723,13 +2990,13 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
// Look through reference types; they aren't part of the type of an
// expression for the purposes of conversions.
- if (const ReferenceType *RefTy = Ty->getAsReferenceType())
+ if (const ReferenceType *RefTy = Ty->getAs<ReferenceType>())
Ty = RefTy->getPointeeType();
// We don't care about qualifiers on the type.
Ty = Ty.getUnqualifiedType();
- if (const PointerType *PointerTy = Ty->getAsPointerType()) {
+ if (const PointerType *PointerTy = Ty->getAs<PointerType>()) {
QualType PointeeTy = PointerTy->getPointeeType();
// Insert our type, and its more-qualified variants, into the set
@@ -2739,20 +3006,22 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
// Add 'cv void*' to our set of types.
if (!Ty->isVoidType()) {
- QualType QualVoid
- = Context.VoidTy.getQualifiedType(PointeeTy.getCVRQualifiers());
+ QualType QualVoid
+ = Context.getCVRQualifiedType(Context.VoidTy,
+ PointeeTy.getCVRQualifiers());
AddPointerWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid));
}
// If this is a pointer to a class type, add pointers to its bases
// (with the same level of cv-qualification as the original
// derived class, of course).
- if (const RecordType *PointeeRec = PointeeTy->getAsRecordType()) {
+ if (const RecordType *PointeeRec = PointeeTy->getAs<RecordType>()) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(PointeeRec->getDecl());
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
Base != ClassDecl->bases_end(); ++Base) {
QualType BaseTy = Context.getCanonicalType(Base->getType());
- BaseTy = BaseTy.getQualifiedType(PointeeTy.getCVRQualifiers());
+ BaseTy = Context.getCVRQualifiedType(BaseTy.getUnqualifiedType(),
+ PointeeTy.getCVRQualifiers());
// Add the pointer type, recursively, so that we get all of
// the indirect base classes, too.
@@ -2766,15 +3035,27 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
} else if (Ty->isEnumeralType()) {
EnumerationTypes.insert(Ty);
} else if (AllowUserConversions) {
- if (const RecordType *TyRec = Ty->getAsRecordType()) {
+ if (const RecordType *TyRec = Ty->getAs<RecordType>()) {
+ if (SemaRef.RequireCompleteType(SourceLocation(), Ty, 0)) {
+ // No conversion functions in incomplete types.
+ return;
+ }
+
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- // FIXME: Visit conversion functions in the base classes, too.
- OverloadedFunctionDecl *Conversions
- = ClassDecl->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator Func
+ OverloadedFunctionDecl *Conversions
+ = ClassDecl->getVisibleConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+ CXXConversionDecl *Conv;
+ FunctionTemplateDecl *ConvTemplate;
+ GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+
+ // Skip conversion function templates; they don't tell us anything
+ // about which builtin types we can convert to.
+ if (ConvTemplate)
+ continue;
+
if (AllowExplicitConversions || !Conv->isExplicit())
AddTypesConvertedFrom(Conv->getConversionType(), false, false);
}
@@ -2782,13 +3063,39 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
}
}
+/// \brief Helper function for AddBuiltinOperatorCandidates() that adds
+/// the volatile- and non-volatile-qualified assignment operators for the
+/// given type to the candidate set.
+static void AddBuiltinAssignmentOperatorCandidates(Sema &S,
+ QualType T,
+ Expr **Args,
+ unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet) {
+ QualType ParamTypes[2];
+
+ // T& operator=(T&, T)
+ ParamTypes[0] = S.Context.getLValueReferenceType(T);
+ ParamTypes[1] = T;
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssignmentOperator=*/true);
+
+ if (!S.Context.getCanonicalType(T).isVolatileQualified()) {
+ // volatile T& operator=(volatile T&, T)
+ ParamTypes[0]
+ = S.Context.getLValueReferenceType(S.Context.getVolatileType(T));
+ ParamTypes[1] = T;
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssignmentOperator=*/true);
+ }
+}
+
/// AddBuiltinOperatorCandidates - Add the appropriate built-in
/// operator overloads to the candidate set (C++ [over.built]), based
/// on the operator @p Op and the arguments given. For example, if the
/// operator is a binary '+', this routine might add "int
/// operator+(int, int)" to cover integer addition.
void
-Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
+Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet) {
// The set of "promoted arithmetic types", which are the arithmetic
@@ -2798,13 +3105,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// FIXME: What about complex?
const unsigned FirstIntegralType = 0;
const unsigned LastIntegralType = 13;
- const unsigned FirstPromotedIntegralType = 7,
+ const unsigned FirstPromotedIntegralType = 7,
LastPromotedIntegralType = 13;
const unsigned FirstPromotedArithmeticType = 7,
LastPromotedArithmeticType = 16;
const unsigned NumArithmeticTypes = 16;
QualType ArithmeticTypes[NumArithmeticTypes] = {
Context.BoolTy, Context.CharTy, Context.WCharTy,
+// FIXME: Context.Char16Ty, Context.Char32Ty,
Context.SignedCharTy, Context.ShortTy,
Context.UnsignedCharTy, Context.UnsignedShortTy,
Context.IntTy, Context.LongTy, Context.LongLongTy,
@@ -2815,7 +3123,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// Find all of the types that the arguments can convert to, but only
// if the operator we're looking at has built-in operator candidates
// that make use of these types.
- BuiltinCandidateTypeSet CandidateTypes(Context);
+ BuiltinCandidateTypeSet CandidateTypes(*this);
if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual ||
Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual ||
Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal ||
@@ -2838,7 +3146,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
break;
case OO_Star: // '*' is either unary or binary
- if (NumArgs == 1)
+ if (NumArgs == 1)
goto UnaryStar;
else
goto BinaryStar;
@@ -2883,10 +3191,10 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// VQ T& operator--(VQ T&);
// T operator--(VQ T&, int);
- for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1);
+ for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1);
Arith < NumArithmeticTypes; ++Arith) {
QualType ArithTy = ArithmeticTypes[Arith];
- QualType ParamTypes[2]
+ QualType ParamTypes[2]
= { Context.getLValueReferenceType(ArithTy), Context.IntTy };
// Non-volatile version.
@@ -2896,7 +3204,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet);
// Volatile version
- ParamTypes[0] = Context.getLValueReferenceType(ArithTy.withVolatile());
+ ParamTypes[0]
+ = Context.getLValueReferenceType(Context.getVolatileType(ArithTy));
if (NumArgs == 1)
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
else
@@ -2916,13 +3225,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
Ptr != CandidateTypes.pointer_end(); ++Ptr) {
// Skip pointer types that aren't pointers to object types.
- if (!(*Ptr)->getAsPointerType()->getPointeeType()->isObjectType())
+ if (!(*Ptr)->getAs<PointerType>()->getPointeeType()->isObjectType())
continue;
- QualType ParamTypes[2] = {
- Context.getLValueReferenceType(*Ptr), Context.IntTy
+ QualType ParamTypes[2] = {
+ Context.getLValueReferenceType(*Ptr), Context.IntTy
};
-
+
// Without volatile
if (NumArgs == 1)
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
@@ -2931,7 +3240,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) {
// With volatile
- ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile());
+ ParamTypes[0]
+ = Context.getLValueReferenceType(Context.getVolatileType(*Ptr));
if (NumArgs == 1)
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
else
@@ -2954,8 +3264,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
Ptr != CandidateTypes.pointer_end(); ++Ptr) {
QualType ParamTy = *Ptr;
- QualType PointeeTy = ParamTy->getAsPointerType()->getPointeeType();
- AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy),
+ QualType PointeeTy = ParamTy->getAs<PointerType>()->getPointeeType();
+ AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy),
&ParamTy, Args, 1, CandidateSet);
}
break;
@@ -2971,7 +3281,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
QualType ParamTy = *Ptr;
AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet);
}
-
+
// Fall through
UnaryMinus:
@@ -2981,7 +3291,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// T operator+(T);
// T operator-(T);
- for (unsigned Arith = FirstPromotedArithmeticType;
+ for (unsigned Arith = FirstPromotedArithmeticType;
Arith < LastPromotedArithmeticType; ++Arith) {
QualType ArithTy = ArithmeticTypes[Arith];
AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet);
@@ -2994,7 +3304,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// operator functions of the form
//
// T operator~(T);
- for (unsigned Int = FirstPromotedIntegralType;
+ for (unsigned Int = FirstPromotedIntegralType;
Int < LastPromotedIntegralType; ++Int) {
QualType IntTy = ArithmeticTypes[Int];
AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet);
@@ -3017,17 +3327,34 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// operator '->', the built-in candidates set is empty.
break;
+ case OO_EqualEqual:
+ case OO_ExclaimEqual:
+ // C++ [over.match.oper]p16:
+ // For every pointer to member type T, there exist candidate operator
+ // functions of the form
+ //
+ // bool operator==(T,T);
+ // bool operator!=(T,T);
+ for (BuiltinCandidateTypeSet::iterator
+ MemPtr = CandidateTypes.member_pointer_begin(),
+ MemPtrEnd = CandidateTypes.member_pointer_end();
+ MemPtr != MemPtrEnd;
+ ++MemPtr) {
+ QualType ParamTypes[2] = { *MemPtr, *MemPtr };
+ AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ }
+
+ // Fall through
+
case OO_Less:
case OO_Greater:
case OO_LessEqual:
case OO_GreaterEqual:
- case OO_EqualEqual:
- case OO_ExclaimEqual:
// C++ [over.built]p15:
//
// For every pointer or enumeration type T, there exist
// candidate operator functions of the form
- //
+ //
// bool operator<(T, T);
// bool operator>(T, T);
// bool operator<=(T, T);
@@ -3039,7 +3366,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
QualType ParamTypes[2] = { *Ptr, *Ptr };
AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
}
- for (BuiltinCandidateTypeSet::iterator Enum
+ for (BuiltinCandidateTypeSet::iterator Enum
= CandidateTypes.enumeration_begin();
Enum != CandidateTypes.enumeration_end(); ++Enum) {
QualType ParamTypes[2] = { *Enum, *Enum };
@@ -3058,7 +3385,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// For every cv-qualified or cv-unqualified object type T
// there exist candidate operator functions of the form
- //
+ //
// T* operator+(T*, ptrdiff_t);
// T& operator[](T*, ptrdiff_t); [BELOW]
// T* operator-(T*, ptrdiff_t);
@@ -3071,7 +3398,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// exist candidate operator functions of the form
//
// ptrdiff_t operator-(T, T);
- for (BuiltinCandidateTypeSet::iterator Ptr
+ for (BuiltinCandidateTypeSet::iterator Ptr
= CandidateTypes.pointer_begin();
Ptr != CandidateTypes.pointer_end(); ++Ptr) {
QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() };
@@ -3126,14 +3453,15 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// where LR is the result of the usual arithmetic conversions
// between types L and R.
// Our candidates ignore the first parameter.
- for (unsigned Left = FirstPromotedArithmeticType;
+ for (unsigned Left = FirstPromotedArithmeticType;
Left < LastPromotedArithmeticType; ++Left) {
- for (unsigned Right = FirstPromotedArithmeticType;
+ for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] };
- QualType Result
- = isComparison? Context.BoolTy
- : UsualArithmeticConversionsType(LandR[0], LandR[1]);
+ QualType Result
+ = isComparison
+ ? Context.BoolTy
+ : Context.UsualArithmeticConversionsType(LandR[0], LandR[1]);
AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
}
@@ -3159,14 +3487,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// where LR is the result of the usual arithmetic conversions
// between types L and R.
- for (unsigned Left = FirstPromotedIntegralType;
+ for (unsigned Left = FirstPromotedIntegralType;
Left < LastPromotedIntegralType; ++Left) {
- for (unsigned Right = FirstPromotedIntegralType;
+ for (unsigned Right = FirstPromotedIntegralType;
Right < LastPromotedIntegralType; ++Right) {
QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] };
QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater)
? LandR[0]
- : UsualArithmeticConversionsType(LandR[0], LandR[1]);
+ : Context.UsualArithmeticConversionsType(LandR[0], LandR[1]);
AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
}
@@ -3176,30 +3504,23 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// C++ [over.built]p20:
//
// For every pair (T, VQ), where T is an enumeration or
- // (FIXME:) pointer to member type and VQ is either volatile or
+ // pointer to member type and VQ is either volatile or
// empty, there exist candidate operator functions of the form
//
// VQ T& operator=(VQ T&, T);
- for (BuiltinCandidateTypeSet::iterator Enum
- = CandidateTypes.enumeration_begin();
- Enum != CandidateTypes.enumeration_end(); ++Enum) {
- QualType ParamTypes[2];
-
- // T& operator=(T&, T)
- ParamTypes[0] = Context.getLValueReferenceType(*Enum);
- ParamTypes[1] = *Enum;
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssignmentOperator=*/false);
-
- if (!Context.getCanonicalType(*Enum).isVolatileQualified()) {
- // volatile T& operator=(volatile T&, T)
- ParamTypes[0] = Context.getLValueReferenceType((*Enum).withVolatile());
- ParamTypes[1] = *Enum;
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssignmentOperator=*/false);
- }
- }
- // Fall through.
+ for (BuiltinCandidateTypeSet::iterator
+ Enum = CandidateTypes.enumeration_begin(),
+ EnumEnd = CandidateTypes.enumeration_end();
+ Enum != EnumEnd; ++Enum)
+ AddBuiltinAssignmentOperatorCandidates(*this, *Enum, Args, 2,
+ CandidateSet);
+ for (BuiltinCandidateTypeSet::iterator
+ MemPtr = CandidateTypes.member_pointer_begin(),
+ MemPtrEnd = CandidateTypes.member_pointer_end();
+ MemPtr != MemPtrEnd; ++MemPtr)
+ AddBuiltinAssignmentOperatorCandidates(*this, *MemPtr, Args, 2,
+ CandidateSet);
+ // Fall through.
case OO_PlusEqual:
case OO_MinusEqual:
@@ -3231,7 +3552,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) {
// volatile version
- ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile());
+ ParamTypes[0]
+ = Context.getLValueReferenceType(Context.getVolatileType(*Ptr));
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
/*IsAssigmentOperator=*/Op == OO_Equal);
}
@@ -3253,7 +3575,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// VQ L& operator+=(VQ L&, R);
// VQ L& operator-=(VQ L&, R);
for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) {
- for (unsigned Right = FirstPromotedArithmeticType;
+ for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
QualType ParamTypes[2];
ParamTypes[1] = ArithmeticTypes[Right];
@@ -3264,7 +3586,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
/*IsAssigmentOperator=*/Op == OO_Equal);
// Add this built-in operator as a candidate (VQ is 'volatile').
- ParamTypes[0] = ArithmeticTypes[Left].withVolatile();
+ ParamTypes[0] = Context.getVolatileType(ArithmeticTypes[Left]);
ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
/*IsAssigmentOperator=*/Op == OO_Equal);
@@ -3291,7 +3613,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// VQ L& operator^=(VQ L&, R);
// VQ L& operator|=(VQ L&, R);
for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) {
- for (unsigned Right = FirstPromotedIntegralType;
+ for (unsigned Right = FirstPromotedIntegralType;
Right < LastPromotedIntegralType; ++Right) {
QualType ParamTypes[2];
ParamTypes[1] = ArithmeticTypes[Right];
@@ -3302,7 +3624,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// Add this built-in operator as a candidate (VQ is 'volatile').
ParamTypes[0] = ArithmeticTypes[Left];
- ParamTypes[0].addVolatile();
+ ParamTypes[0] = Context.getVolatileType(ParamTypes[0]);
ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
}
@@ -3314,7 +3636,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// There also exist candidate operator functions of the form
//
- // bool operator!(bool);
+ // bool operator!(bool);
// bool operator&&(bool, bool); [BELOW]
// bool operator||(bool, bool); [BELOW]
QualType ParamTy = Context.BoolTy;
@@ -3345,7 +3667,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
//
// For every cv-qualified or cv-unqualified object type T there
// exist candidate operator functions of the form
- //
+ //
// T* operator+(T*, ptrdiff_t); [ABOVE]
// T& operator[](T*, ptrdiff_t);
// T* operator-(T*, ptrdiff_t); [ABOVE]
@@ -3354,7 +3676,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
Ptr != CandidateTypes.pointer_end(); ++Ptr) {
QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() };
- QualType PointeeType = (*Ptr)->getAsPointerType()->getPointeeType();
+ QualType PointeeType = (*Ptr)->getAs<PointerType>()->getPointeeType();
QualType ResultTy = Context.getLValueReferenceType(PointeeType);
// T& operator[](T*, ptrdiff_t)
@@ -3368,7 +3690,43 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
break;
case OO_ArrowStar:
- // FIXME: No support for pointer-to-members yet.
+ // C++ [over.built]p11:
+ // For every quintuple (C1, C2, T, CV1, CV2), where C2 is a class type,
+ // C1 is the same type as C2 or is a derived class of C2, T is an object
+ // type or a function type, and CV1 and CV2 are cv-qualifier-seqs,
+ // there exist candidate operator functions of the form
+ // CV12 T& operator->*(CV1 C1*, CV2 T C2::*);
+ // where CV12 is the union of CV1 and CV2.
+ {
+ for (BuiltinCandidateTypeSet::iterator Ptr =
+ CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ QualType C1Ty = (*Ptr);
+ QualType C1;
+ QualifierCollector Q1;
+ if (const PointerType *PointerTy = C1Ty->getAs<PointerType>()) {
+ C1 = QualType(Q1.strip(PointerTy->getPointeeType()), 0);
+ if (!isa<RecordType>(C1))
+ continue;
+ }
+ for (BuiltinCandidateTypeSet::iterator
+ MemPtr = CandidateTypes.member_pointer_begin(),
+ MemPtrEnd = CandidateTypes.member_pointer_end();
+ MemPtr != MemPtrEnd; ++MemPtr) {
+ const MemberPointerType *mptr = cast<MemberPointerType>(*MemPtr);
+ QualType C2 = QualType(mptr->getClass(), 0);
+ C2 = C2.getUnqualifiedType();
+ if (C1 != C2 && !IsDerivedFrom(C1, C2))
+ break;
+ QualType ParamTypes[2] = { *Ptr, *MemPtr };
+ // build CV12 T&
+ QualType T = mptr->getPointeeType();
+ T = Q1.apply(T);
+ QualType ResultTy = Context.getLValueReferenceType(T);
+ AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
+ }
+ }
+ }
break;
case OO_Conditional:
@@ -3404,12 +3762,18 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
/// given function name (which may also be an operator name) and adds
/// all of the overload candidates found by ADL to the overload
/// candidate set (C++ [basic.lookup.argdep]).
-void
+void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet) {
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool PartialOverloading) {
FunctionSet Functions;
+ // FIXME: Should we be trafficking in canonical function decls throughout?
+
// Record all of the function candidates that we've already
// added to the overload set, so that we don't add those same
// candidates a second time.
@@ -3422,6 +3786,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
Functions.insert(FunTmpl);
}
+ // FIXME: Pass in the explicit template arguments?
ArgumentDependentLookup(Name, Args, NumArgs, Functions);
// Erase all of the candidates we already knew about.
@@ -3440,21 +3805,26 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
for (FunctionSet::iterator Func = Functions.begin(),
FuncEnd = Functions.end();
Func != FuncEnd; ++Func) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func))
- AddOverloadCandidate(FD, Args, NumArgs, CandidateSet);
- else
- AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func),
- /*FIXME: explicit args */false, 0, 0,
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) {
+ if (HasExplicitTemplateArgs)
+ continue;
+
+ AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+ false, false, PartialOverloading);
+ } else
+ AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func),
+ HasExplicitTemplateArgs,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
}
}
/// isBetterOverloadCandidate - Determines whether the first overload
/// candidate is a better candidate than the second (C++ 13.3.3p1).
-bool
+bool
Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
- const OverloadCandidate& Cand2)
-{
+ const OverloadCandidate& Cand2) {
// Define viable functions to be better candidates than non-viable
// functions.
if (!Cand2.Viable)
@@ -3472,10 +3842,10 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
if (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument)
StartArg = 1;
- // (C++ 13.3.3p1): a viable function F1 is defined to be a better
- // function than another viable function F2 if for all arguments i,
- // ICSi(F1) is not a worse conversion sequence than ICSi(F2), and
- // then...
+ // C++ [over.match.best]p1:
+ // A viable function F1 is defined to be a better function than another
+ // viable function F2 if for all arguments i, ICSi(F1) is not a worse
+ // conversion sequence than ICSi(F2), and then...
unsigned NumArgs = Cand1.Conversions.size();
assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch");
bool HasBetterConversion = false;
@@ -3497,22 +3867,38 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
}
}
+ // -- for some argument j, ICSj(F1) is a better conversion sequence than
+ // ICSj(F2), or, if not that,
if (HasBetterConversion)
return true;
- // FIXME: Several other bullets in (C++ 13.3.3p1) need to be
- // implemented, but they require template support.
+ // - F1 is a non-template function and F2 is a function template
+ // specialization, or, if not that,
+ if (Cand1.Function && !Cand1.Function->getPrimaryTemplate() &&
+ Cand2.Function && Cand2.Function->getPrimaryTemplate())
+ return true;
+
+ // -- F1 and F2 are function template specializations, and the function
+ // template for F1 is more specialized than the template for F2
+ // according to the partial ordering rules described in 14.5.5.2, or,
+ // if not that,
+ if (Cand1.Function && Cand1.Function->getPrimaryTemplate() &&
+ Cand2.Function && Cand2.Function->getPrimaryTemplate())
+ if (FunctionTemplateDecl *BetterTemplate
+ = getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
+ Cand2.Function->getPrimaryTemplate(),
+ isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion
+ : TPOC_Call))
+ return BetterTemplate == Cand1.Function->getPrimaryTemplate();
- // C++ [over.match.best]p1b4:
- //
// -- the context is an initialization by user-defined conversion
// (see 8.5, 13.3.1.5) and the standard conversion sequence
// from the return type of F1 to the destination type (i.e.,
// the type of the entity being initialized) is a better
// conversion sequence than the standard conversion sequence
// from the return type of F2 to the destination type.
- if (Cand1.Function && Cand2.Function &&
- isa<CXXConversionDecl>(Cand1.Function) &&
+ if (Cand1.Function && Cand2.Function &&
+ isa<CXXConversionDecl>(Cand1.Function) &&
isa<CXXConversionDecl>(Cand2.Function)) {
switch (CompareStandardConversionSequences(Cand1.FinalConversion,
Cand2.FinalConversion)) {
@@ -3533,7 +3919,7 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
return false;
}
-/// \brief Computes the best viable function (C++ 13.3.3)
+/// \brief Computes the best viable function (C++ 13.3.3)
/// within an overload candidate set.
///
/// \param CandidateSet the set of candidate functions.
@@ -3541,15 +3927,14 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
/// \param Loc the location of the function name (or operator symbol) for
/// which overload resolution occurs.
///
-/// \param Best f overload resolution was successful or found a deleted
+/// \param Best f overload resolution was successful or found a deleted
/// function, Best points to the candidate function found.
///
/// \returns The result of overload resolution.
-Sema::OverloadingResult
+Sema::OverloadingResult
Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
SourceLocation Loc,
- OverloadCandidateSet::iterator& Best)
-{
+ OverloadCandidateSet::iterator& Best) {
// Find the best viable function.
Best = CandidateSet.end();
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
@@ -3568,24 +3953,24 @@ Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
// function. If not, we have an ambiguity.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
Cand != CandidateSet.end(); ++Cand) {
- if (Cand->Viable &&
+ if (Cand->Viable &&
Cand != Best &&
!isBetterOverloadCandidate(*Best, *Cand)) {
Best = CandidateSet.end();
return OR_Ambiguous;
}
}
-
+
// Best is the best viable function.
if (Best->Function &&
- (Best->Function->isDeleted() ||
+ (Best->Function->isDeleted() ||
Best->Function->getAttr<UnavailableAttr>()))
return OR_Deleted;
// C++ [basic.def.odr]p2:
// An overloaded function is used if it is selected by overload resolution
- // when referred to from a potentially-evaluated expression. [Note: this
- // covers calls to named functions (5.2.2), operator overloading
+ // when referred to from a potentially-evaluated expression. [Note: this
+ // covers calls to named functions (5.2.2), operator overloading
// (clause 13), user-defined conversions (12.3.2), allocation function for
// placement new (5.3.4), as well as non-default initialization (8.5).
if (Best->Function)
@@ -3596,12 +3981,14 @@ Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
/// PrintOverloadCandidates - When overload resolution fails, prints
/// diagnostic messages containing the candidates in the candidate
/// set. If OnlyViable is true, only viable candidates will be printed.
-void
+void
Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
- bool OnlyViable)
-{
+ bool OnlyViable,
+ const char *Opc,
+ SourceLocation OpLoc) {
OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
LastCand = CandidateSet.end();
+ bool Reported = false;
for (; Cand != LastCand; ++Cand) {
if (Cand->Viable || !OnlyViable) {
if (Cand->Function) {
@@ -3610,10 +3997,36 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
// Deleted or "unavailable" function.
Diag(Cand->Function->getLocation(), diag::err_ovl_candidate_deleted)
<< Cand->Function->isDeleted();
+ } else if (FunctionTemplateDecl *FunTmpl
+ = Cand->Function->getPrimaryTemplate()) {
+ // Function template specialization
+ // FIXME: Give a better reason!
+ Diag(Cand->Function->getLocation(), diag::err_ovl_template_candidate)
+ << getTemplateArgumentBindingsText(FunTmpl->getTemplateParameters(),
+ *Cand->Function->getTemplateSpecializationArgs());
} else {
// Normal function
- // FIXME: Give a better reason!
- Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
+ bool errReported = false;
+ if (!Cand->Viable && Cand->Conversions.size() > 0) {
+ for (int i = Cand->Conversions.size()-1; i >= 0; i--) {
+ const ImplicitConversionSequence &Conversion =
+ Cand->Conversions[i];
+ if ((Conversion.ConversionKind !=
+ ImplicitConversionSequence::BadConversion) ||
+ Conversion.ConversionFunctionSet.size() == 0)
+ continue;
+ Diag(Cand->Function->getLocation(),
+ diag::err_ovl_candidate_not_viable) << (i+1);
+ errReported = true;
+ for (int j = Conversion.ConversionFunctionSet.size()-1;
+ j >= 0; j--) {
+ FunctionDecl *Func = Conversion.ConversionFunctionSet[j];
+ Diag(Func->getLocation(), diag::err_ovl_candidate);
+ }
+ }
+ }
+ if (!errReported)
+ Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
}
} else if (Cand->IsSurrogate) {
// Desugar the type of the surrogate down to a function type,
@@ -3624,20 +4037,20 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
bool isRValueReference = false;
bool isPointer = false;
if (const LValueReferenceType *FnTypeRef =
- FnType->getAsLValueReferenceType()) {
+ FnType->getAs<LValueReferenceType>()) {
FnType = FnTypeRef->getPointeeType();
isLValueReference = true;
} else if (const RValueReferenceType *FnTypeRef =
- FnType->getAsRValueReferenceType()) {
+ FnType->getAs<RValueReferenceType>()) {
FnType = FnTypeRef->getPointeeType();
isRValueReference = true;
}
- if (const PointerType *FnTypePtr = FnType->getAsPointerType()) {
+ if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) {
FnType = FnTypePtr->getPointeeType();
isPointer = true;
}
// Desugar down to a function type.
- FnType = QualType(FnType->getAsFunctionType(), 0);
+ FnType = QualType(FnType->getAs<FunctionType>(), 0);
// Reconstruct the pointer/reference as appropriate.
if (isPointer) FnType = Context.getPointerType(FnType);
if (isRValueReference) FnType = Context.getRValueReferenceType(FnType);
@@ -3645,17 +4058,42 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand)
<< FnType;
- } else {
- // FIXME: We need to get the identifier in here
- // FIXME: Do we want the error message to point at the operator?
- // (built-ins won't have a location)
- QualType FnType
- = Context.getFunctionType(Cand->BuiltinTypes.ResultTy,
- Cand->BuiltinTypes.ParamTypes,
- Cand->Conversions.size(),
- false, 0);
-
- Diag(SourceLocation(), diag::err_ovl_builtin_candidate) << FnType;
+ } else if (OnlyViable) {
+ assert(Cand->Conversions.size() <= 2 &&
+ "builtin-binary-operator-not-binary");
+ if (Cand->Conversions.size() == 1)
+ Diag(OpLoc, diag::err_ovl_builtin_unary_candidate)
+ << Opc << Cand->BuiltinTypes.ParamTypes[0];
+ else
+ Diag(OpLoc, diag::err_ovl_builtin_binary_candidate)
+ << Opc << Cand->BuiltinTypes.ParamTypes[0]
+ << Cand->BuiltinTypes.ParamTypes[1];
+ }
+ else if (!Cand->Viable && !Reported) {
+ // Non-viability might be due to ambiguous user-defined conversions,
+ // needed for built-in operators. Report them as well, but only once
+ // as we have typically many built-in candidates.
+ unsigned NoOperands = Cand->Conversions.size();
+ for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
+ const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
+ if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion ||
+ ICS.ConversionFunctionSet.empty())
+ continue;
+ if (CXXConversionDecl *Func = dyn_cast<CXXConversionDecl>(
+ Cand->Conversions[ArgIdx].ConversionFunctionSet[0])) {
+ QualType FromTy =
+ QualType(
+ static_cast<Type*>(ICS.UserDefined.Before.FromTypePtr),0);
+ Diag(OpLoc,diag::note_ambiguous_type_conversion)
+ << FromTy << Func->getConversionType();
+ }
+ for (unsigned j = 0; j < ICS.ConversionFunctionSet.size(); j++) {
+ FunctionDecl *Func =
+ Cand->Conversions[ArgIdx].ConversionFunctionSet[j];
+ Diag(Func->getLocation(),diag::err_ovl_candidate);
+ }
+ }
+ Reported = true;
}
}
}
@@ -3669,7 +4107,7 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
/// @code
/// int f(double);
/// int f(int);
-///
+///
/// int (*pfd)(double) = f; // selects f(double)
/// @endcode
///
@@ -3681,23 +4119,24 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain) {
QualType FunctionType = ToType;
bool IsMember = false;
- if (const PointerType *ToTypePtr = ToType->getAsPointerType())
+ if (const PointerType *ToTypePtr = ToType->getAs<PointerType>())
FunctionType = ToTypePtr->getPointeeType();
- else if (const ReferenceType *ToTypeRef = ToType->getAsReferenceType())
+ else if (const ReferenceType *ToTypeRef = ToType->getAs<ReferenceType>())
FunctionType = ToTypeRef->getPointeeType();
else if (const MemberPointerType *MemTypePtr =
- ToType->getAsMemberPointerType()) {
+ ToType->getAs<MemberPointerType>()) {
FunctionType = MemTypePtr->getPointeeType();
IsMember = true;
}
// We only look at pointers or references to functions.
- if (!FunctionType->isFunctionType())
+ FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType();
+ if (!FunctionType->isFunctionType())
return 0;
// Find the actual overloaded function declaration.
OverloadedFunctionDecl *Ovl = 0;
-
+
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
// overloaded function name is ignored (5.1). ]
@@ -3712,27 +4151,76 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
}
// Try to dig out the overloaded function.
- if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr))
+ FunctionTemplateDecl *FunctionTemplate = 0;
+ if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) {
Ovl = dyn_cast<OverloadedFunctionDecl>(DR->getDecl());
+ FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DR->getDecl());
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(OvlExpr)) {
+ Ovl = dyn_cast<OverloadedFunctionDecl>(ME->getMemberDecl());
+ FunctionTemplate = dyn_cast<FunctionTemplateDecl>(ME->getMemberDecl());
+ // FIXME: Explicit template arguments
+ }
+ // FIXME: TemplateIdRefExpr?
- // If there's no overloaded function declaration, we're done.
- if (!Ovl)
+ // If there's no overloaded function declaration or function template,
+ // we're done.
+ if (!Ovl && !FunctionTemplate)
return 0;
-
+
+ OverloadIterator Fun;
+ if (Ovl)
+ Fun = Ovl;
+ else
+ Fun = FunctionTemplate;
+
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
- // FIXME: When templates or using declarations come along, we'll actually
- // have to deal with duplicates, partial ordering, etc. For now, we
- // can just do a simple search.
- FunctionType = Context.getCanonicalType(FunctionType.getUnqualifiedType());
- for (OverloadedFunctionDecl::function_iterator Fun = Ovl->function_begin();
- Fun != Ovl->function_end(); ++Fun) {
+ llvm::SmallPtrSet<FunctionDecl *, 4> Matches;
+ bool FoundNonTemplateFunction = false;
+ for (OverloadIterator FunEnd; Fun != FunEnd; ++Fun) {
// C++ [over.over]p3:
// Non-member functions and static member functions match
// targets of type "pointer-to-function" or "reference-to-function."
// Nonstatic member functions match targets of
// type "pointer-to-member-function."
// Note that according to DR 247, the containing class does not matter.
+
+ if (FunctionTemplateDecl *FunctionTemplate
+ = dyn_cast<FunctionTemplateDecl>(*Fun)) {
+ if (CXXMethodDecl *Method
+ = dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) {
+ // Skip non-static function templates when converting to pointer, and
+ // static when converting to member pointer.
+ if (Method->isStatic() == IsMember)
+ continue;
+ } else if (IsMember)
+ continue;
+
+ // C++ [over.over]p2:
+ // If the name is a function template, template argument deduction is
+ // done (14.8.2.2), and if the argument deduction succeeds, the
+ // resulting template argument list is used to generate a single
+ // function template specialization, which is added to the set of
+ // overloaded functions considered.
+ // FIXME: We don't really want to build the specialization here, do we?
+ FunctionDecl *Specialization = 0;
+ TemplateDeductionInfo Info(Context);
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArguments(FunctionTemplate, /*FIXME*/false,
+ /*FIXME:*/0, /*FIXME:*/0,
+ FunctionType, Specialization, Info)) {
+ // FIXME: make a note of the failed deduction for diagnostics.
+ (void)Result;
+ } else {
+ // FIXME: If the match isn't exact, shouldn't we just drop this as
+ // a candidate? Find a testcase before changing the code.
+ assert(FunctionType
+ == Context.getCanonicalType(Specialization->getType()));
+ Matches.insert(
+ cast<FunctionDecl>(Specialization->getCanonicalDecl()));
+ }
+ }
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Fun)) {
// Skip non-static functions when converting to pointer, and static
// when converting to member pointer.
@@ -3742,38 +4230,106 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
continue;
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Fun)) {
- if (FunctionType == Context.getCanonicalType(FunDecl->getType()))
- return FunDecl;
- } else {
- unsigned DiagID
- = PP.getDiagnostics().getCustomDiagID(Diagnostic::Warning,
- "Clang does not yet support templated conversion functions");
- Diag(From->getLocStart(), DiagID);
+ if (FunctionType == Context.getCanonicalType(FunDecl->getType())) {
+ Matches.insert(cast<FunctionDecl>(Fun->getCanonicalDecl()));
+ FoundNonTemplateFunction = true;
+ }
}
}
+ // If there were 0 or 1 matches, we're done.
+ if (Matches.empty())
+ return 0;
+ else if (Matches.size() == 1)
+ return *Matches.begin();
+
+ // C++ [over.over]p4:
+ // If more than one function is selected, [...]
+ typedef llvm::SmallPtrSet<FunctionDecl *, 4>::iterator MatchIter;
+ if (!FoundNonTemplateFunction) {
+ // [...] and any given function template specialization F1 is
+ // eliminated if the set contains a second function template
+ // specialization whose function template is more specialized
+ // than the function template of F1 according to the partial
+ // ordering rules of 14.5.5.2.
+
+ // The algorithm specified above is quadratic. We instead use a
+ // two-pass algorithm (similar to the one used to identify the
+ // best viable function in an overload set) that identifies the
+ // best function template (if it exists).
+ llvm::SmallVector<FunctionDecl *, 8> TemplateMatches(Matches.begin(),
+ Matches.end());
+ return getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(),
+ TPOC_Other, From->getLocStart(),
+ PDiag(),
+ PDiag(diag::err_addr_ovl_ambiguous)
+ << TemplateMatches[0]->getDeclName(),
+ PDiag(diag::err_ovl_template_candidate));
+ }
+
+ // [...] any function template specializations in the set are
+ // eliminated if the set also contains a non-template function, [...]
+ llvm::SmallVector<FunctionDecl *, 4> RemainingMatches;
+ for (MatchIter M = Matches.begin(), MEnd = Matches.end(); M != MEnd; ++M)
+ if ((*M)->getPrimaryTemplate() == 0)
+ RemainingMatches.push_back(*M);
+
+ // [...] After such eliminations, if any, there shall remain exactly one
+ // selected function.
+ if (RemainingMatches.size() == 1)
+ return RemainingMatches.front();
+
+ // FIXME: We should probably return the same thing that BestViableFunction
+ // returns (even if we issue the diagnostics here).
+ Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
+ << RemainingMatches[0]->getDeclName();
+ for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I)
+ Diag(RemainingMatches[I]->getLocation(), diag::err_ovl_candidate);
return 0;
}
-/// ResolveOverloadedCallFn - Given the call expression that calls Fn
-/// (which eventually refers to the declaration Func) and the call
-/// arguments Args/NumArgs, attempt to resolve the function call down
-/// to a specific function. If overload resolution succeeds, returns
-/// the function declaration produced by overload
-/// resolution. Otherwise, emits diagnostics, deletes all of the
-/// arguments and Fn, and returns NULL.
-FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
- DeclarationName UnqualifiedName,
- bool HasExplicitTemplateArgs,
+/// \brief Add a single candidate to the overload set.
+static void AddOverloadedCallCandidate(Sema &S,
+ AnyFunctionDecl Callee,
+ bool &ArgumentDependentLookup,
+ bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
- SourceLocation *CommaLocs,
- SourceLocation RParenLoc,
- bool &ArgumentDependentLookup) {
- OverloadCandidateSet CandidateSet;
-
+ unsigned NumExplicitTemplateArgs,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet,
+ bool PartialOverloading) {
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
+ assert(!HasExplicitTemplateArgs && "Explicit template arguments?");
+ S.AddOverloadCandidate(Func, Args, NumArgs, CandidateSet, false, false,
+ PartialOverloading);
+
+ if (Func->getDeclContext()->isRecord() ||
+ Func->getDeclContext()->isFunctionOrMethod())
+ ArgumentDependentLookup = false;
+ return;
+ }
+
+ FunctionTemplateDecl *FuncTemplate = cast<FunctionTemplateDecl>(Callee);
+ S.AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ Args, NumArgs, CandidateSet);
+
+ if (FuncTemplate->getDeclContext()->isRecord())
+ ArgumentDependentLookup = false;
+}
+
+/// \brief Add the overload candidates named by callee and/or found by argument
+/// dependent lookup to the given overload set.
+void Sema::AddOverloadedCallCandidates(NamedDecl *Callee,
+ DeclarationName &UnqualifiedName,
+ bool &ArgumentDependentLookup,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet,
+ bool PartialOverloading) {
// Add the functions denoted by Callee to the set of candidate
// functions. While we're doing so, track whether argument-dependent
// lookup still applies, per:
@@ -3783,66 +4339,75 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
// and let Y be the lookup set produced by argument dependent
// lookup (defined as follows). If X contains
//
- // -- a declaration of a class member, or
+ // -- a declaration of a class member, or
//
// -- a block-scope function declaration that is not a
- // using-declaration, or
- //
+ // using-declaration (FIXME: check for using declaration), or
+ //
// -- a declaration that is neither a function or a function
// template
//
- // then Y is empty.
- if (OverloadedFunctionDecl *Ovl
- = dyn_cast_or_null<OverloadedFunctionDecl>(Callee)) {
+ // then Y is empty.
+ if (!Callee) {
+ // Nothing to do.
+ } else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(Callee)) {
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
- Func != FuncEnd; ++Func) {
- DeclContext *Ctx = 0;
- if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Func)) {
- if (HasExplicitTemplateArgs)
- continue;
-
- AddOverloadCandidate(FunDecl, Args, NumArgs, CandidateSet);
- Ctx = FunDecl->getDeclContext();
- } else {
- FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*Func);
- AddTemplateOverloadCandidate(FunTmpl, HasExplicitTemplateArgs,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- Args, NumArgs, CandidateSet);
- Ctx = FunTmpl->getDeclContext();
- }
-
-
- if (Ctx->isRecord() || Ctx->isFunctionOrMethod())
- ArgumentDependentLookup = false;
- }
- } else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) {
- assert(!HasExplicitTemplateArgs && "Explicit template arguments?");
- AddOverloadCandidate(Func, Args, NumArgs, CandidateSet);
-
- if (Func->getDeclContext()->isRecord() ||
- Func->getDeclContext()->isFunctionOrMethod())
- ArgumentDependentLookup = false;
- } else if (FunctionTemplateDecl *FuncTemplate
- = dyn_cast_or_null<FunctionTemplateDecl>(Callee)) {
- AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- Args, NumArgs, CandidateSet);
-
- if (FuncTemplate->getDeclContext()->isRecord())
- ArgumentDependentLookup = false;
- }
-
+ Func != FuncEnd; ++Func)
+ AddOverloadedCallCandidate(*this, *Func, ArgumentDependentLookup,
+ HasExplicitTemplateArgs,
+ ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ Args, NumArgs, CandidateSet,
+ PartialOverloading);
+ } else if (isa<FunctionDecl>(Callee) || isa<FunctionTemplateDecl>(Callee))
+ AddOverloadedCallCandidate(*this,
+ AnyFunctionDecl::getFromNamedDecl(Callee),
+ ArgumentDependentLookup,
+ HasExplicitTemplateArgs,
+ ExplicitTemplateArgs, NumExplicitTemplateArgs,
+ Args, NumArgs, CandidateSet,
+ PartialOverloading);
+ // FIXME: assert isa<FunctionDecl> || isa<FunctionTemplateDecl> rather than
+ // checking dynamically.
+
if (Callee)
UnqualifiedName = Callee->getDeclName();
-
- // FIXME: Pass explicit template arguments through for ADL
+
if (ArgumentDependentLookup)
AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs,
- CandidateSet);
+ HasExplicitTemplateArgs,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ CandidateSet,
+ PartialOverloading);
+}
+
+/// ResolveOverloadedCallFn - Given the call expression that calls Fn
+/// (which eventually refers to the declaration Func) and the call
+/// arguments Args/NumArgs, attempt to resolve the function call down
+/// to a specific function. If overload resolution succeeds, returns
+/// the function declaration produced by overload
+/// resolution. Otherwise, emits diagnostics, deletes all of the
+/// arguments and Fn, and returns NULL.
+FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
+ DeclarationName UnqualifiedName,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc,
+ bool &ArgumentDependentLookup) {
+ OverloadCandidateSet CandidateSet;
+ // Add the functions denoted by Callee to the set of candidate
+ // functions.
+ AddOverloadedCallCandidates(Callee, UnqualifiedName, ArgumentDependentLookup,
+ HasExplicitTemplateArgs, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs, Args, NumArgs,
+ CandidateSet);
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) {
case OR_Success:
@@ -3897,7 +4462,7 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
unsigned OpcIn,
FunctionSet &Functions,
- ExprArg input) {
+ ExprArg input) {
UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
Expr *Input = (Expr *)input.get();
@@ -3907,28 +4472,28 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
Expr *Args[2] = { Input, 0 };
unsigned NumArgs = 1;
-
+
// For post-increment and post-decrement, add the implicit '0' as
// the second argument, so that we know this is a post-increment or
// post-decrement.
if (Opc == UnaryOperator::PostInc || Opc == UnaryOperator::PostDec) {
llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false);
- Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy,
+ Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy,
SourceLocation());
NumArgs = 2;
}
if (Input->isTypeDependent()) {
- OverloadedFunctionDecl *Overloads
+ OverloadedFunctionDecl *Overloads
= OverloadedFunctionDecl::Create(Context, CurContext, OpName);
- for (FunctionSet::iterator Func = Functions.begin(),
+ for (FunctionSet::iterator Func = Functions.begin(),
FuncEnd = Functions.end();
Func != FuncEnd; ++Func)
Overloads->addOverload(*Func);
DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
OpLoc, false, false);
-
+
input.release();
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
&Args[0], NumArgs,
@@ -3954,11 +4519,11 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
case OR_Success: {
// We found a built-in operator or an overloaded operator.
FunctionDecl *FnDecl = Best->Function;
-
+
if (FnDecl) {
// We matched an overloaded operator. Build a call to that
// operator.
-
+
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
if (PerformObjectArgumentInitialization(Input, Method))
@@ -3972,19 +4537,24 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
}
// Determine the result type
- QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
- ResultTy = ResultTy.getNonReferenceType();
-
+ QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
+
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
SourceLocation());
UsualUnaryConversions(FnExpr);
-
+
input.release();
- return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
- &Input, 1, ResultTy,
- OpLoc));
+
+ ExprOwningPtr<CallExpr> TheCall(this,
+ new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
+ &Input, 1, ResultTy, OpLoc));
+
+ if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
+ FnDecl))
+ return ExprError();
+
+ return MaybeBindToTemporary(TheCall.release());
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -4006,7 +4576,8 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true,
+ UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
case OR_Deleted:
@@ -4042,12 +4613,13 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
///
/// \param LHS Left-hand argument.
/// \param RHS Right-hand argument.
-Sema::OwningExprResult
+Sema::OwningExprResult
Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
- unsigned OpcIn,
+ unsigned OpcIn,
FunctionSet &Functions,
Expr *LHS, Expr *RHS) {
Expr *Args[2] = { LHS, RHS };
+ LHS=RHS=0; //Please use only Args instead of LHS/RHS couple
BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn);
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
@@ -4055,24 +4627,24 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// If either side is type-dependent, create an appropriate dependent
// expression.
- if (LHS->isTypeDependent() || RHS->isTypeDependent()) {
+ if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
// .* cannot be overloaded.
if (Opc == BinaryOperator::PtrMemD)
- return Owned(new (Context) BinaryOperator(LHS, RHS, Opc,
+ return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc,
Context.DependentTy, OpLoc));
- OverloadedFunctionDecl *Overloads
+ OverloadedFunctionDecl *Overloads
= OverloadedFunctionDecl::Create(Context, CurContext, OpName);
- for (FunctionSet::iterator Func = Functions.begin(),
+ for (FunctionSet::iterator Func = Functions.begin(),
FuncEnd = Functions.end();
Func != FuncEnd; ++Func)
Overloads->addOverload(*Func);
DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
OpLoc, false, false);
-
+
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
- Args, 2,
+ Args, 2,
Context.DependentTy,
OpLoc));
}
@@ -4080,14 +4652,14 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// If this is the .* operator, which is not overloadable, just
// create a built-in binary operator.
if (Opc == BinaryOperator::PtrMemD)
- return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
+ return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// If this is one of the assignment operators, we only perform
// overload resolution if the left-hand side is a class or
// enumeration type (C++ [expr.ass]p3).
if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign &&
- !LHS->getType()->isOverloadableType())
- return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
+ !Args[0]->getType()->isOverloadableType())
+ return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build an empty overload set.
OverloadCandidateSet CandidateSet;
@@ -4114,39 +4686,46 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
- if (PerformObjectArgumentInitialization(LHS, Method) ||
- PerformCopyInitialization(RHS, FnDecl->getParamDecl(0)->getType(),
+ if (PerformObjectArgumentInitialization(Args[0], Method) ||
+ PerformCopyInitialization(Args[1], FnDecl->getParamDecl(0)->getType(),
"passing"))
return ExprError();
} else {
// Convert the arguments.
- if (PerformCopyInitialization(LHS, FnDecl->getParamDecl(0)->getType(),
+ if (PerformCopyInitialization(Args[0], FnDecl->getParamDecl(0)->getType(),
"passing") ||
- PerformCopyInitialization(RHS, FnDecl->getParamDecl(1)->getType(),
+ PerformCopyInitialization(Args[1], FnDecl->getParamDecl(1)->getType(),
"passing"))
return ExprError();
}
// Determine the result type
QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
+ = FnDecl->getType()->getAs<FunctionType>()->getResultType();
ResultTy = ResultTy.getNonReferenceType();
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
- SourceLocation());
+ OpLoc);
UsualUnaryConversions(FnExpr);
- return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
- Args, 2, ResultTy,
- OpLoc));
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
+ Args, 2, ResultTy,
+ OpLoc));
+
+ if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
+ FnDecl))
+ return ExprError();
+
+ return MaybeBindToTemporary(TheCall.release());
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
// operator node.
- if (PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0],
+ if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
Best->Conversions[0], "passing") ||
- PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1],
+ PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
Best->Conversions[1], "passing"))
return ExprError();
@@ -4154,40 +4733,55 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
}
}
- case OR_No_Viable_Function:
+ case OR_No_Viable_Function: {
+ // C++ [over.match.oper]p9:
+ // If the operator is the operator , [...] and there are no
+ // viable functions, then the operator is assumed to be the
+ // built-in operator and interpreted according to clause 5.
+ if (Opc == BinaryOperator::Comma)
+ break;
+
// For class as left operand for assignment or compound assigment operator
// do not fall through to handling in built-in, but report that no overloaded
// assignment operator found
- if (LHS->getType()->isRecordType() && Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign) {
+ OwningExprResult Result = ExprError();
+ if (Args[0]->getType()->isRecordType() &&
+ Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign) {
Diag(OpLoc, diag::err_ovl_no_viable_oper)
<< BinaryOperator::getOpcodeStr(Opc)
- << LHS->getSourceRange() << RHS->getSourceRange();
- return ExprError();
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ } else {
+ // No viable function; try to create a built-in operation, which will
+ // produce an error. Then, show the non-viable candidates.
+ Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
- // No viable function; fall through to handling this as a
- // built-in operator, which will produce an error message for us.
- break;
+ assert(Result.isInvalid() &&
+ "C++ binary operator overloading is missing candidates!");
+ if (Result.isInvalid())
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false,
+ BinaryOperator::getOpcodeStr(Opc), OpLoc);
+ return move(Result);
+ }
case OR_Ambiguous:
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< BinaryOperator::getOpcodeStr(Opc)
- << LHS->getSourceRange() << RHS->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true,
+ BinaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
case OR_Deleted:
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
<< BinaryOperator::getOpcodeStr(Opc)
- << LHS->getSourceRange() << RHS->getSourceRange();
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return ExprError();
}
- // Either we found no viable overloaded operator or we matched a
- // built-in operator. In either case, try to build a built-in
- // operation.
- return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
+ // We matched a built-in operator; build it.
+ return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
/// BuildCallToMemberFunction - Build a call to a member
@@ -4198,8 +4792,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
/// expression refers to a member function or an overloaded member
/// function.
Sema::ExprResult
-Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
- SourceLocation LParenLoc, Expr **Args,
+Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
+ SourceLocation LParenLoc, Expr **Args,
unsigned NumArgs, SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
// Dig out the member expression. This holds both the object
@@ -4215,17 +4809,25 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Expr *ObjectArg = MemExpr->getBase();
CXXMethodDecl *Method = 0;
- if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(MemExpr->getMemberDecl())) {
+ if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
+ isa<FunctionTemplateDecl>(MemExpr->getMemberDecl())) {
// Add overload candidates
OverloadCandidateSet CandidateSet;
- for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
- FuncEnd = Ovl->function_end();
+ DeclarationName DeclName = MemExpr->getMemberDecl()->getDeclName();
+
+ for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd;
Func != FuncEnd; ++Func) {
- assert(isa<CXXMethodDecl>(*Func) && "Function is not a method");
- Method = cast<CXXMethodDecl>(*Func);
- AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
- /*SuppressUserConversions=*/false);
+ if ((Method = dyn_cast<CXXMethodDecl>(*Func)))
+ AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ else
+ AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func),
+ MemExpr->hasExplicitTemplateArgumentList(),
+ MemExpr->getTemplateArgs(),
+ MemExpr->getNumTemplateArgs(),
+ ObjectArg, Args, NumArgs,
+ CandidateSet,
+ /*SuppressUsedConversions=*/false);
}
OverloadCandidateSet::iterator Best;
@@ -4235,26 +4837,26 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
break;
case OR_No_Viable_Function:
- Diag(MemExpr->getSourceRange().getBegin(),
+ Diag(MemExpr->getSourceRange().getBegin(),
diag::err_ovl_no_viable_member_function_in_call)
- << Ovl->getDeclName() << MemExprE->getSourceRange();
+ << DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
return true;
case OR_Ambiguous:
- Diag(MemExpr->getSourceRange().getBegin(),
+ Diag(MemExpr->getSourceRange().getBegin(),
diag::err_ovl_ambiguous_member_call)
- << Ovl->getDeclName() << MemExprE->getSourceRange();
+ << DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
return true;
case OR_Deleted:
- Diag(MemExpr->getSourceRange().getBegin(),
+ Diag(MemExpr->getSourceRange().getBegin(),
diag::err_ovl_deleted_member_call)
<< Best->Function->isDeleted()
- << Ovl->getDeclName() << MemExprE->getSourceRange();
+ << DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
return true;
@@ -4266,43 +4868,51 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
}
assert(Method && "Member call to something that isn't a method?");
- ExprOwningPtr<CXXMemberCallExpr>
+ ExprOwningPtr<CXXMemberCallExpr>
TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args,
- NumArgs,
+ NumArgs,
Method->getResultType().getNonReferenceType(),
RParenLoc));
+ // Check for a valid return type.
+ if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(),
+ TheCall.get(), Method))
+ return true;
+
// Convert the object argument (for a non-static member function call).
- if (!Method->isStatic() &&
+ if (!Method->isStatic() &&
PerformObjectArgumentInitialization(ObjectArg, Method))
return true;
MemExpr->setBase(ObjectArg);
// Convert the rest of the arguments
const FunctionProtoType *Proto = cast<FunctionProtoType>(Method->getType());
- if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs,
+ if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs,
RParenLoc))
return true;
- return CheckFunctionCall(Method, TheCall.take()).release();
+ if (CheckFunctionCall(Method, TheCall.get()))
+ return true;
+
+ return MaybeBindToTemporary(TheCall.release()).release();
}
/// BuildCallToObjectOfClassType - Build a call to an object of class
/// type (C++ [over.call.object]), which can end up invoking an
/// overloaded function call operator (@c operator()) or performing a
/// user-defined conversion on the object argument.
-Sema::ExprResult
-Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
+Sema::ExprResult
+Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
- SourceLocation *CommaLocs,
+ SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
assert(Object->getType()->isRecordType() && "Requires object type argument");
- const RecordType *Record = Object->getType()->getAsRecordType();
-
+ const RecordType *Record = Object->getType()->getAs<RecordType>();
+
// C++ [over.call.object]p1:
// If the primary-expression E in the function call syntax
- // evaluates to a class object of type “cv T”, then the set of
+ // evaluates to a class object of type "cv T", then the set of
// candidate functions includes at least the function call
// operators of T. The function call operators of T are obtained by
// ordinary lookup of the name operator() in the context of
@@ -4312,7 +4922,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
DeclContext::lookup_const_iterator Oper, OperEnd;
for (llvm::tie(Oper, OperEnd) = Record->getDecl()->lookup(OpName);
Oper != OperEnd; ++Oper)
- AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs,
+ AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs,
CandidateSet, /*SuppressUserConversions=*/false);
// C++ [over.call.object]p2:
@@ -4332,24 +4942,33 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// functions for each conversion function declared in an
// accessible base class provided the function is not hidden
// within T by another intervening declaration.
- //
- // FIXME: Look in base classes for more conversion operators!
- OverloadedFunctionDecl *Conversions
- = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator
- Func = Conversions->function_begin(),
- FuncEnd = Conversions->function_end();
- Func != FuncEnd; ++Func) {
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
- // Strip the reference type (if any) and then the pointer type (if
- // any) to get down to what might be a function type.
- QualType ConvType = Conv->getConversionType().getNonReferenceType();
- if (const PointerType *ConvPtrType = ConvType->getAsPointerType())
- ConvType = ConvPtrType->getPointeeType();
+ if (!RequireCompleteType(SourceLocation(), Object->getType(), 0)) {
+ // FIXME: Look in base classes for more conversion operators!
+ OverloadedFunctionDecl *Conversions
+ = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator
+ Func = Conversions->function_begin(),
+ FuncEnd = Conversions->function_end();
+ Func != FuncEnd; ++Func) {
+ CXXConversionDecl *Conv;
+ FunctionTemplateDecl *ConvTemplate;
+ GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+
+ // Skip over templated conversion functions; they aren't
+ // surrogates.
+ if (ConvTemplate)
+ continue;
+
+ // Strip the reference type (if any) and then the pointer type (if
+ // any) to get down to what might be a function type.
+ QualType ConvType = Conv->getConversionType().getNonReferenceType();
+ if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
+ ConvType = ConvPtrType->getPointeeType();
- if (const FunctionProtoType *Proto = ConvType->getAsFunctionProtoType())
- AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet);
+ if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
+ AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet);
+ }
}
// Perform overload resolution.
@@ -4361,7 +4980,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
break;
case OR_No_Viable_Function:
- Diag(Object->getSourceRange().getBegin(),
+ Diag(Object->getSourceRange().getBegin(),
diag::err_ovl_no_viable_object_call)
<< Object->getType() << Object->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
@@ -4381,7 +5000,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
<< Object->getType() << Object->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
break;
- }
+ }
if (Best == CandidateSet.end()) {
// We had an error; delete all of the subexpressions and return
@@ -4395,18 +5014,20 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
if (Best->Function == 0) {
// Since there is no function declaration, this is one of the
// surrogate candidates. Dig out the conversion function.
- CXXConversionDecl *Conv
+ CXXConversionDecl *Conv
= cast<CXXConversionDecl>(
Best->Conversions[0].UserDefined.ConversionFunction);
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
// on the object argument, then let ActOnCallExpr finish the job.
- // FIXME: Represent the user-defined conversion in the AST!
- ImpCastExprToType(Object,
- Conv->getConversionType().getNonReferenceType(),
- Conv->getConversionType()->isLValueReferenceType());
- return ActOnCallExpr(S, ExprArg(*this, Object), LParenLoc,
+
+ // Create an implicit member expr to refer to the conversion operator.
+ // and then call it.
+ CXXMemberCallExpr *CE =
+ BuildCXXMemberCallExpr(Object, Conv);
+
+ return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc,
MultiExprArg(*this, (ExprTy**)Args, NumArgs),
CommaLocs, RParenLoc).release();
}
@@ -4415,7 +5036,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// that calls this method, using Object for the implicit object
// parameter and passing along the remaining arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
- const FunctionProtoType *Proto = Method->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *Proto = Method->getType()->getAs<FunctionProtoType>();
unsigned NumArgsInProto = Proto->getNumArgs();
unsigned NumArgsToCheck = NumArgs;
@@ -4433,20 +5054,24 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
MethodArgs[0] = Object;
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
MethodArgs[ArgIdx + 1] = Args[ArgIdx];
-
- Expr *NewFn = new (Context) DeclRefExpr(Method, Method->getType(),
+
+ Expr *NewFn = new (Context) DeclRefExpr(Method, Method->getType(),
SourceLocation());
UsualUnaryConversions(NewFn);
// Once we've built TheCall, all of the expressions are properly
// owned.
QualType ResultTy = Method->getResultType().getNonReferenceType();
- ExprOwningPtr<CXXOperatorCallExpr>
- TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn,
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn,
MethodArgs, NumArgs + 1,
ResultTy, RParenLoc));
delete [] MethodArgs;
+ if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall.get(),
+ Method))
+ return true;
+
// We may have default arguments. If so, we need to allocate more
// slots in the call for them.
if (NumArgs < NumArgsInProto)
@@ -4466,12 +5091,12 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
Expr *Arg;
if (i < NumArgs) {
Arg = Args[i];
-
+
// Pass the argument.
QualType ProtoArgType = Proto->getArgType(i);
IsError |= PerformCopyInitialization(Arg, ProtoArgType, "passing");
} else {
- Arg = new (Context) CXXDefaultArgExpr(Method->getParamDecl(i));
+ Arg = CXXDefaultArgExpr::Create(Context, Method->getParamDecl(i));
}
TheCall->setArg(i + 1, Arg);
@@ -4489,37 +5114,38 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
if (IsError) return true;
- return CheckFunctionCall(Method, TheCall.take()).release();
+ if (CheckFunctionCall(Method, TheCall.get()))
+ return true;
+
+ return MaybeBindToTemporary(TheCall.release()).release();
}
/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator->
-/// (if one exists), where @c Base is an expression of class type and
+/// (if one exists), where @c Base is an expression of class type and
/// @c Member is the name of the member we're trying to find.
-Action::ExprResult
-Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
- SourceLocation MemberLoc,
- IdentifierInfo &Member) {
+Sema::OwningExprResult
+Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
+ Expr *Base = static_cast<Expr *>(BaseIn.get());
assert(Base->getType()->isRecordType() && "left-hand side must have class type");
-
+
// C++ [over.ref]p1:
//
// [...] An expression x->m is interpreted as (x.operator->())->m
// for a class object x of type T if T::operator->() exists and if
// the operator is selected as the best match function by the
// overload resolution mechanism (13.3).
- // FIXME: look in base classes.
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
OverloadCandidateSet CandidateSet;
- const RecordType *BaseRecord = Base->getType()->getAsRecordType();
-
- DeclContext::lookup_const_iterator Oper, OperEnd;
- for (llvm::tie(Oper, OperEnd)
- = BaseRecord->getDecl()->lookup(OpName); Oper != OperEnd; ++Oper)
+ const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
+
+ LookupResult R;
+ LookupQualifiedName(R, BaseRecord->getDecl(), OpName, LookupOrdinaryName);
+
+ for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
+ Oper != OperEnd; ++Oper)
AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Base, 0, 0, CandidateSet,
/*SuppressUserConversions=*/false);
- ExprOwningPtr<Expr> BasePtr(this, Base);
-
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, OpLoc, Best)) {
@@ -4530,44 +5156,49 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
case OR_No_Viable_Function:
if (CandidateSet.empty())
Diag(OpLoc, diag::err_typecheck_member_reference_arrow)
- << BasePtr->getType() << BasePtr->getSourceRange();
+ << Base->getType() << Base->getSourceRange();
else
Diag(OpLoc, diag::err_ovl_no_viable_oper)
- << "operator->" << BasePtr->getSourceRange();
+ << "operator->" << Base->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
- return true;
+ return ExprError();
case OR_Ambiguous:
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
- << "operator->" << BasePtr->getSourceRange();
+ << "->" << Base->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
- return true;
+ return ExprError();
case OR_Deleted:
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
- << "operator->" << BasePtr->getSourceRange();
+ << "->" << Base->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
- return true;
+ return ExprError();
}
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
if (PerformObjectArgumentInitialization(Base, Method))
- return true;
+ return ExprError();
// No concerns about early exits now.
- BasePtr.take();
+ BaseIn.release();
// Build the operator call.
Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(),
SourceLocation());
UsualUnaryConversions(FnExpr);
- Base = new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, &Base, 1,
- Method->getResultType().getNonReferenceType(),
- OpLoc);
- return ActOnMemberReferenceExpr(S, ExprArg(*this, Base), OpLoc, tok::arrow,
- MemberLoc, Member, DeclPtrTy()).release();
+
+ QualType ResultTy = Method->getResultType().getNonReferenceType();
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr,
+ &Base, 1, ResultTy, OpLoc));
+
+ if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall.get(),
+ Method))
+ return ExprError();
+ return move(TheCall);
}
/// FixOverloadedFunctionReference - E is an expression that refers to
@@ -4580,14 +5211,13 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
E->setType(PE->getSubExpr()->getType());
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) {
- assert(UnOp->getOpcode() == UnaryOperator::AddrOf &&
+ assert(UnOp->getOpcode() == UnaryOperator::AddrOf &&
"Can only take the address of an overloaded function");
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
if (Method->isStatic()) {
// Do nothing: static member functions aren't any different
// from non-member functions.
- }
- else if (QualifiedDeclRefExpr *DRE
+ } else if (QualifiedDeclRefExpr *DRE
= dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr())) {
// We have taken the address of a pointer to member
// function. Perform the computation here so that we get the
@@ -4596,7 +5226,7 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
DRE->setType(Fn->getType());
QualType ClassType
= Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
- E->setType(Context.getMemberPointerType(Fn->getType(),
+ E->setType(Context.getMemberPointerType(Fn->getType(),
ClassType.getTypePtr()));
return;
}
@@ -4604,8 +5234,9 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
E->setType(Context.getPointerType(UnOp->getSubExpr()->getType()));
} else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
- assert(isa<OverloadedFunctionDecl>(DR->getDecl()) &&
- "Expected overloaded function");
+ assert((isa<OverloadedFunctionDecl>(DR->getDecl()) ||
+ isa<FunctionTemplateDecl>(DR->getDecl())) &&
+ "Expected overloaded function or function template");
DR->setDecl(Fn);
E->setType(Fn->getType());
} else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) {
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 9de380657612b..898393a9e4d96 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -59,7 +59,7 @@ namespace clang {
ICC_Conversion ///< Conversion
};
- ImplicitConversionCategory
+ ImplicitConversionCategory
GetConversionCategory(ImplicitConversionKind Kind);
/// ImplicitConversionRank - The rank of an implicit conversion
@@ -98,7 +98,7 @@ namespace clang {
ImplicitConversionKind Third : 8;
/// Deprecated - Whether this the deprecated conversion of a
- /// string literal to a pointer to non-const character data
+ /// string literal to a pointer to non-const character data
/// (C++ 4.2p2).
bool Deprecated : 1;
@@ -106,11 +106,11 @@ namespace clang {
/// that we should warn about (if we actually use it).
bool IncompatibleObjC : 1;
- /// ReferenceBinding - True when this is a reference binding
+ /// ReferenceBinding - True when this is a reference binding
/// (C++ [over.ics.ref]).
bool ReferenceBinding : 1;
- /// DirectBinding - True when this is a reference binding that is a
+ /// DirectBinding - True when this is a reference binding that is a
/// direct binding (C++ [dcl.init.ref]).
bool DirectBinding : 1;
@@ -134,7 +134,7 @@ namespace clang {
/// conversions.
CXXConstructorDecl *CopyConstructor;
- void setAsIdentityConversion();
+ void setAsIdentityConversion();
ImplicitConversionRank getRank() const;
bool isPointerConversionToBool() const;
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
@@ -159,7 +159,7 @@ namespace clang {
/// After - Represents the standard conversion that occurs after
/// the actual user-defined conversion.
StandardConversionSequence After;
-
+
/// ConversionFunction - The function that will perform the
/// user-defined conversion.
FunctionDecl* ConversionFunction;
@@ -168,7 +168,7 @@ namespace clang {
};
/// ImplicitConversionSequence - Represents an implicit conversion
- /// sequence, which may be a standard conversion sequence
+ /// sequence, which may be a standard conversion sequence
/// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2),
/// or an ellipsis conversion sequence (C++ 13.3.3.1.3).
struct ImplicitConversionSequence {
@@ -195,7 +195,11 @@ namespace clang {
/// details of the user-defined conversion sequence.
UserDefinedConversionSequence UserDefined;
};
-
+
+ /// When ConversionKind == BadConversion due to multiple conversion
+ /// functions, this will list those functions.
+ llvm::SmallVector<FunctionDecl*, 4> ConversionFunctionSet;
+
// The result of a comparison between implicit conversion
// sequences. Use Sema::CompareImplicitConversionSequences to
// actually perform the comparison.
@@ -211,8 +215,8 @@ namespace clang {
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
struct OverloadCandidate {
/// Function - The actual function that this candidate
- /// represents. When NULL, this is a built-in candidate
- /// (C++ [over.oper]) or a surrogate for a conversion to a
+ /// represents. When NULL, this is a built-in candidate
+ /// (C++ [over.oper]) or a surrogate for a conversion to a
/// function pointer or reference (C++ [over.call.object]).
FunctionDecl *Function;
@@ -222,7 +226,7 @@ namespace clang {
QualType ResultTy;
QualType ParamTypes[3];
} BuiltinTypes;
-
+
/// Surrogate - The conversion function for which this candidate
/// is a surrogate, but only if IsSurrogate is true.
CXXConversionDecl *Surrogate;
@@ -257,7 +261,16 @@ namespace clang {
/// OverloadCandidateSet - A set of overload candidates, used in C++
/// overload resolution (C++ 13.3).
- typedef llvm::SmallVector<OverloadCandidate, 16> OverloadCandidateSet;
+ class OverloadCandidateSet : public llvm::SmallVector<OverloadCandidate, 16> {
+ llvm::SmallPtrSet<Decl *, 16> Functions;
+
+ public:
+ /// \brief Determine when this overload candidate will be new to the
+ /// overload set.
+ bool isNewCandidate(Decl *F) {
+ return Functions.insert(F->getCanonicalDecl());
+ }
+ };
} // end namespace clang
#endif // LLVM_CLANG_SEMA_OVERLOAD_H
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 63191e0e00cce..e8cd6b081de16 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -15,16 +15,26 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
using namespace clang;
Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) {
Expr *E = expr->takeAs<Expr>();
assert(E && "ActOnExprStmt(): missing expression");
-
+ if (E->getType()->isObjCInterfaceType()) {
+ if (LangOpts.ObjCNonFragileABI)
+ Diag(E->getLocEnd(), diag::err_indirection_requires_nonfragile_object)
+ << E->getType();
+ else
+ Diag(E->getLocEnd(), diag::err_direct_interface_unsupported)
+ << E->getType();
+ return StmtError();
+ }
// C99 6.8.3p2: The expression in an expression statement is evaluated as a
// void expression for its side effects. Conversion to void allows any
// operand, even incomplete types.
@@ -42,13 +52,57 @@ Sema::OwningStmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg,
SourceLocation StartLoc,
SourceLocation EndLoc) {
DeclGroupRef DG = dg.getAsVal<DeclGroupRef>();
-
+
// If we have an invalid decl, just return an error.
if (DG.isNull()) return StmtError();
-
+
return Owned(new (Context) DeclStmt(DG, StartLoc, EndLoc));
}
+void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
+ const Expr *E = dyn_cast_or_null<Expr>(S);
+ if (!E)
+ return;
+
+ // Ignore expressions that have void type.
+ if (E->getType()->isVoidType())
+ return;
+
+ SourceLocation Loc;
+ SourceRange R1, R2;
+ if (!E->isUnusedResultAWarning(Loc, R1, R2))
+ return;
+
+ // Okay, we have an unused result. Depending on what the base expression is,
+ // we might want to make a more specific diagnostic. Check for one of these
+ // cases now.
+ unsigned DiagID = diag::warn_unused_expr;
+ E = E->IgnoreParens();
+ if (isa<ObjCImplicitSetterGetterRefExpr>(E))
+ DiagID = diag::warn_unused_property_expr;
+
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ // If the callee has attribute pure, const, or warn_unused_result, warn with
+ // a more specific message to make it clear what is happening.
+ if (const FunctionDecl *FD = CE->getDirectCallee()) {
+ if (FD->getAttr<WarnUnusedResultAttr>()) {
+ Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
+ return;
+ }
+ if (FD->getAttr<PureAttr>()) {
+ Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure";
+ return;
+ }
+ if (FD->getAttr<ConstAttr>()) {
+ Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const";
+ return;
+ }
+ }
+ }
+
+ Diag(Loc, DiagID) << R1 << R2;
+}
+
Action::OwningStmtResult
Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
MultiStmtArg elts, bool isStmtExpr) {
@@ -66,7 +120,7 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
// We found the end of the list or a statement. Scan for another declstmt.
for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i)
/*empty*/;
-
+
if (i != NumElts) {
Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin();
Diag(D->getLocation(), diag::ext_mixed_decls_code);
@@ -74,20 +128,11 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
}
// Warn about unused expressions in statements.
for (unsigned i = 0; i != NumElts; ++i) {
- Expr *E = dyn_cast<Expr>(Elts[i]);
- if (!E) continue;
-
- // Warn about expressions with unused results if they are non-void and if
- // this not the last stmt in a stmt expr.
- if (E->getType()->isVoidType() || (isStmtExpr && i == NumElts-1))
- continue;
-
- SourceLocation Loc;
- SourceRange R1, R2;
- if (!E->isUnusedResultAWarning(Loc, R1, R2))
+ // Ignore statements that are last in a statement expression.
+ if (isStmtExpr && i == NumElts - 1)
continue;
- Diag(Loc, diag::warn_unused_expr) << R1 << R2;
+ DiagnoseUnusedExprResult(Elts[i]);
}
return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R));
@@ -100,9 +145,9 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprArg lhsval,
assert((lhsval.get() != 0) && "missing expression in case statement");
// C99 6.8.4.2p3: The expression shall be an integer constant.
- // However, GCC allows any evaluatable integer expression.
+ // However, GCC allows any evaluatable integer expression.
Expr *LHSVal = static_cast<Expr*>(lhsval.get());
- if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
+ if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
VerifyIntegerConstantExpression(LHSVal))
return StmtError();
@@ -137,7 +182,7 @@ void Sema::ActOnCaseStmtBody(StmtTy *caseStmt, StmtArg subStmt) {
}
Action::OwningStmtResult
-Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
+Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
StmtArg subStmt, Scope *CurScope) {
Stmt *SubStmt = subStmt.takeAs<Stmt>();
@@ -184,40 +229,33 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal,
StmtArg ThenVal, SourceLocation ElseLoc,
StmtArg ElseVal) {
OwningExprResult CondResult(CondVal.release());
-
+
Expr *condExpr = CondResult.takeAs<Expr>();
assert(condExpr && "ActOnIfStmt(): missing expression");
-
- if (!condExpr->isTypeDependent()) {
- DefaultFunctionArrayConversion(condExpr);
- // Take ownership again until we're past the error checking.
+ if (CheckBooleanCondition(condExpr, IfLoc)) {
CondResult = condExpr;
- QualType condType = condExpr->getType();
-
- if (getLangOptions().CPlusPlus) {
- if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4
- return StmtError();
- } else if (!condType->isScalarType()) // C99 6.8.4.1p1
- return StmtError(Diag(IfLoc,
- diag::err_typecheck_statement_requires_scalar)
- << condType << condExpr->getSourceRange());
+ return StmtError();
}
Stmt *thenStmt = ThenVal.takeAs<Stmt>();
+ DiagnoseUnusedExprResult(thenStmt);
// Warn if the if block has a null body without an else value.
// this helps prevent bugs due to typos, such as
// if (condition);
// do_stuff();
- if (!ElseVal.get()) {
+ if (!ElseVal.get()) {
if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt))
Diag(stmt->getSemiLoc(), diag::warn_empty_if_body);
}
+ Stmt *elseStmt = ElseVal.takeAs<Stmt>();
+ DiagnoseUnusedExprResult(elseStmt);
+
CondResult.release();
return Owned(new (Context) IfStmt(IfLoc, condExpr, thenStmt,
- ElseLoc, ElseVal.takeAs<Stmt>()));
+ ElseLoc, elseStmt));
}
Action::OwningStmtResult
@@ -234,9 +272,9 @@ Sema::ActOnStartOfSwitchStmt(ExprArg cond) {
// of this section. Integral promotions are performed.
if (!Cond->isTypeDependent()) {
QualType Ty = Cond->getType();
-
+
// FIXME: Handle class types.
-
+
// If the type is wrong a diagnostic will be emitted later at
// ActOnFinishSwitchStmt.
if (Ty->isIntegralType() || Ty->isEnumeralType()) {
@@ -260,19 +298,19 @@ Sema::ActOnStartOfSwitchStmt(ExprArg cond) {
/// the specified diagnostic.
void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
unsigned NewWidth, bool NewSign,
- SourceLocation Loc,
+ SourceLocation Loc,
unsigned DiagID) {
// Perform a conversion to the promoted condition type if needed.
if (NewWidth > Val.getBitWidth()) {
// If this is an extension, just do it.
llvm::APSInt OldVal(Val);
Val.extend(NewWidth);
-
+
// If the input was signed and negative and the output is unsigned,
// warn.
if (!NewSign && OldVal.isSigned() && OldVal.isNegative())
Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10);
-
+
Val.setIsSigned(NewSign);
} else if (NewWidth < Val.getBitWidth()) {
// If this is a truncation, check for overflow.
@@ -283,7 +321,7 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
ConvVal.setIsSigned(Val.isSigned());
if (ConvVal != Val)
Diag(Loc, DiagID) << Val.toString(10) << ConvVal.toString(10);
-
+
// Regardless of whether a diagnostic was emitted, really do the
// truncation.
Val.trunc(NewWidth);
@@ -293,7 +331,7 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
// overflow as well: unsigned(INTMIN)
llvm::APSInt OldVal(Val);
Val.setIsSigned(NewSign);
-
+
if (Val.isNegative()) // Sign bit changes meaning.
Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10);
}
@@ -339,12 +377,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
assert(SS == (SwitchStmt*)Switch.get() && "switch stack missing push/pop!");
SS->setBody(BodyStmt, SwitchLoc);
- getSwitchStack().pop_back();
+ getSwitchStack().pop_back();
Expr *CondExpr = SS->getCond();
QualType CondType = CondExpr->getType();
- if (!CondExpr->isTypeDependent() &&
+ if (!CondExpr->isTypeDependent() &&
!CondType->isIntegerType()) { // C99 6.8.4.2p1
Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer)
<< CondType << CondExpr->getSourceRange();
@@ -353,29 +391,29 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
// Get the bitwidth of the switched-on value before promotions. We must
// convert the integer case values to this width before comparison.
- bool HasDependentValue
+ bool HasDependentValue
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
- unsigned CondWidth
+ unsigned CondWidth
= HasDependentValue? 0
: static_cast<unsigned>(Context.getTypeSize(CondType));
bool CondIsSigned = CondType->isSignedIntegerType();
-
+
// Accumulate all of the case values in a vector so that we can sort them
// and detect duplicates. This vector contains the APInt for the case after
// it has been converted to the condition type.
typedef llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy;
CaseValsTy CaseVals;
-
+
// Keep track of any GNU case ranges we see. The APSInt is the low value.
std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRanges;
-
+
DefaultStmt *TheDefaultStmt = 0;
-
+
bool CaseListIsErroneous = false;
-
+
for (SwitchCase *SC = SS->getSwitchCaseList(); SC && !HasDependentValue;
SC = SC->getNextSwitchCase()) {
-
+
if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) {
if (TheDefaultStmt) {
Diag(DS->getDefaultLoc(), diag::err_multiple_default_labels_defined);
@@ -388,10 +426,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
CaseListIsErroneous = true;
}
TheDefaultStmt = DS;
-
+
} else {
CaseStmt *CS = cast<CaseStmt>(SC);
-
+
// We already verified that the expression has a i-c-e value (C99
// 6.8.4.2p3) - get that value now.
Expr *Lo = CS->getLHS();
@@ -400,9 +438,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
HasDependentValue = true;
break;
}
-
+
llvm::APSInt LoVal = Lo->EvaluateAsInt(Context);
-
+
// Convert the value to the same width/sign as the condition.
ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
CS->getLHS()->getLocStart(),
@@ -412,16 +450,16 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
// cast.
ImpCastExprToType(Lo, CondType);
CS->setLHS(Lo);
-
+
// If this is a case range, remember it in CaseRanges, otherwise CaseVals.
if (CS->getRHS()) {
- if (CS->getRHS()->isTypeDependent() ||
+ if (CS->getRHS()->isTypeDependent() ||
CS->getRHS()->isValueDependent()) {
HasDependentValue = true;
break;
}
CaseRanges.push_back(std::make_pair(LoVal, CS));
- } else
+ } else
CaseVals.push_back(std::make_pair(LoVal, CS));
}
}
@@ -436,7 +474,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
// If we have a duplicate, report it.
Diag(CaseVals[i+1].second->getLHS()->getLocStart(),
diag::err_duplicate_case) << CaseVals[i].first.toString(10);
- Diag(CaseVals[i].second->getLHS()->getLocStart(),
+ Diag(CaseVals[i].second->getLHS()->getLocStart(),
diag::note_duplicate_case_prev);
// FIXME: We really want to remove the bogus case stmt from the
// substmt, but we have no way to do this right now.
@@ -444,31 +482,31 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
}
}
-
+
// Detect duplicate case ranges, which usually don't exist at all in
// the first place.
if (!CaseRanges.empty()) {
// Sort all the case ranges by their low value so we can easily detect
// overlaps between ranges.
std::stable_sort(CaseRanges.begin(), CaseRanges.end());
-
+
// Scan the ranges, computing the high values and removing empty ranges.
std::vector<llvm::APSInt> HiVals;
for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) {
CaseStmt *CR = CaseRanges[i].second;
Expr *Hi = CR->getRHS();
llvm::APSInt HiVal = Hi->EvaluateAsInt(Context);
-
+
// Convert the value to the same width/sign as the condition.
ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
CR->getRHS()->getLocStart(),
diag::warn_case_value_overflow);
-
+
// If the LHS is not the same type as the condition, insert an implicit
// cast.
ImpCastExprToType(Hi, CondType);
CR->setRHS(Hi);
-
+
// If the low value is bigger than the high value, the case is empty.
if (CaseRanges[i].first > HiVal) {
Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range)
@@ -480,7 +518,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
HiVals.push_back(HiVal);
}
-
+
// Rescan the ranges, looking for overlap with singleton values and other
// ranges. Since the range list is sorted, we only need to compare case
// ranges with their neighbors.
@@ -488,12 +526,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
llvm::APSInt &CRLo = CaseRanges[i].first;
llvm::APSInt &CRHi = HiVals[i];
CaseStmt *CR = CaseRanges[i].second;
-
+
// Check to see whether the case range overlaps with any
// singleton cases.
CaseStmt *OverlapStmt = 0;
llvm::APSInt OverlapVal(32);
-
+
// Find the smallest value >= the lower bound. If I is in the
// case range, then we have overlap.
CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(),
@@ -503,26 +541,26 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
OverlapVal = I->first; // Found overlap with scalar.
OverlapStmt = I->second;
}
-
+
// Find the smallest value bigger than the upper bound.
I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor());
if (I != CaseVals.begin() && (I-1)->first >= CRLo) {
OverlapVal = (I-1)->first; // Found overlap with scalar.
OverlapStmt = (I-1)->second;
}
-
+
// Check to see if this case stmt overlaps with the subsequent
// case range.
if (i && CRLo <= HiVals[i-1]) {
OverlapVal = HiVals[i-1]; // Found overlap with range.
OverlapStmt = CaseRanges[i-1].second;
}
-
+
if (OverlapStmt) {
// If we have a duplicate, report it.
Diag(CR->getLHS()->getLocStart(), diag::err_duplicate_case)
<< OverlapVal.toString(10);
- Diag(OverlapStmt->getLHS()->getLocStart(),
+ Diag(OverlapStmt->getLHS()->getLocStart(),
diag::note_duplicate_case_prev);
// FIXME: We really want to remove the bogus case stmt from the
// substmt, but we have no way to do this right now.
@@ -547,23 +585,16 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) {
Expr *condExpr = CondArg.takeAs<Expr>();
assert(condExpr && "ActOnWhileStmt(): missing expression");
- if (!condExpr->isTypeDependent()) {
- DefaultFunctionArrayConversion(condExpr);
+ if (CheckBooleanCondition(condExpr, WhileLoc)) {
CondArg = condExpr;
- QualType condType = condExpr->getType();
-
- if (getLangOptions().CPlusPlus) {
- if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4
- return StmtError();
- } else if (!condType->isScalarType()) // C99 6.8.5p2
- return StmtError(Diag(WhileLoc,
- diag::err_typecheck_statement_requires_scalar)
- << condType << condExpr->getSourceRange());
+ return StmtError();
}
+ Stmt *bodyStmt = Body.takeAs<Stmt>();
+ DiagnoseUnusedExprResult(bodyStmt);
+
CondArg.release();
- return Owned(new (Context) WhileStmt(condExpr, Body.takeAs<Stmt>(),
- WhileLoc));
+ return Owned(new (Context) WhileStmt(condExpr, bodyStmt, WhileLoc));
}
Action::OwningStmtResult
@@ -573,22 +604,16 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
Expr *condExpr = Cond.takeAs<Expr>();
assert(condExpr && "ActOnDoStmt(): missing expression");
- if (!condExpr->isTypeDependent()) {
- DefaultFunctionArrayConversion(condExpr);
+ if (CheckBooleanCondition(condExpr, DoLoc)) {
Cond = condExpr;
- QualType condType = condExpr->getType();
-
- if (getLangOptions().CPlusPlus) {
- if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4
- return StmtError();
- } else if (!condType->isScalarType()) // C99 6.8.5p2
- return StmtError(Diag(DoLoc,
- diag::err_typecheck_statement_requires_scalar)
- << condType << condExpr->getSourceRange());
+ return StmtError();
}
+ Stmt *bodyStmt = Body.takeAs<Stmt>();
+ DiagnoseUnusedExprResult(bodyStmt);
+
Cond.release();
- return Owned(new (Context) DoStmt(Body.takeAs<Stmt>(), condExpr, DoLoc,
+ return Owned(new (Context) DoStmt(bodyStmt, condExpr, DoLoc,
WhileLoc, CondRParen));
}
@@ -597,7 +622,7 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
StmtArg first, ExprArg second, ExprArg third,
SourceLocation RParenLoc, StmtArg body) {
Stmt *First = static_cast<Stmt*>(first.get());
- Expr *Second = static_cast<Expr*>(second.get());
+ Expr *Second = second.takeAs<Expr>();
Expr *Third = static_cast<Expr*>(third.get());
Stmt *Body = static_cast<Stmt*>(body.get());
@@ -617,20 +642,16 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
}
}
}
- if (Second && !Second->isTypeDependent()) {
- DefaultFunctionArrayConversion(Second);
- QualType SecondType = Second->getType();
-
- if (getLangOptions().CPlusPlus) {
- if (CheckCXXBooleanCondition(Second)) // C++ 6.4p4
- return StmtError();
- } else if (!SecondType->isScalarType()) // C99 6.8.5p2
- return StmtError(Diag(ForLoc,
- diag::err_typecheck_statement_requires_scalar)
- << SecondType << Second->getSourceRange());
+ if (Second && CheckBooleanCondition(Second, ForLoc)) {
+ second = Second;
+ return StmtError();
}
+
+ DiagnoseUnusedExprResult(First);
+ DiagnoseUnusedExprResult(Third);
+ DiagnoseUnusedExprResult(Body);
+
first.release();
- second.release();
third.release();
body.release();
return Owned(new (Context) ForStmt(First, Second, Third, Body, ForLoc,
@@ -667,16 +688,17 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
diag::err_selector_element_not_lvalue)
<< First->getSourceRange());
- FirstType = static_cast<Expr*>(First)->getType();
+ FirstType = static_cast<Expr*>(First)->getType();
}
- if (!Context.isObjCObjectPointerType(FirstType))
+ if (!FirstType->isObjCObjectPointerType() &&
+ !FirstType->isBlockPointerType())
Diag(ForLoc, diag::err_selector_element_type)
<< FirstType << First->getSourceRange();
}
if (Second) {
DefaultFunctionArrayConversion(Second);
QualType SecondType = Second->getType();
- if (!Context.isObjCObjectPointerType(SecondType))
+ if (!SecondType->isObjCObjectPointerType())
Diag(ForLoc, diag::err_collection_expr_type)
<< SecondType << Second->getSourceRange();
}
@@ -791,8 +813,8 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// we have a non-void block with an expression, continue checking
QualType RetValType = RetValExp->getType();
- // C99 6.8.6.4p3(136): The return statement is not an assignment. The
- // overlap restriction of subclause 6.5.16.1 does not apply to the case of
+ // C99 6.8.6.4p3(136): The return statement is not an assignment. The
+ // overlap restriction of subclause 6.5.16.1 does not apply to the case of
// function return.
// In C++ the return statement is handled via a copy initialization.
@@ -834,8 +856,8 @@ static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
}
Action::OwningStmtResult
-Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
- Expr *RetValExp = rex->takeAs<Expr>();
+Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
+ Expr *RetValExp = rex.takeAs<Expr>();
if (CurBlock)
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
@@ -849,9 +871,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
FnRetType = MD->getResultType();
else // If we don't have a function/method context, bail.
return StmtError();
-
+
if (FnRetType->isVoidType()) {
- if (RetValExp) {// C99 6.8.6.4p1 (ext_ since GCC warns)
+ if (RetValExp && !RetValExp->isTypeDependent()) {
+ // C99 6.8.6.4p1 (ext_ since GCC warns)
unsigned D = diag::ext_return_has_expr;
if (RetValExp->getType()->isVoidType())
D = diag::ext_return_has_void_expr;
@@ -864,6 +887,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
<< CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl)
<< RetValExp->getSourceRange();
}
+
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
}
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
}
@@ -883,8 +908,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
// we have a non-void function with an expression, continue checking
- // C99 6.8.6.4p3(136): The return statement is not an assignment. The
- // overlap restriction of subclause 6.5.16.1 does not apply to the case of
+ // C99 6.8.6.4p3(136): The return statement is not an assignment. The
+ // overlap restriction of subclause 6.5.16.1 does not apply to the case of
// function return.
// C++0x 12.8p15: When certain criteria are met, an implementation is
@@ -912,6 +937,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
+ if (RetValExp)
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
}
@@ -964,7 +991,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get());
llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
-
+
// The parser verifies that there is a string literal here.
if (AsmString->isWide())
return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
@@ -976,7 +1003,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- TargetInfo::ConstraintInfo Info(Literal->getStrData(),
+ TargetInfo::ConstraintInfo Info(Literal->getStrData(),
Literal->getByteLength(),
Names[i]);
if (!Context.Target.validateOutputConstraint(Info))
@@ -991,7 +1018,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
diag::err_asm_invalid_lvalue_in_output)
<< OutputExpr->getSourceRange());
}
-
+
OutputConstraintInfos.push_back(Info);
}
@@ -1003,7 +1030,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- TargetInfo::ConstraintInfo Info(Literal->getStrData(),
+ TargetInfo::ConstraintInfo Info(Literal->getStrData(),
Literal->getByteLength(),
Names[i]);
if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(),
@@ -1028,13 +1055,13 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
if (InputExpr->getType()->isVoidType()) {
return StmtError(Diag(InputExpr->getLocStart(),
diag::err_asm_invalid_type_in_input)
- << InputExpr->getType() << Info.getConstraintStr()
+ << InputExpr->getType() << Info.getConstraintStr()
<< InputExpr->getSourceRange());
}
}
-
+
DefaultFunctionArrayConversion(Exprs[i]);
-
+
InputConstraintInfos.push_back(Info);
}
@@ -1045,13 +1072,13 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- llvm::SmallString<16> Clobber(Literal->getStrData(),
- Literal->getStrData() +
- Literal->getByteLength());
+ std::string Clobber(Literal->getStrData(),
+ Literal->getStrData() +
+ Literal->getByteLength());
if (!Context.Target.isValidGCCRegisterName(Clobber.c_str()))
return StmtError(Diag(Literal->getLocStart(),
- diag::err_asm_unknown_register_name) << Clobber.c_str());
+ diag::err_asm_unknown_register_name) << Clobber);
}
constraints.release();
@@ -1072,16 +1099,16 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
DeleteStmt(NS);
return StmtError();
}
-
+
// Validate tied input operands for type mismatches.
for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
-
+
// If this is a tied constraint, verify that the output and input have
// either exactly the same type, or that they are int/ptr operands with the
// same size (int/long, int*/long, are ok etc).
if (!Info.hasTiedOperand()) continue;
-
+
unsigned TiedTo = Info.getTiedOperand();
Expr *OutputExpr = Exprs[TiedTo];
Expr *InputExpr = Exprs[i+NumOutputs];
@@ -1089,11 +1116,11 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
QualType OutTy = OutputExpr->getType();
if (Context.hasSameType(InTy, OutTy))
continue; // All types can be tied to themselves.
-
+
// Int/ptr operands have some special cases that we allow.
if ((OutTy->isIntegerType() || OutTy->isPointerType()) &&
(InTy->isIntegerType() || InTy->isPointerType())) {
-
+
// They are ok if they are the same size. Tying void* to int is ok if
// they are the same size, for example. This also allows tying void* to
// int*.
@@ -1101,7 +1128,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
uint64_t InSize = Context.getTypeSize(InTy);
if (OutSize == InSize)
continue;
-
+
// If the smaller input/output operand is not mentioned in the asm string,
// then we can promote it and the asm string won't notice. Check this
// case now.
@@ -1109,7 +1136,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
AsmStmt::AsmStringPiece &Piece = Pieces[p];
if (!Piece.isOperand()) continue;
-
+
// If this is a reference to the input and if the input was the smaller
// one, then we have to reject this asm.
if (Piece.getOperandNo() == i+NumOutputs) {
@@ -1128,7 +1155,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
}
}
}
-
+
// If the smaller value wasn't mentioned in the asm string, and if the
// output was a register, just extend the shorter one to the size of the
// larger one.
@@ -1136,7 +1163,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
OutputConstraintInfos[TiedTo].allowsRegister())
continue;
}
-
+
Diag(InputExpr->getLocStart(),
diag::err_asm_tying_incompatible_types)
<< InTy << OutTy << OutputExpr->getSourceRange()
@@ -1144,7 +1171,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
DeleteStmt(NS);
return StmtError();
}
-
+
return Owned(NS);
}
@@ -1154,18 +1181,18 @@ Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
StmtArg Body, StmtArg catchList) {
Stmt *CatchList = catchList.takeAs<Stmt>();
ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>());
-
+
// PVD == 0 implies @catch(...).
if (PVD) {
// If we already know the decl is invalid, reject it.
if (PVD->isInvalidDecl())
return StmtError();
-
- if (!Context.isObjCObjectPointerType(PVD->getType()))
- return StmtError(Diag(PVD->getLocation(),
+
+ if (!PVD->getType()->isObjCObjectPointerType())
+ return StmtError(Diag(PVD->getLocation(),
diag::err_catch_param_not_objc_type));
if (PVD->getType()->isObjCQualifiedIdType())
- return StmtError(Diag(PVD->getLocation(),
+ return StmtError(Diag(PVD->getLocation(),
diag::err_illegal_qualifiers_on_catch_parm));
}
@@ -1203,8 +1230,8 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
} else {
QualType ThrowType = ThrowExpr->getType();
// Make sure the expression type is an ObjC pointer or "void *".
- if (!Context.isObjCObjectPointerType(ThrowType)) {
- const PointerType *PT = ThrowType->getAsPointerType();
+ if (!ThrowType->isObjCObjectPointerType()) {
+ const PointerType *PT = ThrowType->getAs<PointerType>();
if (!PT || !PT->getPointeeType()->isVoidType())
return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
<< ThrowExpr->getType() << ThrowExpr->getSourceRange());
@@ -1220,14 +1247,14 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr,
// Make sure the expression type is an ObjC pointer or "void *".
Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get());
- if (!Context.isObjCObjectPointerType(SyncExpr->getType())) {
- const PointerType *PT = SyncExpr->getType()->getAsPointerType();
+ if (!SyncExpr->getType()->isObjCObjectPointerType()) {
+ const PointerType *PT = SyncExpr->getType()->getAs<PointerType>();
if (!PT || !PT->getPointeeType()->isVoidType())
return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object)
<< SyncExpr->getType() << SyncExpr->getSourceRange());
}
-
- return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc,
+
+ return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc,
SynchExpr.takeAs<Stmt>(),
SynchBody.takeAs<Stmt>()));
}
@@ -1243,6 +1270,35 @@ Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclPtrTy ExDecl,
HandlerBlock.takeAs<Stmt>()));
}
+class TypeWithHandler {
+ QualType t;
+ CXXCatchStmt *stmt;
+public:
+ TypeWithHandler(const QualType &type, CXXCatchStmt *statement)
+ : t(type), stmt(statement) {}
+
+ // An arbitrary order is fine as long as it places identical
+ // types next to each other.
+ bool operator<(const TypeWithHandler &y) const {
+ if (t.getAsOpaquePtr() < y.t.getAsOpaquePtr())
+ return true;
+ if (t.getAsOpaquePtr() > y.t.getAsOpaquePtr())
+ return false;
+ else
+ return getTypeSpecStartLoc() < y.getTypeSpecStartLoc();
+ }
+
+ bool operator==(const TypeWithHandler& other) const {
+ return t == other.t;
+ }
+
+ QualType getQualType() const { return t; }
+ CXXCatchStmt *getCatchStmt() const { return stmt; }
+ SourceLocation getTypeSpecStartLoc() const {
+ return stmt->getExceptionDecl()->getTypeSpecStartLoc();
+ }
+};
+
/// ActOnCXXTryBlock - Takes a try compound-statement and a number of
/// handlers and creates a try statement from them.
Action::OwningStmtResult
@@ -1253,13 +1309,44 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock,
"The parser shouldn't call this if there are no handlers.");
Stmt **Handlers = reinterpret_cast<Stmt**>(RawHandlers.get());
- for(unsigned i = 0; i < NumHandlers - 1; ++i) {
+ llvm::SmallVector<TypeWithHandler, 8> TypesWithHandlers;
+
+ for (unsigned i = 0; i < NumHandlers; ++i) {
CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]);
- if (!Handler->getExceptionDecl())
- return StmtError(Diag(Handler->getLocStart(), diag::err_early_catch_all));
+ if (!Handler->getExceptionDecl()) {
+ if (i < NumHandlers - 1)
+ return StmtError(Diag(Handler->getLocStart(),
+ diag::err_early_catch_all));
+
+ continue;
+ }
+
+ const QualType CaughtType = Handler->getCaughtType();
+ const QualType CanonicalCaughtType = Context.getCanonicalType(CaughtType);
+ TypesWithHandlers.push_back(TypeWithHandler(CanonicalCaughtType, Handler));
}
- // FIXME: We should detect handlers for the same type as an earlier one.
- // This one is rather easy.
+
+ // Detect handlers for the same type as an earlier one.
+ if (NumHandlers > 1) {
+ llvm::array_pod_sort(TypesWithHandlers.begin(), TypesWithHandlers.end());
+
+ TypeWithHandler prev = TypesWithHandlers[0];
+ for (unsigned i = 1; i < TypesWithHandlers.size(); ++i) {
+ TypeWithHandler curr = TypesWithHandlers[i];
+
+ if (curr == prev) {
+ Diag(curr.getTypeSpecStartLoc(),
+ diag::warn_exception_caught_by_earlier_handler)
+ << curr.getCatchStmt()->getCaughtType().getAsString();
+ Diag(prev.getTypeSpecStartLoc(),
+ diag::note_previous_exception_handler)
+ << prev.getCatchStmt()->getCaughtType().getAsString();
+ }
+
+ prev = curr;
+ }
+ }
+
// FIXME: We should detect handlers that cannot catch anything because an
// earlier handler catches a superclass. Need to find a method that is not
// quadratic for this.
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 568d68c9a7e82..d56b4e114e74c 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1,104 +1,239 @@
//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===/
-
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//===----------------------------------------------------------------------===/
-
//
// This file implements semantic analysis for C++ templates.
//===----------------------------------------------------------------------===/
#include "Sema.h"
+#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/LangOptions.h"
-
+#include "clang/Basic/PartialDiagnostic.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
-/// isTemplateName - Determines whether the identifier II is a
-/// template name in the current scope, and returns the template
-/// declaration if II names a template. An optional CXXScope can be
-/// passed to indicate the C++ scope in which the identifier will be
-/// found.
-TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
- TemplateTy &TemplateResult,
- const CXXScopeSpec *SS) {
- NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName);
-
- TemplateNameKind TNK = TNK_Non_template;
- TemplateDecl *Template = 0;
-
- if (IIDecl) {
- if ((Template = dyn_cast<TemplateDecl>(IIDecl))) {
- if (isa<FunctionTemplateDecl>(IIDecl))
- TNK = TNK_Function_template;
- else if (isa<ClassTemplateDecl>(IIDecl) ||
- isa<TemplateTemplateParmDecl>(IIDecl))
- TNK = TNK_Type_template;
- else
- assert(false && "Unknown template declaration kind");
- } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) {
- // C++ [temp.local]p1:
- // Like normal (non-template) classes, class templates have an
- // injected-class-name (Clause 9). The injected-class-name
- // can be used with or without a template-argument-list. When
- // it is used without a template-argument-list, it is
- // equivalent to the injected-class-name followed by the
- // template-parameters of the class template enclosed in
- // <>. When it is used with a template-argument-list, it
- // refers to the specified class template specialization,
- // which could be the current specialization or another
- // specialization.
- if (Record->isInjectedClassName()) {
- Record = cast<CXXRecordDecl>(Context.getCanonicalDecl(Record));
- if ((Template = Record->getDescribedClassTemplate()))
- TNK = TNK_Type_template;
- else if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
- Template = Spec->getSpecializedTemplate();
- TNK = TNK_Type_template;
- }
- }
+/// \brief Determine whether the declaration found is acceptable as the name
+/// of a template and, if so, return that template declaration. Otherwise,
+/// returns NULL.
+static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) {
+ if (!D)
+ return 0;
+
+ if (isa<TemplateDecl>(D))
+ return D;
+
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+ // C++ [temp.local]p1:
+ // Like normal (non-template) classes, class templates have an
+ // injected-class-name (Clause 9). The injected-class-name
+ // can be used with or without a template-argument-list. When
+ // it is used without a template-argument-list, it is
+ // equivalent to the injected-class-name followed by the
+ // template-parameters of the class template enclosed in
+ // <>. When it is used with a template-argument-list, it
+ // refers to the specified class template specialization,
+ // which could be the current specialization or another
+ // specialization.
+ if (Record->isInjectedClassName()) {
+ Record = cast<CXXRecordDecl>(Record->getDeclContext());
+ if (Record->getDescribedClassTemplate())
+ return Record->getDescribedClassTemplate();
+
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+ return Spec->getSpecializedTemplate();
}
- // FIXME: What follows is a slightly less gross hack than what used to
- // follow.
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) {
- if (FD->getDescribedFunctionTemplate()) {
- TemplateResult = TemplateTy::make(FD);
- return TNK_Function_template;
+ return 0;
+ }
+
+ OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D);
+ if (!Ovl)
+ return 0;
+
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ if (FunctionTemplateDecl *FuncTmpl = dyn_cast<FunctionTemplateDecl>(*F)) {
+ // We've found a function template. Determine whether there are
+ // any other function templates we need to bundle together in an
+ // OverloadedFunctionDecl
+ for (++F; F != FEnd; ++F) {
+ if (isa<FunctionTemplateDecl>(*F))
+ break;
}
- } else if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(IIDecl)) {
- for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
- FEnd = Ovl->function_end();
- F != FEnd; ++F) {
- if (isa<FunctionTemplateDecl>(*F)) {
- TemplateResult = TemplateTy::make(Ovl);
- return TNK_Function_template;
+
+ if (F != FEnd) {
+ // Build an overloaded function decl containing only the
+ // function templates in Ovl.
+ OverloadedFunctionDecl *OvlTemplate
+ = OverloadedFunctionDecl::Create(Context,
+ Ovl->getDeclContext(),
+ Ovl->getDeclName());
+ OvlTemplate->addOverload(FuncTmpl);
+ OvlTemplate->addOverload(*F);
+ for (++F; F != FEnd; ++F) {
+ if (isa<FunctionTemplateDecl>(*F))
+ OvlTemplate->addOverload(*F);
}
+
+ return OvlTemplate;
}
+
+ return FuncTmpl;
}
+ }
+
+ return 0;
+}
- if (TNK != TNK_Non_template) {
- if (SS && SS->isSet() && !SS->isInvalid()) {
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
- TemplateResult
- = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier,
- false,
- Template));
- } else
- TemplateResult = TemplateTy::make(TemplateName(Template));
+TemplateNameKind Sema::isTemplateName(Scope *S,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ const CXXScopeSpec *SS,
+ TypeTy *ObjectTypePtr,
+ bool EnteringContext,
+ TemplateTy &TemplateResult) {
+ // Determine where to perform name lookup
+ DeclContext *LookupCtx = 0;
+ bool isDependent = false;
+ if (ObjectTypePtr) {
+ // This nested-name-specifier occurs in a member access expression, e.g.,
+ // x->B::f, and we are looking into the type of the object.
+ assert((!SS || !SS->isSet()) &&
+ "ObjectType and scope specifier cannot coexist");
+ QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
+ LookupCtx = computeDeclContext(ObjectType);
+ isDependent = ObjectType->isDependentType();
+ } else if (SS && SS->isSet()) {
+ // This nested-name-specifier occurs after another nested-name-specifier,
+ // so long into the context associated with the prior nested-name-specifier.
+
+ LookupCtx = computeDeclContext(*SS, EnteringContext);
+ isDependent = isDependentScopeSpecifier(*SS);
+ }
+
+ LookupResult Found;
+ bool ObjectTypeSearchedInScope = false;
+ if (LookupCtx) {
+ // Perform "qualified" name lookup into the declaration context we
+ // computed, which is either the type of the base of a member access
+ // expression or the declaration context associated with a prior
+ // nested-name-specifier.
+
+ // The declaration context must be complete.
+ if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS))
+ return TNK_Non_template;
+
+ LookupQualifiedName(Found, LookupCtx, &II, LookupOrdinaryName);
+
+ if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) {
+ // C++ [basic.lookup.classref]p1:
+ // In a class member access expression (5.2.5), if the . or -> token is
+ // immediately followed by an identifier followed by a <, the
+ // identifier must be looked up to determine whether the < is the
+ // beginning of a template argument list (14.2) or a less-than operator.
+ // The identifier is first looked up in the class of the object
+ // expression. If the identifier is not found, it is then looked up in
+ // the context of the entire postfix-expression and shall name a class
+ // or function template.
+ //
+ // FIXME: When we're instantiating a template, do we actually have to
+ // look in the scope of the template? Seems fishy...
+ LookupName(Found, S, &II, LookupOrdinaryName);
+ ObjectTypeSearchedInScope = true;
}
+ } else if (isDependent) {
+ // We cannot look into a dependent object type or
+ return TNK_Non_template;
+ } else {
+ // Perform unqualified name lookup in the current scope.
+ LookupName(Found, S, &II, LookupOrdinaryName);
}
- return TNK;
+
+ // FIXME: Cope with ambiguous name-lookup results.
+ assert(!Found.isAmbiguous() &&
+ "Cannot handle template name-lookup ambiguities");
+
+ NamedDecl *Template
+ = isAcceptableTemplateName(Context, Found.getAsSingleDecl(Context));
+ if (!Template)
+ return TNK_Non_template;
+
+ if (ObjectTypePtr && !ObjectTypeSearchedInScope) {
+ // C++ [basic.lookup.classref]p1:
+ // [...] If the lookup in the class of the object expression finds a
+ // template, the name is also looked up in the context of the entire
+ // postfix-expression and [...]
+ //
+ LookupResult FoundOuter;
+ LookupName(FoundOuter, S, &II, LookupOrdinaryName);
+ // FIXME: Handle ambiguities in this lookup better
+ NamedDecl *OuterTemplate
+ = isAcceptableTemplateName(Context, FoundOuter.getAsSingleDecl(Context));
+
+ if (!OuterTemplate) {
+ // - if the name is not found, the name found in the class of the
+ // object expression is used, otherwise
+ } else if (!isa<ClassTemplateDecl>(OuterTemplate)) {
+ // - if the name is found in the context of the entire
+ // postfix-expression and does not name a class template, the name
+ // found in the class of the object expression is used, otherwise
+ } else {
+ // - if the name found is a class template, it must refer to the same
+ // entity as the one found in the class of the object expression,
+ // otherwise the program is ill-formed.
+ if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) {
+ Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
+ << &II;
+ Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type)
+ << QualType::getFromOpaquePtr(ObjectTypePtr);
+ Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope);
+
+ // Recover by taking the template that we found in the object
+ // expression's type.
+ }
+ }
+ }
+
+ if (SS && SS->isSet() && !SS->isInvalid()) {
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(Template))
+ TemplateResult
+ = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
+ Ovl));
+ else
+ TemplateResult
+ = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
+ cast<TemplateDecl>(Template)));
+ } else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(Template)) {
+ TemplateResult = TemplateTy::make(TemplateName(Ovl));
+ } else {
+ TemplateResult = TemplateTy::make(
+ TemplateName(cast<TemplateDecl>(Template)));
+ }
+
+ if (isa<ClassTemplateDecl>(Template) ||
+ isa<TemplateTemplateParmDecl>(Template))
+ return TNK_Type_template;
+
+ assert((isa<FunctionTemplateDecl>(Template) ||
+ isa<OverloadedFunctionDecl>(Template)) &&
+ "Unhandled template kind in Sema::isTemplateName");
+ return TNK_Function_template;
}
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
@@ -115,7 +250,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
// C++ [temp.local]p4:
// A template-parameter shall not be redeclared within its
// scope (including nested scopes).
- Diag(Loc, diag::err_template_param_shadow)
+ Diag(Loc, diag::err_template_param_shadow)
<< cast<NamedDecl>(PrevDecl)->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_template_param_here);
return true;
@@ -125,7 +260,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
/// the parameter D to reference the templated declaration and return a pointer
/// to the template declaration. Otherwise, do nothing to D and return null.
TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) {
- if (TemplateDecl *Temp = dyn_cast<TemplateDecl>(D.getAs<Decl>())) {
+ if (TemplateDecl *Temp = dyn_cast_or_null<TemplateDecl>(D.getAs<Decl>())) {
D = DeclPtrTy::make(Temp->getTemplatedDecl());
return Temp;
}
@@ -138,24 +273,24 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) {
/// (otherwise, "class" was used), and KeyLoc is the location of the
/// "class" or "typename" keyword. ParamName is the name of the
/// parameter (NULL indicates an unnamed template parameter) and
-/// ParamName is the location of the parameter name (if any).
+/// ParamName is the location of the parameter name (if any).
/// If the type parameter has a default argument, it will be added
/// later via ActOnTypeParameterDefault.
-Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
+Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
SourceLocation EllipsisLoc,
SourceLocation KeyLoc,
IdentifierInfo *ParamName,
SourceLocation ParamNameLoc,
unsigned Depth, unsigned Position) {
- assert(S->isTemplateParamScope() &&
- "Template type parameter not in template parameter scope!");
+ assert(S->isTemplateParamScope() &&
+ "Template type parameter not in template parameter scope!");
bool Invalid = false;
if (ParamName) {
- NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName);
+ NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName);
if (PrevDecl && PrevDecl->isTemplateParameter())
Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc,
- PrevDecl);
+ PrevDecl);
}
SourceLocation Loc = ParamNameLoc;
@@ -163,8 +298,8 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
Loc = KeyLoc;
TemplateTypeParmDecl *Param
- = TemplateTypeParmDecl::Create(Context, CurContext, Loc,
- Depth, Position, ParamName, Typename,
+ = TemplateTypeParmDecl::Create(Context, CurContext, Loc,
+ Depth, Position, ParamName, Typename,
Ellipsis);
if (Invalid)
Param->setInvalidDecl();
@@ -179,27 +314,28 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
}
/// ActOnTypeParameterDefault - Adds a default argument (the type
-/// Default) to the given template type parameter (TypeParam).
-void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
+/// Default) to the given template type parameter (TypeParam).
+void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
SourceLocation EqualLoc,
- SourceLocation DefaultLoc,
+ SourceLocation DefaultLoc,
TypeTy *DefaultT) {
- TemplateTypeParmDecl *Parm
+ TemplateTypeParmDecl *Parm
= cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>());
- QualType Default = QualType::getFromOpaquePtr(DefaultT);
+ // FIXME: Preserve type source info.
+ QualType Default = GetTypeFromParser(DefaultT);
// C++0x [temp.param]p9:
// A default template-argument may be specified for any kind of
- // template-parameter that is not a template parameter pack.
+ // template-parameter that is not a template parameter pack.
if (Parm->isParameterPack()) {
Diag(DefaultLoc, diag::err_template_param_pack_default_arg);
return;
}
-
+
// C++ [temp.param]p14:
// A template-parameter shall not be used in its own default argument.
// FIXME: Implement this check! Needs a recursive walk over the types.
-
+
// Check the template argument itself.
if (CheckTemplateArgument(Parm, Default, DefaultLoc)) {
Parm->setInvalidDecl();
@@ -214,7 +350,7 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
///
/// \returns the (possibly-promoted) parameter type if valid;
/// otherwise, produces a diagnostic and returns a NULL type.
-QualType
+QualType
Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
// C++ [temp.param]p4:
//
@@ -223,11 +359,11 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
//
// -- integral or enumeration type,
if (T->isIntegralType() || T->isEnumeralType() ||
- // -- pointer to object or pointer to function,
- (T->isPointerType() &&
- (T->getAsPointerType()->getPointeeType()->isObjectType() ||
- T->getAsPointerType()->getPointeeType()->isFunctionType())) ||
- // -- reference to object or reference to function,
+ // -- pointer to object or pointer to function,
+ (T->isPointerType() &&
+ (T->getAs<PointerType>()->getPointeeType()->isObjectType() ||
+ T->getAs<PointerType>()->getPointeeType()->isFunctionType())) ||
+ // -- reference to object or reference to function,
T->isReferenceType() ||
// -- pointer to member.
T->isMemberPointerType() ||
@@ -258,9 +394,10 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
/// class Array") has been parsed. S is the current scope and D is
/// the parsed declarator.
Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
- unsigned Depth,
+ unsigned Depth,
unsigned Position) {
- QualType T = GetTypeForDeclarator(D, S);
+ DeclaratorInfo *DInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &DInfo);
assert(S->isTemplateParamScope() &&
"Non-type template parameter not in template parameter scope!");
@@ -268,7 +405,7 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
IdentifierInfo *ParamName = D.getIdentifier();
if (ParamName) {
- NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName);
+ NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName);
if (PrevDecl && PrevDecl->isTemplateParameter())
Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
PrevDecl);
@@ -282,7 +419,7 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
NonTypeTemplateParmDecl *Param
= NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(),
- Depth, Position, ParamName, T);
+ Depth, Position, ParamName, T, DInfo);
if (Invalid)
Param->setInvalidDecl();
@@ -299,14 +436,14 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
void Sema::ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParamD,
SourceLocation EqualLoc,
ExprArg DefaultE) {
- NonTypeTemplateParmDecl *TemplateParm
+ NonTypeTemplateParmDecl *TemplateParm
= cast<NonTypeTemplateParmDecl>(TemplateParamD.getAs<Decl>());
Expr *Default = static_cast<Expr *>(DefaultE.get());
-
+
// C++ [temp.param]p14:
// A template-parameter shall not be used in its own default argument.
// FIXME: Implement this check! Needs a recursive walk over the types.
-
+
// Check the well-formedness of the default template argument.
TemplateArgument Converted;
if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default,
@@ -328,8 +465,7 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
IdentifierInfo *Name,
SourceLocation NameLoc,
unsigned Depth,
- unsigned Position)
-{
+ unsigned Position) {
assert(S->isTemplateParamScope() &&
"Template template parameter not in template parameter scope!");
@@ -363,12 +499,12 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD,
SourceLocation EqualLoc,
ExprArg DefaultE) {
- TemplateTemplateParmDecl *TemplateParm
+ TemplateTemplateParmDecl *TemplateParm
= cast<TemplateTemplateParmDecl>(TemplateParamD.getAs<Decl>());
// Since a template-template parameter's default argument is an
// id-expression, it must be a DeclRefExpr.
- DeclRefExpr *Default
+ DeclRefExpr *Default
= cast<DeclRefExpr>(static_cast<Expr *>(DefaultE.get()));
// C++ [temp.param]p14:
@@ -377,12 +513,12 @@ void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD,
// Check the well-formedness of the template argument.
if (!isa<TemplateDecl>(Default->getDecl())) {
- Diag(Default->getSourceRange().getBegin(),
+ Diag(Default->getSourceRange().getBegin(),
diag::err_template_arg_must_be_template)
<< Default->getSourceRange();
TemplateParm->setInvalidDecl();
return;
- }
+ }
if (CheckTemplateArgument(TemplateParm, Default)) {
TemplateParm->setInvalidDecl();
return;
@@ -397,7 +533,7 @@ void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD,
Sema::TemplateParamsTy *
Sema::ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
- SourceLocation TemplateLoc,
+ SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
DeclPtrTy *Params, unsigned NumParams,
SourceLocation RAngleLoc) {
@@ -405,31 +541,28 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
Diag(ExportLoc, diag::note_template_export_unsupported);
return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
- (Decl**)Params, NumParams, RAngleLoc);
+ (NamedDecl**)Params, NumParams,
+ RAngleLoc);
}
Sema::DeclResult
-Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
+Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
- MultiTemplateParamsArg TemplateParameterLists,
+ TemplateParameterList *TemplateParams,
AccessSpecifier AS) {
- assert(TemplateParameterLists.size() > 0 && "No template parameter lists?");
- assert(TK != TK_Reference && "Can only declare or define class templates");
+ assert(TemplateParams && TemplateParams->size() > 0 &&
+ "No template parameters");
+ assert(TUK != TUK_Reference && "Can only declare or define class templates");
bool Invalid = false;
// Check that we can declare a template here.
- if (CheckTemplateDeclScope(S, TemplateParameterLists))
+ if (CheckTemplateDeclScope(S, TemplateParams))
return true;
- TagDecl::TagKind Kind;
- switch (TagSpec) {
- default: assert(0 && "Unknown tag type!");
- case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
- case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
- case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
- }
+ TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
+ assert(Kind != TagDecl::TK_enum && "can't build template of enumerated type");
// There is no such thing as an unnamed class template.
if (!Name) {
@@ -438,31 +571,73 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
}
// Find any previous declaration with this name.
- LookupResult Previous = LookupParsedName(S, &SS, Name, LookupOrdinaryName,
- true);
+ DeclContext *SemanticContext;
+ LookupResult Previous;
+ if (SS.isNotEmpty() && !SS.isInvalid()) {
+ if (RequireCompleteDeclContext(SS))
+ return true;
+
+ SemanticContext = computeDeclContext(SS, true);
+ if (!SemanticContext) {
+ // FIXME: Produce a reasonable diagnostic here
+ return true;
+ }
+
+ LookupQualifiedName(Previous, SemanticContext, Name, LookupOrdinaryName,
+ true);
+ } else {
+ SemanticContext = CurContext;
+ LookupName(Previous, S, Name, LookupOrdinaryName, true);
+ }
+
assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?");
NamedDecl *PrevDecl = 0;
if (Previous.begin() != Previous.end())
PrevDecl = *Previous.begin();
- if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
+ if (PrevDecl && TUK == TUK_Friend) {
+ // C++ [namespace.memdef]p3:
+ // [...] When looking for a prior declaration of a class or a function
+ // declared as a friend, and when the name of the friend class or
+ // function is neither a qualified name nor a template-id, scopes outside
+ // the innermost enclosing namespace scope are not considered.
+ DeclContext *OutermostContext = CurContext;
+ while (!OutermostContext->isFileContext())
+ OutermostContext = OutermostContext->getLookupParent();
+
+ if (OutermostContext->Equals(PrevDecl->getDeclContext()) ||
+ OutermostContext->Encloses(PrevDecl->getDeclContext())) {
+ SemanticContext = PrevDecl->getDeclContext();
+ } else {
+ // Declarations in outer scopes don't matter. However, the outermost
+ // context we computed is the semntic context for our new
+ // declaration.
+ PrevDecl = 0;
+ SemanticContext = OutermostContext;
+ }
+ } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
PrevDecl = 0;
-
- DeclContext *SemanticContext = CurContext;
- if (SS.isNotEmpty() && !SS.isInvalid()) {
- SemanticContext = computeDeclContext(SS);
-
- // FIXME: need to match up several levels of template parameter lists here.
- }
-
- // FIXME: member templates!
- TemplateParameterList *TemplateParams
- = static_cast<TemplateParameterList *>(*TemplateParameterLists.release());
// If there is a previous declaration with the same name, check
// whether this is a valid redeclaration.
- ClassTemplateDecl *PrevClassTemplate
+ ClassTemplateDecl *PrevClassTemplate
= dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
+
+ // We may have found the injected-class-name of a class template,
+ // class template partial specialization, or class template specialization.
+ // In these cases, grab the template that is being defined or specialized.
+ if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) &&
+ cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) {
+ PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext());
+ PrevClassTemplate
+ = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate();
+ if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) {
+ PrevClassTemplate
+ = cast<ClassTemplateSpecializationDecl>(PrevDecl)
+ ->getSpecializedTemplate();
+ }
+ }
+
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible.
if (!TemplateParameterListsAreEqual(TemplateParams,
@@ -477,16 +652,16 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
// template declaration (7.1.5.3).
RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) {
- Diag(KWLoc, diag::err_use_with_wrong_tag)
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
- << CodeModificationHint::CreateReplacement(KWLoc,
+ << CodeModificationHint::CreateReplacement(KWLoc,
PrevRecordDecl->getKindName());
Diag(PrevRecordDecl->getLocation(), diag::note_previous_use);
Kind = PrevRecordDecl->getTagKind();
}
// Check for redefinition of this class template.
- if (TK == TK_Definition) {
+ if (TUK == TUK_Definition) {
if (TagDecl *Def = PrevRecordDecl->getDefinition(Context)) {
Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
@@ -517,13 +692,13 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
if (CheckTemplateParameterList(TemplateParams,
PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0))
Invalid = true;
-
+
// FIXME: If we had a scope specifier, we better have a previous template
// declaration!
- CXXRecordDecl *NewClass =
- CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name,
- PrevClassTemplate?
+ CXXRecordDecl *NewClass =
+ CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc,
+ PrevClassTemplate?
PrevClassTemplate->getTemplatedDecl() : 0,
/*DelayTypeCreation=*/true);
@@ -534,27 +709,60 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
NewClass->setDescribedClassTemplate(NewTemplate);
// Build the type for the class template declaration now.
- QualType T =
- Context.getTypeDeclType(NewClass,
- PrevClassTemplate?
- PrevClassTemplate->getTemplatedDecl() : 0);
+ QualType T =
+ Context.getTypeDeclType(NewClass,
+ PrevClassTemplate?
+ PrevClassTemplate->getTemplatedDecl() : 0);
assert(T->isDependentType() && "Class template type is not dependent?");
(void)T;
- // Set the access specifier.
- SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
+ // If we are providing an explicit specialization of a member that is a
+ // class template, make a note of that.
+ if (PrevClassTemplate &&
+ PrevClassTemplate->getInstantiatedFromMemberTemplate())
+ PrevClassTemplate->setMemberSpecialization();
+ // Set the access specifier.
+ if (!Invalid && TUK != TUK_Friend)
+ SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
+
// Set the lexical context of these templates
NewClass->setLexicalDeclContext(CurContext);
NewTemplate->setLexicalDeclContext(CurContext);
- if (TK == TK_Definition)
+ if (TUK == TUK_Definition)
NewClass->startDefinition();
if (Attr)
ProcessDeclAttributeList(S, NewClass, Attr);
- PushOnScopeChains(NewTemplate, S);
+ if (TUK != TUK_Friend)
+ PushOnScopeChains(NewTemplate, S);
+ else {
+ if (PrevClassTemplate && PrevClassTemplate->getAccess() != AS_none) {
+ NewTemplate->setAccess(PrevClassTemplate->getAccess());
+ NewClass->setAccess(PrevClassTemplate->getAccess());
+ }
+
+ NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */
+ PrevClassTemplate != NULL);
+
+ // Friend templates are visible in fairly strange ways.
+ if (!CurContext->isDependentContext()) {
+ DeclContext *DC = SemanticContext->getLookupContext();
+ DC->makeDeclVisibleInContext(NewTemplate, /* Recoverable = */ false);
+ if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
+ PushOnScopeChains(NewTemplate, EnclosingScope,
+ /* AddToContext = */ false);
+ }
+
+ FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
+ NewClass->getLocation(),
+ NewTemplate,
+ /*FIXME:*/NewClass->getLocation());
+ Friend->setAccess(AS_public);
+ CurContext->addDecl(Friend);
+ }
if (Invalid) {
NewTemplate->setInvalidDecl();
@@ -585,7 +793,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
TemplateParameterList *OldParams) {
bool Invalid = false;
-
+
// C++ [temp.param]p10:
// The set of default template-arguments available for use with a
// template declaration or definition is obtained by merging the
@@ -618,7 +826,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// If a template parameter of a class template is a template parameter pack,
// it must be the last template parameter.
if (SawParameterPack) {
- Diag(ParameterPackLoc,
+ Diag(ParameterPackLoc,
diag::err_template_param_pack_must_be_last_template_parameter);
Invalid = true;
}
@@ -626,15 +834,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// Merge default arguments for template type parameters.
if (TemplateTypeParmDecl *NewTypeParm
= dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
- TemplateTypeParmDecl *OldTypeParm
+ TemplateTypeParmDecl *OldTypeParm
= OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
-
+
if (NewTypeParm->isParameterPack()) {
assert(!NewTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
SawParameterPack = true;
ParameterPackLoc = NewTypeParm->getLocation();
- } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
+ } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
NewTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
@@ -654,13 +862,12 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
PreviousDefaultArgLoc = NewTypeParm->getDefaultArgumentLoc();
} else if (SawDefaultArgument)
MissingDefaultArg = true;
- }
- // Merge default arguments for non-type template parameters
- else if (NonTypeTemplateParmDecl *NewNonTypeParm
+ } else if (NonTypeTemplateParmDecl *NewNonTypeParm
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
+ // Merge default arguments for non-type template parameters
NonTypeTemplateParmDecl *OldNonTypeParm
= OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0;
- if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
+ if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
NewNonTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
@@ -681,15 +888,14 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
SawDefaultArgument = true;
PreviousDefaultArgLoc = NewNonTypeParm->getDefaultArgumentLoc();
} else if (SawDefaultArgument)
- MissingDefaultArg = true;
- }
+ MissingDefaultArg = true;
+ } else {
// Merge default arguments for template template parameters
- else {
TemplateTemplateParmDecl *NewTemplateParm
= cast<TemplateTemplateParmDecl>(*NewParam);
TemplateTemplateParmDecl *OldTemplateParm
= OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
- if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
+ if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
NewTemplateParm->hasDefaultArgument()) {
OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc();
NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc();
@@ -709,7 +915,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
SawDefaultArgument = true;
PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc();
} else if (SawDefaultArgument)
- MissingDefaultArg = true;
+ MissingDefaultArg = true;
}
if (RedundantDefaultArg) {
@@ -724,7 +930,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// If a template-parameter has a default template-argument,
// all subsequent template-parameters shall have a default
// template-argument supplied.
- Diag((*NewParam)->getLocation(),
+ Diag((*NewParam)->getLocation(),
diag::err_template_param_default_arg_missing);
Diag(PreviousDefaultArgLoc, diag::note_template_param_prev_default_arg);
Invalid = true;
@@ -739,11 +945,157 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
return Invalid;
}
+/// \brief Match the given template parameter lists to the given scope
+/// specifier, returning the template parameter list that applies to the
+/// name.
+///
+/// \param DeclStartLoc the start of the declaration that has a scope
+/// specifier or a template parameter list.
+///
+/// \param SS the scope specifier that will be matched to the given template
+/// parameter lists. This scope specifier precedes a qualified name that is
+/// being declared.
+///
+/// \param ParamLists the template parameter lists, from the outermost to the
+/// innermost template parameter lists.
+///
+/// \param NumParamLists the number of template parameter lists in ParamLists.
+///
+/// \param IsExplicitSpecialization will be set true if the entity being
+/// declared is an explicit specialization, false otherwise.
+///
+/// \returns the template parameter list, if any, that corresponds to the
+/// name that is preceded by the scope specifier @p SS. This template
+/// parameter list may be have template parameters (if we're declaring a
+/// template) or may have no template parameters (if we're declaring a
+/// template specialization), or may be NULL (if we were's declaring isn't
+/// itself a template).
+TemplateParameterList *
+Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
+ const CXXScopeSpec &SS,
+ TemplateParameterList **ParamLists,
+ unsigned NumParamLists,
+ bool &IsExplicitSpecialization) {
+ IsExplicitSpecialization = false;
+
+ // Find the template-ids that occur within the nested-name-specifier. These
+ // template-ids will match up with the template parameter lists.
+ llvm::SmallVector<const TemplateSpecializationType *, 4>
+ TemplateIdsInSpecifier;
+ for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
+ NNS; NNS = NNS->getPrefix()) {
+ if (const TemplateSpecializationType *SpecType
+ = dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) {
+ TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl();
+ if (!Template)
+ continue; // FIXME: should this be an error? probably...
+
+ if (const RecordType *Record = SpecType->getAs<RecordType>()) {
+ ClassTemplateSpecializationDecl *SpecDecl
+ = cast<ClassTemplateSpecializationDecl>(Record->getDecl());
+ // If the nested name specifier refers to an explicit specialization,
+ // we don't need a template<> header.
+ // FIXME: revisit this approach once we cope with specializations
+ // properly.
+ if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization)
+ continue;
+ }
+
+ TemplateIdsInSpecifier.push_back(SpecType);
+ }
+ }
+
+ // Reverse the list of template-ids in the scope specifier, so that we can
+ // more easily match up the template-ids and the template parameter lists.
+ std::reverse(TemplateIdsInSpecifier.begin(), TemplateIdsInSpecifier.end());
+
+ SourceLocation FirstTemplateLoc = DeclStartLoc;
+ if (NumParamLists)
+ FirstTemplateLoc = ParamLists[0]->getTemplateLoc();
+
+ // Match the template-ids found in the specifier to the template parameter
+ // lists.
+ unsigned Idx = 0;
+ for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size();
+ Idx != NumTemplateIds; ++Idx) {
+ QualType TemplateId = QualType(TemplateIdsInSpecifier[Idx], 0);
+ bool DependentTemplateId = TemplateId->isDependentType();
+ if (Idx >= NumParamLists) {
+ // We have a template-id without a corresponding template parameter
+ // list.
+ if (DependentTemplateId) {
+ // FIXME: the location information here isn't great.
+ Diag(SS.getRange().getBegin(),
+ diag::err_template_spec_needs_template_parameters)
+ << TemplateId
+ << SS.getRange();
+ } else {
+ Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header)
+ << SS.getRange()
+ << CodeModificationHint::CreateInsertion(FirstTemplateLoc,
+ "template<> ");
+ IsExplicitSpecialization = true;
+ }
+ return 0;
+ }
+
+ // Check the template parameter list against its corresponding template-id.
+ if (DependentTemplateId) {
+ TemplateDecl *Template
+ = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl();
+
+ if (ClassTemplateDecl *ClassTemplate
+ = dyn_cast<ClassTemplateDecl>(Template)) {
+ TemplateParameterList *ExpectedTemplateParams = 0;
+ // Is this template-id naming the primary template?
+ if (Context.hasSameType(TemplateId,
+ ClassTemplate->getInjectedClassNameType(Context)))
+ ExpectedTemplateParams = ClassTemplate->getTemplateParameters();
+ // ... or a partial specialization?
+ else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = ClassTemplate->findPartialSpecialization(TemplateId))
+ ExpectedTemplateParams = PartialSpec->getTemplateParameters();
+
+ if (ExpectedTemplateParams)
+ TemplateParameterListsAreEqual(ParamLists[Idx],
+ ExpectedTemplateParams,
+ true);
+ }
+ } else if (ParamLists[Idx]->size() > 0)
+ Diag(ParamLists[Idx]->getTemplateLoc(),
+ diag::err_template_param_list_matches_nontemplate)
+ << TemplateId
+ << ParamLists[Idx]->getSourceRange();
+ else
+ IsExplicitSpecialization = true;
+ }
+
+ // If there were at least as many template-ids as there were template
+ // parameter lists, then there are no template parameter lists remaining for
+ // the declaration itself.
+ if (Idx >= NumParamLists)
+ return 0;
+
+ // If there were too many template parameter lists, complain about that now.
+ if (Idx != NumParamLists - 1) {
+ while (Idx < NumParamLists - 1) {
+ Diag(ParamLists[Idx]->getTemplateLoc(),
+ diag::err_template_spec_extra_headers)
+ << SourceRange(ParamLists[Idx]->getTemplateLoc(),
+ ParamLists[Idx]->getRAngleLoc());
+ ++Idx;
+ }
+ }
+
+ // Return the last template parameter list, which corresponds to the
+ // entity being declared.
+ return ParamLists[NumParamLists - 1];
+}
+
/// \brief Translates template arguments as provided by the parser
/// into template arguments used by semantic analysis.
-static void
-translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
- SourceLocation *TemplateArgLocs,
+void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
llvm::SmallVector<TemplateArgument, 16> &TemplateArgs) {
TemplateArgs.reserve(TemplateArgsIn.size());
@@ -752,72 +1104,12 @@ translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) {
TemplateArgs.push_back(
ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg],
- QualType::getFromOpaquePtr(Args[Arg]))
+ //FIXME: Preserve type source info.
+ Sema::GetTypeFromParser(Args[Arg]))
: TemplateArgument(reinterpret_cast<Expr *>(Args[Arg])));
}
}
-/// \brief Build a canonical version of a template argument list.
-///
-/// This function builds a canonical version of the given template
-/// argument list, where each of the template arguments has been
-/// converted into its canonical form. This routine is typically used
-/// to canonicalize a template argument list when the template name
-/// itself is dependent. When the template name refers to an actual
-/// template declaration, Sema::CheckTemplateArgumentList should be
-/// used to check and canonicalize the template arguments.
-///
-/// \param TemplateArgs The incoming template arguments.
-///
-/// \param NumTemplateArgs The number of template arguments in \p
-/// TemplateArgs.
-///
-/// \param Canonical A vector to be filled with the canonical versions
-/// of the template arguments.
-///
-/// \param Context The ASTContext in which the template arguments live.
-static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- llvm::SmallVectorImpl<TemplateArgument> &Canonical,
- ASTContext &Context) {
- Canonical.reserve(NumTemplateArgs);
- for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) {
- switch (TemplateArgs[Idx].getKind()) {
- case TemplateArgument::Null:
- assert(false && "Should never see a NULL template argument here");
- break;
-
- case TemplateArgument::Expression:
- // FIXME: Build canonical expression (!)
- Canonical.push_back(TemplateArgs[Idx]);
- break;
-
- case TemplateArgument::Declaration:
- Canonical.push_back(
- TemplateArgument(SourceLocation(),
- Context.getCanonicalDecl(TemplateArgs[Idx].getAsDecl())));
- break;
-
- case TemplateArgument::Integral:
- Canonical.push_back(TemplateArgument(SourceLocation(),
- *TemplateArgs[Idx].getAsIntegral(),
- TemplateArgs[Idx].getIntegralType()));
- break;
-
- case TemplateArgument::Type: {
- QualType CanonType
- = Context.getCanonicalType(TemplateArgs[Idx].getAsType());
- Canonical.push_back(TemplateArgument(SourceLocation(), CanonType));
- break;
- }
-
- case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
- break;
- }
- }
-}
-
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@@ -828,34 +1120,20 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
if (!Template) {
// The template name does not resolve to a template, so we just
// build a dependent template-id type.
-
- // Canonicalize the template arguments to build the canonical
- // template-id type.
- llvm::SmallVector<TemplateArgument, 16> CanonicalTemplateArgs;
- CanonicalizeTemplateArguments(TemplateArgs, NumTemplateArgs,
- CanonicalTemplateArgs, Context);
-
- TemplateName CanonName = Context.getCanonicalTemplateName(Name);
- QualType CanonType
- = Context.getTemplateSpecializationType(CanonName,
- &CanonicalTemplateArgs[0],
- CanonicalTemplateArgs.size());
-
- // Build the dependent template-id type.
return Context.getTemplateSpecializationType(Name, TemplateArgs,
- NumTemplateArgs, CanonType);
+ NumTemplateArgs);
}
// Check that the template argument list is well-formed for this
// template.
TemplateArgumentListBuilder Converted(Template->getTemplateParameters(),
NumTemplateArgs);
- if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
+ if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
TemplateArgs, NumTemplateArgs, RAngleLoc,
false, Converted))
return QualType();
- assert((Converted.structuredSize() ==
+ assert((Converted.structuredSize() ==
Template->getTemplateParameters()->size()) &&
"Converted template argument list is too short!");
@@ -872,17 +1150,24 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
//
// template<typename T, typename U = T> struct A;
TemplateName CanonName = Context.getCanonicalTemplateName(Name);
- CanonType = Context.getTemplateSpecializationType(CanonName,
+ CanonType = Context.getTemplateSpecializationType(CanonName,
Converted.getFlatArguments(),
Converted.flatSize());
- } else if (ClassTemplateDecl *ClassTemplate
+
+ // FIXME: CanonType is not actually the canonical type, and unfortunately
+ // it is a TemplateTypeSpecializationType that we will never use again.
+ // In the future, we need to teach getTemplateSpecializationType to only
+ // build the canonical type and return that to us.
+ CanonType = Context.getCanonicalType(CanonType);
+ } else if (ClassTemplateDecl *ClassTemplate
= dyn_cast<ClassTemplateDecl>(Template)) {
// Find the class template specialization declaration that
// corresponds to these arguments.
llvm::FoldingSetNodeID ID;
- ClassTemplateSpecializationDecl::Profile(ID,
+ ClassTemplateSpecializationDecl::Profile(ID,
Converted.getFlatArguments(),
- Converted.flatSize());
+ Converted.flatSize(),
+ Context);
void *InsertPos = 0;
ClassTemplateSpecializationDecl *Decl
= ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
@@ -890,9 +1175,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// This is the first time we have referenced this class template
// specialization. Create the canonical declaration and add it to
// the set of specializations.
- Decl = ClassTemplateSpecializationDecl::Create(Context,
+ Decl = ClassTemplateSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
- TemplateLoc,
+ ClassTemplate->getLocation(),
ClassTemplate,
Converted, 0);
ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
@@ -901,17 +1186,18 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
CanonType = Context.getTypeDeclType(Decl);
}
-
+
// Build the fully-sugared type for this class template
// specialization, which refers back to the class template
// specialization we created or found.
+ //FIXME: Preserve type source info.
return Context.getTemplateSpecializationType(Name, TemplateArgs,
NumTemplateArgs, CanonType);
}
Action::TypeResult
Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
- SourceLocation LAngleLoc,
+ SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc) {
@@ -933,6 +1219,38 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
return Result.getAsOpaquePtr();
}
+Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult,
+ TagUseKind TUK,
+ DeclSpec::TST TagSpec,
+ SourceLocation TagLoc) {
+ if (TypeResult.isInvalid())
+ return Sema::TypeResult();
+
+ QualType Type = QualType::getFromOpaquePtr(TypeResult.get());
+
+ // Verify the tag specifier.
+ TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
+
+ if (const RecordType *RT = Type->getAs<RecordType>()) {
+ RecordDecl *D = RT->getDecl();
+
+ IdentifierInfo *Id = D->getIdentifier();
+ assert(Id && "templated class must have an identifier");
+
+ if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) {
+ Diag(TagLoc, diag::err_use_with_wrong_tag)
+ << Type
+ << CodeModificationHint::CreateReplacement(SourceRange(TagLoc),
+ D->getKindName());
+ Diag(D->getLocation(), diag::note_previous_use);
+ }
+ }
+
+ QualType ElabType = Context.getElaboratedType(Type, TagKind);
+
+ return ElabType.getAsOpaquePtr();
+}
+
Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
@@ -941,14 +1259,14 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template,
SourceLocation RAngleLoc) {
// FIXME: Can we do any checking at this point? I guess we could check the
// template arguments that we have against the template name, if the template
- // name refers to a single template. That's not a terribly common case,
+ // name refers to a single template. That's not a terribly common case,
// though.
- return Owned(TemplateIdRefExpr::Create(Context,
+ return Owned(TemplateIdRefExpr::Create(Context,
/*FIXME: New type?*/Context.OverloadTy,
/*FIXME: Necessary?*/0,
/*FIXME: Necessary?*/SourceRange(),
Template, TemplateNameLoc, LAngleLoc,
- TemplateArgs,
+ TemplateArgs,
NumTemplateArgs, RAngleLoc));
}
@@ -959,16 +1277,52 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc) {
TemplateName Template = TemplateD.getAsVal<TemplateName>();
-
+
// Translate the parser's template argument list in our AST format.
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
-
+ TemplateArgsIn.release();
+
return BuildTemplateIdExpr(Template, TemplateNameLoc, LAngleLoc,
TemplateArgs.data(), TemplateArgs.size(),
RAngleLoc);
}
+Sema::OwningExprResult
+Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ TemplateTy TemplateD,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc) {
+ TemplateName Template = TemplateD.getAsVal<TemplateName>();
+
+ // FIXME: We're going to end up looking up the template based on its name,
+ // twice!
+ DeclarationName Name;
+ if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
+ Name = ActualTemplate->getDeclName();
+ else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl())
+ Name = Ovl->getDeclName();
+ else
+ Name = Template.getAsDependentTemplateName()->getName();
+
+ // Translate the parser's template argument list in our AST format.
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
+ TemplateArgsIn.release();
+
+ // Do we have the save the actual template name? We might need it...
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, TemplateNameLoc,
+ Name, true, LAngleLoc,
+ TemplateArgs.data(), TemplateArgs.size(),
+ RAngleLoc, DeclPtrTy(), &SS);
+}
+
/// \brief Form a dependent template name.
///
/// This action forms a dependent template name given the template
@@ -976,20 +1330,15 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD,
/// example, given "MetaFun::template apply", the scope specifier \p
/// SS will be "MetaFun::", \p TemplateKWLoc contains the location
/// of the "template" keyword, and "apply" is the \p Name.
-Sema::TemplateTy
+Sema::TemplateTy
Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc,
- const CXXScopeSpec &SS) {
- if (!SS.isSet() || SS.isInvalid())
- return TemplateTy();
-
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
-
- // FIXME: member of the current instantiation
-
- if (!Qualifier->isDependent()) {
+ const CXXScopeSpec &SS,
+ TypeTy *ObjectType) {
+ if ((ObjectType &&
+ computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) ||
+ (SS.isSet() && computeDeclContext(SS, false))) {
// C++0x [temp.names]p5:
// If a name prefixed by the keyword template is not the name of
// a template, the program is ill-formed. [Note: the keyword
@@ -1007,7 +1356,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
// "template" keyword is now permitted). We follow the C++0x
// rules, even in C++03 mode, retroactively applying the DR.
TemplateTy Template;
- TemplateNameKind TNK = isTemplateName(Name, 0, Template, &SS);
+ TemplateNameKind TNK = isTemplateName(0, Name, NameLoc, &SS, ObjectType,
+ false, Template);
if (TNK == TNK_Non_template) {
Diag(NameLoc, diag::err_template_kw_refers_to_non_template)
<< &Name;
@@ -1017,10 +1367,12 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
return Template;
}
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
}
-bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
+bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
const TemplateArgument &Arg,
TemplateArgumentListBuilder &Converted) {
// Check template type parameter.
@@ -1033,13 +1385,13 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
// is not a type.
Diag(Arg.getLocation(), diag::err_template_arg_must_be_type);
Diag(Param->getLocation(), diag::note_template_param_here);
-
+
return true;
- }
+ }
if (CheckTemplateArgument(Param, Arg.getAsType(), Arg.getLocation()))
return true;
-
+
// Add the converted template type argument.
Converted.Append(
TemplateArgument(Arg.getLocation(),
@@ -1062,9 +1414,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
unsigned NumArgs = NumTemplateArgs;
bool Invalid = false;
- bool HasParameterPack =
+ bool HasParameterPack =
NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
-
+
if ((NumArgs > NumParams && !HasParameterPack) ||
(NumArgs < Params->getMinRequiredArguments() &&
!PartialTemplateArgs)) {
@@ -1084,8 +1436,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
<< Params->getSourceRange();
Invalid = true;
}
-
- // C++ [temp.arg]p1:
+
+ // C++ [temp.arg]p1:
// [...] The type and form of each template-argument specified in
// a template-id shall match the type and form specified for the
// corresponding parameter declared by the template in its
@@ -1096,7 +1448,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
Param != ParamEnd; ++Param, ++ArgIdx) {
if (ArgIdx > NumArgs && PartialTemplateArgs)
break;
-
+
// Decode the template argument
TemplateArgument Arg;
if (ArgIdx >= NumArgs) {
@@ -1109,7 +1461,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
Converted.EndPack();
break;
}
-
+
if (!TTP->hasDefaultArgument())
break;
@@ -1118,49 +1470,51 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
if (ArgType->isDependentType()) {
- InstantiatingTemplate Inst(*this, TemplateLoc,
+ InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
TemplateArgumentList TemplateArgs(Context, Converted,
/*TakeArgs=*/false);
- ArgType = InstantiateType(ArgType, TemplateArgs,
- TTP->getDefaultArgumentLoc(),
- TTP->getDeclName());
+ ArgType = SubstType(ArgType,
+ MultiLevelTemplateArgumentList(TemplateArgs),
+ TTP->getDefaultArgumentLoc(),
+ TTP->getDeclName());
}
if (ArgType.isNull())
return true;
Arg = TemplateArgument(TTP->getLocation(), ArgType);
- } else if (NonTypeTemplateParmDecl *NTTP
+ } else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (!NTTP->hasDefaultArgument())
break;
- InstantiatingTemplate Inst(*this, TemplateLoc,
+ InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
-
+
TemplateArgumentList TemplateArgs(Context, Converted,
/*TakeArgs=*/false);
- Sema::OwningExprResult E = InstantiateExpr(NTTP->getDefaultArgument(),
- TemplateArgs);
+ Sema::OwningExprResult E
+ = SubstExpr(NTTP->getDefaultArgument(),
+ MultiLevelTemplateArgumentList(TemplateArgs));
if (E.isInvalid())
return true;
-
+
Arg = TemplateArgument(E.takeAs<Expr>());
} else {
- TemplateTemplateParmDecl *TempParm
- = cast<TemplateTemplateParmDecl>(*Param);
+ TemplateTemplateParmDecl *TempParm
+ = cast<TemplateTemplateParmDecl>(*Param);
if (!TempParm->hasDefaultArgument())
break;
- // FIXME: Instantiate default argument
+ // FIXME: Subst default argument
Arg = TemplateArgument(TempParm->getDefaultArgument());
}
} else {
@@ -1177,35 +1531,36 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (CheckTemplateTypeArgument(TTP, TemplateArgs[ArgIdx], Converted))
Invalid = true;
}
-
+
Converted.EndPack();
} else {
if (CheckTemplateTypeArgument(TTP, Arg, Converted))
Invalid = true;
}
- } else if (NonTypeTemplateParmDecl *NTTP
+ } else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
// Check non-type template parameters.
- // Instantiate the type of the non-type template parameter with
- // the template arguments we've seen thus far.
+ // Do substitution on the type of the non-type template parameter
+ // with the template arguments we've seen thus far.
QualType NTTPType = NTTP->getType();
if (NTTPType->isDependentType()) {
- // Instantiate the type of the non-type template parameter.
- InstantiatingTemplate Inst(*this, TemplateLoc,
+ // Do substitution on the type of the non-type template parameter.
+ InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
TemplateArgumentList TemplateArgs(Context, Converted,
/*TakeArgs=*/false);
- NTTPType = InstantiateType(NTTPType, TemplateArgs,
- NTTP->getLocation(),
- NTTP->getDeclName());
+ NTTPType = SubstType(NTTPType,
+ MultiLevelTemplateArgumentList(TemplateArgs),
+ NTTP->getLocation(),
+ NTTP->getDeclName());
// If that worked, check the non-type template parameter type
// for validity.
if (!NTTPType.isNull())
- NTTPType = CheckNonTypeTemplateParameterType(NTTPType,
+ NTTPType = CheckNonTypeTemplateParameterType(NTTPType,
NTTP->getLocation());
if (NTTPType.isNull()) {
Invalid = true;
@@ -1217,7 +1572,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
case TemplateArgument::Null:
assert(false && "Should never see a NULL template argument here");
break;
-
+
case TemplateArgument::Expression: {
Expr *E = Arg.getAsExpr();
TemplateArgument Result;
@@ -1238,7 +1593,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
case TemplateArgument::Type:
// We have a non-type template parameter but the template
// argument is a type.
-
+
// C++ [temp.arg]p2:
// In a template-argument, an ambiguity between a type-id and
// an expression is resolved to a type-id, regardless of the
@@ -1254,37 +1609,37 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
Diag((*Param)->getLocation(), diag::note_template_param_here);
Invalid = true;
break;
-
+
case TemplateArgument::Pack:
assert(0 && "FIXME: Implement!");
break;
}
- } else {
+ } else {
// Check template template parameters.
- TemplateTemplateParmDecl *TempParm
+ TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
-
+
switch (Arg.getKind()) {
case TemplateArgument::Null:
assert(false && "Should never see a NULL template argument here");
break;
-
+
case TemplateArgument::Expression: {
Expr *ArgExpr = Arg.getAsExpr();
if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
Invalid = true;
-
+
// Add the converted template argument.
- Decl *D
- = Context.getCanonicalDecl(cast<DeclRefExpr>(ArgExpr)->getDecl());
+ Decl *D
+ = cast<DeclRefExpr>(ArgExpr)->getDecl()->getCanonicalDecl();
Converted.Append(TemplateArgument(Arg.getLocation(), D));
continue;
}
}
// fall through
-
+
case TemplateArgument::Type: {
// We have a template template parameter but the template
// argument does not refer to a template.
@@ -1298,11 +1653,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// it to the list of converted arguments.
Converted.Append(Arg);
break;
-
+
case TemplateArgument::Integral:
assert(false && "Integral argument with template template parameter");
break;
-
+
case TemplateArgument::Pack:
assert(0 && "FIXME: Implement!");
break;
@@ -1318,7 +1673,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
///
/// This routine implements the semantics of C++ [temp.arg.type]. It
/// returns true if an error occurred, and false otherwise.
-bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
+bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
QualType Arg, SourceLocation ArgLoc) {
// C++ [temp.arg.type]p2:
// A local type, a type with no linkage, an unnamed type or a type
@@ -1327,14 +1682,14 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
//
// FIXME: Perform the recursive and no-linkage type checks.
const TagType *Tag = 0;
- if (const EnumType *EnumT = Arg->getAsEnumType())
+ if (const EnumType *EnumT = Arg->getAs<EnumType>())
Tag = EnumT;
- else if (const RecordType *RecordT = Arg->getAsRecordType())
+ else if (const RecordType *RecordT = Arg->getAs<RecordType>())
Tag = RecordT;
if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod())
return Diag(ArgLoc, diag::err_template_arg_local_type)
<< QualType(Tag, 0);
- else if (Tag && !Tag->getDecl()->getDeclName() &&
+ else if (Tag && !Tag->getDecl()->getDeclName() &&
!Tag->getDecl()->getTypedefForAnonDecl()) {
Diag(ArgLoc, diag::err_template_arg_unnamed_type);
Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
@@ -1359,7 +1714,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
return false;
// C++ [temp.arg.nontype]p1:
- //
+ //
// A template-argument for a non-type, non-template
// template-parameter shall be one of: [...]
//
@@ -1370,11 +1725,11 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
// the name refers to a function or array, or if the
// corresponding template-parameter is a reference; or
DeclRefExpr *DRE = 0;
-
+
// Ignore (and complain about) any excess parentheses.
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
if (!Invalid) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_extra_parens)
<< Arg->getSourceRange();
Invalid = true;
@@ -1390,7 +1745,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
DRE = dyn_cast<DeclRefExpr>(Arg);
if (!DRE || !isa<ValueDecl>(DRE->getDecl()))
- return Diag(Arg->getSourceRange().getBegin(),
+ return Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_object_or_func_form)
<< Arg->getSourceRange();
@@ -1402,14 +1757,14 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
// Cannot refer to non-static member functions
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl()))
if (!Method->isStatic())
- return Diag(Arg->getSourceRange().getBegin(),
+ return Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_method)
<< Method << Arg->getSourceRange();
-
+
// Functions must have external linkage.
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
if (Func->getStorageClass() == FunctionDecl::Static) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_function_not_extern)
<< Func << Arg->getSourceRange();
Diag(Func->getLocation(), diag::note_template_arg_internal_object)
@@ -1424,7 +1779,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
if (!Var->hasGlobalStorage()) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_object_not_extern)
<< Var << Arg->getSourceRange();
Diag(Var->getLocation(), diag::note_template_arg_internal_object)
@@ -1436,19 +1791,19 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
Entity = Var;
return Invalid;
}
-
+
// We found something else, but we don't know specifically what it is.
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_object_or_func)
<< Arg->getSourceRange();
- Diag(DRE->getDecl()->getLocation(),
+ Diag(DRE->getDecl()->getLocation(),
diag::note_template_arg_refers_here);
return true;
}
/// \brief Checks whether the given template argument is a pointer to
/// member constant according to C++ [temp.arg.nontype]p1.
-bool
+bool
Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
bool Invalid = false;
@@ -1461,7 +1816,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
return false;
// C++ [temp.arg.nontype]p1:
- //
+ //
// A template-argument for a non-type, non-template
// template-parameter shall be one of: [...]
//
@@ -1471,7 +1826,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
// Ignore (and complain about) any excess parentheses.
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
if (!Invalid) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_extra_parens)
<< Arg->getSourceRange();
Invalid = true;
@@ -1501,10 +1856,10 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
}
// We found something else, but we don't know specifically what it is.
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_pointer_to_member_form)
<< Arg->getSourceRange();
- Diag(DRE->getDecl()->getLocation(),
+ Diag(DRE->getDecl()->getLocation(),
diag::note_template_arg_refers_here);
return true;
}
@@ -1519,7 +1874,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
///
/// If no error was detected, Converted receives the converted template argument.
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
- QualType InstantiatedParamType, Expr *&Arg,
+ QualType InstantiatedParamType, Expr *&Arg,
TemplateArgument &Converted) {
SourceLocation StartLoc = Arg->getSourceRange().getBegin();
@@ -1555,7 +1910,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
SourceLocation NonConstantLoc;
llvm::APSInt Value;
if (!ArgType->isIntegralType() && !ArgType->isEnumeralType()) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_integral_or_enumeral)
<< ArgType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
@@ -1584,7 +1939,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ImpCastExprToType(Arg, ParamType);
} else {
// We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
<< Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
@@ -1592,7 +1947,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
QualType IntegerType = Context.getCanonicalType(ParamType);
- if (const EnumType *Enum = IntegerType->getAsEnumType())
+ if (const EnumType *Enum = IntegerType->getAs<EnumType>())
IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType());
if (!Arg->isValueDependent()) {
@@ -1610,7 +1965,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Check that we don't overflow the template parameter type.
unsigned AllowedBits = Context.getTypeSize(IntegerType);
if (Value.getActiveBits() > AllowedBits) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_too_large)
<< Value.toString(10) << Param->getType()
<< Arg->getSourceRange();
@@ -1634,7 +1989,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
Converted = TemplateArgument(StartLoc, Value,
- ParamType->isEnumeralType() ? ParamType
+ ParamType->isEnumeralType() ? ParamType
: IntegerType);
return false;
}
@@ -1648,13 +2003,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// function is selected from the set (13.4).
// In C++0x, any std::nullptr_t value can be converted.
(ParamType->isPointerType() &&
- ParamType->getAsPointerType()->getPointeeType()->isFunctionType()) ||
+ ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type reference to
// function, no conversions apply. If the template-argument
// represents a set of overloaded functions, the matching
// function is selected from the set (13.4).
(ParamType->isReferenceType() &&
- ParamType->getAsReferenceType()->getPointeeType()->isFunctionType()) ||
+ ParamType->getAs<ReferenceType>()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type pointer to
// member function, no conversions apply. If the
// template-argument represents a set of overloaded member
@@ -1662,9 +2017,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// the set (13.4).
// Again, C++0x allows a std::nullptr_t value.
(ParamType->isMemberPointerType() &&
- ParamType->getAsMemberPointerType()->getPointeeType()
+ ParamType->getAs<MemberPointerType>()->getPointeeType()
->isFunctionType())) {
- if (Context.hasSameUnqualifiedType(ArgType,
+ if (Context.hasSameUnqualifiedType(ArgType,
ParamType.getNonReferenceType())) {
// We don't have to do anything: the types already match.
} else if (ArgType->isNullPtrType() && (ParamType->isPointerType() ||
@@ -1674,7 +2029,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
} else if (ArgType->isFunctionType() && ParamType->isPointerType()) {
ArgType = Context.getPointerType(ArgType);
ImpCastExprToType(Arg, ArgType);
- } else if (FunctionDecl *Fn
+ } else if (FunctionDecl *Fn
= ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) {
if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
return true;
@@ -1687,31 +2042,33 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
}
- if (!Context.hasSameUnqualifiedType(ArgType,
+ if (!Context.hasSameUnqualifiedType(ArgType,
ParamType.getNonReferenceType())) {
// We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
<< Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
-
+
if (ParamType->isMemberPointerType()) {
NamedDecl *Member = 0;
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
- Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member));
+ if (Member)
+ Member = cast<NamedDecl>(Member->getCanonicalDecl());
Converted = TemplateArgument(StartLoc, Member);
return false;
}
-
+
NamedDecl *Entity = 0;
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity));
+ if (Entity)
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
Converted = TemplateArgument(StartLoc, Entity);
return false;
}
@@ -1721,7 +2078,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// object, qualification conversions (4.4) and the
// array-to-pointer conversion (4.2) are applied.
// C++0x also allows a value of std::nullptr_t.
- assert(ParamType->getAsPointerType()->getPointeeType()->isObjectType() &&
+ assert(ParamType->getAs<PointerType>()->getPointeeType()->isObjectType() &&
"Only object pointers allowed here");
if (ArgType->isNullPtrType()) {
@@ -1736,26 +2093,27 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ArgType = ParamType;
ImpCastExprToType(Arg, ParamType);
}
-
+
if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) {
// We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
<< Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
-
+
NamedDecl *Entity = 0;
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity));
+ if (Entity)
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
Converted = TemplateArgument(StartLoc, Entity);
return false;
}
-
- if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
+
+ if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) {
// -- For a non-type template-parameter of type reference to
// object, no conversions apply. The type referred to by the
// reference may be more cv-qualified than the (otherwise
@@ -1766,7 +2124,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
"Only object references allowed here");
if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_no_ref_bind)
<< InstantiatedParamType << Arg->getType()
<< Arg->getSourceRange();
@@ -1774,10 +2132,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- unsigned ParamQuals
+ unsigned ParamQuals
= Context.getCanonicalType(ParamType).getCVRQualifiers();
unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers();
-
+
if ((ParamQuals | ArgQuals) != ParamQuals) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_ref_bind_ignores_quals)
@@ -1786,12 +2144,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
-
+
NamedDecl *Entity = 0;
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
Converted = TemplateArgument(StartLoc, Entity);
return false;
}
@@ -1809,18 +2167,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ImpCastExprToType(Arg, ParamType);
} else {
// We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
<< Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
+ return true;
}
NamedDecl *Member = 0;
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
-
- Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member));
+
+ if (Member)
+ Member = cast<NamedDecl>(Member->getCanonicalDecl());
Converted = TemplateArgument(StartLoc, Member);
return false;
}
@@ -1846,9 +2205,9 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
// Note that we also allow template template parameters here, which
// will happen when we are dealing with, e.g., class template
// partial specializations.
- if (!isa<ClassTemplateDecl>(Template) &&
+ if (!isa<ClassTemplateDecl>(Template) &&
!isa<TemplateTemplateParmDecl>(Template)) {
- assert(isa<FunctionTemplateDecl>(Template) &&
+ assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
Diag(Arg->getLocStart(), diag::err_template_arg_not_class_template);
Diag(Template->getLocation(), diag::note_template_arg_refers_here_func)
@@ -1864,7 +2223,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
/// \brief Determine whether the given template parameter lists are
/// equivalent.
///
-/// \param New The new template parameter list, typically written in the
+/// \param New The new template parameter list, typically written in the
/// source code as part of a new template declaration.
///
/// \param Old The old template parameter list, typically found via
@@ -1886,7 +2245,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
///
/// \returns True if the template parameter lists are equal, false
/// otherwise.
-bool
+bool
Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
bool Complain,
@@ -1898,7 +2257,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
if (TemplateArgLoc.isValid()) {
Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch);
NextDiag = diag::note_template_param_list_different_arity;
- }
+ }
Diag(New->getTemplateLoc(), NextDiag)
<< (New->size() > Old->size())
<< IsTemplateTemplateParm
@@ -1939,15 +2298,15 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
// types within the template parameter list of the template template
// parameter can be checked, and (2) the template type parameter depths
// will match up.
- QualType OldParmType
+ QualType OldParmType
= Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*OldParm));
- QualType NewParmType
+ QualType NewParmType
= Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*NewParm));
- assert(Context.getCanonicalType(OldParmType) ==
- Context.getCanonicalType(NewParmType) &&
+ assert(Context.getCanonicalType(OldParmType) ==
+ Context.getCanonicalType(NewParmType) &&
"type parameter mismatch?");
#endif
- } else if (NonTypeTemplateParmDecl *OldNTTP
+ } else if (NonTypeTemplateParmDecl *OldNTTP
= dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) {
// The types of non-type template parameters must agree.
NonTypeTemplateParmDecl *NewNTTP
@@ -1957,14 +2316,14 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
if (Complain) {
unsigned NextDiag = diag::err_template_nontype_parm_different_type;
if (TemplateArgLoc.isValid()) {
- Diag(TemplateArgLoc,
+ Diag(TemplateArgLoc,
diag::err_template_arg_template_params_mismatch);
NextDiag = diag::note_template_nontype_parm_different_type;
}
Diag(NewNTTP->getLocation(), NextDiag)
<< NewNTTP->getType()
<< IsTemplateTemplateParm;
- Diag(OldNTTP->getLocation(),
+ Diag(OldNTTP->getLocation(),
diag::note_template_nontype_parm_prev_declaration)
<< OldNTTP->getType();
}
@@ -1974,9 +2333,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
// The template parameter lists of template template
// parameters must agree.
// FIXME: Could we perform a faster "type" comparison here?
- assert(isa<TemplateTemplateParmDecl>(*OldParm) &&
+ assert(isa<TemplateTemplateParmDecl>(*OldParm) &&
"Only template template parameters handled here");
- TemplateTemplateParmDecl *OldTTP
+ TemplateTemplateParmDecl *OldTTP
= cast<TemplateTemplateParmDecl>(*OldParm);
TemplateTemplateParmDecl *NewTTP
= cast<TemplateTemplateParmDecl>(*NewParm);
@@ -1996,56 +2355,105 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
///
/// If the template declaration is valid in this scope, returns
/// false. Otherwise, issues a diagnostic and returns true.
-bool
-Sema::CheckTemplateDeclScope(Scope *S,
- MultiTemplateParamsArg &TemplateParameterLists) {
- assert(TemplateParameterLists.size() > 0 && "Not a template");
-
+bool
+Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
// Find the nearest enclosing declaration scope.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
-
- TemplateParameterList *TemplateParams =
- static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
- SourceLocation TemplateLoc = TemplateParams->getTemplateLoc();
- SourceRange TemplateRange
- = SourceRange(TemplateLoc, TemplateParams->getRAngleLoc());
// C++ [temp]p2:
// A template-declaration can appear only as a namespace scope or
// class scope declaration.
DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
- while (Ctx && isa<LinkageSpecDecl>(Ctx)) {
- if (cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx)
- return Diag(TemplateLoc, diag::err_template_linkage)
- << TemplateRange;
+ if (Ctx && isa<LinkageSpecDecl>(Ctx) &&
+ cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx)
+ return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage)
+ << TemplateParams->getSourceRange();
+ while (Ctx && isa<LinkageSpecDecl>(Ctx))
Ctx = Ctx->getParent();
- }
if (Ctx && (Ctx->isFileContext() || Ctx->isRecord()))
return false;
- return Diag(TemplateLoc, diag::err_template_outside_namespace_or_class_scope)
- << TemplateRange;
+ return Diag(TemplateParams->getTemplateLoc(),
+ diag::err_template_outside_namespace_or_class_scope)
+ << TemplateParams->getSourceRange();
+}
+
+/// \brief Determine what kind of template specialization the given declaration
+/// is.
+static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) {
+ if (!D)
+ return TSK_Undeclared;
+
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D))
+ return Record->getTemplateSpecializationKind();
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
+ return Function->getTemplateSpecializationKind();
+ if (VarDecl *Var = dyn_cast<VarDecl>(D))
+ return Var->getTemplateSpecializationKind();
+
+ return TSK_Undeclared;
}
-/// \brief Check whether a class template specialization or explicit
-/// instantiation in the current context is well-formed.
+/// \brief Check whether a specialization or explicit instantiation is
+/// well-formed in the current context.
///
-/// This routine determines whether a class template specialization or
-/// explicit instantiation can be declared in the current context
-/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]p2) and emits
-/// appropriate diagnostics if there was an error. It returns true if
-// there was an error that we cannot recover from, and false otherwise.
-bool
-Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
- ClassTemplateSpecializationDecl *PrevDecl,
- SourceLocation TemplateNameLoc,
- SourceRange ScopeSpecifierRange,
- bool PartialSpecialization,
- bool ExplicitInstantiation) {
+/// This routine determines whether a template specialization or
+/// explicit instantiation can be declared in the current context
+/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]p2).
+///
+/// \param S the semantic analysis object for which this check is being
+/// performed.
+///
+/// \param Specialized the entity being specialized or instantiated, which
+/// may be a kind of template (class template, function template, etc.) or
+/// a member of a class template (member function, static data member,
+/// member class).
+///
+/// \param PrevDecl the previous declaration of this entity, if any.
+///
+/// \param Loc the location of the explicit specialization or instantiation of
+/// this entity.
+///
+/// \param IsPartialSpecialization whether this is a partial specialization of
+/// a class template.
+///
+/// \param TSK the kind of specialization or implicit instantiation being
+/// performed.
+///
+/// \returns true if there was an error that we cannot recover from, false
+/// otherwise.
+static bool CheckTemplateSpecializationScope(Sema &S,
+ NamedDecl *Specialized,
+ NamedDecl *PrevDecl,
+ SourceLocation Loc,
+ bool IsPartialSpecialization,
+ TemplateSpecializationKind TSK) {
+ // Keep these "kind" numbers in sync with the %select statements in the
+ // various diagnostics emitted by this routine.
+ int EntityKind = 0;
+ bool isTemplateSpecialization = false;
+ if (isa<ClassTemplateDecl>(Specialized)) {
+ EntityKind = IsPartialSpecialization? 1 : 0;
+ isTemplateSpecialization = true;
+ } else if (isa<FunctionTemplateDecl>(Specialized)) {
+ EntityKind = 2;
+ isTemplateSpecialization = true;
+ } else if (isa<CXXMethodDecl>(Specialized))
+ EntityKind = 3;
+ else if (isa<VarDecl>(Specialized))
+ EntityKind = 4;
+ else if (isa<RecordDecl>(Specialized))
+ EntityKind = 5;
+ else {
+ S.Diag(Loc, diag::err_template_spec_unknown_kind) << TSK;
+ S.Diag(Specialized->getLocation(), diag::note_specialized_entity) << TSK;
+ return true;
+ }
+
// C++ [temp.expl.spec]p2:
// An explicit specialization shall be declared in the namespace
// of which the template is a member, or, for member templates, in
@@ -2059,66 +2467,79 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
// the explicit specialization was declared, or in a namespace
// that encloses the one in which the explicit specialization was
// declared.
- if (CurContext->getLookupContext()->isFunctionOrMethod()) {
- int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0;
- Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope)
- << Kind << ClassTemplate;
+ if (S.CurContext->getLookupContext()->isFunctionOrMethod()) {
+ S.Diag(Loc, diag::err_template_spec_decl_function_scope)
+ << TSK << Specialized;
return true;
}
- DeclContext *DC = CurContext->getEnclosingNamespaceContext();
- DeclContext *TemplateContext
- = ClassTemplate->getDeclContext()->getEnclosingNamespaceContext();
- if ((!PrevDecl || PrevDecl->getSpecializationKind() == TSK_Undeclared) &&
- !ExplicitInstantiation) {
- // There is no prior declaration of this entity, so this
- // specialization must be in the same context as the template
- // itself.
- if (DC != TemplateContext) {
- if (isa<TranslationUnitDecl>(TemplateContext))
- Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope_global)
- << PartialSpecialization
- << ClassTemplate << ScopeSpecifierRange;
- else if (isa<NamespaceDecl>(TemplateContext))
- Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope)
- << PartialSpecialization << ClassTemplate
- << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange;
-
- Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
- }
-
- return false;
+ if (S.CurContext->isRecord() && !IsPartialSpecialization) {
+ S.Diag(Loc, diag::err_template_spec_decl_class_scope)
+ << TSK << Specialized;
+ return true;
}
-
- // We have a previous declaration of this entity. Make sure that
- // this redeclaration (or definition) occurs in an enclosing namespace.
- if (!CurContext->Encloses(TemplateContext)) {
- // FIXME: In C++98, we would like to turn these errors into warnings,
- // dependent on a -Wc++0x flag.
- bool SuppressedDiag = false;
- int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0;
- if (isa<TranslationUnitDecl>(TemplateContext)) {
- if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
- Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
- << Kind << ClassTemplate << ScopeSpecifierRange;
- else
- SuppressedDiag = true;
- } else if (isa<NamespaceDecl>(TemplateContext)) {
- if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
- Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope)
- << Kind << ClassTemplate
- << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange;
- else
- SuppressedDiag = true;
+
+ // C++ [temp.class.spec]p6:
+ // A class template partial specialization may be declared or redeclared
+ // in any namespace scope in which its definition may be defined (14.5.1
+ // and 14.5.2).
+ bool ComplainedAboutScope = false;
+ DeclContext *SpecializedContext
+ = Specialized->getDeclContext()->getEnclosingNamespaceContext();
+ DeclContext *DC = S.CurContext->getEnclosingNamespaceContext();
+ if (TSK == TSK_ExplicitSpecialization) {
+ if ((!PrevDecl ||
+ getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared ||
+ getTemplateSpecializationKind(PrevDecl) == TSK_ImplicitInstantiation)){
+ // There is no prior declaration of this entity, so this
+ // specialization must be in the same context as the template
+ // itself.
+ if (!DC->Equals(SpecializedContext)) {
+ if (isa<TranslationUnitDecl>(SpecializedContext))
+ S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global)
+ << EntityKind << Specialized;
+ else if (isa<NamespaceDecl>(SpecializedContext))
+ S.Diag(Loc, diag::err_template_spec_decl_out_of_scope)
+ << EntityKind << Specialized
+ << cast<NamedDecl>(SpecializedContext);
+
+ S.Diag(Specialized->getLocation(), diag::note_specialized_entity)
+ << TSK;
+ ComplainedAboutScope = true;
+ }
}
-
- if (!SuppressedDiag)
- Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
}
-
+
+ // Make sure that this redeclaration (or definition) occurs in an enclosing
+ // namespace. We perform this check for explicit specializations and, in
+ // C++0x, for explicit instantiations as well (per DR275).
+ // FIXME: -Wc++0x should make these warnings.
+ // Note that HandleDeclarator() performs this check for explicit
+ // specializations of function templates, static data members, and member
+ // functions, so we skip the check here for those kinds of entities.
+ // FIXME: HandleDeclarator's diagnostics aren't quite as good, though.
+ // Should we refactor that check, so that it occurs later?
+ if (!ComplainedAboutScope && !DC->Encloses(SpecializedContext) &&
+ ((TSK == TSK_ExplicitSpecialization &&
+ !(isa<FunctionTemplateDecl>(Specialized) || isa<VarDecl>(Specialized) ||
+ isa<FunctionDecl>(Specialized))) ||
+ S.getLangOptions().CPlusPlus0x)) {
+ if (isa<TranslationUnitDecl>(SpecializedContext))
+ S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
+ << EntityKind << Specialized;
+ else if (isa<NamespaceDecl>(SpecializedContext))
+ S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
+ << EntityKind << Specialized
+ << cast<NamedDecl>(SpecializedContext);
+
+ S.Diag(Specialized->getLocation(), diag::note_specialized_entity) << TSK;
+ }
+
+ // FIXME: check for specialization-after-instantiation errors and such.
+
return false;
}
-
+
/// \brief Check the non-type template arguments of a class template
/// partial specialization according to C++ [temp.class.spec]p9.
///
@@ -2142,16 +2563,16 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
// FIXME: the interface to this function will have to change to
// accommodate variadic templates.
MirrorsPrimaryTemplate = true;
-
+
const TemplateArgument *ArgList = TemplateArgs.getFlatArguments();
-
+
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
// Determine whether the template argument list of the partial
// specialization is identical to the implicit argument list of
// the primary template. The caller may need to diagnostic this as
// an error per C++ [temp.class.spec]p9b3.
if (MirrorsPrimaryTemplate) {
- if (TemplateTypeParmDecl *TTP
+ if (TemplateTypeParmDecl *TTP
= dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(I))) {
if (Context.getCanonicalType(Context.getTypeDeclType(TTP)) !=
Context.getCanonicalType(ArgList[I].getAsType()))
@@ -2161,11 +2582,11 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
TemplateParams->getParam(I))) {
// FIXME: We should settle on either Declaration storage or
// Expression storage for template template parameters.
- TemplateTemplateParmDecl *ArgDecl
+ TemplateTemplateParmDecl *ArgDecl
= dyn_cast_or_null<TemplateTemplateParmDecl>(
ArgList[I].getAsDecl());
if (!ArgDecl)
- if (DeclRefExpr *DRE
+ if (DeclRefExpr *DRE
= dyn_cast_or_null<DeclRefExpr>(ArgList[I].getAsExpr()))
ArgDecl = dyn_cast<TemplateTemplateParmDecl>(DRE->getDecl());
@@ -2176,7 +2597,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
}
}
- NonTypeTemplateParmDecl *Param
+ NonTypeTemplateParmDecl *Param
= dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I));
if (!Param) {
continue;
@@ -2197,9 +2618,9 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
// specialized non-type arguments, so skip any non-specialized
// arguments.
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr))
- if (NonTypeTemplateParmDecl *NTTP
+ if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl())) {
- if (MirrorsPrimaryTemplate &&
+ if (MirrorsPrimaryTemplate &&
(Param->getIndex() != NTTP->getIndex() ||
Param->getDepth() != NTTP->getDepth()))
MirrorsPrimaryTemplate = false;
@@ -2215,7 +2636,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
// specialization except when the argument expression is a
// simple identifier.
if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) {
- Diag(ArgExpr->getLocStart(),
+ Diag(ArgExpr->getLocStart(),
diag::err_dependent_non_type_arg_in_partial_spec)
<< ArgExpr->getSourceRange();
return true;
@@ -2225,7 +2646,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
// specialized non-type argument shall not be dependent on a
// parameter of the specialization.
if (Param->getType()->isDependentType()) {
- Diag(ArgExpr->getLocStart(),
+ Diag(ArgExpr->getLocStart(),
diag::err_dependent_typed_non_type_arg_in_partial_spec)
<< Param->getType()
<< ArgExpr->getSourceRange();
@@ -2240,8 +2661,9 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
}
Sema::DeclResult
-Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
- SourceLocation KWLoc,
+Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
+ TagUseKind TUK,
+ SourceLocation KWLoc,
const CXXScopeSpec &SS,
TemplateTy TemplateD,
SourceLocation TemplateNameLoc,
@@ -2251,65 +2673,72 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation RAngleLoc,
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists) {
+ assert(TUK != TUK_Reference && "References are not specializations");
+
// Find the class template we're specializing
TemplateName Name = TemplateD.getAsVal<TemplateName>();
- ClassTemplateDecl *ClassTemplate
+ ClassTemplateDecl *ClassTemplate
= cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
+ bool isExplicitSpecialization = false;
bool isPartialSpecialization = false;
// Check the validity of the template headers that introduce this
// template.
- // FIXME: Once we have member templates, we'll need to check
- // C++ [temp.expl.spec]p17-18, where we could have multiple levels of
- // template<> headers.
- if (TemplateParameterLists.size() == 0)
- Diag(KWLoc, diag::err_template_spec_needs_header)
- << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
- else {
- TemplateParameterList *TemplateParams
- = static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
- if (TemplateParameterLists.size() > 1) {
- Diag(TemplateParams->getTemplateLoc(),
- diag::err_template_spec_extra_headers);
- return true;
- }
-
- if (TemplateParams->size() > 0) {
- isPartialSpecialization = true;
-
- // C++ [temp.class.spec]p10:
- // The template parameter list of a specialization shall not
- // contain default template argument values.
- for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
- Decl *Param = TemplateParams->getParam(I);
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
- if (TTP->hasDefaultArgument()) {
- Diag(TTP->getDefaultArgumentLoc(),
- diag::err_default_arg_in_partial_spec);
- TTP->setDefaultArgument(QualType(), SourceLocation(), false);
- }
- } else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- if (Expr *DefArg = NTTP->getDefaultArgument()) {
- Diag(NTTP->getDefaultArgumentLoc(),
- diag::err_default_arg_in_partial_spec)
- << DefArg->getSourceRange();
- NTTP->setDefaultArgument(0);
- DefArg->Destroy(Context);
- }
- } else {
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
- if (Expr *DefArg = TTP->getDefaultArgument()) {
- Diag(TTP->getDefaultArgumentLoc(),
- diag::err_default_arg_in_partial_spec)
- << DefArg->getSourceRange();
- TTP->setDefaultArgument(0);
- DefArg->Destroy(Context);
- }
+ // FIXME: We probably shouldn't complain about these headers for
+ // friend declarations.
+ TemplateParameterList *TemplateParams
+ = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
+ (TemplateParameterList**)TemplateParameterLists.get(),
+ TemplateParameterLists.size(),
+ isExplicitSpecialization);
+ if (TemplateParams && TemplateParams->size() > 0) {
+ isPartialSpecialization = true;
+
+ // C++ [temp.class.spec]p10:
+ // The template parameter list of a specialization shall not
+ // contain default template argument values.
+ for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
+ Decl *Param = TemplateParams->getParam(I);
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ if (TTP->hasDefaultArgument()) {
+ Diag(TTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec);
+ TTP->setDefaultArgument(QualType(), SourceLocation(), false);
+ }
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (Expr *DefArg = NTTP->getDefaultArgument()) {
+ Diag(NTTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec)
+ << DefArg->getSourceRange();
+ NTTP->setDefaultArgument(0);
+ DefArg->Destroy(Context);
+ }
+ } else {
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
+ if (Expr *DefArg = TTP->getDefaultArgument()) {
+ Diag(TTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec)
+ << DefArg->getSourceRange();
+ TTP->setDefaultArgument(0);
+ DefArg->Destroy(Context);
}
}
}
+ } else if (TemplateParams) {
+ if (TUK == TUK_Friend)
+ Diag(KWLoc, diag::err_template_spec_friend)
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(TemplateParams->getTemplateLoc(),
+ TemplateParams->getRAngleLoc()))
+ << SourceRange(LAngleLoc, RAngleLoc);
+ else
+ isExplicitSpecialization = true;
+ } else if (TUK != TUK_Friend) {
+ Diag(KWLoc, diag::err_template_spec_needs_header)
+ << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
+ isExplicitSpecialization = true;
}
// Check that the specialization uses the same tag kind as the
@@ -2322,13 +2751,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
}
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
- Kind, KWLoc,
+ Kind, KWLoc,
*ClassTemplate->getIdentifier())) {
- Diag(KWLoc, diag::err_use_with_wrong_tag)
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
- << CodeModificationHint::CreateReplacement(KWLoc,
+ << CodeModificationHint::CreateReplacement(KWLoc,
ClassTemplate->getTemplatedDecl()->getKindName());
- Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
+ Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
diag::note_previous_use);
Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
}
@@ -2341,15 +2770,15 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// template.
TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
TemplateArgs.size());
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
TemplateArgs.data(), TemplateArgs.size(),
RAngleLoc, false, Converted))
return true;
- assert((Converted.structuredSize() ==
+ assert((Converted.structuredSize() ==
ClassTemplate->getTemplateParameters()->size()) &&
"Converted template argument list is too short!");
-
+
// Find the class template (partial) specialization declaration that
// corresponds to these arguments.
llvm::FoldingSetNodeID ID;
@@ -2363,35 +2792,38 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
if (MirrorsPrimaryTemplate) {
// C++ [temp.class.spec]p9b3:
//
- // -- The argument list of the specialization shall not be identical
- // to the implicit argument list of the primary template.
+ // -- The argument list of the specialization shall not be identical
+ // to the implicit argument list of the primary template.
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
- << (TK == TK_Definition)
- << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc,
+ << (TUK == TUK_Definition)
+ << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc,
RAngleLoc));
- return ActOnClassTemplate(S, TagSpec, TK, KWLoc, SS,
+ return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
ClassTemplate->getIdentifier(),
TemplateNameLoc,
Attr,
- move(TemplateParameterLists),
+ TemplateParams,
AS_none);
}
+ // FIXME: Diagnose friend partial specializations
+
// FIXME: Template parameter list matters, too
- ClassTemplatePartialSpecializationDecl::Profile(ID,
+ ClassTemplatePartialSpecializationDecl::Profile(ID,
Converted.getFlatArguments(),
- Converted.flatSize());
- }
- else
+ Converted.flatSize(),
+ Context);
+ } else
ClassTemplateSpecializationDecl::Profile(ID,
Converted.getFlatArguments(),
- Converted.flatSize());
+ Converted.flatSize(),
+ Context);
void *InsertPos = 0;
ClassTemplateSpecializationDecl *PrevDecl = 0;
if (isPartialSpecialization)
PrevDecl
- = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID,
+ = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID,
InsertPos);
else
PrevDecl
@@ -2401,29 +2833,41 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// Check whether we can declare a class template specialization in
// the current scope.
- if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl,
- TemplateNameLoc,
- SS.getRange(),
- isPartialSpecialization,
- /*ExplicitInstantiation=*/false))
+ if (TUK != TUK_Friend &&
+ CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl,
+ TemplateNameLoc, isPartialSpecialization,
+ TSK_ExplicitSpecialization))
return true;
-
- if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
+
+ // The canonical type
+ QualType CanonType;
+ if (PrevDecl &&
+ (PrevDecl->getSpecializationKind() == TSK_Undeclared ||
+ TUK == TUK_Friend)) {
// Since the only prior class template specialization with these
- // arguments was referenced but not declared, reuse that
+ // arguments was referenced but not declared, or we're only
+ // referencing this specialization as a friend, reuse that
// declaration node as our own, updating its source location to
// reflect our new declaration.
Specialization = PrevDecl;
Specialization->setLocation(TemplateNameLoc);
PrevDecl = 0;
+ CanonType = Context.getTypeDeclType(Specialization);
} else if (isPartialSpecialization) {
+ // Build the canonical type that describes the converted template
+ // arguments of the class template partial specialization.
+ CanonType = Context.getTemplateSpecializationType(
+ TemplateName(ClassTemplate),
+ Converted.getFlatArguments(),
+ Converted.flatSize());
+
// Create a new class template partial specialization declaration node.
- TemplateParameterList *TemplateParams
+ TemplateParameterList *TemplateParams
= static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
ClassTemplatePartialSpecializationDecl *PrevPartial
= cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
- ClassTemplatePartialSpecializationDecl *Partial
- = ClassTemplatePartialSpecializationDecl::Create(Context,
+ ClassTemplatePartialSpecializationDecl *Partial
+ = ClassTemplatePartialSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
TemplateParams,
@@ -2445,7 +2889,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// will never be used.
llvm::SmallVector<bool, 8> DeducibleParams;
DeducibleParams.resize(TemplateParams->size());
- MarkDeducedTemplateParameters(Partial->getTemplateArgs(), DeducibleParams);
+ MarkUsedTemplateParameters(Partial->getTemplateArgs(), true,
+ DeducibleParams);
unsigned NumNonDeducible = 0;
for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I)
if (!DeducibleParams[I])
@@ -2459,25 +2904,24 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
if (!DeducibleParams[I]) {
NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
if (Param->getDeclName())
- Diag(Param->getLocation(),
+ Diag(Param->getLocation(),
diag::note_partial_spec_unused_parameter)
<< Param->getDeclName();
else
- Diag(Param->getLocation(),
+ Diag(Param->getLocation(),
diag::note_partial_spec_unused_parameter)
<< std::string("<anonymous>");
}
}
}
-
} else {
// Create a new class template specialization declaration node for
- // this explicit specialization.
+ // this explicit specialization or friend declaration.
Specialization
- = ClassTemplateSpecializationDecl::Create(Context,
+ = ClassTemplateSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
- ClassTemplate,
+ ClassTemplate,
Converted,
PrevDecl);
@@ -2485,21 +2929,40 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
ClassTemplate->getSpecializations().RemoveNode(PrevDecl);
ClassTemplate->getSpecializations().GetOrInsertNode(Specialization);
} else {
- ClassTemplate->getSpecializations().InsertNode(Specialization,
+ ClassTemplate->getSpecializations().InsertNode(Specialization,
InsertPos);
}
+
+ CanonType = Context.getTypeDeclType(Specialization);
}
- // Note that this is an explicit specialization.
- Specialization->setSpecializationKind(TSK_ExplicitSpecialization);
+ // C++ [temp.expl.spec]p6:
+ // If a template, a member template or the member of a class template is
+ // explicitly specialized then that specialization shall be declared
+ // before the first use of that specialization that would cause an implicit
+ // instantiation to take place, in every translation unit in which such a
+ // use occurs; no diagnostic is required.
+ if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) {
+ SourceRange Range(TemplateNameLoc, RAngleLoc);
+ Diag(TemplateNameLoc, diag::err_specialization_after_instantiation)
+ << Context.getTypeDeclType(Specialization) << Range;
+
+ Diag(PrevDecl->getPointOfInstantiation(),
+ diag::note_instantiation_required_here)
+ << (PrevDecl->getTemplateSpecializationKind()
+ != TSK_ImplicitInstantiation);
+ return true;
+ }
+
+ // If this is not a friend, note that this is an explicit specialization.
+ if (TUK != TUK_Friend)
+ Specialization->setSpecializationKind(TSK_ExplicitSpecialization);
// Check that this isn't a redefinition of this specialization.
- if (TK == TK_Definition) {
+ if (TUK == TUK_Definition) {
if (RecordDecl *Def = Specialization->getDefinition(Context)) {
- // FIXME: Should also handle explicit specialization after implicit
- // instantiation with a special diagnostic.
SourceRange Range(TemplateNameLoc, RAngleLoc);
- Diag(TemplateNameLoc, diag::err_redefinition)
+ Diag(TemplateNameLoc, diag::err_redefinition)
<< Context.getTypeDeclType(Specialization) << Range;
Diag(Def->getLocation(), diag::note_previous_definition);
Specialization->setInvalidDecl();
@@ -2514,12 +2977,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// actually wrote the specialization, rather than formatting the
// name based on the "canonical" representation used to store the
// template arguments in the specialization.
- QualType WrittenTy
- = Context.getTemplateSpecializationType(Name,
+ QualType WrittenTy
+ = Context.getTemplateSpecializationType(Name,
TemplateArgs.data(),
TemplateArgs.size(),
- Context.getTypeDeclType(Specialization));
- Specialization->setTypeAsWritten(WrittenTy);
+ CanonType);
+ if (TUK != TUK_Friend)
+ Specialization->setTypeAsWritten(WrittenTy);
TemplateArgsIn.release();
// C++ [temp.expl.spec]p9:
@@ -2531,56 +2995,343 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// but we also maintain the lexical context where the actual
// definition occurs.
Specialization->setLexicalDeclContext(CurContext);
-
+
// We may be starting the definition of this specialization.
- if (TK == TK_Definition)
+ if (TUK == TUK_Definition)
Specialization->startDefinition();
- // Add the specialization into its lexical context, so that it can
- // be seen when iterating through the list of declarations in that
- // context. However, specializations are not found by name lookup.
- CurContext->addDecl(Specialization);
+ if (TUK == TUK_Friend) {
+ FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
+ TemplateNameLoc,
+ WrittenTy.getTypePtr(),
+ /*FIXME:*/KWLoc);
+ Friend->setAccess(AS_public);
+ CurContext->addDecl(Friend);
+ } else {
+ // Add the specialization into its lexical context, so that it can
+ // be seen when iterating through the list of declarations in that
+ // context. However, specializations are not found by name lookup.
+ CurContext->addDecl(Specialization);
+ }
return DeclPtrTy::make(Specialization);
}
-Sema::DeclPtrTy
-Sema::ActOnTemplateDeclarator(Scope *S,
+Sema::DeclPtrTy
+Sema::ActOnTemplateDeclarator(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
return HandleDeclarator(S, D, move(TemplateParameterLists), false);
}
-Sema::DeclPtrTy
-Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
+Sema::DeclPtrTy
+Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
assert(getCurFunctionDecl() == 0 && "Function parsing confused");
assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
"Not a function declarator!");
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
-
+
if (FTI.hasPrototype) {
- // FIXME: Diagnose arguments without names in C.
+ // FIXME: Diagnose arguments without names in C.
}
-
+
Scope *ParentScope = FnBodyScope->getParent();
-
- DeclPtrTy DP = HandleDeclarator(ParentScope, D,
+
+ DeclPtrTy DP = HandleDeclarator(ParentScope, D,
move(TemplateParameterLists),
/*IsFunctionDefinition=*/true);
- FunctionTemplateDecl *FunctionTemplate
- = cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>());
- if (FunctionTemplate)
- return ActOnStartOfFunctionDef(FnBodyScope,
+ if (FunctionTemplateDecl *FunctionTemplate
+ = dyn_cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>()))
+ return ActOnStartOfFunctionDef(FnBodyScope,
DeclPtrTy::make(FunctionTemplate->getTemplatedDecl()));
-
+ if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(DP.getAs<Decl>()))
+ return ActOnStartOfFunctionDef(FnBodyScope, DeclPtrTy::make(Function));
return DeclPtrTy();
}
+/// \brief Perform semantic analysis for the given function template
+/// specialization.
+///
+/// This routine performs all of the semantic analysis required for an
+/// explicit function template specialization. On successful completion,
+/// the function declaration \p FD will become a function template
+/// specialization.
+///
+/// \param FD the function declaration, which will be updated to become a
+/// function template specialization.
+///
+/// \param HasExplicitTemplateArgs whether any template arguments were
+/// explicitly provided.
+///
+/// \param LAngleLoc the location of the left angle bracket ('<'), if
+/// template arguments were explicitly provided.
+///
+/// \param ExplicitTemplateArgs the explicitly-provided template arguments,
+/// if any.
+///
+/// \param NumExplicitTemplateArgs the number of explicitly-provided template
+/// arguments. This number may be zero even when HasExplicitTemplateArgs is
+/// true as in, e.g., \c void sort<>(char*, char*);
+///
+/// \param RAngleLoc the location of the right angle bracket ('>'), if
+/// template arguments were explicitly provided.
+///
+/// \param PrevDecl the set of declarations that
+bool
+Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ SourceLocation RAngleLoc,
+ NamedDecl *&PrevDecl) {
+ // The set of function template specializations that could match this
+ // explicit function template specialization.
+ typedef llvm::SmallVector<FunctionDecl *, 8> CandidateSet;
+ CandidateSet Candidates;
+
+ DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext();
+ for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) {
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl)) {
+ // Only consider templates found within the same semantic lookup scope as
+ // FD.
+ if (!FDLookupContext->Equals(Ovl->getDeclContext()->getLookupContext()))
+ continue;
+
+ // C++ [temp.expl.spec]p11:
+ // A trailing template-argument can be left unspecified in the
+ // template-id naming an explicit function template specialization
+ // provided it can be deduced from the function argument type.
+ // Perform template argument deduction to determine whether we may be
+ // specializing this template.
+ // FIXME: It is somewhat wasteful to build
+ TemplateDeductionInfo Info(Context);
+ FunctionDecl *Specialization = 0;
+ if (TemplateDeductionResult TDK
+ = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ FD->getType(),
+ Specialization,
+ Info)) {
+ // FIXME: Template argument deduction failed; record why it failed, so
+ // that we can provide nifty diagnostics.
+ (void)TDK;
+ continue;
+ }
+
+ // Record this candidate.
+ Candidates.push_back(Specialization);
+ }
+ }
+
+ // Find the most specialized function template.
+ FunctionDecl *Specialization = getMostSpecialized(Candidates.data(),
+ Candidates.size(),
+ TPOC_Other,
+ FD->getLocation(),
+ PartialDiagnostic(diag::err_function_template_spec_no_match)
+ << FD->getDeclName(),
+ PartialDiagnostic(diag::err_function_template_spec_ambiguous)
+ << FD->getDeclName() << HasExplicitTemplateArgs,
+ PartialDiagnostic(diag::note_function_template_spec_matched));
+ if (!Specialization)
+ return true;
+
+ // FIXME: Check if the prior specialization has a point of instantiation.
+ // If so, we have run afoul of .
+
+ // Check the scope of this explicit specialization.
+ if (CheckTemplateSpecializationScope(*this,
+ Specialization->getPrimaryTemplate(),
+ Specialization, FD->getLocation(),
+ false, TSK_ExplicitSpecialization))
+ return true;
+
+ // C++ [temp.expl.spec]p6:
+ // If a template, a member template or the member of a class template is
+ // explicitly specialized then that spe- cialization shall be declared
+ // before the first use of that specialization that would cause an implicit
+ // instantiation to take place, in every translation unit in which such a
+ // use occurs; no diagnostic is required.
+ FunctionTemplateSpecializationInfo *SpecInfo
+ = Specialization->getTemplateSpecializationInfo();
+ assert(SpecInfo && "Function template specialization info missing?");
+ if (SpecInfo->getPointOfInstantiation().isValid()) {
+ Diag(FD->getLocation(), diag::err_specialization_after_instantiation)
+ << FD;
+ Diag(SpecInfo->getPointOfInstantiation(),
+ diag::note_instantiation_required_here)
+ << (Specialization->getTemplateSpecializationKind()
+ != TSK_ImplicitInstantiation);
+ return true;
+ }
+
+ // Mark the prior declaration as an explicit specialization, so that later
+ // clients know that this is an explicit specialization.
+ SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
+
+ // Turn the given function declaration into a function template
+ // specialization, with the template arguments from the previous
+ // specialization.
+ FD->setFunctionTemplateSpecialization(Context,
+ Specialization->getPrimaryTemplate(),
+ new (Context) TemplateArgumentList(
+ *Specialization->getTemplateSpecializationArgs()),
+ /*InsertPos=*/0,
+ TSK_ExplicitSpecialization);
+
+ // The "previous declaration" for this function template specialization is
+ // the prior function template specialization.
+ PrevDecl = Specialization;
+ return false;
+}
+
+/// \brief Perform semantic analysis for the given non-template member
+/// specialization.
+///
+/// This routine performs all of the semantic analysis required for an
+/// explicit member function specialization. On successful completion,
+/// the function declaration \p FD will become a member function
+/// specialization.
+///
+/// \param Member the member declaration, which will be updated to become a
+/// specialization.
+///
+/// \param PrevDecl the set of declarations, one of which may be specialized
+/// by this function specialization.
+bool
+Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) {
+ assert(!isa<TemplateDecl>(Member) && "Only for non-template members");
+
+ // Try to find the member we are instantiating.
+ NamedDecl *Instantiation = 0;
+ NamedDecl *InstantiatedFrom = 0;
+ MemberSpecializationInfo *MSInfo = 0;
+
+ if (!PrevDecl) {
+ // Nowhere to look anyway.
+ } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Member)) {
+ for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl)) {
+ if (Context.hasSameType(Function->getType(), Method->getType())) {
+ Instantiation = Method;
+ InstantiatedFrom = Method->getInstantiatedFromMemberFunction();
+ MSInfo = Method->getMemberSpecializationInfo();
+ break;
+ }
+ }
+ }
+ } else if (isa<VarDecl>(Member)) {
+ if (VarDecl *PrevVar = dyn_cast<VarDecl>(PrevDecl))
+ if (PrevVar->isStaticDataMember()) {
+ Instantiation = PrevDecl;
+ InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember();
+ MSInfo = PrevVar->getMemberSpecializationInfo();
+ }
+ } else if (isa<RecordDecl>(Member)) {
+ if (CXXRecordDecl *PrevRecord = dyn_cast<CXXRecordDecl>(PrevDecl)) {
+ Instantiation = PrevDecl;
+ InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass();
+ MSInfo = PrevRecord->getMemberSpecializationInfo();
+ }
+ }
+
+ if (!Instantiation) {
+ // There is no previous declaration that matches. Since member
+ // specializations are always out-of-line, the caller will complain about
+ // this mismatch later.
+ return false;
+ }
+
+ // Make sure that this is a specialization of a member.
+ if (!InstantiatedFrom) {
+ Diag(Member->getLocation(), diag::err_spec_member_not_instantiated)
+ << Member;
+ Diag(Instantiation->getLocation(), diag::note_specialized_decl);
+ return true;
+ }
+
+ // C++ [temp.expl.spec]p6:
+ // If a template, a member template or the member of a class template is
+ // explicitly specialized then that spe- cialization shall be declared
+ // before the first use of that specialization that would cause an implicit
+ // instantiation to take place, in every translation unit in which such a
+ // use occurs; no diagnostic is required.
+ assert(MSInfo && "Member specialization info missing?");
+ if (MSInfo->getPointOfInstantiation().isValid()) {
+ Diag(Member->getLocation(), diag::err_specialization_after_instantiation)
+ << Member;
+ Diag(MSInfo->getPointOfInstantiation(),
+ diag::note_instantiation_required_here)
+ << (MSInfo->getTemplateSpecializationKind() != TSK_ImplicitInstantiation);
+ return true;
+ }
+
+ // Check the scope of this explicit specialization.
+ if (CheckTemplateSpecializationScope(*this,
+ InstantiatedFrom,
+ Instantiation, Member->getLocation(),
+ false, TSK_ExplicitSpecialization))
+ return true;
+
+ // Note that this is an explicit instantiation of a member.
+ // the original declaration to note that it is an explicit specialization
+ // (if it was previously an implicit instantiation). This latter step
+ // makes bookkeeping easier.
+ if (isa<FunctionDecl>(Member)) {
+ FunctionDecl *InstantiationFunction = cast<FunctionDecl>(Instantiation);
+ if (InstantiationFunction->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationFunction->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationFunction->setLocation(Member->getLocation());
+ }
+
+ cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
+ cast<CXXMethodDecl>(InstantiatedFrom),
+ TSK_ExplicitSpecialization);
+ } else if (isa<VarDecl>(Member)) {
+ VarDecl *InstantiationVar = cast<VarDecl>(Instantiation);
+ if (InstantiationVar->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationVar->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationVar->setLocation(Member->getLocation());
+ }
+
+ Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
+ cast<VarDecl>(InstantiatedFrom),
+ TSK_ExplicitSpecialization);
+ } else {
+ assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
+ CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
+ if (InstantiationClass->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationClass->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationClass->setLocation(Member->getLocation());
+ }
+
+ cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
+ cast<CXXRecordDecl>(InstantiatedFrom),
+ TSK_ExplicitSpecialization);
+ }
+
+ // Save the caller the trouble of having to figure out which declaration
+ // this specialization matches.
+ PrevDecl = Instantiation;
+ return false;
+}
+
// Explicit instantiation of a class template specialization
+// FIXME: Implement extern template semantics
Sema::DeclResult
-Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
- unsigned TagSpec,
+Sema::ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
TemplateTy TemplateD,
@@ -2592,7 +3343,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
AttributeList *Attr) {
// Find the class template we're specializing
TemplateName Name = TemplateD.getAsVal<TemplateName>();
- ClassTemplateDecl *ClassTemplate
+ ClassTemplateDecl *ClassTemplate
= cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
// Check that the specialization uses the same tag kind as the
@@ -2605,29 +3356,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
}
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
- Kind, KWLoc,
+ Kind, KWLoc,
*ClassTemplate->getIdentifier())) {
- Diag(KWLoc, diag::err_use_with_wrong_tag)
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
- << CodeModificationHint::CreateReplacement(KWLoc,
+ << CodeModificationHint::CreateReplacement(KWLoc,
ClassTemplate->getTemplatedDecl()->getKindName());
- Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
+ Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
diag::note_previous_use);
Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
}
- // C++0x [temp.explicit]p2:
- // [...] An explicit instantiation shall appear in an enclosing
- // namespace of its template. [...]
- //
- // This is C++ DR 275.
- if (CheckClassTemplateSpecializationScope(ClassTemplate, 0,
- TemplateNameLoc,
- SS.getRange(),
- /*PartialSpecialization=*/false,
- /*ExplicitInstantiation=*/true))
- return true;
-
+ TemplateSpecializationKind TSK
+ = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+ : TSK_ExplicitInstantiationDeclaration;
+
// Translate the parser's template argument list in our AST format.
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
@@ -2636,35 +3379,47 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// template.
TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
TemplateArgs.size());
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
TemplateArgs.data(), TemplateArgs.size(),
RAngleLoc, false, Converted))
return true;
- assert((Converted.structuredSize() ==
+ assert((Converted.structuredSize() ==
ClassTemplate->getTemplateParameters()->size()) &&
"Converted template argument list is too short!");
-
+
// Find the class template specialization declaration that
// corresponds to these arguments.
llvm::FoldingSetNodeID ID;
- ClassTemplateSpecializationDecl::Profile(ID,
+ ClassTemplateSpecializationDecl::Profile(ID,
Converted.getFlatArguments(),
- Converted.flatSize());
+ Converted.flatSize(),
+ Context);
void *InsertPos = 0;
ClassTemplateSpecializationDecl *PrevDecl
= ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+ // C++0x [temp.explicit]p2:
+ // [...] An explicit instantiation shall appear in an enclosing
+ // namespace of its template. [...]
+ //
+ // This is C++ DR 275.
+ if (CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl,
+ TemplateNameLoc, false,
+ TSK))
+ return true;
+
ClassTemplateSpecializationDecl *Specialization = 0;
bool SpecializationRequiresInstantiation = true;
if (PrevDecl) {
- if (PrevDecl->getSpecializationKind() == TSK_ExplicitInstantiation) {
+ if (PrevDecl->getSpecializationKind()
+ == TSK_ExplicitInstantiationDefinition) {
// This particular specialization has already been declared or
// instantiated. We cannot explicitly instantiate it.
Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate)
<< Context.getTypeDeclType(PrevDecl);
- Diag(PrevDecl->getLocation(),
+ Diag(PrevDecl->getLocation(),
diag::note_previous_explicit_instantiation);
return DeclPtrTy::make(PrevDecl);
}
@@ -2676,10 +3431,10 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// an explicit specialization for that template, the explicit
// instantiation has no effect.
if (!getLangOptions().CPlusPlus0x) {
- Diag(TemplateNameLoc,
+ Diag(TemplateNameLoc,
diag::ext_explicit_instantiation_after_specialization)
<< Context.getTypeDeclType(PrevDecl);
- Diag(PrevDecl->getLocation(),
+ Diag(PrevDecl->getLocation(),
diag::note_previous_template_specialization);
}
@@ -2689,14 +3444,14 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// accurate reproduction of the source code; we don't actually
// use it for anything, since it is semantically irrelevant.
Specialization
- = ClassTemplateSpecializationDecl::Create(Context,
+ = ClassTemplateSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
Converted, 0);
Specialization->setLexicalDeclContext(CurContext);
CurContext->addDecl(Specialization);
- return DeclPtrTy::make(Specialization);
+ return DeclPtrTy::make(PrevDecl);
}
// If we have already (implicitly) instantiated this
@@ -2704,25 +3459,37 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation)
SpecializationRequiresInstantiation = false;
- // Since the only prior class template specialization with these
- // arguments was referenced but not declared, reuse that
- // declaration node as our own, updating its source location to
- // reflect our new declaration.
- Specialization = PrevDecl;
- Specialization->setLocation(TemplateNameLoc);
- PrevDecl = 0;
- } else {
+ if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation ||
+ PrevDecl->getSpecializationKind() == TSK_Undeclared) {
+ // Since the only prior class template specialization with these
+ // arguments was referenced but not declared, reuse that
+ // declaration node as our own, updating its source location to
+ // reflect our new declaration.
+ Specialization = PrevDecl;
+ Specialization->setLocation(TemplateNameLoc);
+ PrevDecl = 0;
+ }
+ }
+
+ if (!Specialization) {
// Create a new class template specialization declaration node for
// this explicit specialization.
Specialization
- = ClassTemplateSpecializationDecl::Create(Context,
+ = ClassTemplateSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
- Converted, 0);
+ Converted, PrevDecl);
- ClassTemplate->getSpecializations().InsertNode(Specialization,
- InsertPos);
+ if (PrevDecl) {
+ // Remove the previous declaration from the folding set, since we want
+ // to introduce a new declaration.
+ ClassTemplate->getSpecializations().RemoveNode(PrevDecl);
+ ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+ }
+
+ // Insert the new specialization.
+ ClassTemplate->getSpecializations().InsertNode(Specialization, InsertPos);
}
// Build the fully-sugared type for this explicit instantiation as
@@ -2732,8 +3499,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// the explicit instantiation, rather than formatting the name based
// on the "canonical" representation used to store the template
// arguments in the specialization.
- QualType WrittenTy
- = Context.getTemplateSpecializationType(Name,
+ QualType WrittenTy
+ = Context.getTemplateSpecializationType(Name,
TemplateArgs.data(),
TemplateArgs.size(),
Context.getTypeDeclType(Specialization));
@@ -2746,6 +3513,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
Specialization->setLexicalDeclContext(CurContext);
CurContext->addDecl(Specialization);
+ Specialization->setPointOfInstantiation(TemplateNameLoc);
+
// C++ [temp.explicit]p3:
// A definition of a class template or class member template
// shall be in scope at the point of the explicit instantiation of
@@ -2754,17 +3523,20 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// This check comes when we actually try to perform the
// instantiation.
if (SpecializationRequiresInstantiation)
- InstantiateClassTemplateSpecialization(Specialization, true);
+ InstantiateClassTemplateSpecialization(Specialization, TSK);
else // Instantiate the members of this class template specialization.
- InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization);
+ InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization,
+ TSK);
return DeclPtrTy::make(Specialization);
}
// Explicit instantiation of a member class of a class template.
Sema::DeclResult
-Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
- unsigned TagSpec,
+Sema::ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
IdentifierInfo *Name,
@@ -2772,8 +3544,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
AttributeList *Attr) {
bool Owned = false;
- DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TK_Reference,
- KWLoc, SS, Name, NameLoc, Attr, AS_none, Owned);
+ bool IsDependent = false;
+ DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TUK_Reference,
+ KWLoc, SS, Name, NameLoc, Attr, AS_none,
+ MultiTemplateParamsArg(*this, 0, 0),
+ Owned, IsDependent);
+ assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
+
if (!TagD)
return true;
@@ -2804,7 +3581,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
if (getLangOptions().CPlusPlus0x) {
// FIXME: In C++98, we would like to turn these errors into warnings,
// dependent on a -Wc++0x flag.
- DeclContext *PatternContext
+ DeclContext *PatternContext
= Pattern->getDeclContext()->getEnclosingNamespaceContext();
if (!CurContext->Encloses(PatternContext)) {
Diag(TemplateLoc, diag::err_explicit_instantiation_out_of_scope)
@@ -2813,17 +3590,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
}
}
+ TemplateSpecializationKind TSK
+ = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+ : TSK_ExplicitInstantiationDeclaration;
+
if (!Record->getDefinition(Context)) {
// If the class has a definition, instantiate it (and all of its
// members, recursively).
Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
- if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern,
+ if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern,
getTemplateInstantiationArgs(Record),
- /*ExplicitInstantiation=*/true))
+ TSK))
return true;
- } else // Instantiate all of the members of class.
- InstantiateClassMembers(TemplateLoc, Record,
- getTemplateInstantiationArgs(Record));
+ } else // Instantiate all of the members of the class.
+ InstantiateClassMembers(TemplateLoc, Record,
+ getTemplateInstantiationArgs(Record), TSK);
// FIXME: We don't have any representation for explicit instantiations of
// member classes. Such a representation is not needed for compilation, but it
@@ -2832,10 +3613,221 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
return TagD;
}
+Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ Declarator &D) {
+ // Explicit instantiations always require a name.
+ DeclarationName Name = GetNameForDeclarator(D);
+ if (!Name) {
+ if (!D.isInvalidType())
+ Diag(D.getDeclSpec().getSourceRange().getBegin(),
+ diag::err_explicit_instantiation_requires_name)
+ << D.getDeclSpec().getSourceRange()
+ << D.getSourceRange();
+
+ return true;
+ }
+
+ // The scope passed in may not be a decl scope. Zip up the scope tree until
+ // we find one that is.
+ while ((S->getFlags() & Scope::DeclScope) == 0 ||
+ (S->getFlags() & Scope::TemplateParamScope) != 0)
+ S = S->getParent();
+
+ // Determine the type of the declaration.
+ QualType R = GetTypeForDeclarator(D, S, 0);
+ if (R.isNull())
+ return true;
+
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ // Cannot explicitly instantiate a typedef.
+ Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef)
+ << Name;
+ return true;
+ }
+
+ // Determine what kind of explicit instantiation we have.
+ TemplateSpecializationKind TSK
+ = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+ : TSK_ExplicitInstantiationDeclaration;
+
+ LookupResult Previous;
+ LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
+ Name, LookupOrdinaryName);
+
+ if (!R->isFunctionType()) {
+ // C++ [temp.explicit]p1:
+ // A [...] static data member of a class template can be explicitly
+ // instantiated from the member definition associated with its class
+ // template.
+ if (Previous.isAmbiguous()) {
+ return DiagnoseAmbiguousLookup(Previous, Name, D.getIdentifierLoc(),
+ D.getSourceRange());
+ }
+
+ VarDecl *Prev = dyn_cast_or_null<VarDecl>(
+ Previous.getAsSingleDecl(Context));
+ if (!Prev || !Prev->isStaticDataMember()) {
+ // We expect to see a data data member here.
+ Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
+ << Name;
+ for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
+ P != PEnd; ++P)
+ Diag((*P)->getLocation(), diag::note_explicit_instantiation_here);
+ return true;
+ }
+
+ if (!Prev->getInstantiatedFromStaticDataMember()) {
+ // FIXME: Check for explicit specialization?
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_data_member_not_instantiated)
+ << Prev;
+ Diag(Prev->getLocation(), diag::note_explicit_instantiation_here);
+ // FIXME: Can we provide a note showing where this was declared?
+ return true;
+ }
+
+ // Instantiate static data member.
+ // FIXME: Check for prior specializations and such.
+ Prev->setTemplateSpecializationKind(TSK);
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false);
+
+ // FIXME: Create an ExplicitInstantiation node?
+ return DeclPtrTy();
+ }
+
+ // If the declarator is a template-id, translate the parser's template
+ // argument list into our AST format.
+ bool HasExplicitTemplateArgs = false;
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ if (D.getKind() == Declarator::DK_TemplateId) {
+ TemplateIdAnnotation *TemplateId = D.getTemplateId();
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
+ translateTemplateArguments(TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateArgs);
+ HasExplicitTemplateArgs = true;
+ TemplateArgsPtr.release();
+ }
+
+ // C++ [temp.explicit]p1:
+ // A [...] function [...] can be explicitly instantiated from its template.
+ // A member function [...] of a class template can be explicitly
+ // instantiated from the member definition associated with its class
+ // template.
+ llvm::SmallVector<FunctionDecl *, 8> Matches;
+ for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
+ P != PEnd; ++P) {
+ NamedDecl *Prev = *P;
+ if (!HasExplicitTemplateArgs) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) {
+ if (Context.hasSameUnqualifiedType(Method->getType(), R)) {
+ Matches.clear();
+ Matches.push_back(Method);
+ break;
+ }
+ }
+ }
+
+ FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Prev);
+ if (!FunTmpl)
+ continue;
+
+ TemplateDeductionInfo Info(Context);
+ FunctionDecl *Specialization = 0;
+ if (TemplateDeductionResult TDK
+ = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs,
+ TemplateArgs.data(), TemplateArgs.size(),
+ R, Specialization, Info)) {
+ // FIXME: Keep track of almost-matches?
+ (void)TDK;
+ continue;
+ }
+
+ Matches.push_back(Specialization);
+ }
+
+ // Find the most specialized function template specialization.
+ FunctionDecl *Specialization
+ = getMostSpecialized(Matches.data(), Matches.size(), TPOC_Other,
+ D.getIdentifierLoc(),
+ PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name,
+ PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name,
+ PartialDiagnostic(diag::note_explicit_instantiation_candidate));
+
+ if (!Specialization)
+ return true;
+
+ switch (Specialization->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_member_function_not_instantiated)
+ << Specialization
+ << (Specialization->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization);
+ Diag(Specialization->getLocation(), diag::note_explicit_instantiation_here);
+ return true;
+
+ case TSK_ExplicitSpecialization:
+ // C++ [temp.explicit]p4:
+ // For a given set of template parameters, if an explicit instantiation
+ // of a template appears after a declaration of an explicit
+ // specialization for that template, the explicit instantiation has no
+ // effect.
+ break;
+
+ case TSK_ExplicitInstantiationDefinition:
+ // FIXME: Check that we aren't trying to perform an explicit instantiation
+ // declaration now.
+ // Fall through
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ // Instantiate the function, if this is an explicit instantiation
+ // definition.
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization,
+ false);
+
+ Specialization->setTemplateSpecializationKind(TSK);
+ break;
+ }
+
+ // FIXME: Create some kind of ExplicitInstantiationDecl here.
+ return DeclPtrTy();
+}
+
+Sema::TypeResult
+Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
+ const CXXScopeSpec &SS, IdentifierInfo *Name,
+ SourceLocation TagLoc, SourceLocation NameLoc) {
+ // This has to hold, because SS is expected to be defined.
+ assert(Name && "Expected a name in a dependent tag");
+
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ if (!NNS)
+ return true;
+
+ QualType T = CheckTypenameType(NNS, *Name, SourceRange(TagLoc, NameLoc));
+ if (T.isNull())
+ return true;
+
+ TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
+ QualType ElabType = Context.getElaboratedType(T, TagKind);
+
+ return ElabType.getAsOpaquePtr();
+}
+
Sema::TypeResult
Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
const IdentifierInfo &II, SourceLocation IdLoc) {
- NestedNameSpecifier *NNS
+ NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
if (!NNS)
return true;
@@ -2849,17 +3841,23 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
Sema::TypeResult
Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
SourceLocation TemplateLoc, TypeTy *Ty) {
- QualType T = QualType::getFromOpaquePtr(Ty);
- NestedNameSpecifier *NNS
+ QualType T = GetTypeFromParser(Ty);
+ NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- const TemplateSpecializationType *TemplateId
- = T->getAsTemplateSpecializationType();
+ const TemplateSpecializationType *TemplateId
+ = T->getAs<TemplateSpecializationType>();
assert(TemplateId && "Expected a template specialization type");
- if (NNS->isDependent())
- return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
+ if (computeDeclContext(SS, false)) {
+ // If we can compute a declaration context, then the "typename"
+ // keyword was superfluous. Just build a QualifiedNameType to keep
+ // track of the nested-name-specifier.
- return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
+ // FIXME: Note that the QualifiedNameType had the "typename" keyword!
+ return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
+ }
+
+ return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
}
/// \brief Build the type that describes a C++ typename specifier,
@@ -2875,6 +3873,12 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
// instantiation, then build a typename type.
if (!CurrentInstantiation)
return Context.getTypenameType(NNS, &II);
+
+ // The nested-name-specifier refers to the current instantiation, so the
+ // "typename" keyword itself is superfluous. In C++03, the program is
+ // actually ill-formed. However, DR 382 (in C++0x CD1) allows such
+ // extraneous "typename" keywords, and we retroactively apply this DR to
+ // C++03 code.
}
DeclContext *Ctx = 0;
@@ -2893,20 +3897,17 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
assert(Ctx && "No declaration context?");
DeclarationName Name(&II);
- LookupResult Result = LookupQualifiedName(Ctx, Name, LookupOrdinaryName,
- false);
+ LookupResult Result;
+ LookupQualifiedName(Result, Ctx, Name, LookupOrdinaryName, false);
unsigned DiagID = 0;
Decl *Referenced = 0;
switch (Result.getKind()) {
case LookupResult::NotFound:
- if (Ctx->isTranslationUnit())
- DiagID = diag::err_typename_nested_not_found_global;
- else
- DiagID = diag::err_typename_nested_not_found;
+ DiagID = diag::err_typename_nested_not_found;
break;
case LookupResult::Found:
- if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getAsDecl())) {
+ if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
// We found a type. Build a QualifiedNameType, since the
// typename-specifier was just sugar. FIXME: Tell
// QualifiedNameType that it has a "typename" prefix.
@@ -2914,7 +3915,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
}
DiagID = diag::err_typename_nested_not_type;
- Referenced = Result.getAsDecl();
+ Referenced = Result.getFoundDecl();
break;
case LookupResult::FoundOverloaded:
@@ -2922,21 +3923,207 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
Referenced = *Result.begin();
break;
- case LookupResult::AmbiguousBaseSubobjectTypes:
- case LookupResult::AmbiguousBaseSubobjects:
- case LookupResult::AmbiguousReference:
+ case LookupResult::Ambiguous:
DiagnoseAmbiguousLookup(Result, Name, Range.getEnd(), Range);
return QualType();
}
// If we get here, it's because name lookup did not find a
// type. Emit an appropriate diagnostic and return an error.
- if (NamedDecl *NamedCtx = dyn_cast<NamedDecl>(Ctx))
- Diag(Range.getEnd(), DiagID) << Range << Name << NamedCtx;
- else
- Diag(Range.getEnd(), DiagID) << Range << Name;
+ Diag(Range.getEnd(), DiagID) << Range << Name << Ctx;
if (Referenced)
Diag(Referenced->getLocation(), diag::note_typename_refers_here)
<< Name;
return QualType();
}
+
+namespace {
+ // See Sema::RebuildTypeInCurrentInstantiation
+ class VISIBILITY_HIDDEN CurrentInstantiationRebuilder
+ : public TreeTransform<CurrentInstantiationRebuilder> {
+ SourceLocation Loc;
+ DeclarationName Entity;
+
+ public:
+ CurrentInstantiationRebuilder(Sema &SemaRef,
+ SourceLocation Loc,
+ DeclarationName Entity)
+ : TreeTransform<CurrentInstantiationRebuilder>(SemaRef),
+ Loc(Loc), Entity(Entity) { }
+
+ /// \brief Determine whether the given type \p T has already been
+ /// transformed.
+ ///
+ /// For the purposes of type reconstruction, a type has already been
+ /// transformed if it is NULL or if it is not dependent.
+ bool AlreadyTransformed(QualType T) {
+ return T.isNull() || !T->isDependentType();
+ }
+
+ /// \brief Returns the location of the entity whose type is being
+ /// rebuilt.
+ SourceLocation getBaseLocation() { return Loc; }
+
+ /// \brief Returns the name of the entity whose type is being rebuilt.
+ DeclarationName getBaseEntity() { return Entity; }
+
+ /// \brief Transforms an expression by returning the expression itself
+ /// (an identity function).
+ ///
+ /// FIXME: This is completely unsafe; we will need to actually clone the
+ /// expressions.
+ Sema::OwningExprResult TransformExpr(Expr *E) {
+ return getSema().Owned(E);
+ }
+
+ /// \brief Transforms a typename type by determining whether the type now
+ /// refers to a member of the current instantiation, and then
+ /// type-checking and building a QualifiedNameType (when possible).
+ QualType TransformTypenameType(const TypenameType *T);
+ };
+}
+
+QualType
+CurrentInstantiationRebuilder::TransformTypenameType(const TypenameType *T) {
+ NestedNameSpecifier *NNS
+ = TransformNestedNameSpecifier(T->getQualifier(),
+ /*FIXME:*/SourceRange(getBaseLocation()));
+ if (!NNS)
+ return QualType();
+
+ // If the nested-name-specifier did not change, and we cannot compute the
+ // context corresponding to the nested-name-specifier, then this
+ // typename type will not change; exit early.
+ CXXScopeSpec SS;
+ SS.setRange(SourceRange(getBaseLocation()));
+ SS.setScopeRep(NNS);
+ if (NNS == T->getQualifier() && getSema().computeDeclContext(SS) == 0)
+ return QualType(T, 0);
+
+ // Rebuild the typename type, which will probably turn into a
+ // QualifiedNameType.
+ if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
+ QualType NewTemplateId
+ = TransformType(QualType(TemplateId, 0));
+ if (NewTemplateId.isNull())
+ return QualType();
+
+ if (NNS == T->getQualifier() &&
+ NewTemplateId == QualType(TemplateId, 0))
+ return QualType(T, 0);
+
+ return getDerived().RebuildTypenameType(NNS, NewTemplateId);
+ }
+
+ return getDerived().RebuildTypenameType(NNS, T->getIdentifier());
+}
+
+/// \brief Rebuilds a type within the context of the current instantiation.
+///
+/// The type \p T is part of the type of an out-of-line member definition of
+/// a class template (or class template partial specialization) that was parsed
+/// and constructed before we entered the scope of the class template (or
+/// partial specialization thereof). This routine will rebuild that type now
+/// that we have entered the declarator's scope, which may produce different
+/// canonical types, e.g.,
+///
+/// \code
+/// template<typename T>
+/// struct X {
+/// typedef T* pointer;
+/// pointer data();
+/// };
+///
+/// template<typename T>
+/// typename X<T>::pointer X<T>::data() { ... }
+/// \endcode
+///
+/// Here, the type "typename X<T>::pointer" will be created as a TypenameType,
+/// since we do not know that we can look into X<T> when we parsed the type.
+/// This function will rebuild the type, performing the lookup of "pointer"
+/// in X<T> and returning a QualifiedNameType whose canonical type is the same
+/// as the canonical type of T*, allowing the return types of the out-of-line
+/// definition and the declaration to match.
+QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
+ DeclarationName Name) {
+ if (T.isNull() || !T->isDependentType())
+ return T;
+
+ CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name);
+ return Rebuilder.TransformType(T);
+}
+
+/// \brief Produces a formatted string that describes the binding of
+/// template parameters to template arguments.
+std::string
+Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgumentList &Args) {
+ std::string Result;
+
+ if (!Params || Params->size() == 0)
+ return Result;
+
+ for (unsigned I = 0, N = Params->size(); I != N; ++I) {
+ if (I == 0)
+ Result += "[with ";
+ else
+ Result += ", ";
+
+ if (const IdentifierInfo *Id = Params->getParam(I)->getIdentifier()) {
+ Result += Id->getName();
+ } else {
+ Result += '$';
+ Result += llvm::utostr(I);
+ }
+
+ Result += " = ";
+
+ switch (Args[I].getKind()) {
+ case TemplateArgument::Null:
+ Result += "<no value>";
+ break;
+
+ case TemplateArgument::Type: {
+ std::string TypeStr;
+ Args[I].getAsType().getAsStringInternal(TypeStr,
+ Context.PrintingPolicy);
+ Result += TypeStr;
+ break;
+ }
+
+ case TemplateArgument::Declaration: {
+ bool Unnamed = true;
+ if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Args[I].getAsDecl())) {
+ if (ND->getDeclName()) {
+ Unnamed = false;
+ Result += ND->getNameAsString();
+ }
+ }
+
+ if (Unnamed) {
+ Result += "<anonymous>";
+ }
+ break;
+ }
+
+ case TemplateArgument::Integral: {
+ Result += Args[I].getAsIntegral()->toString(10);
+ break;
+ }
+
+ case TemplateArgument::Expression: {
+ assert(false && "No expressions in deduced template arguments!");
+ Result += "<expression>";
+ break;
+ }
+
+ case TemplateArgument::Pack:
+ // FIXME: Format template argument packs
+ Result += "<template argument pack>";
+ break;
+ }
+ }
+
+ Result += ']';
+ return Result;
+}
diff --git a/lib/Sema/SemaTemplate.h b/lib/Sema/SemaTemplate.h
new file mode 100644
index 0000000000000..2bfb25a3d1048
--- /dev/null
+++ b/lib/Sema/SemaTemplate.h
@@ -0,0 +1,104 @@
+//===------- SemaTemplate.h - C++ Templates ---------------------*- C++ -*-===/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+// This file provides types used in the semantic analysis of C++ templates.
+//
+//===----------------------------------------------------------------------===/
+#ifndef LLVM_CLANG_SEMA_TEMPLATE_H
+#define LLVM_CLANG_SEMA_TEMPLATE_H
+
+#include "clang/AST/DeclTemplate.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cassert>
+
+namespace clang {
+ /// \brief Data structure that captures multiple levels of template argument
+ /// lists for use in template instantiation.
+ ///
+ /// Multiple levels of template arguments occur when instantiating the
+ /// definitions of member templates. For example:
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// template<T Value>
+ /// struct Y {
+ /// void f();
+ /// };
+ /// };
+ /// \endcode
+ ///
+ /// When instantiating X<int>::Y<17>::f, the multi-level template argument
+ /// list will contain a template argument list (int) at depth 0 and a
+ /// template argument list (17) at depth 1.
+ struct MultiLevelTemplateArgumentList {
+ /// \brief The template argument lists, stored from the innermost template
+ /// argument list (first) to the outermost template argument list (last).
+ llvm::SmallVector<const TemplateArgumentList *, 4> TemplateArgumentLists;
+
+ public:
+ /// \brief Construct an empty set of template argument lists.
+ MultiLevelTemplateArgumentList() { }
+
+ /// \brief Construct a single-level template argument list.
+ explicit
+ MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) {
+ TemplateArgumentLists.push_back(&TemplateArgs);
+ }
+
+ /// \brief Determine the number of levels in this template argument
+ /// list.
+ unsigned getNumLevels() const { return TemplateArgumentLists.size(); }
+
+ /// \brief Retrieve the template argument at a given depth and index.
+ const TemplateArgument &operator()(unsigned Depth, unsigned Index) const {
+ assert(Depth < TemplateArgumentLists.size());
+ assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1]->size());
+ return TemplateArgumentLists[getNumLevels() - Depth - 1]->get(Index);
+ }
+
+ /// \brief Determine whether there is a non-NULL template argument at the
+ /// given depth and index.
+ ///
+ /// There must exist a template argument list at the given depth.
+ bool hasTemplateArgument(unsigned Depth, unsigned Index) const {
+ assert(Depth < TemplateArgumentLists.size());
+
+ if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1]->size())
+ return false;
+
+ return !(*this)(Depth, Index).isNull();
+ }
+
+ /// \brief Add a new outermost level to the multi-level template argument
+ /// list.
+ void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) {
+ TemplateArgumentLists.push_back(TemplateArgs);
+ }
+
+ /// \brief Retrieve the innermost template argument list.
+ const TemplateArgumentList &getInnermost() const {
+ return *TemplateArgumentLists.front();
+ }
+ };
+
+ /// \brief The context in which partial ordering of function templates occurs.
+ enum TemplatePartialOrderingContext {
+ /// \brief Partial ordering of function templates for a function call.
+ TPOC_Call,
+ /// \brief Partial ordering of function templates for a call to a
+ /// conversion function.
+ TPOC_Conversion,
+ /// \brief Partial ordering of function templates in other contexts, e.g.,
+ /// taking the address of a function template or matching a function
+ /// template specialization to a function template.
+ TPOC_Other
+ };
+}
+
+#endif // LLVM_CLANG_SEMA_TEMPLATE_H
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 5a0578f6bcb70..b981389d1d15b 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/Compiler.h"
+#include <algorithm>
namespace clang {
/// \brief Various flags that control template argument deduction.
@@ -38,14 +39,18 @@ namespace clang {
/// \brief Within template argument deduction from a function call,
/// we are matching in a case where we can perform template argument
/// deduction from a template-id of a derived class of the argument type.
- TDF_DerivedClass = 0x04
+ TDF_DerivedClass = 0x04,
+ /// \brief Allow non-dependent types to differ, e.g., when performing
+ /// template argument deduction from a function call where conversions
+ /// may apply.
+ TDF_SkipNonDependent = 0x08
};
}
using namespace clang;
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(ASTContext &Context,
TemplateParameterList *TemplateParams,
const TemplateArgument &Param,
const TemplateArgument &Arg,
@@ -58,27 +63,27 @@ DeduceTemplateArguments(ASTContext &Context,
static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
if (ImplicitCastExpr *IC = dyn_cast<ImplicitCastExpr>(E))
E = IC->getSubExpr();
-
+
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());
-
+
return 0;
}
-/// \brief Deduce the value of the given non-type template parameter
+/// \brief Deduce the value of the given non-type template parameter
/// from the given constant.
static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(ASTContext &Context,
- NonTypeTemplateParmDecl *NTTP,
+DeduceNonTypeTemplateArgument(ASTContext &Context,
+ NonTypeTemplateParmDecl *NTTP,
llvm::APSInt Value,
Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
- assert(NTTP->getDepth() == 0 &&
+ assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
-
+
if (Deduced[NTTP->getIndex()].isNull()) {
QualType T = NTTP->getType();
-
+
// FIXME: Make sure we didn't overflow our data type!
unsigned AllowedBits = Context.getTypeSize(T);
if (Value.getBitWidth() != AllowedBits)
@@ -88,10 +93,10 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(), Value, T);
return Sema::TDK_Success;
}
-
+
assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral);
-
- // If the template argument was previously deduced to a negative value,
+
+ // If the template argument was previously deduced to a negative value,
// then our deduction fails.
const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral();
if (PrevValuePtr->isNegative()) {
@@ -117,36 +122,47 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
return Sema::TDK_Success;
}
-/// \brief Deduce the value of the given non-type template parameter
+/// \brief Deduce the value of the given non-type template parameter
/// from the given type- or value-dependent expression.
///
/// \returns true if deduction succeeded, false otherwise.
static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(ASTContext &Context,
+DeduceNonTypeTemplateArgument(ASTContext &Context,
NonTypeTemplateParmDecl *NTTP,
Expr *Value,
Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
- assert(NTTP->getDepth() == 0 &&
+ assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
assert((Value->isTypeDependent() || Value->isValueDependent()) &&
"Expression template argument must be type- or value-dependent.");
-
+
if (Deduced[NTTP->getIndex()].isNull()) {
// FIXME: Clone the Value?
Deduced[NTTP->getIndex()] = TemplateArgument(Value);
return Sema::TDK_Success;
}
-
+
if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral) {
- // Okay, we deduced a constant in one case and a dependent expression
- // in another case. FIXME: Later, we will check that instantiating the
+ // Okay, we deduced a constant in one case and a dependent expression
+ // in another case. FIXME: Later, we will check that instantiating the
// dependent expression gives us the constant value.
return Sema::TDK_Success;
}
-
- // FIXME: Compare the expressions for equality!
+
+ if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) {
+ // Compare the expressions for equality
+ llvm::FoldingSetNodeID ID1, ID2;
+ Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, Context, true);
+ Value->Profile(ID2, Context, true);
+ if (ID1 == ID2)
+ return Sema::TDK_Success;
+
+ // FIXME: Fill in argument mismatch information
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
return Sema::TDK_Success;
}
@@ -164,14 +180,14 @@ DeduceTemplateArguments(ASTContext &Context,
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
TemplateDecl *ArgDecl = Arg.getAsTemplateDecl();
-
+
if (!ParamDecl || !ArgDecl) {
// FIXME: fill in Info.Param/Info.FirstArg
return Sema::TDK_Inconsistent;
}
- ParamDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ParamDecl));
- ArgDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ArgDecl));
+ ParamDecl = cast<TemplateDecl>(ParamDecl->getCanonicalDecl());
+ ArgDecl = cast<TemplateDecl>(ArgDecl->getCanonicalDecl());
if (ParamDecl != ArgDecl) {
// FIXME: fill in Info.Param/Info.FirstArg
return Sema::TDK_Inconsistent;
@@ -180,6 +196,161 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_Success;
}
+/// \brief Deduce the template arguments by comparing the template parameter
+/// type (which is a template-id) with the template argument type.
+///
+/// \param Context the AST context in which this deduction occurs.
+///
+/// \param TemplateParams the template parameters that we are deducing
+///
+/// \param Param the parameter type
+///
+/// \param Arg the argument type
+///
+/// \param Info information about the template argument deduction itself
+///
+/// \param Deduced the deduced template arguments
+///
+/// \returns the result of template argument deduction so far. Note that a
+/// "success" result means that template argument deduction has not yet failed,
+/// but it may still fail, later, for other reasons.
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ const TemplateSpecializationType *Param,
+ QualType Arg,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ assert(Arg->isCanonical() && "Argument type must be canonical");
+
+ // Check whether the template argument is a dependent template-id.
+ // FIXME: This is untested code; it can be tested when we implement
+ // partial ordering of class template partial specializations.
+ if (const TemplateSpecializationType *SpecArg
+ = dyn_cast<TemplateSpecializationType>(Arg)) {
+ // Perform template argument deduction for the template name.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context,
+ Param->getTemplateName(),
+ SpecArg->getTemplateName(),
+ Info, Deduced))
+ return Result;
+
+ unsigned NumArgs = Param->getNumArgs();
+
+ // FIXME: When one of the template-names refers to a
+ // declaration with default template arguments, do we need to
+ // fill in those default template arguments here? Most likely,
+ // the answer is "yes", but I don't see any references. This
+ // issue may be resolved elsewhere, because we may want to
+ // instantiate default template arguments when we actually write
+ // the template-id.
+ if (SpecArg->getNumArgs() != NumArgs)
+ return Sema::TDK_NonDeducedMismatch;
+
+ // Perform template argument deduction on each template
+ // argument.
+ for (unsigned I = 0; I != NumArgs; ++I)
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ Param->getArg(I),
+ SpecArg->getArg(I),
+ Info, Deduced))
+ return Result;
+
+ return Sema::TDK_Success;
+ }
+
+ // If the argument type is a class template specialization, we
+ // perform template argument deduction using its template
+ // arguments.
+ const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
+ if (!RecordArg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ ClassTemplateSpecializationDecl *SpecArg
+ = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
+ if (!SpecArg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ // Perform template argument deduction for the template name.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context,
+ Param->getTemplateName(),
+ TemplateName(SpecArg->getSpecializedTemplate()),
+ Info, Deduced))
+ return Result;
+
+ // FIXME: Can the # of arguments in the parameter and the argument
+ // differ due to default arguments?
+ unsigned NumArgs = Param->getNumArgs();
+ const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
+ if (NumArgs != ArgArgs.size())
+ return Sema::TDK_NonDeducedMismatch;
+
+ for (unsigned I = 0; I != NumArgs; ++I)
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ Param->getArg(I),
+ ArgArgs.get(I),
+ Info, Deduced))
+ return Result;
+
+ return Sema::TDK_Success;
+}
+
+/// \brief Returns a completely-unqualified array type, capturing the
+/// qualifiers in Quals.
+///
+/// \param Context the AST context in which the array type was built.
+///
+/// \param T a canonical type that may be an array type.
+///
+/// \param Quals will receive the full set of qualifiers that were
+/// applied to the element type of the array.
+///
+/// \returns if \p T is an array type, the completely unqualified array type
+/// that corresponds to T. Otherwise, returns T.
+static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T,
+ Qualifiers &Quals) {
+ assert(T->isCanonical() && "Only operates on canonical types");
+ if (!isa<ArrayType>(T)) {
+ Quals = T.getQualifiers();
+ return T.getUnqualifiedType();
+ }
+
+ assert(!T.hasQualifiers() && "canonical array type has qualifiers!");
+
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) {
+ QualType Elt = getUnqualifiedArrayType(Context, CAT->getElementType(),
+ Quals);
+ if (Elt == CAT->getElementType())
+ return T;
+
+ return Context.getConstantArrayType(Elt, CAT->getSize(),
+ CAT->getSizeModifier(), 0);
+ }
+
+ if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) {
+ QualType Elt = getUnqualifiedArrayType(Context, IAT->getElementType(),
+ Quals);
+ if (Elt == IAT->getElementType())
+ return T;
+
+ return Context.getIncompleteArrayType(Elt, IAT->getSizeModifier(), 0);
+ }
+
+ const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T);
+ QualType Elt = getUnqualifiedArrayType(Context, DSAT->getElementType(),
+ Quals);
+ if (Elt == DSAT->getElementType())
+ return T;
+
+ return Context.getDependentSizedArrayType(Elt, DSAT->getSizeExpr()->Retain(),
+ DSAT->getSizeModifier(), 0,
+ SourceRange());
+}
+
/// \brief Deduce the template arguments by comparing the parameter type and
/// the argument type (C++ [temp.deduct.type]).
///
@@ -196,13 +367,13 @@ DeduceTemplateArguments(ASTContext &Context,
/// \param Deduced the deduced template arguments
///
/// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe
-/// how template argument deduction is performed.
+/// how template argument deduction is performed.
///
/// \returns the result of template argument deduction so far. Note that a
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(ASTContext &Context,
TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
@@ -215,28 +386,47 @@ DeduceTemplateArguments(ASTContext &Context,
// C++0x [temp.deduct.call]p4 bullet 1:
// - If the original P is a reference type, the deduced A (i.e., the type
- // referred to by the reference) can be more cv-qualified than the
+ // referred to by the reference) can be more cv-qualified than the
// transformed A.
if (TDF & TDF_ParamWithReferenceType) {
- unsigned ExtraQualsOnParam
- = Param.getCVRQualifiers() & ~Arg.getCVRQualifiers();
- Param.setCVRQualifiers(Param.getCVRQualifiers() & ~ExtraQualsOnParam);
+ Qualifiers Quals = Param.getQualifiers();
+ Quals.setCVRQualifiers(Quals.getCVRQualifiers() & Arg.getCVRQualifiers());
+ Param = Context.getQualifiedType(Param.getUnqualifiedType(), Quals);
}
-
+
// If the parameter type is not dependent, there is nothing to deduce.
- if (!Param->isDependentType())
+ if (!Param->isDependentType()) {
+ if (!(TDF & TDF_SkipNonDependent) && Param != Arg) {
+
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
return Sema::TDK_Success;
+ }
// C++ [temp.deduct.type]p9:
- // A template type argument T, a template template argument TT or a
- // template non-type argument i can be deduced if P and A have one of
+ // A template type argument T, a template template argument TT or a
+ // template non-type argument i can be deduced if P and A have one of
// the following forms:
//
// T
// cv-list T
- if (const TemplateTypeParmType *TemplateTypeParm
- = Param->getAsTemplateTypeParmType()) {
+ if (const TemplateTypeParmType *TemplateTypeParm
+ = Param->getAs<TemplateTypeParmType>()) {
unsigned Index = TemplateTypeParm->getIndex();
+ bool RecanonicalizeArg = false;
+
+ // If the argument type is an array type, move the qualifiers up to the
+ // top level, so they can be matched with the qualifiers on the parameter.
+ // FIXME: address spaces, ObjC GC qualifiers
+ if (isa<ArrayType>(Arg)) {
+ Qualifiers Quals;
+ Arg = getUnqualifiedArrayType(Context, Arg, Quals);
+ if (Quals) {
+ Arg = Context.getQualifiedType(Arg, Quals);
+ RecanonicalizeArg = true;
+ }
+ }
// The argument type can not be less qualified than the parameter
// type.
@@ -248,21 +438,23 @@ DeduceTemplateArguments(ASTContext &Context,
}
assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
-
- unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
- QualType DeducedType = Arg.getQualifiedType(Quals);
+
+ QualType DeducedType = Arg;
+ DeducedType.removeCVRQualifiers(Param.getCVRQualifiers());
+ if (RecanonicalizeArg)
+ DeducedType = Context.getCanonicalType(DeducedType);
if (Deduced[Index].isNull())
Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType);
else {
- // C++ [temp.deduct.type]p2:
+ // C++ [temp.deduct.type]p2:
// [...] If type deduction cannot be done for any P/A pair, or if for
- // any pair the deduction leads to more than one possible set of
- // deduced values, or if different pairs yield different deduced
- // values, or if any template argument remains neither deduced nor
+ // any pair the deduction leads to more than one possible set of
+ // deduced values, or if different pairs yield different deduced
+ // values, or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
if (Deduced[Index].getAsType() != DeducedType) {
- Info.Param
+ Info.Param
= cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
Info.FirstArg = Deduced[Index];
Info.SecondArg = TemplateArgument(SourceLocation(), Arg);
@@ -283,7 +475,7 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_NonDeducedMismatch;
} else {
if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_NonDeducedMismatch;
}
}
@@ -291,26 +483,26 @@ DeduceTemplateArguments(ASTContext &Context,
// No deduction possible for these types
case Type::Builtin:
return Sema::TDK_NonDeducedMismatch;
-
+
// T *
case Type::Pointer: {
- const PointerType *PointerArg = Arg->getAsPointerType();
+ const PointerType *PointerArg = Arg->getAs<PointerType>();
if (!PointerArg)
return Sema::TDK_NonDeducedMismatch;
-
+
unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
return DeduceTemplateArguments(Context, TemplateParams,
cast<PointerType>(Param)->getPointeeType(),
PointerArg->getPointeeType(),
Info, Deduced, SubTDF);
}
-
+
// T &
case Type::LValueReference: {
- const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType();
+ const LValueReferenceType *ReferenceArg = Arg->getAs<LValueReferenceType>();
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
-
+
return DeduceTemplateArguments(Context, TemplateParams,
cast<LValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
@@ -319,23 +511,23 @@ DeduceTemplateArguments(ASTContext &Context,
// T && [C++0x]
case Type::RValueReference: {
- const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType();
+ const RValueReferenceType *ReferenceArg = Arg->getAs<RValueReferenceType>();
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
-
+
return DeduceTemplateArguments(Context, TemplateParams,
cast<RValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
Info, Deduced, 0);
}
-
+
// T [] (implied, but not stated explicitly)
case Type::IncompleteArray: {
- const IncompleteArrayType *IncompleteArrayArg =
+ const IncompleteArrayType *IncompleteArrayArg =
Context.getAsIncompleteArrayType(Arg);
if (!IncompleteArrayArg)
return Sema::TDK_NonDeducedMismatch;
-
+
return DeduceTemplateArguments(Context, TemplateParams,
Context.getAsIncompleteArrayType(Param)->getElementType(),
IncompleteArrayArg->getElementType(),
@@ -344,16 +536,16 @@ DeduceTemplateArguments(ASTContext &Context,
// T [integer-constant]
case Type::ConstantArray: {
- const ConstantArrayType *ConstantArrayArg =
+ const ConstantArrayType *ConstantArrayArg =
Context.getAsConstantArrayType(Arg);
if (!ConstantArrayArg)
return Sema::TDK_NonDeducedMismatch;
-
- const ConstantArrayType *ConstantArrayParm =
+
+ const ConstantArrayType *ConstantArrayParm =
Context.getAsConstantArrayType(Param);
if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
return Sema::TDK_NonDeducedMismatch;
-
+
return DeduceTemplateArguments(Context, TemplateParams,
ConstantArrayParm->getElementType(),
ConstantArrayArg->getElementType(),
@@ -365,7 +557,7 @@ DeduceTemplateArguments(ASTContext &Context,
const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg);
if (!ArrayArg)
return Sema::TDK_NonDeducedMismatch;
-
+
// Check the element type of the arrays
const DependentSizedArrayType *DependentArrayParm
= cast<DependentSizedArrayType>(Param);
@@ -375,18 +567,18 @@ DeduceTemplateArguments(ASTContext &Context,
ArrayArg->getElementType(),
Info, Deduced, 0))
return Result;
-
+
// Determine the array bound is something we can deduce.
- NonTypeTemplateParmDecl *NTTP
+ NonTypeTemplateParmDecl *NTTP
= getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
-
- // We can perform template argument deduction for the given non-type
+
+ // We can perform template argument deduction for the given non-type
// template parameter.
- assert(NTTP->getDepth() == 0 &&
+ assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument at depth > 0");
- if (const ConstantArrayType *ConstantArrayArg
+ if (const ConstantArrayType *ConstantArrayArg
= dyn_cast<ConstantArrayType>(ArrayArg)) {
llvm::APSInt Size(ConstantArrayArg->getSize());
return DeduceNonTypeTemplateArgument(Context, NTTP, Size,
@@ -397,30 +589,30 @@ DeduceTemplateArguments(ASTContext &Context,
return DeduceNonTypeTemplateArgument(Context, NTTP,
DependentArrayArg->getSizeExpr(),
Info, Deduced);
-
+
// Incomplete type does not match a dependently-sized array type
return Sema::TDK_NonDeducedMismatch;
}
-
- // type(*)(T)
- // T(*)()
- // T(*)(T)
+
+ // type(*)(T)
+ // T(*)()
+ // T(*)(T)
case Type::FunctionProto: {
- const FunctionProtoType *FunctionProtoArg =
+ const FunctionProtoType *FunctionProtoArg =
dyn_cast<FunctionProtoType>(Arg);
if (!FunctionProtoArg)
return Sema::TDK_NonDeducedMismatch;
-
- const FunctionProtoType *FunctionProtoParam =
+
+ const FunctionProtoType *FunctionProtoParam =
cast<FunctionProtoType>(Param);
- if (FunctionProtoParam->getTypeQuals() !=
+ if (FunctionProtoParam->getTypeQuals() !=
FunctionProtoArg->getTypeQuals())
return Sema::TDK_NonDeducedMismatch;
-
+
if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs())
return Sema::TDK_NonDeducedMismatch;
-
+
if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic())
return Sema::TDK_NonDeducedMismatch;
@@ -431,7 +623,7 @@ DeduceTemplateArguments(ASTContext &Context,
FunctionProtoArg->getResultType(),
Info, Deduced, 0))
return Result;
-
+
for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
// Check argument types.
if (Sema::TemplateDeductionResult Result
@@ -441,10 +633,10 @@ DeduceTemplateArguments(ASTContext &Context,
Info, Deduced, 0))
return Result;
}
-
+
return Sema::TDK_Success;
}
-
+
// template-name<T> (where template-name refers to a class template)
// template-name<i>
// TT<T> (TODO)
@@ -454,83 +646,69 @@ DeduceTemplateArguments(ASTContext &Context,
const TemplateSpecializationType *SpecParam
= cast<TemplateSpecializationType>(Param);
- // Check whether the template argument is a dependent template-id.
- // FIXME: This is untested code; it can be tested when we implement
- // partial ordering of class template partial specializations.
- if (const TemplateSpecializationType *SpecArg
- = dyn_cast<TemplateSpecializationType>(Arg)) {
- // Perform template argument deduction for the template name.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context,
- SpecParam->getTemplateName(),
- SpecArg->getTemplateName(),
- Info, Deduced))
- return Result;
-
- unsigned NumArgs = SpecParam->getNumArgs();
-
- // FIXME: When one of the template-names refers to a
- // declaration with default template arguments, do we need to
- // fill in those default template arguments here? Most likely,
- // the answer is "yes", but I don't see any references. This
- // issue may be resolved elsewhere, because we may want to
- // instantiate default template arguments when
- if (SpecArg->getNumArgs() != NumArgs)
- return Sema::TDK_NonDeducedMismatch;
-
- // Perform template argument deduction on each template
- // argument.
- for (unsigned I = 0; I != NumArgs; ++I)
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
- SpecParam->getArg(I),
- SpecArg->getArg(I),
- Info, Deduced))
- return Result;
-
- return Sema::TDK_Success;
- }
-
- // If the argument type is a class template specialization, we
- // perform template argument deduction using its template
- // arguments.
- const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
- if (!RecordArg)
- return Sema::TDK_NonDeducedMismatch;
-
- // FIXME: Check TDF_DerivedClass here. When this flag is set, we need
- // to troll through the base classes of the argument and try matching
- // all of them. Failure to match does not mean that there is a problem,
- // of course.
-
- ClassTemplateSpecializationDecl *SpecArg
- = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
- if (!SpecArg)
- return Sema::TDK_NonDeducedMismatch;
-
- // Perform template argument deduction for the template name.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context,
- SpecParam->getTemplateName(),
- TemplateName(SpecArg->getSpecializedTemplate()),
- Info, Deduced))
- return Result;
+ // Try to deduce template arguments from the template-id.
+ Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams, SpecParam, Arg,
+ Info, Deduced);
+
+ if (Result && (TDF & TDF_DerivedClass)) {
+ // C++ [temp.deduct.call]p3b3:
+ // If P is a class, and P has the form template-id, then A can be a
+ // derived class of the deduced A. Likewise, if P is a pointer to a
+ // class of the form template-id, A can be a pointer to a derived
+ // class pointed to by the deduced A.
+ //
+ // More importantly:
+ // These alternatives are considered only if type deduction would
+ // otherwise fail.
+ if (const RecordType *RecordT = dyn_cast<RecordType>(Arg)) {
+ // Use data recursion to crawl through the list of base classes.
+ // Visited contains the set of nodes we have already visited, while
+ // ToVisit is our stack of records that we still need to visit.
+ llvm::SmallPtrSet<const RecordType *, 8> Visited;
+ llvm::SmallVector<const RecordType *, 8> ToVisit;
+ ToVisit.push_back(RecordT);
+ bool Successful = false;
+ while (!ToVisit.empty()) {
+ // Retrieve the next class in the inheritance hierarchy.
+ const RecordType *NextT = ToVisit.back();
+ ToVisit.pop_back();
+
+ // If we have already seen this type, skip it.
+ if (!Visited.insert(NextT))
+ continue;
+
+ // If this is a base class, try to perform template argument
+ // deduction from it.
+ if (NextT != RecordT) {
+ Sema::TemplateDeductionResult BaseResult
+ = DeduceTemplateArguments(Context, TemplateParams, SpecParam,
+ QualType(NextT, 0), Info, Deduced);
+
+ // If template argument deduction for this base was successful,
+ // note that we had some success.
+ if (BaseResult == Sema::TDK_Success)
+ Successful = true;
+ }
+
+ // Visit base classes
+ CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl());
+ for (CXXRecordDecl::base_class_iterator Base = Next->bases_begin(),
+ BaseEnd = Next->bases_end();
+ Base != BaseEnd; ++Base) {
+ assert(Base->getType()->isRecordType() &&
+ "Base class that isn't a record?");
+ ToVisit.push_back(Base->getType()->getAs<RecordType>());
+ }
+ }
+
+ if (Successful)
+ return Sema::TDK_Success;
+ }
- // FIXME: Can the # of arguments in the parameter and the argument differ?
- unsigned NumArgs = SpecParam->getNumArgs();
- const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
- if (NumArgs != ArgArgs.size())
- return Sema::TDK_NonDeducedMismatch;
+ }
- for (unsigned I = 0; I != NumArgs; ++I)
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
- SpecParam->getArg(I),
- ArgArgs.get(I),
- Info, Deduced))
- return Result;
-
- return Sema::TDK_Success;
+ return Result;
}
// T type::*
@@ -564,16 +742,16 @@ DeduceTemplateArguments(ASTContext &Context,
// (clang extension)
//
- // type(^)(T)
- // T(^)()
- // T(^)(T)
+ // type(^)(T)
+ // T(^)()
+ // T(^)(T)
case Type::BlockPointer: {
const BlockPointerType *BlockPtrParam = cast<BlockPointerType>(Param);
const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg);
-
+
if (!BlockPtrArg)
return Sema::TDK_NonDeducedMismatch;
-
+
return DeduceTemplateArguments(Context, TemplateParams,
BlockPtrParam->getPointeeType(),
BlockPtrArg->getPointeeType(), Info,
@@ -595,7 +773,7 @@ DeduceTemplateArguments(ASTContext &Context,
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(ASTContext &Context,
TemplateParameterList *TemplateParams,
const TemplateArgument &Param,
const TemplateArgument &Arg,
@@ -605,8 +783,8 @@ DeduceTemplateArguments(ASTContext &Context,
case TemplateArgument::Null:
assert(false && "Null template argument in parameter list");
break;
-
- case TemplateArgument::Type:
+
+ case TemplateArgument::Type:
assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch");
return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(),
Arg.getAsType(), Info, Deduced, 0);
@@ -617,7 +795,7 @@ DeduceTemplateArguments(ASTContext &Context,
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
-
+
case TemplateArgument::Integral:
if (Arg.getKind() == TemplateArgument::Integral) {
// FIXME: Zero extension + sign checking here?
@@ -639,25 +817,25 @@ DeduceTemplateArguments(ASTContext &Context,
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
-
+
case TemplateArgument::Expression: {
- if (NonTypeTemplateParmDecl *NTTP
+ if (NonTypeTemplateParmDecl *NTTP
= getDeducedParameterFromExpr(Param.getAsExpr())) {
if (Arg.getKind() == TemplateArgument::Integral)
// FIXME: Sign problems here
- return DeduceNonTypeTemplateArgument(Context, NTTP,
- *Arg.getAsIntegral(),
+ return DeduceNonTypeTemplateArgument(Context, NTTP,
+ *Arg.getAsIntegral(),
Info, Deduced);
if (Arg.getKind() == TemplateArgument::Expression)
return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(),
Info, Deduced);
-
+
assert(false && "Type/value mismatch");
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
}
-
+
// Can't deduce anything, but that's okay.
return Sema::TDK_Success;
}
@@ -665,11 +843,11 @@ DeduceTemplateArguments(ASTContext &Context,
assert(0 && "FIXME: Implement!");
break;
}
-
+
return Sema::TDK_Success;
}
-static Sema::TemplateDeductionResult
+static Sema::TemplateDeductionResult
DeduceTemplateArguments(ASTContext &Context,
TemplateParameterList *TemplateParams,
const TemplateArgumentList &ParamList,
@@ -680,7 +858,7 @@ DeduceTemplateArguments(ASTContext &Context,
for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
if (Sema::TemplateDeductionResult Result
= DeduceTemplateArguments(Context, TemplateParams,
- ParamList[I], ArgList[I],
+ ParamList[I], ArgList[I],
Info, Deduced))
return Result;
}
@@ -688,41 +866,41 @@ DeduceTemplateArguments(ASTContext &Context,
}
/// \brief Determine whether two template arguments are the same.
-static bool isSameTemplateArg(ASTContext &Context,
+static bool isSameTemplateArg(ASTContext &Context,
const TemplateArgument &X,
const TemplateArgument &Y) {
if (X.getKind() != Y.getKind())
return false;
-
+
switch (X.getKind()) {
case TemplateArgument::Null:
assert(false && "Comparing NULL template argument");
break;
-
+
case TemplateArgument::Type:
return Context.getCanonicalType(X.getAsType()) ==
Context.getCanonicalType(Y.getAsType());
-
+
case TemplateArgument::Declaration:
- return Context.getCanonicalDecl(X.getAsDecl()) ==
- Context.getCanonicalDecl(Y.getAsDecl());
-
+ return X.getAsDecl()->getCanonicalDecl() ==
+ Y.getAsDecl()->getCanonicalDecl();
+
case TemplateArgument::Integral:
return *X.getAsIntegral() == *Y.getAsIntegral();
-
+
case TemplateArgument::Expression:
// FIXME: We assume that all expressions are distinct, but we should
// really check their canonical forms.
return false;
-
+
case TemplateArgument::Pack:
if (X.pack_size() != Y.pack_size())
return false;
-
- for (TemplateArgument::pack_iterator XP = X.pack_begin(),
- XPEnd = X.pack_end(),
+
+ for (TemplateArgument::pack_iterator XP = X.pack_begin(),
+ XPEnd = X.pack_end(),
YP = Y.pack_begin();
- XP != XPEnd; ++XP, ++YP)
+ XP != XPEnd; ++XP, ++YP)
if (!isSameTemplateArg(Context, *XP, *YP))
return false;
@@ -739,7 +917,7 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
return TemplateParameter(TTP);
else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
return TemplateParameter(NTTP);
-
+
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
@@ -759,9 +937,9 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
llvm::SmallVector<TemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context,
+ = ::DeduceTemplateArguments(Context,
Partial->getTemplateParameters(),
- Partial->getTemplateArgs(),
+ Partial->getTemplateArgs(),
TemplateArgs, Info, Deduced))
return Result;
@@ -777,11 +955,12 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Deduced.size());
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
if (Deduced[I].isNull()) {
- Decl *Param
- = const_cast<Decl *>(Partial->getTemplateParameters()->getParam(I));
+ Decl *Param
+ = const_cast<NamedDecl *>(
+ Partial->getTemplateParameters()->getParam(I));
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
Info.Param = TTP;
- else if (NonTypeTemplateParmDecl *NTTP
+ else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param))
Info.Param = NTTP;
else
@@ -793,7 +972,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
}
// Form the template argument list from the deduced template arguments.
- TemplateArgumentList *DeducedArgumentList
+ TemplateArgumentList *DeducedArgumentList
= new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
Info.reset(DeducedArgumentList);
@@ -801,44 +980,45 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// arguments of the class template partial specialization, and
// verify that the instantiated template arguments are both valid
// and are equivalent to the template arguments originally provided
- // to the class template.
+ // to the class template.
ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
const TemplateArgumentList &PartialTemplateArgs = Partial->getTemplateArgs();
for (unsigned I = 0, N = PartialTemplateArgs.flat_size(); I != N; ++I) {
- Decl *Param = const_cast<Decl *>(
+ Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
- TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I],
- *DeducedArgumentList);
+ TemplateArgument InstArg
+ = Subst(PartialTemplateArgs[I],
+ MultiLevelTemplateArgumentList(*DeducedArgumentList));
if (InstArg.isNull()) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I];
- return TDK_SubstitutionFailure;
+ return TDK_SubstitutionFailure;
}
-
+
if (InstArg.getKind() == TemplateArgument::Expression) {
- // When the argument is an expression, check the expression result
+ // When the argument is an expression, check the expression result
// against the actual template parameter to get down to the canonical
// template argument.
Expr *InstExpr = InstArg.getAsExpr();
- if (NonTypeTemplateParmDecl *NTTP
+ if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I];
- return TDK_SubstitutionFailure;
+ return TDK_SubstitutionFailure;
}
- } else if (TemplateTemplateParmDecl *TTP
+ } else if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(Param)) {
// FIXME: template template arguments should really resolve to decls
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InstExpr);
if (!DRE || CheckTemplateArgument(TTP, DRE)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I];
- return TDK_SubstitutionFailure;
+ return TDK_SubstitutionFailure;
}
}
}
-
+
if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = TemplateArgs[I];
@@ -855,27 +1035,244 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
/// \brief Determine whether the given type T is a simple-template-id type.
static bool isSimpleTemplateIdType(QualType T) {
- if (const TemplateSpecializationType *Spec
- = T->getAsTemplateSpecializationType())
+ if (const TemplateSpecializationType *Spec
+ = T->getAs<TemplateSpecializationType>())
return Spec->getTemplateName().getAsTemplateDecl() != 0;
-
+
return false;
}
-
+
+/// \brief Substitute the explicitly-provided template arguments into the
+/// given function template according to C++ [temp.arg.explicit].
+///
+/// \param FunctionTemplate the function template into which the explicit
+/// template arguments will be substituted.
+///
+/// \param ExplicitTemplateArguments the explicitly-specified template
+/// arguments.
+///
+/// \param NumExplicitTemplateArguments the number of explicitly-specified
+/// template arguments in @p ExplicitTemplateArguments. This value may be zero.
+///
+/// \param Deduced the deduced template arguments, which will be populated
+/// with the converted and checked explicit template arguments.
+///
+/// \param ParamTypes will be populated with the instantiated function
+/// parameters.
+///
+/// \param FunctionType if non-NULL, the result type of the function template
+/// will also be instantiated and the pointed-to value will be updated with
+/// the instantiated function type.
+///
+/// \param Info if substitution fails for any reason, this object will be
+/// populated with more information about the failure.
+///
+/// \returns TDK_Success if substitution was successful, or some failure
+/// condition.
+Sema::TemplateDeductionResult
+Sema::SubstituteExplicitTemplateArguments(
+ FunctionTemplateDecl *FunctionTemplate,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<QualType> &ParamTypes,
+ QualType *FunctionType,
+ TemplateDeductionInfo &Info) {
+ FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+
+ if (NumExplicitTemplateArgs == 0) {
+ // No arguments to substitute; just copy over the parameter types and
+ // fill in the function type.
+ for (FunctionDecl::param_iterator P = Function->param_begin(),
+ PEnd = Function->param_end();
+ P != PEnd;
+ ++P)
+ ParamTypes.push_back((*P)->getType());
+
+ if (FunctionType)
+ *FunctionType = Function->getType();
+ return TDK_Success;
+ }
+
+ // Substitution of the explicit template arguments into a function template
+ /// is a SFINAE context. Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // C++ [temp.arg.explicit]p3:
+ // Template arguments that are present shall be specified in the
+ // declaration order of their corresponding template-parameters. The
+ // template argument list shall not specify more template-arguments than
+ // there are corresponding template-parameters.
+ TemplateArgumentListBuilder Builder(TemplateParams,
+ NumExplicitTemplateArgs);
+
+ // Enter a new template instantiation context where we check the
+ // explicitly-specified template arguments against this function template,
+ // and then substitute them into the function parameter types.
+ InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
+ FunctionTemplate, Deduced.data(), Deduced.size(),
+ ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution);
+ if (Inst)
+ return TDK_InstantiationDepth;
+
+ if (CheckTemplateArgumentList(FunctionTemplate,
+ SourceLocation(), SourceLocation(),
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ SourceLocation(),
+ true,
+ Builder) || Trap.hasErrorOccurred())
+ return TDK_InvalidExplicitArguments;
+
+ // Form the template argument list from the explicitly-specified
+ // template arguments.
+ TemplateArgumentList *ExplicitArgumentList
+ = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
+ Info.reset(ExplicitArgumentList);
+
+ // Instantiate the types of each of the function parameters given the
+ // explicitly-specified template arguments.
+ for (FunctionDecl::param_iterator P = Function->param_begin(),
+ PEnd = Function->param_end();
+ P != PEnd;
+ ++P) {
+ QualType ParamType
+ = SubstType((*P)->getType(),
+ MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+ (*P)->getLocation(), (*P)->getDeclName());
+ if (ParamType.isNull() || Trap.hasErrorOccurred())
+ return TDK_SubstitutionFailure;
+
+ ParamTypes.push_back(ParamType);
+ }
+
+ // If the caller wants a full function type back, instantiate the return
+ // type and form that function type.
+ if (FunctionType) {
+ // FIXME: exception-specifications?
+ const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>();
+ assert(Proto && "Function template does not have a prototype?");
+
+ QualType ResultType
+ = SubstType(Proto->getResultType(),
+ MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+ Function->getTypeSpecStartLoc(),
+ Function->getDeclName());
+ if (ResultType.isNull() || Trap.hasErrorOccurred())
+ return TDK_SubstitutionFailure;
+
+ *FunctionType = BuildFunctionType(ResultType,
+ ParamTypes.data(), ParamTypes.size(),
+ Proto->isVariadic(),
+ Proto->getTypeQuals(),
+ Function->getLocation(),
+ Function->getDeclName());
+ if (FunctionType->isNull() || Trap.hasErrorOccurred())
+ return TDK_SubstitutionFailure;
+ }
+
+ // C++ [temp.arg.explicit]p2:
+ // Trailing template arguments that can be deduced (14.8.2) may be
+ // omitted from the list of explicit template-arguments. If all of the
+ // template arguments can be deduced, they may all be omitted; in this
+ // case, the empty template argument list <> itself may also be omitted.
+ //
+ // Take all of the explicitly-specified arguments and put them into the
+ // set of deduced template arguments.
+ Deduced.reserve(TemplateParams->size());
+ for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I)
+ Deduced.push_back(ExplicitArgumentList->get(I));
+
+ return TDK_Success;
+}
+
+/// \brief Finish template argument deduction for a function template,
+/// checking the deduced template arguments for completeness and forming
+/// the function template specialization.
+Sema::TemplateDeductionResult
+Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info) {
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+
+ // C++ [temp.deduct.type]p2:
+ // [...] or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size());
+ for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
+ if (Deduced[I].isNull()) {
+ Info.Param = makeTemplateParameter(
+ const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+ return TDK_Incomplete;
+ }
+
+ Builder.Append(Deduced[I]);
+ }
+
+ // Form the template argument list from the deduced template arguments.
+ TemplateArgumentList *DeducedArgumentList
+ = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
+ Info.reset(DeducedArgumentList);
+
+ // Template argument deduction for function templates in a SFINAE context.
+ // Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // Enter a new template instantiation context while we instantiate the
+ // actual function declaration.
+ InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
+ FunctionTemplate, Deduced.data(), Deduced.size(),
+ ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
+ if (Inst)
+ return TDK_InstantiationDepth;
+
+ // Substitute the deduced template arguments into the function template
+ // declaration to produce the function template specialization.
+ Specialization = cast_or_null<FunctionDecl>(
+ SubstDecl(FunctionTemplate->getTemplatedDecl(),
+ FunctionTemplate->getDeclContext(),
+ MultiLevelTemplateArgumentList(*DeducedArgumentList)));
+ if (!Specialization)
+ return TDK_SubstitutionFailure;
+
+ assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() ==
+ FunctionTemplate->getCanonicalDecl());
+
+ // If the template argument list is owned by the function template
+ // specialization, release it.
+ if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList)
+ Info.take();
+
+ // There may have been an error that did not prevent us from constructing a
+ // declaration. Mark the declaration invalid and return with a substitution
+ // failure.
+ if (Trap.hasErrorOccurred()) {
+ Specialization->setInvalidDecl(true);
+ return TDK_SubstitutionFailure;
+ }
+
+ return TDK_Success;
+}
+
/// \brief Perform template argument deduction from a function call
/// (C++ [temp.deduct.call]).
///
/// \param FunctionTemplate the function template for which we are performing
/// template argument deduction.
///
-/// \param HasExplicitTemplateArgs whether any template arguments were
+/// \param HasExplicitTemplateArgs whether any template arguments were
/// explicitly specified.
///
/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
/// the explicitly-specified template arguments.
///
/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
-/// the number of explicitly-specified template arguments in
+/// the number of explicitly-specified template arguments in
/// @p ExplicitTemplateArguments. This value may be zero.
///
/// \param Args the function call arguments
@@ -883,7 +1280,7 @@ static bool isSimpleTemplateIdType(QualType T) {
/// \param NumArgs the number of arguments in Args
///
/// \param Specialization if template argument deduction was successful,
-/// this will be set to the function template specialization produced by
+/// this will be set to the function template specialization produced by
/// template argument deduction.
///
/// \param Info the argument will be updated to provide additional information
@@ -908,17 +1305,13 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
if (NumArgs < Function->getMinRequiredArguments())
return TDK_TooFewArguments;
else if (NumArgs > Function->getNumParams()) {
- const FunctionProtoType *Proto
- = Function->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>();
if (!Proto->isVariadic())
return TDK_TooManyArguments;
-
+
CheckArgs = Function->getNumParams();
}
-
- // Template argument deduction for function templates in a SFINAE context.
- // Trap any errors that might occur.
- SFINAETrap Trap(*this);
// The types of the parameters from which we will perform template argument
// deduction.
@@ -927,89 +1320,40 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
llvm::SmallVector<TemplateArgument, 4> Deduced;
llvm::SmallVector<QualType, 4> ParamTypes;
if (NumExplicitTemplateArgs) {
- // C++ [temp.arg.explicit]p3:
- // Template arguments that are present shall be specified in the
- // declaration order of their corresponding template-parameters. The
- // template argument list shall not specify more template-arguments than
- // there are corresponding template-parameters.
- TemplateArgumentListBuilder Builder(TemplateParams,
- NumExplicitTemplateArgs);
-
- // Enter a new template instantiation context where we check the
- // explicitly-specified template arguments against this function template,
- // and then substitute them into the function parameter types.
- InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
- FunctionTemplate, Deduced.data(), Deduced.size(),
- ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution);
- if (Inst)
- return TDK_InstantiationDepth;
-
- if (CheckTemplateArgumentList(FunctionTemplate,
- SourceLocation(), SourceLocation(),
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- SourceLocation(),
- true,
- Builder) || Trap.hasErrorOccurred())
- return TDK_InvalidExplicitArguments;
-
- // Form the template argument list from the explicitly-specified
- // template arguments.
- TemplateArgumentList *ExplicitArgumentList
- = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
- Info.reset(ExplicitArgumentList);
-
- // Instantiate the types of each of the function parameters given the
- // explicitly-specified template arguments.
- for (FunctionDecl::param_iterator P = Function->param_begin(),
- PEnd = Function->param_end();
- P != PEnd;
- ++P) {
- QualType ParamType = InstantiateType((*P)->getType(),
- *ExplicitArgumentList,
- (*P)->getLocation(),
- (*P)->getDeclName());
- if (ParamType.isNull() || Trap.hasErrorOccurred())
- return TDK_SubstitutionFailure;
-
- ParamTypes.push_back(ParamType);
- }
-
- // C++ [temp.arg.explicit]p2:
- // Trailing template arguments that can be deduced (14.8.2) may be
- // omitted from the list of explicit template- arguments. If all of the
- // template arguments can be deduced, they may all be omitted; in this
- // case, the empty template argument list <> itself may also be omitted.
- //
- // Take all of the explicitly-specified arguments and put them into the
- // set of deduced template arguments.
- Deduced.reserve(TemplateParams->size());
- for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I)
- Deduced.push_back(ExplicitArgumentList->get(I));
+ TemplateDeductionResult Result =
+ SubstituteExplicitTemplateArguments(FunctionTemplate,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ Deduced,
+ ParamTypes,
+ 0,
+ Info);
+ if (Result)
+ return Result;
} else {
// Just fill in the parameter types from the function declaration.
for (unsigned I = 0; I != CheckArgs; ++I)
ParamTypes.push_back(Function->getParamDecl(I)->getType());
}
-
+
// Deduce template arguments from the function parameters.
- Deduced.resize(TemplateParams->size());
+ Deduced.resize(TemplateParams->size());
for (unsigned I = 0; I != CheckArgs; ++I) {
QualType ParamType = ParamTypes[I];
QualType ArgType = Args[I]->getType();
-
+
// C++ [temp.deduct.call]p2:
// If P is not a reference type:
QualType CanonParamType = Context.getCanonicalType(ParamType);
bool ParamWasReference = isa<ReferenceType>(CanonParamType);
if (!ParamWasReference) {
- // - If A is an array type, the pointer type produced by the
- // array-to-pointer standard conversion (4.2) is used in place of
+ // - If A is an array type, the pointer type produced by the
+ // array-to-pointer standard conversion (4.2) is used in place of
// A for type deduction; otherwise,
if (ArgType->isArrayType())
ArgType = Context.getArrayDecayedType(ArgType);
- // - If A is a function type, the pointer type produced by the
- // function-to-pointer standard conversion (4.3) is used in place
+ // - If A is a function type, the pointer type produced by the
+ // function-to-pointer standard conversion (4.3) is used in place
// of A for type deduction; otherwise,
else if (ArgType->isFunctionType())
ArgType = Context.getPointerType(ArgType);
@@ -1021,252 +1365,884 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
ArgType = CanonArgType.getUnqualifiedType();
}
}
-
+
// C++0x [temp.deduct.call]p3:
// If P is a cv-qualified type, the top level cv-qualifiers of P’s type
- // are ignored for type deduction.
+ // are ignored for type deduction.
if (CanonParamType.getCVRQualifiers())
ParamType = CanonParamType.getUnqualifiedType();
- if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
- // [...] If P is a reference type, the type referred to by P is used
- // for type deduction.
+ if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) {
+ // [...] If P is a reference type, the type referred to by P is used
+ // for type deduction.
ParamType = ParamRefType->getPointeeType();
-
- // [...] If P is of the form T&&, where T is a template parameter, and
- // the argument is an lvalue, the type A& is used in place of A for
+
+ // [...] If P is of the form T&&, where T is a template parameter, and
+ // the argument is an lvalue, the type A& is used in place of A for
// type deduction.
if (isa<RValueReferenceType>(ParamRefType) &&
- ParamRefType->getAsTemplateTypeParmType() &&
+ ParamRefType->getAs<TemplateTypeParmType>() &&
Args[I]->isLvalue(Context) == Expr::LV_Valid)
ArgType = Context.getLValueReferenceType(ArgType);
}
-
+
// C++0x [temp.deduct.call]p4:
// In general, the deduction process attempts to find template argument
// values that will make the deduced A identical to A (after the type A
// is transformed as described above). [...]
- unsigned TDF = 0;
-
+ unsigned TDF = TDF_SkipNonDependent;
+
// - If the original P is a reference type, the deduced A (i.e., the
// type referred to by the reference) can be more cv-qualified than
// the transformed A.
if (ParamWasReference)
TDF |= TDF_ParamWithReferenceType;
- // - The transformed A can be another pointer or pointer to member
- // type that can be converted to the deduced A via a qualification
+ // - The transformed A can be another pointer or pointer to member
+ // type that can be converted to the deduced A via a qualification
// conversion (4.4).
if (ArgType->isPointerType() || ArgType->isMemberPointerType())
TDF |= TDF_IgnoreQualifiers;
- // - If P is a class and P has the form simple-template-id, then the
+ // - If P is a class and P has the form simple-template-id, then the
// transformed A can be a derived class of the deduced A. Likewise,
// if P is a pointer to a class of the form simple-template-id, the
// transformed A can be a pointer to a derived class pointed to by
// the deduced A.
if (isSimpleTemplateIdType(ParamType) ||
- (isa<PointerType>(ParamType) &&
+ (isa<PointerType>(ParamType) &&
isSimpleTemplateIdType(
- ParamType->getAsPointerType()->getPointeeType())))
+ ParamType->getAs<PointerType>()->getPointeeType())))
TDF |= TDF_DerivedClass;
-
+
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(Context, TemplateParams,
ParamType, ArgType, Info, Deduced,
TDF))
return Result;
+
+ // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
+ // pointer parameters.
+
+ // FIXME: we need to check that the deduced A is the same as A,
+ // modulo the various allowed differences.
+ }
+
+ return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+ Specialization, Info);
+}
+
+/// \brief Deduce template arguments when taking the address of a function
+/// template (C++ [temp.deduct.funcaddr]) or matching a
+///
+/// \param FunctionTemplate the function template for which we are performing
+/// template argument deduction.
+///
+/// \param HasExplicitTemplateArgs whether any template arguments were
+/// explicitly specified.
+///
+/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
+/// the explicitly-specified template arguments.
+///
+/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
+/// the number of explicitly-specified template arguments in
+/// @p ExplicitTemplateArguments. This value may be zero.
+///
+/// \param ArgFunctionType the function type that will be used as the
+/// "argument" type (A) when performing template argument deduction from the
+/// function template's function type.
+///
+/// \param Specialization if template argument deduction was successful,
+/// this will be set to the function template specialization produced by
+/// template argument deduction.
+///
+/// \param Info the argument will be updated to provide additional information
+/// about template argument deduction.
+///
+/// \returns the result of template argument deduction.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ bool HasExplicitTemplateArgs,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ QualType ArgFunctionType,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info) {
+ FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ QualType FunctionType = Function->getType();
+
+ // Substitute any explicit template arguments.
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<QualType, 4> ParamTypes;
+ if (HasExplicitTemplateArgs) {
+ if (TemplateDeductionResult Result
+ = SubstituteExplicitTemplateArguments(FunctionTemplate,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ Deduced, ParamTypes,
+ &FunctionType, Info))
+ return Result;
+ }
+
+ // Template argument deduction for function templates in a SFINAE context.
+ // Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // Deduce template arguments from the function type.
+ Deduced.resize(TemplateParams->size());
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(Context, TemplateParams,
+ FunctionType, ArgFunctionType, Info,
+ Deduced, 0))
+ return Result;
+
+ return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+ Specialization, Info);
+}
+
+/// \brief Deduce template arguments for a templated conversion
+/// function (C++ [temp.deduct.conv]) and, if successful, produce a
+/// conversion function template specialization.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ QualType ToType,
+ CXXConversionDecl *&Specialization,
+ TemplateDeductionInfo &Info) {
+ CXXConversionDecl *Conv
+ = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl());
+ QualType FromType = Conv->getConversionType();
+
+ // Canonicalize the types for deduction.
+ QualType P = Context.getCanonicalType(FromType);
+ QualType A = Context.getCanonicalType(ToType);
+
+ // C++0x [temp.deduct.conv]p3:
+ // If P is a reference type, the type referred to by P is used for
+ // type deduction.
+ if (const ReferenceType *PRef = P->getAs<ReferenceType>())
+ P = PRef->getPointeeType();
+
+ // C++0x [temp.deduct.conv]p3:
+ // If A is a reference type, the type referred to by A is used
+ // for type deduction.
+ if (const ReferenceType *ARef = A->getAs<ReferenceType>())
+ A = ARef->getPointeeType();
+ // C++ [temp.deduct.conv]p2:
+ //
+ // If A is not a reference type:
+ else {
+ assert(!A->isReferenceType() && "Reference types were handled above");
+
+ // - If P is an array type, the pointer type produced by the
+ // array-to-pointer standard conversion (4.2) is used in place
+ // of P for type deduction; otherwise,
+ if (P->isArrayType())
+ P = Context.getArrayDecayedType(P);
+ // - If P is a function type, the pointer type produced by the
+ // function-to-pointer standard conversion (4.3) is used in
+ // place of P for type deduction; otherwise,
+ else if (P->isFunctionType())
+ P = Context.getPointerType(P);
+ // - If P is a cv-qualified type, the top level cv-qualifiers of
+ // P’s type are ignored for type deduction.
+ else
+ P = P.getUnqualifiedType();
+
+ // C++0x [temp.deduct.conv]p3:
+ // If A is a cv-qualified type, the top level cv-qualifiers of A’s
+ // type are ignored for type deduction.
+ A = A.getUnqualifiedType();
+ }
+
+ // Template argument deduction for function templates in a SFINAE context.
+ // Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // C++ [temp.deduct.conv]p1:
+ // Template argument deduction is done by comparing the return
+ // type of the template conversion function (call it P) with the
+ // type that is required as the result of the conversion (call it
+ // A) as described in 14.8.2.4.
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Deduced.resize(TemplateParams->size());
+
+ // C++0x [temp.deduct.conv]p4:
+ // In general, the deduction process attempts to find template
+ // argument values that will make the deduced A identical to
+ // A. However, there are two cases that allow a difference:
+ unsigned TDF = 0;
+ // - If the original A is a reference type, A can be more
+ // cv-qualified than the deduced A (i.e., the type referred to
+ // by the reference)
+ if (ToType->isReferenceType())
+ TDF |= TDF_ParamWithReferenceType;
+ // - The deduced A can be another pointer or pointer to member
+ // type that can be converted to A via a qualification
+ // conversion.
+ //
+ // (C++0x [temp.deduct.conv]p6 clarifies that this only happens when
+ // both P and A are pointers or member pointers. In this case, we
+ // just ignore cv-qualifiers completely).
+ if ((P->isPointerType() && A->isPointerType()) ||
+ (P->isMemberPointerType() && P->isMemberPointerType()))
+ TDF |= TDF_IgnoreQualifiers;
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(Context, TemplateParams,
+ P, A, Info, Deduced, TDF))
+ return Result;
+
+ // FIXME: we need to check that the deduced A is the same as A,
+ // modulo the various allowed differences.
+
+ // Finish template argument deduction.
+ FunctionDecl *Spec = 0;
+ TemplateDeductionResult Result
+ = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info);
+ Specialization = cast_or_null<CXXConversionDecl>(Spec);
+ return Result;
+}
+
+/// \brief Stores the result of comparing the qualifiers of two types.
+enum DeductionQualifierComparison {
+ NeitherMoreQualified = 0,
+ ParamMoreQualified,
+ ArgMoreQualified
+};
+
+/// \brief Deduce the template arguments during partial ordering by comparing
+/// the parameter type and the argument type (C++0x [temp.deduct.partial]).
+///
+/// \param Context the AST context in which this deduction occurs.
+///
+/// \param TemplateParams the template parameters that we are deducing
+///
+/// \param ParamIn the parameter type
+///
+/// \param ArgIn the argument type
+///
+/// \param Info information about the template argument deduction itself
+///
+/// \param Deduced the deduced template arguments
+///
+/// \returns the result of template argument deduction so far. Note that a
+/// "success" result means that template argument deduction has not yet failed,
+/// but it may still fail, later, for other reasons.
+static Sema::TemplateDeductionResult
+DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ QualType ParamIn, QualType ArgIn,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
+ CanQualType Param = Context.getCanonicalType(ParamIn);
+ CanQualType Arg = Context.getCanonicalType(ArgIn);
+
+ // C++0x [temp.deduct.partial]p5:
+ // Before the partial ordering is done, certain transformations are
+ // performed on the types used for partial ordering:
+ // - If P is a reference type, P is replaced by the type referred to.
+ CanQual<ReferenceType> ParamRef = Param->getAs<ReferenceType>();
+ if (ParamRef)
+ Param = ParamRef->getPointeeType();
+
+ // - If A is a reference type, A is replaced by the type referred to.
+ CanQual<ReferenceType> ArgRef = Arg->getAs<ReferenceType>();
+ if (ArgRef)
+ Arg = ArgRef->getPointeeType();
+
+ if (QualifierComparisons && ParamRef && ArgRef) {
+ // C++0x [temp.deduct.partial]p6:
+ // If both P and A were reference types (before being replaced with the
+ // type referred to above), determine which of the two types (if any) is
+ // more cv-qualified than the other; otherwise the types are considered to
+ // be equally cv-qualified for partial ordering purposes. The result of this
+ // determination will be used below.
+ //
+ // We save this information for later, using it only when deduction
+ // succeeds in both directions.
+ DeductionQualifierComparison QualifierResult = NeitherMoreQualified;
+ if (Param.isMoreQualifiedThan(Arg))
+ QualifierResult = ParamMoreQualified;
+ else if (Arg.isMoreQualifiedThan(Param))
+ QualifierResult = ArgMoreQualified;
+ QualifierComparisons->push_back(QualifierResult);
+ }
+
+ // C++0x [temp.deduct.partial]p7:
+ // Remove any top-level cv-qualifiers:
+ // - If P is a cv-qualified type, P is replaced by the cv-unqualified
+ // version of P.
+ Param = Param.getUnqualifiedType();
+ // - If A is a cv-qualified type, A is replaced by the cv-unqualified
+ // version of A.
+ Arg = Arg.getUnqualifiedType();
+
+ // C++0x [temp.deduct.partial]p8:
+ // Using the resulting types P and A the deduction is then done as
+ // described in 14.9.2.5. If deduction succeeds for a given type, the type
+ // from the argument template is considered to be at least as specialized
+ // as the type from the parameter template.
+ return DeduceTemplateArguments(Context, TemplateParams, Param, Arg, Info,
+ Deduced, TDF_None);
+}
+
+static void
+MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Deduced);
+
+/// \brief Determine whether the function template \p FT1 is at least as
+/// specialized as \p FT2.
+static bool isAtLeastAsSpecializedAs(Sema &S,
+ FunctionTemplateDecl *FT1,
+ FunctionTemplateDecl *FT2,
+ TemplatePartialOrderingContext TPOC,
+ llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
+ FunctionDecl *FD1 = FT1->getTemplatedDecl();
+ FunctionDecl *FD2 = FT2->getTemplatedDecl();
+ const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *Proto2 = FD2->getType()->getAs<FunctionProtoType>();
+
+ assert(Proto1 && Proto2 && "Function templates must have prototypes");
+ TemplateParameterList *TemplateParams = FT2->getTemplateParameters();
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Deduced.resize(TemplateParams->size());
+
+ // C++0x [temp.deduct.partial]p3:
+ // The types used to determine the ordering depend on the context in which
+ // the partial ordering is done:
+ Sema::TemplateDeductionInfo Info(S.Context);
+ switch (TPOC) {
+ case TPOC_Call: {
+ // - In the context of a function call, the function parameter types are
+ // used.
+ unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
+ for (unsigned I = 0; I != NumParams; ++I)
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ TemplateParams,
+ Proto2->getArgType(I),
+ Proto1->getArgType(I),
+ Info,
+ Deduced,
+ QualifierComparisons))
+ return false;
+
+ break;
+ }
+
+ case TPOC_Conversion:
+ // - In the context of a call to a conversion operator, the return types
+ // of the conversion function templates are used.
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ TemplateParams,
+ Proto2->getResultType(),
+ Proto1->getResultType(),
+ Info,
+ Deduced,
+ QualifierComparisons))
+ return false;
+ break;
- // FIXME: C++ [temp.deduct.call] paragraphs 6-9 deal with function
- // pointer parameters.
+ case TPOC_Other:
+ // - In other contexts (14.6.6.2) the function template’s function type
+ // is used.
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ TemplateParams,
+ FD2->getType(),
+ FD1->getType(),
+ Info,
+ Deduced,
+ QualifierComparisons))
+ return false;
+ break;
}
- // C++ [temp.deduct.type]p2:
- // [...] or if any template argument remains neither deduced nor
- // explicitly specified, template argument deduction fails.
- TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size());
- for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
- if (Deduced[I].isNull()) {
- Decl *Param
- = const_cast<Decl *>(TemplateParams->getParam(I));
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
- Info.Param = TTP;
- else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param))
- Info.Param = NTTP;
- else
- Info.Param = cast<TemplateTemplateParmDecl>(Param);
- return TDK_Incomplete;
- }
+ // C++0x [temp.deduct.partial]p11:
+ // In most cases, all template parameters must have values in order for
+ // deduction to succeed, but for partial ordering purposes a template
+ // parameter may remain without a value provided it is not used in the
+ // types being used for partial ordering. [ Note: a template parameter used
+ // in a non-deduced context is considered used. -end note]
+ unsigned ArgIdx = 0, NumArgs = Deduced.size();
+ for (; ArgIdx != NumArgs; ++ArgIdx)
+ if (Deduced[ArgIdx].isNull())
+ break;
+
+ if (ArgIdx == NumArgs) {
+ // All template arguments were deduced. FT1 is at least as specialized
+ // as FT2.
+ return true;
+ }
+
+ // Figure out which template parameters were used.
+ llvm::SmallVector<bool, 4> UsedParameters;
+ UsedParameters.resize(TemplateParams->size());
+ switch (TPOC) {
+ case TPOC_Call: {
+ unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
+ for (unsigned I = 0; I != NumParams; ++I)
+ ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false,
+ UsedParameters);
+ break;
+ }
- Builder.Append(Deduced[I]);
+ case TPOC_Conversion:
+ ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false,
+ UsedParameters);
+ break;
+
+ case TPOC_Other:
+ ::MarkUsedTemplateParameters(S, FD2->getType(), false, UsedParameters);
+ break;
}
- // Form the template argument list from the deduced template arguments.
- TemplateArgumentList *DeducedArgumentList
- = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
- Info.reset(DeducedArgumentList);
+ for (; ArgIdx != NumArgs; ++ArgIdx)
+ // If this argument had no value deduced but was used in one of the types
+ // used for partial ordering, then deduction fails.
+ if (Deduced[ArgIdx].isNull() && UsedParameters[ArgIdx])
+ return false;
- // Enter a new template instantiation context while we instantiate the
- // actual function declaration.
- InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
- FunctionTemplate, Deduced.data(), Deduced.size(),
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
- if (Inst)
- return TDK_InstantiationDepth;
-
- // Substitute the deduced template arguments into the function template
- // declaration to produce the function template specialization.
- Specialization = cast_or_null<FunctionDecl>(
- InstantiateDecl(FunctionTemplate->getTemplatedDecl(),
- FunctionTemplate->getDeclContext(),
- *DeducedArgumentList));
- if (!Specialization)
- return TDK_SubstitutionFailure;
+ return true;
+}
+
+
+/// \brief Returns the more specialized function template according
+/// to the rules of function template partial ordering (C++ [temp.func.order]).
+///
+/// \param FT1 the first function template
+///
+/// \param FT2 the second function template
+///
+/// \param TPOC the context in which we are performing partial ordering of
+/// function templates.
+///
+/// \returns the more specialized function template. If neither
+/// template is more specialized, returns NULL.
+FunctionTemplateDecl *
+Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
+ FunctionTemplateDecl *FT2,
+ TemplatePartialOrderingContext TPOC) {
+ llvm::SmallVector<DeductionQualifierComparison, 4> QualifierComparisons;
+ bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, TPOC, 0);
+ bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, TPOC,
+ &QualifierComparisons);
- // If the template argument list is owned by the function template
- // specialization, release it.
- if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList)
- Info.take();
+ if (Better1 != Better2) // We have a clear winner
+ return Better1? FT1 : FT2;
+
+ if (!Better1 && !Better2) // Neither is better than the other
+ return 0;
+
+
+ // C++0x [temp.deduct.partial]p10:
+ // If for each type being considered a given template is at least as
+ // specialized for all types and more specialized for some set of types and
+ // the other template is not more specialized for any types or is not at
+ // least as specialized for any types, then the given template is more
+ // specialized than the other template. Otherwise, neither template is more
+ // specialized than the other.
+ Better1 = false;
+ Better2 = false;
+ for (unsigned I = 0, N = QualifierComparisons.size(); I != N; ++I) {
+ // C++0x [temp.deduct.partial]p9:
+ // If, for a given type, deduction succeeds in both directions (i.e., the
+ // types are identical after the transformations above) and if the type
+ // from the argument template is more cv-qualified than the type from the
+ // parameter template (as described above) that type is considered to be
+ // more specialized than the other. If neither type is more cv-qualified
+ // than the other then neither type is more specialized than the other.
+ switch (QualifierComparisons[I]) {
+ case NeitherMoreQualified:
+ break;
+
+ case ParamMoreQualified:
+ Better1 = true;
+ if (Better2)
+ return 0;
+ break;
+
+ case ArgMoreQualified:
+ Better2 = true;
+ if (Better1)
+ return 0;
+ break;
+ }
+ }
+
+ assert(!(Better1 && Better2) && "Should have broken out in the loop above");
+ if (Better1)
+ return FT1;
+ else if (Better2)
+ return FT2;
+ else
+ return 0;
+}
- // There may have been an error that did not prevent us from constructing a
- // declaration. Mark the declaration invalid and return with a substitution
- // failure.
- if (Trap.hasErrorOccurred()) {
- Specialization->setInvalidDecl(true);
- return TDK_SubstitutionFailure;
+/// \brief Determine if the two templates are equivalent.
+static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
+ if (T1 == T2)
+ return true;
+
+ if (!T1 || !T2)
+ return false;
+
+ return T1->getCanonicalDecl() == T2->getCanonicalDecl();
+}
+
+/// \brief Retrieve the most specialized of the given function template
+/// specializations.
+///
+/// \param Specializations the set of function template specializations that
+/// we will be comparing.
+///
+/// \param NumSpecializations the number of function template specializations in
+/// \p Specializations
+///
+/// \param TPOC the partial ordering context to use to compare the function
+/// template specializations.
+///
+/// \param Loc the location where the ambiguity or no-specializations
+/// diagnostic should occur.
+///
+/// \param NoneDiag partial diagnostic used to diagnose cases where there are
+/// no matching candidates.
+///
+/// \param AmbigDiag partial diagnostic used to diagnose an ambiguity, if one
+/// occurs.
+///
+/// \param CandidateDiag partial diagnostic used for each function template
+/// specialization that is a candidate in the ambiguous ordering. One parameter
+/// in this diagnostic should be unbound, which will correspond to the string
+/// describing the template arguments for the function template specialization.
+///
+/// \param Index if non-NULL and the result of this function is non-nULL,
+/// receives the index corresponding to the resulting function template
+/// specialization.
+///
+/// \returns the most specialized function template specialization, if
+/// found. Otherwise, returns NULL.
+///
+/// \todo FIXME: Consider passing in the "also-ran" candidates that failed
+/// template argument deduction.
+FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
+ unsigned NumSpecializations,
+ TemplatePartialOrderingContext TPOC,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag,
+ unsigned *Index) {
+ if (NumSpecializations == 0) {
+ Diag(Loc, NoneDiag);
+ return 0;
}
- return TDK_Success;
+ if (NumSpecializations == 1) {
+ if (Index)
+ *Index = 0;
+
+ return Specializations[0];
+ }
+
+
+ // Find the function template that is better than all of the templates it
+ // has been compared to.
+ unsigned Best = 0;
+ FunctionTemplateDecl *BestTemplate
+ = Specializations[Best]->getPrimaryTemplate();
+ assert(BestTemplate && "Not a function template specialization?");
+ for (unsigned I = 1; I != NumSpecializations; ++I) {
+ FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+ assert(Challenger && "Not a function template specialization?");
+ if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
+ TPOC),
+ Challenger)) {
+ Best = I;
+ BestTemplate = Challenger;
+ }
+ }
+
+ // Make sure that the "best" function template is more specialized than all
+ // of the others.
+ bool Ambiguous = false;
+ for (unsigned I = 0; I != NumSpecializations; ++I) {
+ FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+ if (I != Best &&
+ !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
+ TPOC),
+ BestTemplate)) {
+ Ambiguous = true;
+ break;
+ }
+ }
+
+ if (!Ambiguous) {
+ // We found an answer. Return it.
+ if (Index)
+ *Index = Best;
+ return Specializations[Best];
+ }
+
+ // Diagnose the ambiguity.
+ Diag(Loc, AmbigDiag);
+
+ // FIXME: Can we order the candidates in some sane way?
+ for (unsigned I = 0; I != NumSpecializations; ++I)
+ Diag(Specializations[I]->getLocation(), CandidateDiag)
+ << getTemplateArgumentBindingsText(
+ Specializations[I]->getPrimaryTemplate()->getTemplateParameters(),
+ *Specializations[I]->getTemplateSpecializationArgs());
+
+ return 0;
+}
+
+/// \brief Returns the more specialized class template partial specialization
+/// according to the rules of partial ordering of class template partial
+/// specializations (C++ [temp.class.order]).
+///
+/// \param PS1 the first class template partial specialization
+///
+/// \param PS2 the second class template partial specialization
+///
+/// \returns the more specialized class template partial specialization. If
+/// neither partial specialization is more specialized, returns NULL.
+ClassTemplatePartialSpecializationDecl *
+Sema::getMoreSpecializedPartialSpecialization(
+ ClassTemplatePartialSpecializationDecl *PS1,
+ ClassTemplatePartialSpecializationDecl *PS2) {
+ // C++ [temp.class.order]p1:
+ // For two class template partial specializations, the first is at least as
+ // specialized as the second if, given the following rewrite to two
+ // function templates, the first function template is at least as
+ // specialized as the second according to the ordering rules for function
+ // templates (14.6.6.2):
+ // - the first function template has the same template parameters as the
+ // first partial specialization and has a single function parameter
+ // whose type is a class template specialization with the template
+ // arguments of the first partial specialization, and
+ // - the second function template has the same template parameters as the
+ // second partial specialization and has a single function parameter
+ // whose type is a class template specialization with the template
+ // arguments of the second partial specialization.
+ //
+ // Rather than synthesize function templates, we merely perform the
+ // equivalent partial ordering by performing deduction directly on the
+ // template arguments of the class template partial specializations. This
+ // computation is slightly simpler than the general problem of function
+ // template partial ordering, because class template partial specializations
+ // are more constrained. We know that every template parameter is deduc
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Sema::TemplateDeductionInfo Info(Context);
+
+ // Determine whether PS1 is at least as specialized as PS2
+ Deduced.resize(PS2->getTemplateParameters()->size());
+ bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
+ PS2->getTemplateParameters(),
+ Context.getTypeDeclType(PS2),
+ Context.getTypeDeclType(PS1),
+ Info,
+ Deduced,
+ 0);
+
+ // Determine whether PS2 is at least as specialized as PS1
+ Deduced.resize(PS1->getTemplateParameters()->size());
+ bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
+ PS1->getTemplateParameters(),
+ Context.getTypeDeclType(PS1),
+ Context.getTypeDeclType(PS2),
+ Info,
+ Deduced,
+ 0);
+
+ if (Better1 == Better2)
+ return 0;
+
+ return Better1? PS1 : PS2;
}
-static void
-MarkDeducedTemplateParameters(Sema &SemaRef,
- const TemplateArgument &TemplateArg,
- llvm::SmallVectorImpl<bool> &Deduced);
+static void
+MarkUsedTemplateParameters(Sema &SemaRef,
+ const TemplateArgument &TemplateArg,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used);
-/// \brief Mark the template arguments that are deduced by the given
+/// \brief Mark the template parameters that are used by the given
/// expression.
-static void
-MarkDeducedTemplateParameters(const Expr *E,
- llvm::SmallVectorImpl<bool> &Deduced) {
+static void
+MarkUsedTemplateParameters(Sema &SemaRef,
+ const Expr *E,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
+ // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to
+ // find other occurrences of template parameters.
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
if (!E)
return;
- const NonTypeTemplateParmDecl *NTTP
+ const NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());
if (!NTTP)
return;
- Deduced[NTTP->getIndex()] = true;
+ Used[NTTP->getIndex()] = true;
+}
+
+/// \brief Mark the template parameters that are used by the given
+/// nested name specifier.
+static void
+MarkUsedTemplateParameters(Sema &SemaRef,
+ NestedNameSpecifier *NNS,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
+ if (!NNS)
+ return;
+
+ MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Used);
+ MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0),
+ OnlyDeduced, Used);
+}
+
+/// \brief Mark the template parameters that are used by the given
+/// template name.
+static void
+MarkUsedTemplateParameters(Sema &SemaRef,
+ TemplateName Name,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
+ if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(Template))
+ Used[TTP->getIndex()] = true;
+ return;
+ }
+
+ if (DependentTemplateName *DTN = Name.getAsDependentTemplateName())
+ MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Used);
}
-/// \brief Mark the template parameters that are deduced by the given
+/// \brief Mark the template parameters that are used by the given
/// type.
-static void
-MarkDeducedTemplateParameters(Sema &SemaRef, QualType T,
- llvm::SmallVectorImpl<bool> &Deduced) {
+static void
+MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
+ if (T.isNull())
+ return;
+
// Non-dependent types have nothing deducible
if (!T->isDependentType())
return;
T = SemaRef.Context.getCanonicalType(T);
switch (T->getTypeClass()) {
- case Type::ExtQual:
- MarkDeducedTemplateParameters(SemaRef,
- QualType(cast<ExtQualType>(T)->getBaseType(), 0),
- Deduced);
- break;
-
case Type::Pointer:
- MarkDeducedTemplateParameters(SemaRef,
- cast<PointerType>(T)->getPointeeType(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<PointerType>(T)->getPointeeType(),
+ OnlyDeduced,
+ Used);
break;
case Type::BlockPointer:
- MarkDeducedTemplateParameters(SemaRef,
- cast<BlockPointerType>(T)->getPointeeType(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<BlockPointerType>(T)->getPointeeType(),
+ OnlyDeduced,
+ Used);
break;
case Type::LValueReference:
case Type::RValueReference:
- MarkDeducedTemplateParameters(SemaRef,
- cast<ReferenceType>(T)->getPointeeType(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<ReferenceType>(T)->getPointeeType(),
+ OnlyDeduced,
+ Used);
break;
case Type::MemberPointer: {
const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
- MarkDeducedTemplateParameters(SemaRef, MemPtr->getPointeeType(), Deduced);
- MarkDeducedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef, MemPtr->getPointeeType(), OnlyDeduced,
+ Used);
+ MarkUsedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
+ OnlyDeduced, Used);
break;
}
case Type::DependentSizedArray:
- MarkDeducedTemplateParameters(cast<DependentSizedArrayType>(T)->getSizeExpr(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<DependentSizedArrayType>(T)->getSizeExpr(),
+ OnlyDeduced, Used);
// Fall through to check the element type
case Type::ConstantArray:
case Type::IncompleteArray:
- MarkDeducedTemplateParameters(SemaRef,
- cast<ArrayType>(T)->getElementType(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<ArrayType>(T)->getElementType(),
+ OnlyDeduced, Used);
break;
case Type::Vector:
case Type::ExtVector:
- MarkDeducedTemplateParameters(SemaRef,
- cast<VectorType>(T)->getElementType(),
- Deduced);
+ MarkUsedTemplateParameters(SemaRef,
+ cast<VectorType>(T)->getElementType(),
+ OnlyDeduced, Used);
break;
case Type::DependentSizedExtVector: {
const DependentSizedExtVectorType *VecType
= cast<DependentSizedExtVectorType>(T);
- MarkDeducedTemplateParameters(SemaRef, VecType->getElementType(), Deduced);
- MarkDeducedTemplateParameters(VecType->getSizeExpr(), Deduced);
+ MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced,
+ Used);
+ MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced,
+ Used);
break;
}
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
- MarkDeducedTemplateParameters(SemaRef, Proto->getResultType(), Deduced);
+ MarkUsedTemplateParameters(SemaRef, Proto->getResultType(), OnlyDeduced,
+ Used);
for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I)
- MarkDeducedTemplateParameters(SemaRef, Proto->getArgType(I), Deduced);
+ MarkUsedTemplateParameters(SemaRef, Proto->getArgType(I), OnlyDeduced,
+ Used);
break;
}
case Type::TemplateTypeParm:
- Deduced[cast<TemplateTypeParmType>(T)->getIndex()] = true;
+ Used[cast<TemplateTypeParmType>(T)->getIndex()] = true;
break;
case Type::TemplateSpecialization: {
- const TemplateSpecializationType *Spec
+ const TemplateSpecializationType *Spec
= cast<TemplateSpecializationType>(T);
- if (TemplateDecl *Template = Spec->getTemplateName().getAsTemplateDecl())
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(Template))
- Deduced[TTP->getIndex()] = true;
-
- for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkDeducedTemplateParameters(SemaRef, Spec->getArg(I), Deduced);
-
+ MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced,
+ Used);
+ for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
+ MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Used);
break;
}
- // None of these types have any deducible parts.
+ case Type::Complex:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<ComplexType>(T)->getElementType(),
+ OnlyDeduced, Used);
+ break;
+
+ case Type::Typename:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<TypenameType>(T)->getQualifier(),
+ OnlyDeduced, Used);
+ break;
+
+ // None of these types have any template parameters in them.
case Type::Builtin:
case Type::FixedWidthInt:
- case Type::Complex:
case Type::VariableArray:
case Type::FunctionNoProto:
case Type::Record:
case Type::Enum:
- case Type::Typename:
case Type::ObjCInterface:
- case Type::ObjCQualifiedInterface:
case Type::ObjCObjectPointer:
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
@@ -1277,32 +2253,39 @@ MarkDeducedTemplateParameters(Sema &SemaRef, QualType T,
}
}
-/// \brief Mark the template parameters that are deduced by this
+/// \brief Mark the template parameters that are used by this
/// template argument.
-static void
-MarkDeducedTemplateParameters(Sema &SemaRef,
- const TemplateArgument &TemplateArg,
- llvm::SmallVectorImpl<bool> &Deduced) {
+static void
+MarkUsedTemplateParameters(Sema &SemaRef,
+ const TemplateArgument &TemplateArg,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
switch (TemplateArg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
break;
-
+
case TemplateArgument::Type:
- MarkDeducedTemplateParameters(SemaRef, TemplateArg.getAsType(), Deduced);
+ MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsType(), OnlyDeduced,
+ Used);
break;
case TemplateArgument::Declaration:
- if (TemplateTemplateParmDecl *TTP
+ if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl()))
- Deduced[TTP->getIndex()] = true;
+ Used[TTP->getIndex()] = true;
break;
case TemplateArgument::Expression:
- MarkDeducedTemplateParameters(TemplateArg.getAsExpr(), Deduced);
+ MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced,
+ Used);
break;
+
case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
+ for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(),
+ PEnd = TemplateArg.pack_end();
+ P != PEnd; ++P)
+ MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Used);
break;
}
}
@@ -1316,9 +2299,25 @@ MarkDeducedTemplateParameters(Sema &SemaRef,
/// \param Deduced a bit vector whose elements will be set to \c true
/// to indicate when the corresponding template parameter will be
/// deduced.
-void
-Sema::MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
- llvm::SmallVectorImpl<bool> &Deduced) {
+void
+Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
+ bool OnlyDeduced,
+ llvm::SmallVectorImpl<bool> &Used) {
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
- ::MarkDeducedTemplateParameters(*this, TemplateArgs[I], Deduced);
+ ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Used);
+}
+
+/// \brief Marks all of the template parameters that will be deduced by a
+/// call to the given function template.
+void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallVectorImpl<bool> &Deduced) {
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ Deduced.clear();
+ Deduced.resize(TemplateParams->size());
+
+ FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+ for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I)
+ ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(),
+ true, Deduced);
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 6c2dc77b4cce0..65260c8e1e63b 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===/
#include "Sema.h"
+#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
@@ -25,32 +26,65 @@ using namespace clang;
// Template Instantiation Support
//===----------------------------------------------------------------------===/
-/// \brief Retrieve the template argument list that should be used to
-/// instantiate the given declaration.
-const TemplateArgumentList &
+/// \brief Retrieve the template argument list(s) that should be used to
+/// instantiate the definition of the given declaration.
+MultiLevelTemplateArgumentList
Sema::getTemplateInstantiationArgs(NamedDecl *D) {
- // Template arguments for a class template specialization.
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(D))
- return Spec->getTemplateArgs();
-
- // Template arguments for a function template specialization.
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
- if (const TemplateArgumentList *TemplateArgs
- = Function->getTemplateSpecializationArgs())
- return *TemplateArgs;
+ // Accumulate the set of template argument lists in this structure.
+ MultiLevelTemplateArgumentList Result;
+
+ DeclContext *Ctx = dyn_cast<DeclContext>(D);
+ if (!Ctx)
+ Ctx = D->getDeclContext();
+
+ while (!Ctx->isFileContext()) {
+ // Add template arguments from a class template instantiation.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
+ // We're done when we hit an explicit specialization.
+ if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization)
+ break;
+
+ Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
- // Template arguments for a member of a class template specialization.
- DeclContext *EnclosingTemplateCtx = D->getDeclContext();
- while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx)) {
- assert(!EnclosingTemplateCtx->isFileContext() &&
- "Tried to get the instantiation arguments of a non-template");
- EnclosingTemplateCtx = EnclosingTemplateCtx->getParent();
+ // If this class template specialization was instantiated from a
+ // specialized member that is a class template, we're done.
+ assert(Spec->getSpecializedTemplate() && "No class template?");
+ if (Spec->getSpecializedTemplate()->isMemberSpecialization())
+ break;
+ }
+ // Add template arguments from a function template specialization.
+ else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
+ if (Function->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
+ break;
+
+ if (const TemplateArgumentList *TemplateArgs
+ = Function->getTemplateSpecializationArgs()) {
+ // Add the template arguments for this specialization.
+ Result.addOuterTemplateArguments(TemplateArgs);
+
+ // If this function was instantiated from a specialized member that is
+ // a function template, we're done.
+ assert(Function->getPrimaryTemplate() && "No function template?");
+ if (Function->getPrimaryTemplate()->isMemberSpecialization())
+ break;
+ }
+
+ // If this is a friend declaration and it declares an entity at
+ // namespace scope, take arguments from its lexical parent
+ // instead of its semantic parent.
+ if (Function->getFriendObjectKind() &&
+ Function->getDeclContext()->isFileContext()) {
+ Ctx = Function->getLexicalDeclContext();
+ continue;
+ }
+ }
+
+ Ctx = Ctx->getParent();
}
- ClassTemplateSpecializationDecl *EnclosingTemplate
- = cast<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx);
- return EnclosingTemplate->getTemplateArgs();
+ return Result;
}
Sema::InstantiatingTemplate::
@@ -74,7 +108,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
}
}
-Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
SourceLocation PointOfInstantiation,
TemplateDecl *Template,
const TemplateArgument *TemplateArgs,
@@ -86,7 +120,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
InstantiationRange);
if (!Invalid) {
ActiveTemplateInstantiation Inst;
- Inst.Kind
+ Inst.Kind
= ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = reinterpret_cast<uintptr_t>(Template);
@@ -98,7 +132,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
}
}
-Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
SourceLocation PointOfInstantiation,
FunctionTemplateDecl *FunctionTemplate,
const TemplateArgument *TemplateArgs,
@@ -106,7 +140,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
ActiveTemplateInstantiation::InstantiationKind Kind,
SourceRange InstantiationRange)
: SemaRef(SemaRef) {
-
+
Invalid = CheckInstantiationDepth(PointOfInstantiation,
InstantiationRange);
if (!Invalid) {
@@ -122,7 +156,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
}
}
-Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
SourceLocation PointOfInstantiation,
ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgument *TemplateArgs,
@@ -134,7 +168,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
InstantiationRange);
if (!Invalid) {
ActiveTemplateInstantiation Inst;
- Inst.Kind
+ Inst.Kind
= ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
@@ -146,6 +180,30 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
}
}
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+ SourceLocation PointOfInstantation,
+ ParmVarDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange)
+ : SemaRef(SemaRef) {
+
+ Invalid = CheckInstantiationDepth(PointOfInstantation, InstantiationRange);
+
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind
+ = ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation;
+ Inst.PointOfInstantiation = PointOfInstantation;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ Invalid = false;
+ }
+}
+
void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
SemaRef.ActiveTemplateInstantiations.pop_back();
@@ -156,11 +214,11 @@ void Sema::InstantiatingTemplate::Clear() {
bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
SourceLocation PointOfInstantiation,
SourceRange InstantiationRange) {
- if (SemaRef.ActiveTemplateInstantiations.size()
+ if (SemaRef.ActiveTemplateInstantiations.size()
<= SemaRef.getLangOptions().InstantiationDepth)
return false;
- SemaRef.Diag(PointOfInstantiation,
+ SemaRef.Diag(PointOfInstantiation,
diag::err_template_recursion_depth_exceeded)
<< SemaRef.getLangOptions().InstantiationDepth
<< InstantiationRange;
@@ -185,21 +243,25 @@ void Sema::PrintInstantiationStack() {
unsigned DiagID = diag::note_template_member_class_here;
if (isa<ClassTemplateSpecializationDecl>(Record))
DiagID = diag::note_template_class_instantiation_here;
- Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
DiagID)
<< Context.getTypeDeclType(Record)
<< Active->InstantiationRange;
- } else {
- FunctionDecl *Function = cast<FunctionDecl>(D);
+ } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
unsigned DiagID;
if (Function->getPrimaryTemplate())
DiagID = diag::note_function_template_spec_here;
else
DiagID = diag::note_template_member_function_here;
- Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
DiagID)
<< Function
<< Active->InstantiationRange;
+ } else {
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_template_static_data_member_def_here)
+ << cast<VarDecl>(D)
+ << Active->InstantiationRange;
}
break;
}
@@ -208,7 +270,7 @@ void Sema::PrintInstantiationStack() {
TemplateDecl *Template = cast<TemplateDecl>((Decl *)Active->Entity);
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
- Active->TemplateArgs,
+ Active->TemplateArgs,
Active->NumTemplateArgs,
Context.PrintingPolicy);
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
@@ -219,14 +281,14 @@ void Sema::PrintInstantiationStack() {
}
case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: {
- FunctionTemplateDecl *FnTmpl
+ FunctionTemplateDecl *FnTmpl
= cast<FunctionTemplateDecl>((Decl *)Active->Entity);
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
diag::note_explicit_template_arg_substitution_here)
<< FnTmpl << Active->InstantiationRange;
break;
}
-
+
case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution:
if (ClassTemplatePartialSpecializationDecl *PartialSpec
= dyn_cast<ClassTemplatePartialSpecializationDecl>(
@@ -244,6 +306,22 @@ void Sema::PrintInstantiationStack() {
}
break;
+ case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: {
+ ParmVarDecl *Param = cast<ParmVarDecl>((Decl *)Active->Entity);
+ FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext());
+
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ Active->TemplateArgs,
+ Active->NumTemplateArgs,
+ Context.PrintingPolicy);
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_default_function_arg_instantiation_here)
+ << (FD->getNameAsString() + TemplateArgsStr)
+ << Active->InstantiationRange;
+ break;
+ }
+
}
}
}
@@ -258,14 +336,16 @@ bool Sema::isSFINAEContext() const {
switch(Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation:
+ case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
+
// This is a template instantiation, so there is no SFINAE.
return false;
-
+
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
// A default template argument instantiation may or may not be a
// SFINAE context; look further up the stack.
break;
-
+
case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution:
case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution:
// We're either substitution explicitly-specified template arguments
@@ -281,482 +361,274 @@ bool Sema::isSFINAEContext() const {
// Template Instantiation for Types
//===----------------------------------------------------------------------===/
namespace {
- class VISIBILITY_HIDDEN TemplateTypeInstantiator {
- Sema &SemaRef;
- const TemplateArgumentList &TemplateArgs;
+ class VISIBILITY_HIDDEN TemplateInstantiator
+ : public TreeTransform<TemplateInstantiator> {
+ const MultiLevelTemplateArgumentList &TemplateArgs;
SourceLocation Loc;
DeclarationName Entity;
public:
- TemplateTypeInstantiator(Sema &SemaRef,
- const TemplateArgumentList &TemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity)
- : SemaRef(SemaRef), TemplateArgs(TemplateArgs),
- Loc(Loc), Entity(Entity) { }
-
- QualType operator()(QualType T) const { return Instantiate(T); }
-
- QualType Instantiate(QualType T) const;
-
- // Declare instantiate functions for each type.
-#define TYPE(Class, Base) \
- QualType Instantiate##Class##Type(const Class##Type *T) const;
-#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
- };
-}
-
-QualType
-TemplateTypeInstantiator::InstantiateExtQualType(const ExtQualType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ExtQualType yet");
- return QualType();
-}
-
-QualType
-TemplateTypeInstantiator::InstantiateBuiltinType(const BuiltinType *T) const {
- assert(false && "Builtin types are not dependent and cannot be instantiated");
- return QualType(T, 0);
-}
-
-QualType
-TemplateTypeInstantiator::
-InstantiateFixedWidthIntType(const FixedWidthIntType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate FixedWidthIntType yet");
- return QualType();
-}
-
-QualType
-TemplateTypeInstantiator::InstantiateComplexType(const ComplexType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ComplexType yet");
- return QualType();
-}
-
-QualType
-TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T) const {
- QualType PointeeType = Instantiate(T->getPointeeType());
- if (PointeeType.isNull())
- return QualType();
-
- return SemaRef.BuildPointerType(PointeeType, 0, Loc, Entity);
-}
+ typedef TreeTransform<TemplateInstantiator> inherited;
+
+ TemplateInstantiator(Sema &SemaRef,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation Loc,
+ DeclarationName Entity)
+ : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+ Entity(Entity) { }
+
+ /// \brief Determine whether the given type \p T has already been
+ /// transformed.
+ ///
+ /// For the purposes of template instantiation, a type has already been
+ /// transformed if it is NULL or if it is not dependent.
+ bool AlreadyTransformed(QualType T) {
+ return T.isNull() || !T->isDependentType();
+ }
-QualType
-TemplateTypeInstantiator::InstantiateBlockPointerType(
- const BlockPointerType *T) const {
- QualType PointeeType = Instantiate(T->getPointeeType());
- if (PointeeType.isNull())
- return QualType();
-
- return SemaRef.BuildBlockPointerType(PointeeType, 0, Loc, Entity);
-}
+ /// \brief Returns the location of the entity being instantiated, if known.
+ SourceLocation getBaseLocation() { return Loc; }
-QualType
-TemplateTypeInstantiator::InstantiateLValueReferenceType(
- const LValueReferenceType *T) const {
- QualType ReferentType = Instantiate(T->getPointeeType());
- if (ReferentType.isNull())
- return QualType();
+ /// \brief Returns the name of the entity being instantiated, if any.
+ DeclarationName getBaseEntity() { return Entity; }
- return SemaRef.BuildReferenceType(ReferentType, true, 0, Loc, Entity);
-}
+ /// \brief Transform the given declaration by instantiating a reference to
+ /// this declaration.
+ Decl *TransformDecl(Decl *D);
-QualType
-TemplateTypeInstantiator::InstantiateRValueReferenceType(
- const RValueReferenceType *T) const {
- QualType ReferentType = Instantiate(T->getPointeeType());
- if (ReferentType.isNull())
- return QualType();
+ /// \brief Transform the definition of the given declaration by
+ /// instantiating it.
+ Decl *TransformDefinition(Decl *D);
- return SemaRef.BuildReferenceType(ReferentType, false, 0, Loc, Entity);
-}
+ /// \brief Rebuild the exception declaration and register the declaration
+ /// as an instantiated local.
+ VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T,
+ DeclaratorInfo *Declarator,
+ IdentifierInfo *Name,
+ SourceLocation Loc, SourceRange TypeRange);
-QualType
-TemplateTypeInstantiator::
-InstantiateMemberPointerType(const MemberPointerType *T) const {
- QualType PointeeType = Instantiate(T->getPointeeType());
- if (PointeeType.isNull())
- return QualType();
+ /// \brief Check for tag mismatches when instantiating an
+ /// elaborated type.
+ QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag);
- QualType ClassType = Instantiate(QualType(T->getClass(), 0));
- if (ClassType.isNull())
- return QualType();
+ Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
+ Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
- return SemaRef.BuildMemberPointerType(PointeeType, ClassType, 0, Loc,
- Entity);
-}
-
-QualType
-TemplateTypeInstantiator::
-InstantiateConstantArrayType(const ConstantArrayType *T) const {
- QualType ElementType = Instantiate(T->getElementType());
- if (ElementType.isNull())
- return ElementType;
-
- // Build a temporary integer literal to specify the size for
- // BuildArrayType. Since we have already checked the size as part of
- // creating the dependent array type in the first place, we know
- // there aren't any errors. However, we do need to determine what
- // C++ type to give the size expression.
- llvm::APInt Size = T->getSize();
- QualType Types[] = {
- SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy,
- SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy,
- SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty
+ /// \brief Transforms a template type parameter type by performing
+ /// substitution of the corresponding template type argument.
+ QualType TransformTemplateTypeParmType(const TemplateTypeParmType *T);
};
- const unsigned NumTypes = sizeof(Types) / sizeof(QualType);
- QualType SizeType;
- for (unsigned I = 0; I != NumTypes; ++I)
- if (Size.getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) {
- SizeType = Types[I];
- break;
- }
-
- if (SizeType.isNull())
- SizeType = SemaRef.Context.getFixedWidthIntType(Size.getBitWidth(), false);
-
- IntegerLiteral ArraySize(Size, SizeType, Loc);
- return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
- &ArraySize, T->getIndexTypeQualifier(),
- Loc, Entity);
}
-QualType
-TemplateTypeInstantiator::
-InstantiateIncompleteArrayType(const IncompleteArrayType *T) const {
- QualType ElementType = Instantiate(T->getElementType());
- if (ElementType.isNull())
- return ElementType;
-
- return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
- 0, T->getIndexTypeQualifier(),
- Loc, Entity);
-}
+Decl *TemplateInstantiator::TransformDecl(Decl *D) {
+ if (!D)
+ return 0;
-QualType
-TemplateTypeInstantiator::
-InstantiateVariableArrayType(const VariableArrayType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate VariableArrayType yet");
- return QualType();
-}
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
+ assert(TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsDecl() &&
+ "Wrong kind of template template argument");
+ return cast<TemplateDecl>(TemplateArgs(TTP->getDepth(),
+ TTP->getPosition()).getAsDecl());
+ }
-QualType
-TemplateTypeInstantiator::
-InstantiateDependentSizedArrayType(const DependentSizedArrayType *T) const {
- Expr *ArraySize = T->getSizeExpr();
- assert(ArraySize->isValueDependent() &&
- "dependent sized array types must have value dependent size expr");
-
- // Instantiate the element type if needed
- QualType ElementType = T->getElementType();
- if (ElementType->isDependentType()) {
- ElementType = Instantiate(ElementType);
- if (ElementType.isNull())
- return QualType();
- }
-
- // Instantiate the size expression
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
- Sema::OwningExprResult InstantiatedArraySize =
- SemaRef.InstantiateExpr(ArraySize, TemplateArgs);
- if (InstantiatedArraySize.isInvalid())
- return QualType();
-
- return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
- InstantiatedArraySize.takeAs<Expr>(),
- T->getIndexTypeQualifier(), Loc, Entity);
-}
+ // If the corresponding template argument is NULL or non-existent, it's
+ // because we are performing instantiation from explicitly-specified
+ // template arguments in a function template, but there were some
+ // arguments left unspecified.
+ if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
+ TTP->getPosition()))
+ return D;
-QualType
-TemplateTypeInstantiator::
-InstantiateDependentSizedExtVectorType(
- const DependentSizedExtVectorType *T) const {
-
- // Instantiate the element type if needed.
- QualType ElementType = T->getElementType();
- if (ElementType->isDependentType()) {
- ElementType = Instantiate(ElementType);
- if (ElementType.isNull())
- return QualType();
+ // FIXME: Implement depth reduction of template template parameters
+ assert(false &&
+ "Reducing depth of template template parameters is not yet implemented");
}
- // The expression in a dependent-sized extended vector type is not
- // potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
- // Instantiate the size expression.
- const Expr *SizeExpr = T->getSizeExpr();
- Sema::OwningExprResult InstantiatedArraySize =
- SemaRef.InstantiateExpr(const_cast<Expr *>(SizeExpr), TemplateArgs);
- if (InstantiatedArraySize.isInvalid())
- return QualType();
-
- return SemaRef.BuildExtVectorType(ElementType,
- SemaRef.Owned(
- InstantiatedArraySize.takeAs<Expr>()),
- T->getAttributeLoc());
+ return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D), TemplateArgs);
}
-QualType
-TemplateTypeInstantiator::InstantiateVectorType(const VectorType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate VectorType yet");
- return QualType();
-}
-
-QualType
-TemplateTypeInstantiator::InstantiateExtVectorType(
- const ExtVectorType *T) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ExtVectorType yet");
- return QualType();
-}
-
-QualType
-TemplateTypeInstantiator::
-InstantiateFunctionProtoType(const FunctionProtoType *T) const {
- QualType ResultType = Instantiate(T->getResultType());
- if (ResultType.isNull())
- return ResultType;
-
- llvm::SmallVector<QualType, 4> ParamTypes;
- for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(),
- ParamEnd = T->arg_type_end();
- Param != ParamEnd; ++Param) {
- QualType P = Instantiate(*Param);
- if (P.isNull())
- return P;
-
- ParamTypes.push_back(P);
- }
-
- return SemaRef.BuildFunctionType(ResultType, ParamTypes.data(),
- ParamTypes.size(),
- T->isVariadic(), T->getTypeQuals(),
- Loc, Entity);
-}
+Decl *TemplateInstantiator::TransformDefinition(Decl *D) {
+ Decl *Inst = getSema().SubstDecl(D, getSema().CurContext, TemplateArgs);
+ if (!Inst)
+ return 0;
-QualType
-TemplateTypeInstantiator::
-InstantiateFunctionNoProtoType(const FunctionNoProtoType *T) const {
- assert(false && "Functions without prototypes cannot be dependent.");
- return QualType();
+ getSema().CurrentInstantiationScope->InstantiatedLocal(D, Inst);
+ return Inst;
}
-QualType
-TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T) const {
- TypedefDecl *Typedef
- = cast_or_null<TypedefDecl>(
- SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
- if (!Typedef)
- return QualType();
-
- return SemaRef.Context.getTypeDeclType(Typedef);
+VarDecl *
+TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl,
+ QualType T,
+ DeclaratorInfo *Declarator,
+ IdentifierInfo *Name,
+ SourceLocation Loc,
+ SourceRange TypeRange) {
+ VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, T, Declarator,
+ Name, Loc, TypeRange);
+ if (Var && !Var->isInvalidDecl())
+ getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var);
+ return Var;
}
-QualType
-TemplateTypeInstantiator::InstantiateTypeOfExprType(
- const TypeOfExprType *T) const {
- // The expression in a typeof is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
- Sema::OwningExprResult E
- = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs);
- if (E.isInvalid())
- return QualType();
+QualType
+TemplateInstantiator::RebuildElaboratedType(QualType T,
+ ElaboratedType::TagKind Tag) {
+ if (const TagType *TT = T->getAs<TagType>()) {
+ TagDecl* TD = TT->getDecl();
+
+ // FIXME: this location is very wrong; we really need typelocs.
+ SourceLocation TagLocation = TD->getTagKeywordLoc();
+
+ // FIXME: type might be anonymous.
+ IdentifierInfo *Id = TD->getIdentifier();
+
+ // TODO: should we even warn on struct/class mismatches for this? Seems
+ // like it's likely to produce a lot of spurious errors.
+ if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) {
+ SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
+ << Id
+ << CodeModificationHint::CreateReplacement(SourceRange(TagLocation),
+ TD->getKindName());
+ SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
+ }
+ }
- return SemaRef.BuildTypeofExprType(E.takeAs<Expr>());
+ return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag);
}
-QualType
-TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T) const {
- QualType Underlying = Instantiate(T->getUnderlyingType());
- if (Underlying.isNull())
- return QualType();
+Sema::OwningExprResult
+TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
+ if (!E->isTypeDependent())
+ return SemaRef.Owned(E->Retain());
- return SemaRef.Context.getTypeOfType(Underlying);
-}
+ FunctionDecl *currentDecl = getSema().getCurFunctionDecl();
+ assert(currentDecl && "Must have current function declaration when "
+ "instantiating.");
-QualType
-TemplateTypeInstantiator::InstantiateDecltypeType(const DecltypeType *T) const {
- // C++0x [dcl.type.simple]p4:
- // The operand of the decltype specifier is an unevaluated operand.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Action::Unevaluated);
-
- Sema::OwningExprResult E
- = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs);
+ PredefinedExpr::IdentType IT = E->getIdentType();
- if (E.isInvalid())
- return QualType();
-
- return SemaRef.BuildDecltypeType(E.takeAs<Expr>());
-}
+ unsigned Length =
+ PredefinedExpr::ComputeName(getSema().Context, IT, currentDecl).length();
-QualType
-TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T) const {
- RecordDecl *Record
- = cast_or_null<RecordDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
- if (!Record)
- return QualType();
-
- return SemaRef.Context.getTypeDeclType(Record);
+ llvm::APInt LengthI(32, Length + 1);
+ QualType ResTy = getSema().Context.CharTy.withConst();
+ ResTy = getSema().Context.getConstantArrayType(ResTy, LengthI,
+ ArrayType::Normal, 0);
+ PredefinedExpr *PE =
+ new (getSema().Context) PredefinedExpr(E->getLocation(), ResTy, IT);
+ return getSema().Owned(PE);
}
-QualType
-TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T) const {
- EnumDecl *Enum
- = cast_or_null<EnumDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
- if (!Enum)
- return QualType();
-
- return SemaRef.Context.getTypeDeclType(Enum);
-}
+Sema::OwningExprResult
+TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
+ // FIXME: Clean this up a bit
+ NamedDecl *D = E->getDecl();
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ if (NTTP->getDepth() >= TemplateArgs.getNumLevels()) {
+ assert(false && "Cannot reduce non-type template parameter depth yet");
+ return getSema().ExprError();
+ }
-QualType
-TemplateTypeInstantiator::
-InstantiateTemplateTypeParmType(const TemplateTypeParmType *T) const {
- if (T->getDepth() == 0) {
- // Replace the template type parameter with its corresponding
- // template argument.
-
- // If the corresponding template argument is NULL or doesn't exist, it's
- // because we are performing instantiation from explicitly-specified
- // template arguments in a function template class, but there were some
+ // If the corresponding template argument is NULL or non-existent, it's
+ // because we are performing instantiation from explicitly-specified
+ // template arguments in a function template, but there were some
// arguments left unspecified.
- if (T->getIndex() >= TemplateArgs.size() ||
- TemplateArgs[T->getIndex()].isNull())
- return QualType(T, 0); // Would be nice to keep the original type here
-
- assert(TemplateArgs[T->getIndex()].getKind() == TemplateArgument::Type &&
- "Template argument kind mismatch");
- return TemplateArgs[T->getIndex()].getAsType();
- }
+ if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
+ NTTP->getPosition()))
+ return SemaRef.Owned(E->Retain());
- // The template type parameter comes from an inner template (e.g.,
- // the template parameter list of a member template inside the
- // template we are instantiating). Create a new template type
- // parameter with the template "level" reduced by one.
- return SemaRef.Context.getTemplateTypeParmType(T->getDepth() - 1,
- T->getIndex(),
- T->isParameterPack(),
- T->getName());
-}
+ const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(),
+ NTTP->getPosition());
-QualType
-TemplateTypeInstantiator::
-InstantiateTemplateSpecializationType(
- const TemplateSpecializationType *T) const {
- llvm::SmallVector<TemplateArgument, 4> InstantiatedTemplateArgs;
- InstantiatedTemplateArgs.reserve(T->getNumArgs());
- for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
- Arg != ArgEnd; ++Arg) {
- TemplateArgument InstArg = SemaRef.Instantiate(*Arg, TemplateArgs);
- if (InstArg.isNull())
- return QualType();
-
- InstantiatedTemplateArgs.push_back(InstArg);
- }
+ // The template argument itself might be an expression, in which
+ // case we just return that expression.
+ if (Arg.getKind() == TemplateArgument::Expression)
+ return SemaRef.Owned(Arg.getAsExpr()->Retain());
- // FIXME: We're missing the locations of the template name, '<', and '>'.
+ if (Arg.getKind() == TemplateArgument::Declaration) {
+ ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
- TemplateName Name = SemaRef.InstantiateTemplateName(T->getTemplateName(),
- Loc,
- TemplateArgs);
+ VD = cast_or_null<ValueDecl>(
+ getSema().FindInstantiatedDecl(VD, TemplateArgs));
+ if (!VD)
+ return SemaRef.ExprError();
- return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(),
- InstantiatedTemplateArgs.data(),
- InstantiatedTemplateArgs.size(),
- SourceLocation());
-}
-
-QualType
-TemplateTypeInstantiator::
-InstantiateQualifiedNameType(const QualifiedNameType *T) const {
- // When we instantiated a qualified name type, there's no point in
- // keeping the qualification around in the instantiated result. So,
- // just instantiate the named type.
- return (*this)(T->getNamedType());
-}
+ return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(),
+ /*FIXME:*/false, /*FIXME:*/false);
+ }
-QualType
-TemplateTypeInstantiator::
-InstantiateTypenameType(const TypenameType *T) const {
- if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
- // When the typename type refers to a template-id, the template-id
- // is dependent and has enough information to instantiate the
- // result of the typename type. Since we don't care about keeping
- // the spelling of the typename type in template instantiations,
- // we just instantiate the template-id.
- return InstantiateTemplateSpecializationType(TemplateId);
+ assert(Arg.getKind() == TemplateArgument::Integral);
+ QualType T = Arg.getIntegralType();
+ if (T->isCharType() || T->isWideCharType())
+ return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
+ Arg.getAsIntegral()->getZExtValue(),
+ T->isWideCharType(),
+ T,
+ E->getSourceRange().getBegin()));
+ if (T->isBooleanType())
+ return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
+ Arg.getAsIntegral()->getBoolValue(),
+ T,
+ E->getSourceRange().getBegin()));
+
+ assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
+ return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
+ *Arg.getAsIntegral(),
+ T,
+ E->getSourceRange().getBegin()));
}
- NestedNameSpecifier *NNS
- = SemaRef.InstantiateNestedNameSpecifier(T->getQualifier(),
- SourceRange(Loc),
- TemplateArgs);
- if (!NNS)
- return QualType();
+ NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D, TemplateArgs);
+ if (!InstD)
+ return SemaRef.ExprError();
- return SemaRef.CheckTypenameType(NNS, *T->getIdentifier(), SourceRange(Loc));
-}
+ // If we instantiated an UnresolvedUsingDecl and got back an UsingDecl,
+ // we need to get the underlying decl.
+ // FIXME: Is this correct? Maybe FindInstantiatedDecl should do this?
+ InstD = InstD->getUnderlyingDecl();
-QualType
-TemplateTypeInstantiator::
-InstantiateObjCObjectPointerType(const ObjCObjectPointerType *T) const {
- assert(false && "Objective-C types cannot be dependent");
- return QualType();
+ // FIXME: nested-name-specifier for QualifiedDeclRefExpr
+ return SemaRef.BuildDeclarationNameExpr(E->getLocation(), InstD,
+ /*FIXME:*/false,
+ /*FIXME:*/0,
+ /*FIXME:*/false);
}
QualType
-TemplateTypeInstantiator::
-InstantiateObjCInterfaceType(const ObjCInterfaceType *T) const {
- assert(false && "Objective-C types cannot be dependent");
- return QualType();
-}
+TemplateInstantiator::TransformTemplateTypeParmType(
+ const TemplateTypeParmType *T) {
+ if (T->getDepth() < TemplateArgs.getNumLevels()) {
+ // Replace the template type parameter with its corresponding
+ // template argument.
-QualType
-TemplateTypeInstantiator::
-InstantiateObjCQualifiedInterfaceType(
- const ObjCQualifiedInterfaceType *T) const {
- assert(false && "Objective-C types cannot be dependent");
- return QualType();
-}
+ // If the corresponding template argument is NULL or doesn't exist, it's
+ // because we are performing instantiation from explicitly-specified
+ // template arguments in a function template class, but there were some
+ // arguments left unspecified.
+ if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex()))
+ return QualType(T, 0);
-/// \brief The actual implementation of Sema::InstantiateType().
-QualType TemplateTypeInstantiator::Instantiate(QualType T) const {
- // If T is not a dependent type, there is nothing to do.
- if (!T->isDependentType())
- return T;
+ assert(TemplateArgs(T->getDepth(), T->getIndex()).getKind()
+ == TemplateArgument::Type &&
+ "Template argument kind mismatch");
- QualType Result;
- switch (T->getTypeClass()) {
-#define TYPE(Class, Base) \
- case Type::Class: \
- Result = Instantiate##Class##Type(cast<Class##Type>(T.getTypePtr())); \
- break;
-#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+ return TemplateArgs(T->getDepth(), T->getIndex()).getAsType();
}
- // C++ [dcl.ref]p1:
- // [...] Cv-qualified references are ill-formed except when
- // the cv-qualifiers are introduced through the use of a
- // typedef (7.1.3) or of a template type argument (14.3), in
- // which case the cv-qualifiers are ignored.
- //
- // The same rule applies to function types.
- if (!Result.isNull() && T.getCVRQualifiers() &&
- !Result->isFunctionType() && !Result->isReferenceType())
- Result = Result.getWithAdditionalQualifiers(T.getCVRQualifiers());
- return Result;
+ // The template type parameter comes from an inner template (e.g.,
+ // the template parameter list of a member template inside the
+ // template we are instantiating). Create a new template type
+ // parameter with the template "level" reduced by one.
+ return getSema().Context.getTemplateTypeParmType(
+ T->getDepth() - TemplateArgs.getNumLevels(),
+ T->getIndex(),
+ T->isParameterPack(),
+ T->getName());
}
-/// \brief Instantiate the type T with a given set of template arguments.
+/// \brief Perform substitution on the type T with a given set of template
+/// arguments.
///
/// This routine substitutes the given template arguments into the
/// type T and produces the instantiated type.
@@ -782,9 +654,9 @@ QualType TemplateTypeInstantiator::Instantiate(QualType T) const {
///
/// \returns If the instantiation succeeds, the instantiated
/// type. Otherwise, produces diagnostics and returns a NULL type.
-QualType Sema::InstantiateType(QualType T,
- const TemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity) {
+QualType Sema::SubstType(QualType T,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation Loc, DeclarationName Entity) {
assert(!ActiveTemplateInstantiations.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -793,35 +665,34 @@ QualType Sema::InstantiateType(QualType T,
if (!T->isDependentType())
return T;
- TemplateTypeInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
- return Instantiator(T);
+ TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
+ return Instantiator.TransformType(T);
}
-/// \brief Instantiate the base class specifiers of the given class
-/// template specialization.
+/// \brief Perform substitution on the base class specifiers of the
+/// given class template specialization.
///
/// Produces a diagnostic and returns true on error, returns false and
/// attaches the instantiated base classes to the class template
/// specialization if successful.
-bool
-Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
- CXXRecordDecl *Pattern,
- const TemplateArgumentList &TemplateArgs) {
+bool
+Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
+ CXXRecordDecl *Pattern,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
bool Invalid = false;
llvm::SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases;
- for (ClassTemplateSpecializationDecl::base_class_iterator
+ for (ClassTemplateSpecializationDecl::base_class_iterator
Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end();
Base != BaseEnd; ++Base) {
if (!Base->getType()->isDependentType()) {
- // FIXME: Allocate via ASTContext
- InstantiatedBases.push_back(new CXXBaseSpecifier(*Base));
+ InstantiatedBases.push_back(new (Context) CXXBaseSpecifier(*Base));
continue;
}
- QualType BaseType = InstantiateType(Base->getType(),
- TemplateArgs,
- Base->getSourceRange().getBegin(),
- DeclarationName());
+ QualType BaseType = SubstType(Base->getType(),
+ TemplateArgs,
+ Base->getSourceRange().getBegin(),
+ DeclarationName());
if (BaseType.isNull()) {
Invalid = true;
continue;
@@ -864,25 +735,33 @@ Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
/// \param TemplateArgs The template arguments to be substituted into
/// the pattern.
///
+/// \param TSK the kind of implicit or explicit instantiation to perform.
+///
+/// \param Complain whether to complain if the class cannot be instantiated due
+/// to the lack of a definition.
+///
/// \returns true if an error occurred, false otherwise.
bool
Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
- const TemplateArgumentList &TemplateArgs,
- bool ExplicitInstantiation) {
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK,
+ bool Complain) {
bool Invalid = false;
-
- CXXRecordDecl *PatternDef
+
+ CXXRecordDecl *PatternDef
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
if (!PatternDef) {
- if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
+ if (!Complain) {
+ // Say nothing
+ } else if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
Diag(PointOfInstantiation,
diag::err_implicit_instantiate_member_undefined)
<< Context.getTypeDeclType(Instantiation);
Diag(Pattern->getLocation(), diag::note_member_of_template_here);
} else {
Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
- << ExplicitInstantiation
+ << (TSK != TSK_ImplicitInstantiation)
<< Context.getTypeDeclType(Instantiation);
Diag(Pattern->getLocation(), diag::note_template_decl_here);
}
@@ -902,20 +781,22 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Start the definition of this instantiation.
Instantiation->startDefinition();
- // Instantiate the base class specifiers.
- if (InstantiateBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
+ // Do substitution on the base class specifiers.
+ if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
Invalid = true;
llvm::SmallVector<DeclPtrTy, 4> Fields;
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
- MemberEnd = Pattern->decls_end();
+ MemberEnd = Pattern->decls_end();
Member != MemberEnd; ++Member) {
- Decl *NewMember = InstantiateDecl(*Member, Instantiation, TemplateArgs);
+ Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs);
if (NewMember) {
if (NewMember->isInvalidDecl())
Invalid = true;
else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
Fields.push_back(DeclPtrTy::make(Field));
+ else if (UsingDecl *UD = dyn_cast<UsingDecl>(NewMember))
+ Instantiation->addDecl(UD);
} else {
// FIXME: Eventually, a NULL return will mean that one of the
// instantiations was a semantic disaster, and we'll want to set Invalid =
@@ -938,32 +819,52 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Consumer.HandleTagDeclDefinition(Instantiation);
// If this is an explicit instantiation, instantiate our members, too.
- if (!Invalid && ExplicitInstantiation) {
+ if (!Invalid && TSK != TSK_ImplicitInstantiation) {
Inst.Clear();
- InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs);
+ InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs,
+ TSK);
}
return Invalid;
}
-bool
+bool
Sema::InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec,
- bool ExplicitInstantiation) {
+ TemplateSpecializationKind TSK,
+ bool Complain) {
// Perform the actual instantiation on the canonical declaration.
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
- Context.getCanonicalDecl(ClassTemplateSpec));
-
- // We can only instantiate something that hasn't already been
- // instantiated or specialized. Fail without any diagnostics: our
- // caller will provide an error message.
- if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared)
+ ClassTemplateSpec->getCanonicalDecl());
+
+ // Check whether we have already instantiated or specialized this class
+ // template specialization.
+ if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared) {
+ if (ClassTemplateSpec->getSpecializationKind() ==
+ TSK_ExplicitInstantiationDeclaration &&
+ TSK == TSK_ExplicitInstantiationDefinition) {
+ // An explicit instantiation definition follows an explicit instantiation
+ // declaration (C++0x [temp.explicit]p10); go ahead and perform the
+ // explicit instantiation.
+ ClassTemplateSpec->setSpecializationKind(TSK);
+ InstantiateClassTemplateSpecializationMembers(
+ /*FIXME?*/ClassTemplateSpec->getPointOfInstantiation(),
+ ClassTemplateSpec,
+ TSK);
+ return false;
+ }
+
+ // We can only instantiate something that hasn't already been
+ // instantiated or specialized. Fail without any diagnostics: our
+ // caller will provide an error message.
return true;
+ }
+ if (ClassTemplateSpec->isInvalidDecl())
+ return true;
+
ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
- CXXRecordDecl *Pattern = Template->getTemplatedDecl();
- const TemplateArgumentList *TemplateArgs
- = &ClassTemplateSpec->getTemplateArgs();
+ CXXRecordDecl *Pattern = 0;
// C++ [temp.class.spec.match]p1:
// When a class template is used in a context that requires an
@@ -976,14 +877,14 @@ Sema::InstantiateClassTemplateSpecialization(
typedef std::pair<ClassTemplatePartialSpecializationDecl *,
TemplateArgumentList *> MatchResult;
llvm::SmallVector<MatchResult, 4> Matched;
- for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+ for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
Partial = Template->getPartialSpecializations().begin(),
PartialEnd = Template->getPartialSpecializations().end();
Partial != PartialEnd;
++Partial) {
TemplateDeductionInfo Info(Context);
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(&*Partial,
+ = DeduceTemplateArguments(&*Partial,
ClassTemplateSpec->getTemplateArgs(),
Info)) {
// FIXME: Store the failed-deduction information for use in
@@ -998,7 +899,7 @@ Sema::InstantiateClassTemplateSpecialization(
// -- If exactly one matching specialization is found, the
// instantiation is generated from that specialization.
Pattern = Matched[0].first;
- TemplateArgs = Matched[0].second;
+ ClassTemplateSpec->setInstantiationOf(Matched[0].first, Matched[0].second);
} else if (Matched.size() > 1) {
// -- If more than one matching specialization is found, the
// partial order rules (14.5.4.2) are used to determine
@@ -1007,61 +908,137 @@ Sema::InstantiateClassTemplateSpecialization(
// specialized than all of the other matching
// specializations, then the use of the class template is
// ambiguous and the program is ill-formed.
- // FIXME: Implement partial ordering of class template partial
- // specializations.
- Diag(ClassTemplateSpec->getLocation(),
- diag::unsup_template_partial_spec_ordering);
+ llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ == P->first)
+ Best = P;
+ }
+
+ // Determine if the best partial specialization is more specialized than
+ // the others.
+ bool Ambiguous = false;
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (P != Best &&
+ getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ != Best->first) {
+ Ambiguous = true;
+ break;
+ }
+ }
+
+ if (Ambiguous) {
+ // Partial ordering did not produce a clear winner. Complain.
+ ClassTemplateSpec->setInvalidDecl();
+ Diag(ClassTemplateSpec->getPointOfInstantiation(),
+ diag::err_partial_spec_ordering_ambiguous)
+ << ClassTemplateSpec;
+
+ // Print the matching partial specializations.
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P)
+ Diag(P->first->getLocation(), diag::note_partial_spec_match)
+ << getTemplateArgumentBindingsText(P->first->getTemplateParameters(),
+ *P->second);
+
+ return true;
+ }
+
+ // Instantiate using the best class template partial specialization.
+ Pattern = Best->first;
+ ClassTemplateSpec->setInstantiationOf(Best->first, Best->second);
} else {
// -- If no matches are found, the instantiation is generated
// from the primary template.
-
- // Since we initialized the pattern and template arguments from
- // the primary template, there is nothing more we need to do here.
+ ClassTemplateDecl *OrigTemplate = Template;
+ while (OrigTemplate->getInstantiatedFromMemberTemplate()) {
+ // If we've found an explicit specialization of this class template,
+ // stop here and use that as the pattern.
+ if (OrigTemplate->isMemberSpecialization())
+ break;
+
+ OrigTemplate = OrigTemplate->getInstantiatedFromMemberTemplate();
+ }
+
+ Pattern = OrigTemplate->getTemplatedDecl();
}
- // Note that this is an instantiation.
- ClassTemplateSpec->setSpecializationKind(
- ExplicitInstantiation? TSK_ExplicitInstantiation
- : TSK_ImplicitInstantiation);
+ // Note that this is an instantiation.
+ ClassTemplateSpec->setSpecializationKind(TSK);
+
+ bool Result = InstantiateClass(ClassTemplateSpec->getPointOfInstantiation(),
+ ClassTemplateSpec, Pattern,
+ getTemplateInstantiationArgs(ClassTemplateSpec),
+ TSK,
+ Complain);
- bool Result = InstantiateClass(ClassTemplateSpec->getLocation(),
- ClassTemplateSpec, Pattern, *TemplateArgs,
- ExplicitInstantiation);
-
for (unsigned I = 0, N = Matched.size(); I != N; ++I) {
// FIXME: Implement TemplateArgumentList::Destroy!
// if (Matched[I].first != Pattern)
// Matched[I].second->Destroy(Context);
}
-
+
return Result;
}
-/// \brief Instantiate the definitions of all of the member of the
-/// given class, which is an instantiation of a class template or a
-/// member class of a template.
+/// \brief Instantiates the definitions of all of the member
+/// of the given class, which is an instantiation of a class template
+/// or a member class of a template.
void
Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
- const TemplateArgumentList &TemplateArgs) {
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK) {
for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
DEnd = Instantiation->decls_end();
D != DEnd; ++D) {
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
- if (!Function->getBody())
+ if (Function->getInstantiatedFromMemberFunction()) {
+ // If this member was explicitly specialized, do nothing.
+ if (Function->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization)
+ continue;
+
+ Function->setTemplateSpecializationKind(TSK);
+ }
+
+ if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition)
InstantiateFunctionDefinition(PointOfInstantiation, Function);
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
- const VarDecl *Def = 0;
- if (!Var->getDefinition(Def))
- InstantiateVariableDefinition(Var);
+ if (Var->isStaticDataMember()) {
+ // If this member was explicitly specialized, do nothing.
+ if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ continue;
+
+ Var->setTemplateSpecializationKind(TSK);
+
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
+ }
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
- if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) {
- assert(Record->getInstantiatedFromMemberClass() &&
- "Missing instantiated-from-template information");
+ if (Record->isInjectedClassName())
+ continue;
+
+ assert(Record->getInstantiatedFromMemberClass() &&
+ "Missing instantiated-from-template information");
+
+ // If this member was explicitly specialized, do nothing.
+ if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ continue;
+
+ if (!Record->getDefinition(Context))
InstantiateClass(PointOfInstantiation, Record,
Record->getInstantiatedFromMemberClass(),
- TemplateArgs, true);
- }
+ TemplateArgs,
+ TSK);
+
+ InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs,
+ TSK);
}
}
}
@@ -1069,9 +1046,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
/// \brief Instantiate the definitions of all of the members of the
/// given class template specialization, which was named as part of an
/// explicit instantiation.
-void Sema::InstantiateClassTemplateSpecializationMembers(
+void
+Sema::InstantiateClassTemplateSpecializationMembers(
SourceLocation PointOfInstantiation,
- ClassTemplateSpecializationDecl *ClassTemplateSpec) {
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ TemplateSpecializationKind TSK) {
// C++0x [temp.explicit]p7:
// An explicit instantiation that names a class template
// specialization is an explicit instantion of the same kind
@@ -1081,172 +1060,53 @@ void Sema::InstantiateClassTemplateSpecializationMembers(
// containing the explicit instantiation, except as described
// below.
InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec,
- ClassTemplateSpec->getTemplateArgs());
+ getTemplateInstantiationArgs(ClassTemplateSpec),
+ TSK);
}
-/// \brief Instantiate a nested-name-specifier.
-NestedNameSpecifier *
-Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
- SourceRange Range,
- const TemplateArgumentList &TemplateArgs) {
- // Instantiate the prefix of this nested name specifier.
- NestedNameSpecifier *Prefix = NNS->getPrefix();
- if (Prefix) {
- Prefix = InstantiateNestedNameSpecifier(Prefix, Range, TemplateArgs);
- if (!Prefix)
- return 0;
- }
+Sema::OwningStmtResult
+Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (!S)
+ return Owned(S);
- switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier: {
- assert(Prefix &&
- "Can't have an identifier nested-name-specifier with no prefix");
- CXXScopeSpec SS;
- // FIXME: The source location information is all wrong.
- SS.setRange(Range);
- SS.setScopeRep(Prefix);
- return static_cast<NestedNameSpecifier *>(
- ActOnCXXNestedNameSpecifier(0, SS,
- Range.getEnd(),
- Range.getEnd(),
- *NNS->getAsIdentifier()));
- break;
- }
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformStmt(S);
+}
- case NestedNameSpecifier::Namespace:
- case NestedNameSpecifier::Global:
- return NNS;
-
- case NestedNameSpecifier::TypeSpecWithTemplate:
- case NestedNameSpecifier::TypeSpec: {
- QualType T = QualType(NNS->getAsType(), 0);
- if (!T->isDependentType())
- return NNS;
-
- T = InstantiateType(T, TemplateArgs, Range.getBegin(), DeclarationName());
- if (T.isNull())
- return 0;
-
- if (T->isDependentType() || T->isRecordType() ||
- (getLangOptions().CPlusPlus0x && T->isEnumeralType())) {
- assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here");
- return NestedNameSpecifier::Create(Context, Prefix,
- NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
- T.getTypePtr());
- }
+Sema::OwningExprResult
+Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (!E)
+ return Owned(E);
- Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T;
- return 0;
- }
- }
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformExpr(E);
+}
- // Required to silence a GCC warning
- return 0;
+/// \brief Do template substitution on a nested-name-specifier.
+NestedNameSpecifier *
+Sema::SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs, Range.getBegin(),
+ DeclarationName());
+ return Instantiator.TransformNestedNameSpecifier(NNS, Range);
}
TemplateName
-Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
- const TemplateArgumentList &TemplateArgs) {
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast_or_null<TemplateTemplateParmDecl>(
- Name.getAsTemplateDecl())) {
- assert(TTP->getDepth() == 0 &&
- "Cannot reduce depth of a template template parameter");
- assert(TemplateArgs[TTP->getPosition()].getAsDecl() &&
- "Wrong kind of template template argument");
- ClassTemplateDecl *ClassTemplate
- = dyn_cast<ClassTemplateDecl>(
- TemplateArgs[TTP->getPosition()].getAsDecl());
- assert(ClassTemplate && "Expected a class template");
- if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
- NestedNameSpecifier *NNS
- = InstantiateNestedNameSpecifier(QTN->getQualifier(),
- /*FIXME=*/SourceRange(Loc),
- TemplateArgs);
- if (NNS)
- return Context.getQualifiedTemplateName(NNS,
- QTN->hasTemplateKeyword(),
- ClassTemplate);
- }
-
- return TemplateName(ClassTemplate);
- } else if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
- NestedNameSpecifier *NNS
- = InstantiateNestedNameSpecifier(DTN->getQualifier(),
- /*FIXME=*/SourceRange(Loc),
- TemplateArgs);
-
- if (!NNS) // FIXME: Not the best recovery strategy.
- return Name;
-
- if (NNS->isDependent())
- return Context.getDependentTemplateName(NNS, DTN->getName());
-
- // Somewhat redundant with ActOnDependentTemplateName.
- CXXScopeSpec SS;
- SS.setRange(SourceRange(Loc));
- SS.setScopeRep(NNS);
- TemplateTy Template;
- TemplateNameKind TNK = isTemplateName(*DTN->getName(), 0, Template, &SS);
- if (TNK == TNK_Non_template) {
- Diag(Loc, diag::err_template_kw_refers_to_non_template)
- << DTN->getName();
- return Name;
- } else if (TNK == TNK_Function_template) {
- Diag(Loc, diag::err_template_kw_refers_to_non_template)
- << DTN->getName();
- return Name;
- }
-
- return Template.getAsVal<TemplateName>();
- }
-
-
-
- // FIXME: Even if we're referring to a Decl that isn't a template template
- // parameter, we may need to instantiate the outer contexts of that
- // Decl. However, this won't be needed until we implement member templates.
- return Name;
+Sema::SubstTemplateName(TemplateName Name, SourceLocation Loc,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs, Loc,
+ DeclarationName());
+ return Instantiator.TransformTemplateName(Name);
}
-TemplateArgument Sema::Instantiate(TemplateArgument Arg,
- const TemplateArgumentList &TemplateArgs) {
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- assert(false && "Should never have a NULL template argument");
- break;
-
- case TemplateArgument::Type: {
- QualType T = InstantiateType(Arg.getAsType(), TemplateArgs,
- Arg.getLocation(), DeclarationName());
- if (T.isNull())
- return TemplateArgument();
-
- return TemplateArgument(Arg.getLocation(), T);
- }
-
- case TemplateArgument::Declaration:
- // FIXME: Template instantiation for template template parameters.
- return Arg;
-
- case TemplateArgument::Integral:
- return Arg;
-
- case TemplateArgument::Expression: {
- // Template argument expressions are not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated);
-
- Sema::OwningExprResult E = InstantiateExpr(Arg.getAsExpr(), TemplateArgs);
- if (E.isInvalid())
- return TemplateArgument();
- return TemplateArgument(E.takeAs<Expr>());
- }
-
- case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
- break;
- }
-
- assert(false && "Unhandled template argument kind");
- return TemplateArgument();
+TemplateArgument Sema::Subst(TemplateArgument Arg,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformTemplateArgument(Arg);
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f597199920666..33fa28866e52e 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -15,24 +15,26 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
- class VISIBILITY_HIDDEN TemplateDeclInstantiator
+ class VISIBILITY_HIDDEN TemplateDeclInstantiator
: public DeclVisitor<TemplateDeclInstantiator, Decl *> {
Sema &SemaRef;
DeclContext *Owner;
- const TemplateArgumentList &TemplateArgs;
-
+ const MultiLevelTemplateArgumentList &TemplateArgs;
+
public:
typedef Sema::OwningExprResult OwningExprResult;
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
- const TemplateArgumentList &TemplateArgs)
+ const MultiLevelTemplateArgumentList &TemplateArgs)
: SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { }
-
+
// FIXME: Once we get closer to completion, replace these manually-written
// declarations with automatically-generated ones from
// clang/AST/DeclNodes.def.
@@ -44,26 +46,42 @@ namespace {
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
- Decl *VisitFunctionDecl(FunctionDecl *D);
+ Decl *VisitFriendDecl(FriendDecl *D);
+ Decl *VisitFunctionDecl(FunctionDecl *D,
+ TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
- Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
+ Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
+ TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
+ Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
+ Decl *VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D);
+ Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+ Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
- Decl *VisitDecl(Decl *) {
+ Decl *VisitDecl(Decl *) {
assert(false && "Template instantiation of unknown declaration kind!");
return 0;
}
+ const LangOptions &getLangOptions() {
+ return SemaRef.getLangOptions();
+ }
+
// Helper functions for instantiating methods.
- QualType InstantiateFunctionType(FunctionDecl *D,
+ QualType SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
+
+ TemplateParameterList *
+ SubstTemplateParams(TemplateParameterList *List);
};
}
@@ -83,14 +101,14 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
bool Invalid = false;
QualType T = D->getUnderlyingType();
if (T->isDependentType()) {
- T = SemaRef.InstantiateType(T, TemplateArgs,
- D->getLocation(), D->getDeclName());
+ T = SemaRef.SubstType(T, TemplateArgs,
+ D->getLocation(), D->getDeclName());
if (T.isNull()) {
Invalid = true;
T = SemaRef.Context.IntTy;
}
}
-
+
// Create the new typedef
TypedefDecl *Typedef
= TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(),
@@ -99,44 +117,86 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
Typedef->setInvalidDecl();
Owner->addDecl(Typedef);
-
+
return Typedef;
}
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
- // Instantiate the type of the declaration
- QualType T = SemaRef.InstantiateType(D->getType(), TemplateArgs,
- D->getTypeSpecStartLoc(),
- D->getDeclName());
+ // Do substitution on the type of the declaration
+ QualType T = SemaRef.SubstType(D->getType(), TemplateArgs,
+ D->getTypeSpecStartLoc(),
+ D->getDeclName());
if (T.isNull())
return 0;
// Build the instantiated declaration
VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
- T, D->getStorageClass(),
- D->getTypeSpecStartLoc());
+ T, D->getDeclaratorInfo(),
+ D->getStorageClass());
Var->setThreadSpecified(D->isThreadSpecified());
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
Var->setDeclaredInCondition(D->isDeclaredInCondition());
-
+
+ // If we are instantiating a static data member defined
+ // out-of-line, the instantiation will have the same lexical
+ // context (which will be a namespace scope) as the template.
+ if (D->isOutOfLine())
+ Var->setLexicalDeclContext(D->getLexicalDeclContext());
+
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
bool Redeclaration = false;
SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration);
- Owner->addDecl(Var);
+ if (D->isOutOfLine()) {
+ D->getLexicalDeclContext()->addDecl(Var);
+ Owner->makeDeclVisibleInContext(Var);
+ } else {
+ Owner->addDecl(Var);
+ }
+
+ // Link instantiations of static data members back to the template from
+ // which they were instantiated.
+ if (Var->isStaticDataMember())
+ SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
+ TSK_ImplicitInstantiation);
+
if (D->getInit()) {
- OwningExprResult Init
- = SemaRef.InstantiateExpr(D->getInit(), TemplateArgs);
+ OwningExprResult Init
+ = SemaRef.SubstExpr(D->getInit(), TemplateArgs);
if (Init.isInvalid())
Var->setInvalidDecl();
- else
+ else if (ParenListExpr *PLE = dyn_cast<ParenListExpr>((Expr *)Init.get())) {
+ // FIXME: We're faking all of the comma locations, which is suboptimal.
+ // Do we even need these comma locations?
+ llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
+ if (PLE->getNumExprs() > 0) {
+ FakeCommaLocs.reserve(PLE->getNumExprs() - 1);
+ for (unsigned I = 0, N = PLE->getNumExprs() - 1; I != N; ++I) {
+ Expr *E = PLE->getExpr(I)->Retain();
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken(E->getLocEnd()));
+ }
+ PLE->getExpr(PLE->getNumExprs() - 1)->Retain();
+ }
+
+ // Add the direct initializer to the declaration.
+ SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
+ PLE->getLParenLoc(),
+ Sema::MultiExprArg(SemaRef,
+ (void**)PLE->getExprs(),
+ PLE->getNumExprs()),
+ FakeCommaLocs.data(),
+ PLE->getRParenLoc());
+
+ // When Init is destroyed, it will destroy the instantiated ParenListExpr;
+ // we've explicitly retained all of its subexpressions already.
+ } else
SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
D->hasCXXDirectInitializer());
- } else {
- // FIXME: Call ActOnUninitializedDecl? (Not always)
- }
+ } else if (!Var->isStaticDataMember() || Var->isOutOfLine())
+ SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
return Var;
}
@@ -145,8 +205,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
bool Invalid = false;
QualType T = D->getType();
if (T->isDependentType()) {
- T = SemaRef.InstantiateType(T, TemplateArgs,
- D->getLocation(), D->getDeclName());
+ T = SemaRef.SubstType(T, TemplateArgs,
+ D->getLocation(), D->getDeclName());
if (!T.isNull() && T->isFunctionType()) {
// C++ [temp.arg.type]p3:
// If a declaration acquires a function type through a type
@@ -167,9 +227,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
else if (BitWidth) {
// The bit-width expression is not potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
+
OwningExprResult InstantiatedBitWidth
- = SemaRef.InstantiateExpr(BitWidth, TemplateArgs);
+ = SemaRef.SubstExpr(BitWidth, TemplateArgs);
if (InstantiatedBitWidth.isInvalid()) {
Invalid = true;
BitWidth = 0;
@@ -178,44 +238,90 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
}
FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T,
- cast<RecordDecl>(Owner),
+ D->getDeclaratorInfo(),
+ cast<RecordDecl>(Owner),
D->getLocation(),
D->isMutable(),
BitWidth,
+ D->getTypeSpecStartLoc(),
D->getAccess(),
0);
- if (Field) {
- if (Invalid)
- Field->setInvalidDecl();
-
- Owner->addDecl(Field);
+ if (!Field)
+ return 0;
+
+ if (Invalid)
+ Field->setInvalidDecl();
+
+ if (!Field->getDeclName()) {
+ // Keep track of where this decl came from.
+ SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D);
}
+ Field->setImplicit(D->isImplicit());
+ Owner->addDecl(Field);
+
return Field;
}
+Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
+ FriendDecl::FriendUnion FU;
+
+ // Handle friend type expressions by simply substituting template
+ // parameters into the pattern type.
+ if (Type *Ty = D->getFriendType()) {
+ QualType T = SemaRef.SubstType(QualType(Ty,0), TemplateArgs,
+ D->getLocation(), DeclarationName());
+ if (T.isNull()) return 0;
+
+ assert(getLangOptions().CPlusPlus0x || T->isRecordType());
+ FU = T.getTypePtr();
+
+ // Handle everything else by appropriate substitution.
+ } else {
+ NamedDecl *ND = D->getFriendDecl();
+ assert(ND && "friend decl must be a decl or a type!");
+
+ // FIXME: We have a problem here, because the nested call to Visit(ND)
+ // will inject the thing that the friend references into the current
+ // owner, which is wrong.
+ Decl *NewND = Visit(ND);
+ if (!NewND) return 0;
+
+ FU = cast<NamedDecl>(NewND);
+ }
+
+ FriendDecl *FD =
+ FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU,
+ D->getFriendLoc());
+ FD->setAccess(AS_public);
+ Owner->addDecl(FD);
+ return FD;
+}
+
Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
Expr *AssertExpr = D->getAssertExpr();
-
+
// The expression in a static assertion is not potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
+
OwningExprResult InstantiatedAssertExpr
- = SemaRef.InstantiateExpr(AssertExpr, TemplateArgs);
+ = SemaRef.SubstExpr(AssertExpr, TemplateArgs);
if (InstantiatedAssertExpr.isInvalid())
return 0;
- OwningExprResult Message = SemaRef.Clone(D->getMessage());
- Decl *StaticAssert
- = SemaRef.ActOnStaticAssertDeclaration(D->getLocation(),
+ OwningExprResult Message(SemaRef, D->getMessage());
+ D->getMessage()->Retain();
+ Decl *StaticAssert
+ = SemaRef.ActOnStaticAssertDeclaration(D->getLocation(),
move(InstantiatedAssertExpr),
move(Message)).getAs<Decl>();
return StaticAssert;
}
Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
- EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner,
+ EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
+ D->getTagKeywordLoc(),
/*PrevDecl=*/0);
Enum->setInstantiationOfMemberEnum(D);
Enum->setAccess(D->getAccess());
@@ -232,10 +338,10 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
OwningExprResult Value = SemaRef.Owned((Expr *)0);
if (Expr *UninstValue = EC->getInitExpr()) {
// The enumerator's value expression is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
Action::Unevaluated);
-
- Value = SemaRef.InstantiateExpr(UninstValue, TemplateArgs);
+
+ Value = SemaRef.SubstExpr(UninstValue, TemplateArgs);
}
// Drop the initial value and continue.
@@ -245,7 +351,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
isInvalid = true;
}
- EnumConstantDecl *EnumConst
+ EnumConstantDecl *EnumConst
= SemaRef.CheckEnumConstant(Enum, LastEnumConst,
EC->getLocation(), EC->getIdentifier(),
move(Value));
@@ -262,11 +368,13 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
LastEnumConst = EnumConst;
}
}
-
+
// FIXME: Fixup LBraceLoc and RBraceLoc
+ // FIXME: Empty Scope and AttributeList (required to handle attribute packed).
SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(),
Sema::DeclPtrTy::make(Enum),
- &Enumerators[0], Enumerators.size());
+ &Enumerators[0], Enumerators.size(),
+ 0, 0);
return Enum;
}
@@ -276,100 +384,337 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
return 0;
}
+Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return NULL;
+
+ CXXRecordDecl *Pattern = D->getTemplatedDecl();
+ CXXRecordDecl *RecordInst
+ = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner,
+ Pattern->getLocation(), Pattern->getIdentifier(),
+ Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL,
+ /*DelayTypeCreation=*/true);
+
+ ClassTemplateDecl *Inst
+ = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getIdentifier(), InstParams, RecordInst, 0);
+ RecordInst->setDescribedClassTemplate(Inst);
+ Inst->setAccess(D->getAccess());
+ Inst->setInstantiatedFromMemberTemplate(D);
+
+ // Trigger creation of the type for the instantiation.
+ SemaRef.Context.getTypeDeclType(RecordInst);
+
+ Owner->addDecl(Inst);
+ return Inst;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ assert(false &&"Partial specializations of member templates are unsupported");
+ return 0;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ // FIXME: Dig out the out-of-line definition of this function template?
+
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return NULL;
+
+ FunctionDecl *Instantiated = 0;
+ if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl()))
+ Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod,
+ InstParams));
+ else
+ Instantiated = cast_or_null<FunctionDecl>(VisitFunctionDecl(
+ D->getTemplatedDecl(),
+ InstParams));
+
+ if (!Instantiated)
+ return 0;
+
+ // Link the instantiated function template declaration to the function
+ // template from which it was instantiated.
+ FunctionTemplateDecl *InstTemplate
+ = Instantiated->getDescribedFunctionTemplate();
+ InstTemplate->setAccess(D->getAccess());
+ assert(InstTemplate &&
+ "VisitFunctionDecl/CXXMethodDecl didn't create a template!");
+ if (!InstTemplate->getInstantiatedFromMemberTemplate())
+ InstTemplate->setInstantiatedFromMemberTemplate(D);
+
+ // Add non-friends into the owner.
+ if (!InstTemplate->getFriendObjectKind())
+ Owner->addDecl(InstTemplate);
+ return InstTemplate;
+}
+
Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
CXXRecordDecl *PrevDecl = 0;
if (D->isInjectedClassName())
PrevDecl = cast<CXXRecordDecl>(Owner);
CXXRecordDecl *Record
- = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
- D->getLocation(), D->getIdentifier(), PrevDecl);
+ = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
+ D->getLocation(), D->getIdentifier(),
+ D->getTagKeywordLoc(), PrevDecl);
Record->setImplicit(D->isImplicit());
- Record->setAccess(D->getAccess());
+ // FIXME: Check against AS_none is an ugly hack to work around the issue that
+ // the tag decls introduced by friend class declarations don't have an access
+ // specifier. Remove once this area of the code gets sorted out.
+ if (D->getAccess() != AS_none)
+ Record->setAccess(D->getAccess());
if (!D->isInjectedClassName())
- Record->setInstantiationOfMemberClass(D);
+ Record->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
+
+ // If the original function was part of a friend declaration,
+ // inherit its namespace state.
+ if (Decl::FriendObjectKind FOK = D->getFriendObjectKind())
+ Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared);
+
+ Record->setAnonymousStructOrUnion(D->isAnonymousStructOrUnion());
Owner->addDecl(Record);
return Record;
}
-Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
+/// Normal class members are of more specific types and therefore
+/// don't make it here. This function serves two purposes:
+/// 1) instantiating function templates
+/// 2) substituting friend declarations
+/// FIXME: preserve function definitions in case #2
+ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
+ TemplateParameterList *TemplateParams) {
// Check whether there is already a function template specialization for
// this declaration.
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
void *InsertPos = 0;
- if (FunctionTemplate) {
+ if (FunctionTemplate && !TemplateParams) {
llvm::FoldingSetNodeID ID;
- FunctionTemplateSpecializationInfo::Profile(ID,
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size());
-
- FunctionTemplateSpecializationInfo *Info
- = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
+ FunctionTemplateSpecializationInfo::Profile(ID,
+ TemplateArgs.getInnermost().getFlatArgumentList(),
+ TemplateArgs.getInnermost().flat_size(),
+ SemaRef.Context);
+
+ FunctionTemplateSpecializationInfo *Info
+ = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
InsertPos);
-
+
// If we already have a function template specialization, return it.
if (Info)
return Info->Function;
}
-
+
Sema::LocalInstantiationScope Scope(SemaRef);
-
+
llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = InstantiateFunctionType(D, Params);
+ QualType T = SubstFunctionType(D, Params);
if (T.isNull())
return 0;
-
+
// Build the instantiated method declaration.
- FunctionDecl *Function
- = FunctionDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getDeclName(), T, D->getStorageClass(),
- D->isInline(), D->hasWrittenPrototype(),
- D->getTypeSpecStartLoc());
-
- // FIXME: friend functions
-
+ DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext(),
+ TemplateArgs);
+ FunctionDecl *Function =
+ FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
+ D->getDeclName(), T, D->getDeclaratorInfo(),
+ D->getStorageClass(),
+ D->isInline(), D->hasWrittenPrototype());
+ Function->setLexicalDeclContext(Owner);
+
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Function);
Function->setParams(SemaRef.Context, Params.data(), Params.size());
-
+
+ if (TemplateParams) {
+ // Our resulting instantiation is actually a function template, since we
+ // are substituting only the outer template parameters. For example, given
+ //
+ // template<typename T>
+ // struct X {
+ // template<typename U> friend void f(T, U);
+ // };
+ //
+ // X<int> x;
+ //
+ // We are instantiating the friend function template "f" within X<int>,
+ // which means substituting int for T, but leaving "f" as a friend function
+ // template.
+ // Build the function template itself.
+ FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner,
+ Function->getLocation(),
+ Function->getDeclName(),
+ TemplateParams, Function);
+ Function->setDescribedFunctionTemplate(FunctionTemplate);
+ FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+ }
+
if (InitFunctionInstantiation(Function, D))
Function->setInvalidDecl();
-
+
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
+
NamedDecl *PrevDecl = 0;
- SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration,
+ if (TemplateParams || !FunctionTemplate) {
+ // Look only into the namespace where the friend would be declared to
+ // find a previous declaration. This is the innermost enclosing namespace,
+ // as described in ActOnFriendFunctionDecl.
+ Sema::LookupResult R;
+ SemaRef.LookupQualifiedName(R, DC, Function->getDeclName(),
+ Sema::LookupOrdinaryName, true);
+
+ PrevDecl = R.getAsSingleDecl(SemaRef.Context);
+
+ // In C++, the previous declaration we find might be a tag type
+ // (class or enum). In this case, the new declaration will hide the
+ // tag type. Note that this does does not apply if we're declaring a
+ // typedef (C++ [dcl.typedef]p4).
+ if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
+ PrevDecl = 0;
+ }
+
+ SemaRef.CheckFunctionDeclaration(Function, PrevDecl, false, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
- if (FunctionTemplate) {
+ // If the original function was part of a friend declaration,
+ // inherit its namespace state and add it to the owner.
+ NamedDecl *FromFriendD
+ = TemplateParams? cast<NamedDecl>(D->getDescribedFunctionTemplate()) : D;
+ if (FromFriendD->getFriendObjectKind()) {
+ NamedDecl *ToFriendD = 0;
+ if (TemplateParams) {
+ ToFriendD = cast<NamedDecl>(FunctionTemplate);
+ PrevDecl = FunctionTemplate->getPreviousDeclaration();
+ } else {
+ ToFriendD = Function;
+ PrevDecl = Function->getPreviousDeclaration();
+ }
+ ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL);
+ if (!Owner->isDependentContext() && !PrevDecl)
+ DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false);
+
+ if (!TemplateParams)
+ Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+ }
+
+ if (FunctionTemplate && !TemplateParams) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
- &TemplateArgs,
+ &TemplateArgs.getInnermost(),
InsertPos);
- }
+ }
return Function;
}
-Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
- // FIXME: Look for existing, explicit specializations.
+Decl *
+TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
+ TemplateParameterList *TemplateParams) {
+ FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
+ void *InsertPos = 0;
+ if (FunctionTemplate && !TemplateParams) {
+ // We are creating a function template specialization from a function
+ // template. Check whether there is already a function template
+ // specialization for this particular set of template arguments.
+ llvm::FoldingSetNodeID ID;
+ FunctionTemplateSpecializationInfo::Profile(ID,
+ TemplateArgs.getInnermost().getFlatArgumentList(),
+ TemplateArgs.getInnermost().flat_size(),
+ SemaRef.Context);
+
+ FunctionTemplateSpecializationInfo *Info
+ = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
+ InsertPos);
+
+ // If we already have a function template specialization, return it.
+ if (Info)
+ return Info->Function;
+ }
+
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = InstantiateFunctionType(D, Params);
+ QualType T = SubstFunctionType(D, Params);
if (T.isNull())
return 0;
// Build the instantiated method declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
- CXXMethodDecl *Method
- = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
- D->getDeclName(), T, D->isStatic(),
- D->isInline());
- Method->setInstantiationOfMemberFunction(D);
+ CXXMethodDecl *Method = 0;
+
+ DeclarationName Name = D->getDeclName();
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
+ Name = SemaRef.Context.DeclarationNames.getCXXConstructorName(
+ SemaRef.Context.getCanonicalType(ClassTy));
+ Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
+ Constructor->getLocation(),
+ Name, T,
+ Constructor->getDeclaratorInfo(),
+ Constructor->isExplicit(),
+ Constructor->isInline(), false);
+ } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
+ QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
+ Name = SemaRef.Context.DeclarationNames.getCXXDestructorName(
+ SemaRef.Context.getCanonicalType(ClassTy));
+ Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
+ Destructor->getLocation(), Name,
+ T, Destructor->isInline(), false);
+ } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
+ CanQualType ConvTy
+ = SemaRef.Context.getCanonicalType(
+ T->getAs<FunctionType>()->getResultType());
+ Name = SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(
+ ConvTy);
+ Method = CXXConversionDecl::Create(SemaRef.Context, Record,
+ Conversion->getLocation(), Name,
+ T, Conversion->getDeclaratorInfo(),
+ Conversion->isInline(),
+ Conversion->isExplicit());
+ } else {
+ Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
+ D->getDeclName(), T, D->getDeclaratorInfo(),
+ D->isStatic(), D->isInline());
+ }
+
+ if (TemplateParams) {
+ // Our resulting instantiation is actually a function template, since we
+ // are substituting only the outer template parameters. For example, given
+ //
+ // template<typename T>
+ // struct X {
+ // template<typename U> void f(T, U);
+ // };
+ //
+ // X<int> x;
+ //
+ // We are instantiating the member template "f" within X<int>, which means
+ // substituting int for T, but leaving "f" as a member function template.
+ // Build the function template itself.
+ FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Record,
+ Method->getLocation(),
+ Method->getDeclName(),
+ TemplateParams, Method);
+ if (D->isOutOfLine())
+ FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+ Method->setDescribedFunctionTemplate(FunctionTemplate);
+ } else if (!FunctionTemplate)
+ Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+
+ // If we are instantiating a member function defined
+ // out-of-line, the instantiation will have the same lexical
+ // context (which will be a namespace scope) as the template.
+ if (D->isOutOfLine())
+ Method->setLexicalDeclContext(D->getLexicalDeclContext());
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
@@ -379,167 +724,78 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
if (InitMethodInstantiation(Method, D))
Method->setInvalidDecl();
- NamedDecl *PrevDecl
- = SemaRef.LookupQualifiedName(Owner, Method->getDeclName(),
- Sema::LookupOrdinaryName, true);
- // In C++, the previous declaration we find might be a tag type
- // (class or enum). In this case, the new declaration will hide the
- // tag type. Note that this does does not apply if we're declaring a
- // typedef (C++ [dcl.typedef]p4).
- if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
- PrevDecl = 0;
+ NamedDecl *PrevDecl = 0;
+
+ if (!FunctionTemplate || TemplateParams) {
+ Sema::LookupResult R;
+ SemaRef.LookupQualifiedName(R, Owner, Name, Sema::LookupOrdinaryName, true);
+ PrevDecl = R.getAsSingleDecl(SemaRef.Context);
+
+ // In C++, the previous declaration we find might be a tag type
+ // (class or enum). In this case, the new declaration will hide the
+ // tag type. Note that this does does not apply if we're declaring a
+ // typedef (C++ [dcl.typedef]p4).
+ if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
+ PrevDecl = 0;
+ }
+
+ if (FunctionTemplate && !TemplateParams)
+ // Record this function template specialization.
+ Method->setFunctionTemplateSpecialization(SemaRef.Context,
+ FunctionTemplate,
+ &TemplateArgs.getInnermost(),
+ InsertPos);
+
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
- SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
+ SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
- if (!Method->isInvalidDecl() || !PrevDecl)
+ if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl) &&
+ !Method->getFriendObjectKind())
Owner->addDecl(Method);
+
return Method;
}
Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
- // FIXME: Look for existing, explicit specializations.
- Sema::LocalInstantiationScope Scope(SemaRef);
-
- llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = InstantiateFunctionType(D, Params);
- if (T.isNull())
- return 0;
-
- // Build the instantiated method declaration.
- CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
- QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
- DeclarationName Name
- = SemaRef.Context.DeclarationNames.getCXXConstructorName(
- SemaRef.Context.getCanonicalType(ClassTy));
- CXXConstructorDecl *Constructor
- = CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(),
- Name, T, D->isExplicit(), D->isInline(),
- false);
- Constructor->setInstantiationOfMemberFunction(D);
-
- // Attach the parameters
- for (unsigned P = 0; P < Params.size(); ++P)
- Params[P]->setOwningFunction(Constructor);
- Constructor->setParams(SemaRef.Context, Params.data(), Params.size());
-
- if (InitMethodInstantiation(Constructor, D))
- Constructor->setInvalidDecl();
-
- NamedDecl *PrevDecl
- = SemaRef.LookupQualifiedName(Owner, Name, Sema::LookupOrdinaryName, true);
-
- // In C++, the previous declaration we find might be a tag type
- // (class or enum). In this case, the new declaration will hide the
- // tag type. Note that this does does not apply if we're declaring a
- // typedef (C++ [dcl.typedef]p4).
- if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
- PrevDecl = 0;
- bool Redeclaration = false;
- bool OverloadableAttrRequired = false;
- SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration,
- /*FIXME:*/OverloadableAttrRequired);
-
- Record->addedConstructor(SemaRef.Context, Constructor);
- Owner->addDecl(Constructor);
- return Constructor;
+ return VisitCXXMethodDecl(D);
}
Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
- // FIXME: Look for existing, explicit specializations.
- Sema::LocalInstantiationScope Scope(SemaRef);
-
- llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = InstantiateFunctionType(D, Params);
- if (T.isNull())
- return 0;
- assert(Params.size() == 0 && "Destructor with parameters?");
-
- // Build the instantiated destructor declaration.
- CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
- QualType ClassTy =
- SemaRef.Context.getCanonicalType(SemaRef.Context.getTypeDeclType(Record));
- CXXDestructorDecl *Destructor
- = CXXDestructorDecl::Create(SemaRef.Context, Record,
- D->getLocation(),
- SemaRef.Context.DeclarationNames.getCXXDestructorName(ClassTy),
- T, D->isInline(), false);
- Destructor->setInstantiationOfMemberFunction(D);
- if (InitMethodInstantiation(Destructor, D))
- Destructor->setInvalidDecl();
-
- bool Redeclaration = false;
- bool OverloadableAttrRequired = false;
- NamedDecl *PrevDecl = 0;
- SemaRef.CheckFunctionDeclaration(Destructor, PrevDecl, Redeclaration,
- /*FIXME:*/OverloadableAttrRequired);
- Owner->addDecl(Destructor);
- return Destructor;
+ return VisitCXXMethodDecl(D);
}
Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
- // FIXME: Look for existing, explicit specializations.
- Sema::LocalInstantiationScope Scope(SemaRef);
-
- llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = InstantiateFunctionType(D, Params);
- if (T.isNull())
- return 0;
- assert(Params.size() == 0 && "Destructor with parameters?");
-
- // Build the instantiated conversion declaration.
- CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
- QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
- QualType ConvTy
- = SemaRef.Context.getCanonicalType(T->getAsFunctionType()->getResultType());
- CXXConversionDecl *Conversion
- = CXXConversionDecl::Create(SemaRef.Context, Record,
- D->getLocation(),
- SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(ConvTy),
- T, D->isInline(), D->isExplicit());
- Conversion->setInstantiationOfMemberFunction(D);
- if (InitMethodInstantiation(Conversion, D))
- Conversion->setInvalidDecl();
-
- bool Redeclaration = false;
- bool OverloadableAttrRequired = false;
- NamedDecl *PrevDecl = 0;
- SemaRef.CheckFunctionDeclaration(Conversion, PrevDecl, Redeclaration,
- /*FIXME:*/OverloadableAttrRequired);
- Owner->addDecl(Conversion);
- return Conversion;
+ return VisitCXXMethodDecl(D);
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
- QualType OrigT = SemaRef.InstantiateType(D->getOriginalType(), TemplateArgs,
+ QualType OrigT = SemaRef.SubstType(D->getOriginalType(), TemplateArgs,
D->getLocation(), D->getDeclName());
if (OrigT.isNull())
return 0;
QualType T = SemaRef.adjustParameterType(OrigT);
- if (D->getDefaultArg()) {
- // FIXME: Leave a marker for "uninstantiated" default
- // arguments. They only get instantiated on demand at the call
- // site.
- unsigned DiagID = SemaRef.Diags.getCustomDiagID(Diagnostic::Warning,
- "sorry, dropping default argument during template instantiation");
- SemaRef.Diag(D->getDefaultArg()->getSourceRange().getBegin(), DiagID)
- << D->getDefaultArg()->getSourceRange();
- }
-
// Allocate the parameter
ParmVarDecl *Param = 0;
if (T == OrigT)
Param = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getIdentifier(), T, D->getStorageClass(),
- 0);
+ D->getIdentifier(), T, D->getDeclaratorInfo(),
+ D->getStorageClass(), 0);
else
- Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner,
+ Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
- T, OrigT, D->getStorageClass(), 0);
-
+ T, D->getDeclaratorInfo(), OrigT,
+ D->getStorageClass(), 0);
+
+ // Mark the default argument as being uninstantiated.
+ if (D->hasUninstantiatedDefaultArg())
+ Param->setUninstantiatedDefaultArg(D->getUninstantiatedDefaultArg());
+ else if (Expr *Arg = D->getDefaultArg())
+ Param->setUninstantiatedDefaultArg(Arg);
+
// Note: we don't try to instantiate function parameters until after
// we've instantiated the function's type. Therefore, we don't have
// to check for 'void' parameter types here.
@@ -556,41 +812,130 @@ TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
return VisitParmVarDecl(D);
}
-Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner,
- const TemplateArgumentList &TemplateArgs) {
+Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
+ TemplateTypeParmDecl *D) {
+ // TODO: don't always clone when decls are refcounted.
+ const Type* T = D->getTypeForDecl();
+ assert(T->isTemplateTypeParmType());
+ const TemplateTypeParmType *TTPT = T->getAs<TemplateTypeParmType>();
+
+ TemplateTypeParmDecl *Inst =
+ TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ TTPT->getDepth(), TTPT->getIndex(),
+ TTPT->getName(),
+ D->wasDeclaredWithTypename(),
+ D->isParameterPack());
+
+ if (D->hasDefaultArgument()) {
+ QualType DefaultPattern = D->getDefaultArgument();
+ QualType DefaultInst
+ = SemaRef.SubstType(DefaultPattern, TemplateArgs,
+ D->getDefaultArgumentLoc(),
+ D->getDeclName());
+
+ Inst->setDefaultArgument(DefaultInst,
+ D->getDefaultArgumentLoc(),
+ D->defaultArgumentWasInherited() /* preserve? */);
+ }
+
+ return Inst;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
+ NestedNameSpecifier *NNS =
+ SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(),
+ D->getTargetNestedNameRange(),
+ TemplateArgs);
+ if (!NNS)
+ return 0;
+
+ CXXScopeSpec SS;
+ SS.setRange(D->getTargetNestedNameRange());
+ SS.setScopeRep(NNS);
+
+ NamedDecl *UD =
+ SemaRef.BuildUsingDeclaration(D->getLocation(), SS,
+ D->getTargetNameLocation(),
+ D->getTargetName(), 0, D->isTypeName());
+ if (UD)
+ SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
+ D);
+ return UD;
+}
+
+Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
return Instantiator.Visit(D);
}
-/// \brief Instantiates the type of the given function, including
-/// instantiating all of the function parameters.
+/// \brief Instantiates a nested template parameter list in the current
+/// instantiation context.
///
-/// \param D The function that we will be instantiated
+/// \param L The parameter list to instantiate
+///
+/// \returns NULL if there was an error
+TemplateParameterList *
+TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
+ // Get errors for all the parameters before bailing out.
+ bool Invalid = false;
+
+ unsigned N = L->size();
+ typedef llvm::SmallVector<NamedDecl *, 8> ParamVector;
+ ParamVector Params;
+ Params.reserve(N);
+ for (TemplateParameterList::iterator PI = L->begin(), PE = L->end();
+ PI != PE; ++PI) {
+ NamedDecl *D = cast_or_null<NamedDecl>(Visit(*PI));
+ Params.push_back(D);
+ Invalid = Invalid || !D;
+ }
+
+ // Clean up if we had an error.
+ if (Invalid) {
+ for (ParamVector::iterator PI = Params.begin(), PE = Params.end();
+ PI != PE; ++PI)
+ if (*PI)
+ (*PI)->Destroy(SemaRef.Context);
+ return NULL;
+ }
+
+ TemplateParameterList *InstL
+ = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
+ L->getLAngleLoc(), &Params.front(), N,
+ L->getRAngleLoc());
+ return InstL;
+}
+
+/// \brief Does substitution on the type of the given function, including
+/// all of the function parameters.
+///
+/// \param D The function whose type will be the basis of the substitution
///
/// \param Params the instantiated parameter declarations
-/// \returns the instantiated function's type if successfull, a NULL
+/// \returns the instantiated function's type if successful, a NULL
/// type if there was an error.
-QualType
-TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
+QualType
+TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
bool InvalidDecl = false;
- // Instantiate the function parameters
+ // Substitute all of the function's formal parameter types.
TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs);
llvm::SmallVector<QualType, 4> ParamTys;
- for (FunctionDecl::param_iterator P = D->param_begin(),
+ for (FunctionDecl::param_iterator P = D->param_begin(),
PEnd = D->param_end();
P != PEnd; ++P) {
if (ParmVarDecl *PInst = ParamInstantiator.VisitParmVarDecl(*P)) {
if (PInst->getType()->isVoidType()) {
SemaRef.Diag(PInst->getLocation(), diag::err_param_with_void_type);
PInst->setInvalidDecl();
- }
- else if (SemaRef.RequireNonAbstractType(PInst->getLocation(),
- PInst->getType(),
- diag::err_abstract_type_in_decl,
- Sema::AbstractParamType))
+ } else if (SemaRef.RequireNonAbstractType(PInst->getLocation(),
+ PInst->getType(),
+ diag::err_abstract_type_in_decl,
+ Sema::AbstractParamType))
PInst->setInvalidDecl();
Params.push_back(PInst);
@@ -598,7 +943,7 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
if (PInst->isInvalidDecl())
InvalidDecl = true;
- } else
+ } else
InvalidDecl = true;
}
@@ -606,11 +951,11 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
if (InvalidDecl)
return QualType();
- const FunctionProtoType *Proto = D->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *Proto = D->getType()->getAs<FunctionProtoType>();
assert(Proto && "Missing prototype?");
- QualType ResultType
- = SemaRef.InstantiateType(Proto->getResultType(), TemplateArgs,
- D->getLocation(), D->getDeclName());
+ QualType ResultType
+ = SemaRef.SubstType(Proto->getResultType(), TemplateArgs,
+ D->getLocation(), D->getDeclName());
if (ResultType.isNull())
return QualType();
@@ -619,21 +964,21 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
D->getLocation(), D->getDeclName());
}
-/// \brief Initializes the common fields of an instantiation function
+/// \brief Initializes the common fields of an instantiation function
/// declaration (New) from the corresponding fields of its template (Tmpl).
///
/// \returns true if there was an error
-bool
-TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
+bool
+TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *Tmpl) {
if (Tmpl->isDeleted())
New->setDeleted();
-
+
// If we are performing substituting explicitly-specified template arguments
// or deduced template arguments into a function template and we reach this
// point, we are now past the point where SFINAE applies and have committed
- // to keeping the new function template specialization. We therefore
- // convert the active template instantiation for the function template
+ // to keeping the new function template specialization. We therefore
+ // convert the active template instantiation for the function template
// into a template instantiation for this specific function template
// specialization, which is not a SFINAE context, so that we diagnose any
// further errors in the declaration itself.
@@ -641,15 +986,16 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
ActiveInstType &ActiveInst = SemaRef.ActiveTemplateInstantiations.back();
if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution ||
ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) {
- if (FunctionTemplateDecl *FunTmpl
+ if (FunctionTemplateDecl *FunTmpl
= dyn_cast<FunctionTemplateDecl>((Decl *)ActiveInst.Entity)) {
- assert(FunTmpl->getTemplatedDecl() == Tmpl &&
+ assert(FunTmpl->getTemplatedDecl() == Tmpl &&
"Deduction from the wrong function template?");
+ (void) FunTmpl;
ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
ActiveInst.Entity = reinterpret_cast<uintptr_t>(New);
}
}
-
+
return false;
}
@@ -658,18 +1004,19 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
/// (Tmpl).
///
/// \returns true if there was an error
-bool
-TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
+bool
+TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
CXXMethodDecl *Tmpl) {
if (InitFunctionInstantiation(New, Tmpl))
return true;
-
+
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
New->setAccess(Tmpl->getAccess());
if (Tmpl->isVirtualAsWritten()) {
New->setVirtualAsWritten(true);
Record->setAggregate(false);
Record->setPOD(false);
+ Record->setEmpty(false);
Record->setPolymorphic(true);
}
if (Tmpl->isPure()) {
@@ -702,12 +1049,25 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
return;
assert(!Function->getBody() && "Already instantiated!");
+
+ // Never instantiate an explicit specialization.
+ if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl = 0;
- if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate())
+ if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) {
+ while (Primary->getInstantiatedFromMemberTemplate()) {
+ // If we have hit a point where the user provided a specialization of
+ // this template, we're done looking.
+ if (Primary->isMemberSpecialization())
+ break;
+
+ Primary = Primary->getInstantiatedFromMemberTemplate();
+ }
+
PatternDecl = Primary->getTemplatedDecl();
- else
+ } else
PatternDecl = Function->getInstantiatedFromMemberFunction();
Stmt *Pattern = 0;
if (PatternDecl)
@@ -716,6 +1076,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (!Pattern)
return;
+ // C++0x [temp.explicit]p9:
+ // Except for inline functions, other explicit instantiation declarations
+ // have the effect of suppressing the implicit instantiation of the entity
+ // to which they refer.
+ if (Function->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration &&
+ PatternDecl->isOutOfLine() && !PatternDecl->isInline())
+ return;
+
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
return;
@@ -726,13 +1095,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
std::deque<PendingImplicitInstantiation> SavedPendingImplicitInstantiations;
if (Recursive)
PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
-
+
ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function));
// Introduce a new scope where local variable instantiations will be
// recorded.
LocalInstantiationScope Scope(*this);
-
+
// Introduce the instantiated function parameters into the local
// instantiation scope.
for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I)
@@ -744,23 +1113,35 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
DeclContext *PreviousContext = CurContext;
CurContext = Function;
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Function);
+
+ // If this is a constructor, instantiate the member initializers.
+ if (const CXXConstructorDecl *Ctor =
+ dyn_cast<CXXConstructorDecl>(PatternDecl)) {
+ InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,
+ TemplateArgs);
+ }
+
// Instantiate the function body.
- OwningStmtResult Body
- = InstantiateStmt(Pattern, getTemplateInstantiationArgs(Function));
+ OwningStmtResult Body = SubstStmt(Pattern, TemplateArgs);
- ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
+ if (Body.isInvalid())
+ Function->setInvalidDecl();
+
+ ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
/*IsInstantiation=*/true);
CurContext = PreviousContext;
DeclGroupRef DG(Function);
Consumer.HandleTopLevelDecl(DG);
-
+
if (Recursive) {
// Instantiate any pending implicit instantiations found during the
- // instantiation of this template.
+ // instantiation of this template.
PerformPendingImplicitInstantiations();
-
+
// Restore the set of pending implicit instantiations.
PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
}
@@ -769,35 +1150,296 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
/// \brief Instantiate the definition of the given variable from its
/// template.
///
-/// \param Var the already-instantiated declaration of a variable.
-void Sema::InstantiateVariableDefinition(VarDecl *Var) {
- // FIXME: Implement this!
+/// \param PointOfInstantiation the point at which the instantiation was
+/// required. Note that this is not precisely a "point of instantiation"
+/// for the function, but it's close.
+///
+/// \param Var the already-instantiated declaration of a static member
+/// variable of a class template specialization.
+///
+/// \param Recursive if true, recursively instantiates any functions that
+/// are required by this instantiation.
+void Sema::InstantiateStaticDataMemberDefinition(
+ SourceLocation PointOfInstantiation,
+ VarDecl *Var,
+ bool Recursive) {
+ if (Var->isInvalidDecl())
+ return;
+
+ // Find the out-of-line definition of this static data member.
+ VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
+ bool FoundOutOfLineDef = false;
+ assert(Def && "This data member was not instantiated from a template?");
+ assert(Def->isStaticDataMember() && "Not a static data member?");
+ for (VarDecl::redecl_iterator RD = Def->redecls_begin(),
+ RDEnd = Def->redecls_end();
+ RD != RDEnd; ++RD) {
+ if (RD->getLexicalDeclContext()->isFileContext()) {
+ Def = *RD;
+ FoundOutOfLineDef = true;
+ }
+ }
+
+ if (!FoundOutOfLineDef) {
+ // We did not find an out-of-line definition of this static data member,
+ // so we won't perform any instantiation. Rather, we rely on the user to
+ // instantiate this definition (or provide a specialization for it) in
+ // another translation unit.
+ return;
+ }
+
+ // Never instantiate an explicit specialization.
+ if (Def->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
+
+ // C++0x [temp.explicit]p9:
+ // Except for inline functions, other explicit instantiation declarations
+ // have the effect of suppressing the implicit instantiation of the entity
+ // to which they refer.
+ if (Def->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration)
+ return;
+
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
+ if (Inst)
+ return;
+
+ // If we're performing recursive template instantiation, create our own
+ // queue of pending implicit instantiations that we will instantiate later,
+ // while we're still within our own instantiation context.
+ std::deque<PendingImplicitInstantiation> SavedPendingImplicitInstantiations;
+ if (Recursive)
+ PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Var->getDeclContext();
+
+ Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
+ getTemplateInstantiationArgs(Var)));
+
+ CurContext = PreviousContext;
+
+ if (Var) {
+ DeclGroupRef DG(Var);
+ Consumer.HandleTopLevelDecl(DG);
+ }
+
+ if (Recursive) {
+ // Instantiate any pending implicit instantiations found during the
+ // instantiation of this template.
+ PerformPendingImplicitInstantiations();
+
+ // Restore the set of pending implicit instantiations.
+ PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+ }
+}
+
+void
+Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
+ const CXXConstructorDecl *Tmpl,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+
+ llvm::SmallVector<MemInitTy*, 4> NewInits;
+
+ // Instantiate all the initializers.
+ for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(),
+ InitsEnd = Tmpl->init_end();
+ Inits != InitsEnd; ++Inits) {
+ CXXBaseOrMemberInitializer *Init = *Inits;
+
+ ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this);
+
+ // Instantiate all the arguments.
+ for (ExprIterator Args = Init->arg_begin(), ArgsEnd = Init->arg_end();
+ Args != ArgsEnd; ++Args) {
+ OwningExprResult NewArg = SubstExpr(*Args, TemplateArgs);
+
+ if (NewArg.isInvalid())
+ New->setInvalidDecl();
+ else
+ NewArgs.push_back(NewArg.takeAs<Expr>());
+ }
+
+ MemInitResult NewInit;
+
+ if (Init->isBaseInitializer()) {
+ QualType BaseType(Init->getBaseClass(), 0);
+ BaseType = SubstType(BaseType, TemplateArgs, Init->getSourceLocation(),
+ New->getDeclName());
+
+ NewInit = BuildBaseInitializer(BaseType,
+ (Expr **)NewArgs.data(),
+ NewArgs.size(),
+ Init->getSourceLocation(),
+ Init->getRParenLoc(),
+ New->getParent());
+ } else if (Init->isMemberInitializer()) {
+ FieldDecl *Member;
+
+ // Is this an anonymous union?
+ if (FieldDecl *UnionInit = Init->getAnonUnionMember())
+ Member = cast<FieldDecl>(FindInstantiatedDecl(UnionInit, TemplateArgs));
+ else
+ Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMember(),
+ TemplateArgs));
+
+ NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(),
+ NewArgs.size(),
+ Init->getSourceLocation(),
+ Init->getRParenLoc());
+ }
+
+ if (NewInit.isInvalid())
+ New->setInvalidDecl();
+ else {
+ // FIXME: It would be nice if ASTOwningVector had a release function.
+ NewArgs.take();
+
+ NewInits.push_back((MemInitTy *)NewInit.get());
+ }
+ }
+
+ // Assign all the initializers to the new constructor.
+ ActOnMemInitializers(DeclPtrTy::make(New),
+ /*FIXME: ColonLoc */
+ SourceLocation(),
+ NewInits.data(), NewInits.size());
+}
+
+// TODO: this could be templated if the various decl types used the
+// same method name.
+static bool isInstantiationOf(ClassTemplateDecl *Pattern,
+ ClassTemplateDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberTemplate();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(FunctionTemplateDecl *Pattern,
+ FunctionTemplateDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberTemplate();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(CXXRecordDecl *Pattern,
+ CXXRecordDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberClass();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(FunctionDecl *Pattern,
+ FunctionDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberFunction();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(EnumDecl *Pattern,
+ EnumDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberEnum();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(UnresolvedUsingDecl *Pattern,
+ UsingDecl *Instance,
+ ASTContext &C) {
+ return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern;
+}
+
+static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
+ VarDecl *Instance) {
+ assert(Instance->isStaticDataMember());
+
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromStaticDataMember();
+ } while (Instance);
+
+ return false;
}
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
- if (D->getKind() != Other->getKind())
+ if (D->getKind() != Other->getKind()) {
+ if (UnresolvedUsingDecl *UUD = dyn_cast<UnresolvedUsingDecl>(D)) {
+ if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) {
+ return isInstantiationOf(UUD, UD, Ctx);
+ }
+ }
+
return false;
+ }
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other))
- return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass())
- == Ctx.getCanonicalDecl(D);
+ return isInstantiationOf(cast<CXXRecordDecl>(D), Record);
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other))
- return Ctx.getCanonicalDecl(Function->getInstantiatedFromMemberFunction())
- == Ctx.getCanonicalDecl(D);
+ return isInstantiationOf(cast<FunctionDecl>(D), Function);
if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other))
- return Ctx.getCanonicalDecl(Enum->getInstantiatedFromMemberEnum())
- == Ctx.getCanonicalDecl(D);
+ return isInstantiationOf(cast<EnumDecl>(D), Enum);
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(Other))
+ if (Var->isStaticDataMember())
+ return isInstantiationOfStaticDataMember(cast<VarDecl>(D), Var);
+
+ if (ClassTemplateDecl *Temp = dyn_cast<ClassTemplateDecl>(Other))
+ return isInstantiationOf(cast<ClassTemplateDecl>(D), Temp);
+
+ if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other))
+ return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp);
- // FIXME: How can we find instantiations of anonymous unions?
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) {
+ if (!Field->getDeclName()) {
+ // This is an unnamed field.
+ return Ctx.getInstantiatedFromUnnamedFieldDecl(Field) ==
+ cast<FieldDecl>(D);
+ }
+ }
return D->getDeclName() && isa<NamedDecl>(Other) &&
D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
}
template<typename ForwardIterator>
-static NamedDecl *findInstantiationOf(ASTContext &Ctx,
+static NamedDecl *findInstantiationOf(ASTContext &Ctx,
NamedDecl *D,
ForwardIterator first,
ForwardIterator last) {
@@ -808,6 +1450,18 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
return 0;
}
+/// \brief Finds the instantiation of the given declaration context
+/// within the current instantiation.
+///
+/// \returns NULL if there was an error
+DeclContext *Sema::FindInstantiatedContext(DeclContext* DC,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) {
+ Decl* ID = FindInstantiatedDecl(D, TemplateArgs);
+ return cast_or_null<DeclContext>(ID);
+ } else return DC;
+}
+
/// \brief Find the instantiation of the given declaration within the
/// current instantiation.
///
@@ -834,7 +1488,24 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
/// X<T>::<Kind>::KnownValue) to its instantiation
/// (X<int>::<Kind>::KnownValue). InstantiateCurrentDeclRef() performs
/// this mapping from within the instantiation of X<int>.
-NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
+NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
+ // Transform all of the elements of the overloaded function set.
+ OverloadedFunctionDecl *Result
+ = OverloadedFunctionDecl::Create(Context, CurContext, Ovl->getDeclName());
+
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ Result->addOverload(
+ AnyFunctionDecl::getFromNamedDecl(FindInstantiatedDecl(*F,
+ TemplateArgs)));
+ }
+
+ return Result;
+ }
+
DeclContext *ParentDC = D->getDeclContext();
if (isa<ParmVarDecl>(D) || ParentDC->isFunctionOrMethod()) {
// D is a local of some kind. Look into the map of local
@@ -842,14 +1513,71 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D));
}
- if (NamedDecl *ParentDecl = dyn_cast<NamedDecl>(ParentDC)) {
- ParentDecl = InstantiateCurrentDeclRef(ParentDecl);
- if (!ParentDecl)
- return 0;
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+ if (!Record->isDependentContext())
+ return D;
+
+ // If the RecordDecl is actually the injected-class-name or a "templated"
+ // declaration for a class template or class template partial
+ // specialization, substitute into the injected-class-name of the
+ // class template or partial specialization to find the new DeclContext.
+ QualType T;
+ ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
+
+ if (ClassTemplate) {
+ T = ClassTemplate->getInjectedClassNameType(Context);
+ } else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
+ T = Context.getTypeDeclType(Record);
+ ClassTemplate = PartialSpec->getSpecializedTemplate();
+ }
+
+ if (!T.isNull()) {
+ // Substitute into the injected-class-name to get the type corresponding
+ // to the instantiation we want. This substitution should never fail,
+ // since we know we can instantiate the injected-class-name or we wouldn't
+ // have gotten to the injected-class-name!
+ // FIXME: Can we use the CurrentInstantiationScope to avoid this extra
+ // instantiation in the common case?
+ T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName());
+ assert(!T.isNull() && "Instantiation of injected-class-name cannot fail.");
+
+ if (!T->isDependentType()) {
+ assert(T->isRecordType() && "Instantiation must produce a record type");
+ return T->getAs<RecordType>()->getDecl();
+ }
+
+ // We are performing "partial" template instantiation to create the
+ // member declarations for the members of a class template
+ // specialization. Therefore, D is actually referring to something in
+ // the current instantiation. Look through the current context,
+ // which contains actual instantiations, to find the instantiation of
+ // the "current instantiation" that D refers to.
+ for (DeclContext *DC = CurContext; !DC->isFileContext();
+ DC = DC->getParent()) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(DC))
+ if (isInstantiationOf(ClassTemplate,
+ Spec->getSpecializedTemplate()))
+ return Spec;
+ }
- ParentDC = cast<DeclContext>(ParentDecl);
+ assert(false &&
+ "Unable to find declaration for the current instantiation");
+ return Record;
+ }
+
+ // Fall through to deal with other dependent record types (e.g.,
+ // anonymous unions in class templates).
}
+ if (!ParentDC->isDependentContext())
+ return D;
+
+ ParentDC = FindInstantiatedContext(ParentDC, TemplateArgs);
+ if (!ParentDC)
+ return 0;
+
if (ParentDC != D->getDeclContext()) {
// We performed some kind of instantiation in the parent context,
// so now we need to look into the instantiated parent context to
@@ -867,51 +1595,47 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
// - unnamed class/struct/union/enum within a template
//
// FIXME: Find a better way to find these instantiations!
- Result = findInstantiationOf(Context, D,
+ Result = findInstantiationOf(Context, D,
ParentDC->decls_begin(),
ParentDC->decls_end());
}
+
assert(Result && "Unable to find instantiation of declaration!");
D = Result;
}
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D))
- if (ClassTemplateDecl *ClassTemplate
- = Record->getDescribedClassTemplate()) {
- // When the declaration D was parsed, it referred to the current
- // instantiation. Therefore, look through the current context,
- // which contains actual instantiations, to find the
- // instantiation of the "current instantiation" that D refers
- // to. Alternatively, we could just instantiate the
- // injected-class-name with the current template arguments, but
- // such an instantiation is far more expensive.
- for (DeclContext *DC = CurContext; !DC->isFileContext();
- DC = DC->getParent()) {
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(DC))
- if (Context.getCanonicalDecl(Spec->getSpecializedTemplate())
- == Context.getCanonicalDecl(ClassTemplate))
- return Spec;
- }
-
- assert(false &&
- "Unable to find declaration for the current instantiation");
- }
-
return D;
}
-/// \brief Performs template instantiation for all implicit template
+/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
void Sema::PerformPendingImplicitInstantiations() {
while (!PendingImplicitInstantiations.empty()) {
PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front();
PendingImplicitInstantiations.pop_front();
-
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first))
+
+ // Instantiate function definitions
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) {
+ PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Function),
+ Function->getLocation(), *this,
+ Context.getSourceManager(),
+ "instantiating function definition");
+
if (!Function->getBody())
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
-
- // FIXME: instantiate static member variables
+ continue;
+ }
+
+ // Instantiate static data member definitions.
+ VarDecl *Var = cast<VarDecl>(Inst.first);
+ assert(Var->isStaticDataMember() && "Not a static data member?");
+
+ PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Var),
+ Var->getLocation(), *this,
+ Context.getSourceManager(),
+ "instantiating static data member "
+ "definition");
+
+ InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true);
}
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 3756df870c2c2..3cdf6154232bd 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -13,9 +13,12 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace clang;
@@ -23,8 +26,8 @@ using namespace clang;
/// \brief Perform adjustment on the parameter type of a function.
///
/// This routine adjusts the given parameter type @p T to the actual
-/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
-/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
+/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
+/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
QualType Sema::adjustParameterType(QualType T) {
// C99 6.7.5.3p7:
if (T->isArrayType()) {
@@ -48,15 +51,17 @@ QualType Sema::adjustParameterType(QualType T) {
/// object.
/// \param DS the declaration specifiers
/// \param DeclLoc The location of the declarator identifier or invalid if none.
+/// \param SourceTy QualType representing the type as written in source form.
/// \returns The type described by the declaration specifiers. This function
/// never returns null.
QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
SourceLocation DeclLoc,
- bool &isInvalid) {
+ bool &isInvalid, QualType &SourceTy) {
// FIXME: Should move the logic from DeclSpec::Finish to here for validity
// checking.
QualType Result;
-
+ SourceTy = Result;
+
switch (DS.getTypeSpecType()) {
case DeclSpec::TST_void:
Result = Context.VoidTy;
@@ -87,14 +92,28 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
Result = Context.getUnsignedWCharType();
}
break;
+ case DeclSpec::TST_char16:
+ assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified &&
+ "Unknown TSS value");
+ Result = Context.Char16Ty;
+ break;
+ case DeclSpec::TST_char32:
+ assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified &&
+ "Unknown TSS value");
+ Result = Context.Char32Ty;
+ break;
case DeclSpec::TST_unspecified:
// "<proto1,proto2>" is an objc qualified ID with a missing id.
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ,
+ SourceTy = Context.getObjCProtocolListType(QualType(),
+ (ObjCProtocolDecl**)PQ,
+ DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy,
+ (ObjCProtocolDecl**)PQ,
DS.getNumProtocolQualifiers());
break;
}
-
+
// Unspecified typespec defaults to int in C90. However, the C90 grammar
// [C90 6.5] only allows a decl-spec if there was *some* type-specifier,
// type-qualifier, or storage-class-specifier. If not, emit an extwarn.
@@ -125,7 +144,7 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft) {
Diag(DeclLoc, diag::err_missing_type_specifier)
<< DS.getSourceRange();
-
+
// When this occurs in C++ code, often something is very broken with the
// value being declared, poison it as invalid so we don't get chains of
// errors.
@@ -135,8 +154,8 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
<< DS.getSourceRange();
}
}
-
- // FALL THROUGH.
+
+ // FALL THROUGH.
case DeclSpec::TST_int: {
if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) {
switch (DS.getTypeSpecWidth()) {
@@ -175,40 +194,64 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
case DeclSpec::TST_union:
case DeclSpec::TST_struct: {
Decl *D = static_cast<Decl *>(DS.getTypeRep());
- assert(D && "Didn't get a decl for a class/enum/union/struct?");
+ if (!D) {
+ // This can happen in C++ with ambiguous lookups.
+ Result = Context.IntTy;
+ isInvalid = true;
+ break;
+ }
+
assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
DS.getTypeSpecSign() == 0 &&
"Can't handle qualifiers on typedef names yet!");
// TypeQuals handled by caller.
Result = Context.getTypeDeclType(cast<TypeDecl>(D));
-
+
+ // In C++, make an ElaboratedType.
+ if (getLangOptions().CPlusPlus) {
+ TagDecl::TagKind Tag
+ = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType());
+ Result = Context.getElaboratedType(Result, Tag);
+ }
+
if (D->isInvalidDecl())
isInvalid = true;
break;
- }
+ }
case DeclSpec::TST_typename: {
assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
DS.getTypeSpecSign() == 0 &&
"Can't handle qualifiers on typedef names yet!");
- Result = QualType::getFromOpaquePtr(DS.getTypeRep());
+ Result = GetTypeFromParser(DS.getTypeRep());
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so we have
- // this "hack" for now...
- if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType())
- Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(),
- (ObjCProtocolDecl**)PQ,
- DS.getNumProtocolQualifiers());
- else if (Result == Context.getObjCIdType())
- // id<protocol-list>
- Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ,
+ SourceTy = Context.getObjCProtocolListType(Result,
+ (ObjCProtocolDecl**)PQ,
DS.getNumProtocolQualifiers());
- else if (Result == Context.getObjCClassType()) {
+ if (const ObjCInterfaceType *
+ Interface = Result->getAs<ObjCInterfaceType>()) {
+ // It would be nice if protocol qualifiers were only stored with the
+ // ObjCObjectPointerType. Unfortunately, this isn't possible due
+ // to the following typedef idiom (which is uncommon, but allowed):
+ //
+ // typedef Foo<P> T;
+ // static void func() {
+ // Foo<P> *yy;
+ // T *zz;
+ // }
+ Result = Context.getObjCInterfaceType(Interface->getDecl(),
+ (ObjCProtocolDecl**)PQ,
+ DS.getNumProtocolQualifiers());
+ } else if (Result->isObjCIdType())
+ // id<protocol-list>
+ Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy,
+ (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers());
+ else if (Result->isObjCClassType()) {
if (DeclLoc.isInvalid())
DeclLoc = DS.getSourceRange().getBegin();
// Class<protocol-list>
- Diag(DeclLoc, diag::err_qualified_class_unsupported)
- << DS.getSourceRange();
+ Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy,
+ (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers());
} else {
if (DeclLoc.isInvalid())
DeclLoc = DS.getSourceRange().getBegin();
@@ -217,17 +260,18 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
isInvalid = true;
}
}
-
+
// If this is a reference to an invalid typedef, propagate the invalidity.
if (TypedefType *TDT = dyn_cast<TypedefType>(Result))
if (TDT->getDecl()->isInvalidDecl())
isInvalid = true;
-
+
// TypeQuals handled by caller.
break;
}
case DeclSpec::TST_typeofType:
- Result = QualType::getFromOpaquePtr(DS.getTypeRep());
+ // FIXME: Preserve type source info.
+ Result = GetTypeFromParser(DS.getTypeRep());
assert(!Result.isNull() && "Didn't get a type for typeof?");
// TypeQuals handled by caller.
Result = Context.getTypeOfType(Result);
@@ -255,73 +299,75 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
Result = Context.UndeducedAutoTy;
break;
}
-
+
case DeclSpec::TST_error:
Result = Context.IntTy;
isInvalid = true;
break;
}
-
+
// Handle complex types.
if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) {
if (getLangOptions().Freestanding)
Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex);
Result = Context.getComplexType(Result);
}
-
+
assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary &&
"FIXME: imaginary types not supported yet!");
-
+
// See if there are any attributes on the declspec that apply to the type (as
// opposed to the decl).
if (const AttributeList *AL = DS.getAttributes())
ProcessTypeAttributeList(Result, AL);
-
+
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
// Enforce C99 6.7.3p2: "Types other than pointer types derived from object
// or incomplete types shall not be restrict-qualified." C++ also allows
// restrict-qualified references.
- if (TypeQuals & QualType::Restrict) {
+ if (TypeQuals & DeclSpec::TQ_restrict) {
if (Result->isPointerType() || Result->isReferenceType()) {
- QualType EltTy = Result->isPointerType() ?
- Result->getAsPointerType()->getPointeeType() :
- Result->getAsReferenceType()->getPointeeType();
-
+ QualType EltTy = Result->isPointerType() ?
+ Result->getAs<PointerType>()->getPointeeType() :
+ Result->getAs<ReferenceType>()->getPointeeType();
+
// If we have a pointer or reference, the pointee must have an object
// incomplete type.
if (!EltTy->isIncompleteOrObjectType()) {
Diag(DS.getRestrictSpecLoc(),
diag::err_typecheck_invalid_restrict_invalid_pointee)
<< EltTy << DS.getSourceRange();
- TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier.
+ TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier.
}
} else {
Diag(DS.getRestrictSpecLoc(),
diag::err_typecheck_invalid_restrict_not_pointer)
<< Result << DS.getSourceRange();
- TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier.
+ TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier.
}
}
-
+
// Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification
// of a function type includes any type qualifiers, the behavior is
// undefined."
if (Result->isFunctionType() && TypeQuals) {
// Get some location to point at, either the C or V location.
SourceLocation Loc;
- if (TypeQuals & QualType::Const)
+ if (TypeQuals & DeclSpec::TQ_const)
Loc = DS.getConstSpecLoc();
- else {
- assert((TypeQuals & QualType::Volatile) &&
- "Has CV quals but not C or V?");
+ else if (TypeQuals & DeclSpec::TQ_volatile)
Loc = DS.getVolatileSpecLoc();
+ else {
+ assert((TypeQuals & DeclSpec::TQ_restrict) &&
+ "Has CVR quals but not C, V, or R?");
+ Loc = DS.getRestrictSpecLoc();
}
Diag(Loc, diag::warn_typecheck_function_qualifiers)
<< Result << DS.getSourceRange();
}
-
+
// C++ [dcl.ref]p1:
// Cv-qualified references are ill-formed except when the
// cv-qualifiers are introduced through the use of a typedef
@@ -330,19 +376,23 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
// FIXME: Shouldn't we be checking SCS_typedef here?
if (DS.getTypeSpecType() == DeclSpec::TST_typename &&
TypeQuals && Result->isReferenceType()) {
- TypeQuals &= ~QualType::Const;
- TypeQuals &= ~QualType::Volatile;
- }
-
- Result = Result.getQualifiedType(TypeQuals);
+ TypeQuals &= ~DeclSpec::TQ_const;
+ TypeQuals &= ~DeclSpec::TQ_volatile;
+ }
+
+ Qualifiers Quals = Qualifiers::fromCVRMask(TypeQuals);
+ Result = Context.getQualifiedType(Result, Quals);
}
+
+ if (SourceTy.isNull())
+ SourceTy = Result;
return Result;
}
static std::string getPrintableNameForEntity(DeclarationName Entity) {
if (Entity)
return Entity.getAsString();
-
+
return "type name";
}
@@ -361,7 +411,7 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) {
///
/// \returns A suitable pointer type, if there are no
/// errors. Otherwise, returns a NULL type.
-QualType Sema::BuildPointerType(QualType T, unsigned Quals,
+QualType Sema::BuildPointerType(QualType T, unsigned Quals,
SourceLocation Loc, DeclarationName Entity) {
if (T->isReferenceType()) {
// C++ 8.3.2p4: There shall be no ... pointers to references ...
@@ -370,23 +420,25 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals,
return QualType();
}
+ Qualifiers Qs = Qualifiers::fromCVRMask(Quals);
+
// Enforce C99 6.7.3p2: "Types other than pointer types derived from
// object or incomplete types shall not be restrict-qualified."
- if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) {
+ if (Qs.hasRestrict() && !T->isIncompleteOrObjectType()) {
Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
<< T;
- Quals &= ~QualType::Restrict;
+ Qs.removeRestrict();
}
// Build the pointer type.
- return Context.getPointerType(T).getQualifiedType(Quals);
+ return Context.getQualifiedType(Context.getPointerType(T), Qs);
}
/// \brief Build a reference type.
///
/// \param T The type to which we'll be building a reference.
///
-/// \param Quals The cvr-qualifiers to be applied to the reference type.
+/// \param CVR The cvr-qualifiers to be applied to the reference type.
///
/// \param Loc The location of the entity whose type involves this
/// reference type or, if there is no such entity, the location of the
@@ -397,22 +449,23 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals,
///
/// \returns A suitable reference type, if there are no
/// errors. Otherwise, returns a NULL type.
-QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
+QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned CVR,
SourceLocation Loc, DeclarationName Entity) {
+ Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
if (LValueRef) {
- if (const RValueReferenceType *R = T->getAsRValueReferenceType()) {
+ if (const RValueReferenceType *R = T->getAs<RValueReferenceType>()) {
// C++0x [dcl.typedef]p9: If a typedef TD names a type that is a
// reference to a type T, and attempt to create the type "lvalue
// reference to cv TD" creates the type "lvalue reference to T".
// We use the qualifiers (restrict or none) of the original reference,
// not the new ones. This is consistent with GCC.
- return Context.getLValueReferenceType(R->getPointeeType()).
- getQualifiedType(T.getCVRQualifiers());
+ QualType LVRT = Context.getLValueReferenceType(R->getPointeeType());
+ return Context.getQualifiedType(LVRT, T.getQualifiers());
}
}
if (T->isReferenceType()) {
// C++ [dcl.ref]p4: There shall be no references to references.
- //
+ //
// According to C++ DR 106, references to references are only
// diagnosed when they are written directly (e.g., "int & &"),
// but not when they happen via a typedef:
@@ -420,7 +473,7 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
// typedef int& intref;
// typedef intref& intref2;
//
- // Parser::ParserDeclaratorInternal diagnoses the case where
+ // Parser::ParseDeclaratorInternal diagnoses the case where
// references are written directly; here, we handle the
// collapsing of references-to-references as described in C++
// DR 106 and amended by C++ DR 540.
@@ -428,7 +481,7 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
}
// C++ [dcl.ref]p1:
- // A declarator that specifies the type “reference to cv void”
+ // A declarator that specifies the type "reference to cv void"
// is ill-formed.
if (T->isVoidType()) {
Diag(Loc, diag::err_reference_to_void);
@@ -437,10 +490,10 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
// Enforce C99 6.7.3p2: "Types other than pointer types derived from
// object or incomplete types shall not be restrict-qualified."
- if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) {
+ if (Quals.hasRestrict() && !T->isIncompleteOrObjectType()) {
Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
<< T;
- Quals &= ~QualType::Restrict;
+ Quals.removeRestrict();
}
// C++ [dcl.ref]p1:
@@ -452,13 +505,13 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
// We diagnose extraneous cv-qualifiers for the non-typedef,
// non-template type argument case within the parser. Here, we just
// ignore any extraneous cv-qualifiers.
- Quals &= ~QualType::Const;
- Quals &= ~QualType::Volatile;
+ Quals.removeConst();
+ Quals.removeVolatile();
// Handle restrict on references.
if (LValueRef)
- return Context.getLValueReferenceType(T).getQualifiedType(Quals);
- return Context.getRValueReferenceType(T).getQualifiedType(Quals);
+ return Context.getQualifiedType(Context.getLValueReferenceType(T), Quals);
+ return Context.getQualifiedType(Context.getRValueReferenceType(T), Quals);
}
/// \brief Build an array type.
@@ -466,8 +519,8 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
/// \param T The type of each element in the array.
///
/// \param ASM C99 array size modifier (e.g., '*', 'static').
-///
-/// \param ArraySize Expression describing the size of the array.
+///
+/// \param ArraySize Expression describing the size of the array.
///
/// \param Quals The cvr-qualifiers to be applied to the array's
/// element type.
@@ -483,10 +536,12 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
/// returns a NULL type.
QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
Expr *ArraySize, unsigned Quals,
- SourceLocation Loc, DeclarationName Entity) {
- // C99 6.7.5.2p1: If the element type is an incomplete or function type,
+ SourceRange Brackets, DeclarationName Entity) {
+
+ SourceLocation Loc = Brackets.getBegin();
+ // C99 6.7.5.2p1: If the element type is an incomplete or function type,
// reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
- if (RequireCompleteType(Loc, T,
+ if (RequireCompleteType(Loc, T,
diag::err_illegal_decl_array_incomplete_type))
return QualType();
@@ -495,21 +550,21 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
<< getPrintableNameForEntity(Entity);
return QualType();
}
-
+
// C++ 8.3.2p4: There shall be no ... arrays of references ...
if (T->isReferenceType()) {
Diag(Loc, diag::err_illegal_decl_array_of_references)
<< getPrintableNameForEntity(Entity);
return QualType();
- }
+ }
if (Context.getCanonicalType(T) == Context.UndeducedAutoTy) {
- Diag(Loc, diag::err_illegal_decl_array_of_auto)
+ Diag(Loc, diag::err_illegal_decl_array_of_auto)
<< getPrintableNameForEntity(Entity);
return QualType();
}
-
- if (const RecordType *EltTy = T->getAsRecordType()) {
+
+ if (const RecordType *EltTy = T->getAs<RecordType>()) {
// If the element type is a struct or union that contains a variadic
// array, accept it as a GNU extension: C99 6.7.2.1p2.
if (EltTy->getDecl()->hasFlexibleArrayMember())
@@ -518,7 +573,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
Diag(Loc, diag::err_objc_array_of_interfaces) << T;
return QualType();
}
-
+
// C99 6.7.5.2p1: The size expression shall have integer type.
if (ArraySize && !ArraySize->isTypeDependent() &&
!ArraySize->getType()->isIntegerType()) {
@@ -530,16 +585,16 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
llvm::APSInt ConstVal(32);
if (!ArraySize) {
if (ASM == ArrayType::Star)
- T = Context.getVariableArrayType(T, 0, ASM, Quals);
+ T = Context.getVariableArrayType(T, 0, ASM, Quals, Brackets);
else
T = Context.getIncompleteArrayType(T, ASM, Quals);
} else if (ArraySize->isValueDependent()) {
- T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals);
+ T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets);
} else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
(!T->isDependentType() && !T->isConstantSizeType())) {
// Per C99, a variable array is an array with either a non-constant
// size or an element type that has a non-constant-size
- T = Context.getVariableArrayType(T, ArraySize, ASM, Quals);
+ T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets);
} else {
// C99 6.7.5.2p1: If the expression is a constant expression, it shall
// have a value greater than zero.
@@ -554,17 +609,20 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size)
<< ArraySize->getSourceRange();
}
- }
- T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
+ }
+ T = Context.getConstantArrayWithExprType(T, ConstVal, ArraySize,
+ ASM, Quals, Brackets);
}
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
if (!getLangOptions().C99) {
- if (ArraySize && !ArraySize->isTypeDependent() &&
- !ArraySize->isValueDependent() &&
+ if (ArraySize && !ArraySize->isTypeDependent() &&
+ !ArraySize->isValueDependent() &&
!ArraySize->isIntegerConstantExpr(Context))
- Diag(Loc, diag::ext_vla);
+ Diag(Loc, getLangOptions().CPlusPlus? diag::err_vla_cxx : diag::ext_vla);
else if (ASM != ArrayType::Normal || Quals != 0)
- Diag(Loc, diag::ext_c99_array_usage);
+ Diag(Loc,
+ getLangOptions().CPlusPlus? diag::err_c99_array_usage_cxx
+ : diag::ext_c99_array_usage);
}
return T;
@@ -573,14 +631,14 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
/// \brief Build an ext-vector type.
///
/// Run the required checks for the extended vector type.
-QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize,
+QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize,
SourceLocation AttrLoc) {
Expr *Arg = (Expr *)ArraySize.get();
// unlike gcc's vector_size attribute, we do not allow vectors to be defined
// in conjunction with complex types (pointers, arrays, functions, etc.).
- if (!T->isDependentType() &&
+ if (!T->isDependentType() &&
!T->isIntegerType() && !T->isRealFloatingType()) {
Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T;
return QualType();
@@ -593,25 +651,25 @@ QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize,
<< "ext_vector_type" << Arg->getSourceRange();
return QualType();
}
-
- // unlike gcc's vector_size attribute, the size is specified as the
+
+ // unlike gcc's vector_size attribute, the size is specified as the
// number of elements, not the number of bytes.
- unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue());
-
+ unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue());
+
if (vectorSize == 0) {
Diag(AttrLoc, diag::err_attribute_zero_size)
<< Arg->getSourceRange();
return QualType();
}
-
+
if (!T->isDependentType())
return Context.getExtVectorType(T, vectorSize);
- }
-
- return Context.getDependentSizedExtVectorType(T, ArraySize.takeAs<Expr>(),
+ }
+
+ return Context.getDependentSizedExtVectorType(T, ArraySize.takeAs<Expr>(),
AttrLoc);
}
-
+
/// \brief Build a function type.
///
/// This routine checks the function type according to C++ rules and
@@ -642,7 +700,7 @@ QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize,
/// \returns A suitable function type, if there are no
/// errors. Otherwise, returns a NULL type.
QualType Sema::BuildFunctionType(QualType T,
- QualType *ParamTypes,
+ QualType *ParamTypes,
unsigned NumParamTypes,
bool Variadic, unsigned Quals,
SourceLocation Loc, DeclarationName Entity) {
@@ -650,7 +708,7 @@ QualType Sema::BuildFunctionType(QualType T,
Diag(Loc, diag::err_func_returning_array_function) << T;
return QualType();
}
-
+
bool Invalid = false;
for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
QualType ParamType = adjustParameterType(ParamTypes[Idx]);
@@ -659,29 +717,31 @@ QualType Sema::BuildFunctionType(QualType T,
Invalid = true;
}
- ParamTypes[Idx] = ParamType;
+ ParamTypes[Idx] = adjustFunctionParamType(ParamType);
}
if (Invalid)
return QualType();
- return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic,
+ return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic,
Quals);
}
-
+
/// \brief Build a member pointer type \c T Class::*.
///
/// \param T the type to which the member pointer refers.
/// \param Class the class type into which the member pointer points.
-/// \param Quals Qualifiers applied to the member pointer type
+/// \param CVR Qualifiers applied to the member pointer type
/// \param Loc the location where this type begins
/// \param Entity the name of the entity that will have this member pointer type
///
/// \returns a member pointer type, if successful, or a NULL type if there was
/// an error.
-QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
- unsigned Quals, SourceLocation Loc,
+QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
+ unsigned CVR, SourceLocation Loc,
DeclarationName Entity) {
+ Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
+
// Verify that we're not building a pointer to pointer to function with
// exception specification.
if (CheckDistantExceptionSpec(T)) {
@@ -711,13 +771,13 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
// Enforce C99 6.7.3p2: "Types other than pointer types derived from
// object or incomplete types shall not be restrict-qualified."
- if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) {
+ if (Quals.hasRestrict() && !T->isIncompleteOrObjectType()) {
Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
<< T;
// FIXME: If we're doing this as part of template instantiation,
// we should return immediately.
- Quals &= ~QualType::Restrict;
+ Quals.removeRestrict();
}
if (!Class->isDependentType() && !Class->isRecordType()) {
@@ -725,15 +785,15 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
return QualType();
}
- return Context.getMemberPointerType(T, Class.getTypePtr())
- .getQualifiedType(Quals);
+ return Context.getQualifiedType(
+ Context.getMemberPointerType(T, Class.getTypePtr()), Quals);
}
-
+
/// \brief Build a block pointer type.
///
/// \param T The type to which we'll be building a block pointer.
///
-/// \param Quals The cvr-qualifiers to be applied to the block pointer type.
+/// \param CVR The cvr-qualifiers to be applied to the block pointer type.
///
/// \param Loc The location of the entity whose type involves this
/// block pointer type or, if there is no such entity, the location of the
@@ -744,15 +804,28 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
///
/// \returns A suitable block pointer type, if there are no
/// errors. Otherwise, returns a NULL type.
-QualType Sema::BuildBlockPointerType(QualType T, unsigned Quals,
- SourceLocation Loc,
+QualType Sema::BuildBlockPointerType(QualType T, unsigned CVR,
+ SourceLocation Loc,
DeclarationName Entity) {
- if (!T.getTypePtr()->isFunctionType()) {
+ if (!T->isFunctionType()) {
Diag(Loc, diag::err_nonfunction_block_type);
return QualType();
}
-
- return Context.getBlockPointerType(T).getQualifiedType(Quals);
+
+ Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
+ return Context.getQualifiedType(Context.getBlockPointerType(T), Quals);
+}
+
+QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) {
+ QualType QT = QualType::getFromOpaquePtr(Ty);
+ DeclaratorInfo *DI = 0;
+ if (LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) {
+ QT = LIT->getType();
+ DI = LIT->getDeclaratorInfo();
+ }
+
+ if (DInfo) *DInfo = DI;
+ return QT;
}
/// GetTypeForDeclarator - Convert the type for the specified
@@ -762,7 +835,8 @@ QualType Sema::BuildBlockPointerType(QualType T, unsigned Quals,
/// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq
/// owns the declaration of a type (e.g., the definition of a struct
/// type), then *OwnedDecl will receive the owned declaration.
-QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
+QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
+ DeclaratorInfo **DInfo, unsigned Skip,
TagDecl **OwnedDecl) {
bool OmittedReturnType = false;
@@ -782,10 +856,15 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
// Determine the type of the declarator. Not all forms of declarator
// have a type.
QualType T;
+ // The QualType referring to the type as written in source code. We can't use
+ // T because it can change due to semantic analysis.
+ QualType SourceTy;
+
switch (D.getKind()) {
case Declarator::DK_Abstract:
case Declarator::DK_Normal:
- case Declarator::DK_Operator: {
+ case Declarator::DK_Operator:
+ case Declarator::DK_TemplateId: {
const DeclSpec &DS = D.getDeclSpec();
if (OmittedReturnType) {
// We default to a dependent type initially. Can be modified by
@@ -793,7 +872,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
T = Context.DependentTy;
} else {
bool isInvalid = false;
- T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid);
+ T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid, SourceTy);
if (isInvalid)
D.setInvalidType(true);
else if (OwnedDecl && DS.isTypeSpecOwned())
@@ -811,10 +890,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
T = Context.VoidTy;
break;
}
+
+ if (SourceTy.isNull())
+ SourceTy = T;
if (T == Context.UndeducedAutoTy) {
int Error = -1;
-
+
switch (D.getContext()) {
case Declarator::KNRTypeListContext:
assert(0 && "K&R type lists aren't allowed in C++");
@@ -828,7 +910,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
case TagDecl::TK_struct: Error = 1; /* Struct member */ break;
case TagDecl::TK_union: Error = 2; /* Union member */ break;
case TagDecl::TK_class: Error = 3; /* Class member */ break;
- }
+ }
break;
case Declarator::CXXCatchContext:
Error = 4; // Exception declaration
@@ -854,12 +936,14 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
D.setInvalidType(true);
}
}
-
+
// The name we're declaring, if any.
DeclarationName Name;
if (D.getIdentifier())
Name = D.getIdentifier();
+ bool ShouldBuildInfo = DInfo != 0;
+
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :).
@@ -868,14 +952,29 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
switch (DeclType.Kind) {
default: assert(0 && "Unknown decltype!");
case DeclaratorChunk::BlockPointer:
+ if (ShouldBuildInfo) {
+ if (SourceTy->isFunctionType())
+ SourceTy
+ = Context.getQualifiedType(Context.getBlockPointerType(SourceTy),
+ Qualifiers::fromCVRMask(DeclType.Cls.TypeQuals));
+ else
+ // If not function type Context::getBlockPointerType asserts,
+ // so just give up.
+ ShouldBuildInfo = false;
+ }
+
// If blocks are disabled, emit an error.
if (!LangOpts.Blocks)
Diag(DeclType.Loc, diag::err_blocks_disable);
-
- T = BuildBlockPointerType(T, DeclType.Cls.TypeQuals, D.getIdentifierLoc(),
+
+ T = BuildBlockPointerType(T, DeclType.Cls.TypeQuals, D.getIdentifierLoc(),
Name);
break;
case DeclaratorChunk::Pointer:
+ //FIXME: Use ObjCObjectPointer for info when appropriate.
+ if (ShouldBuildInfo)
+ SourceTy = Context.getQualifiedType(Context.getPointerType(SourceTy),
+ Qualifiers::fromCVRMask(DeclType.Ptr.TypeQuals));
// Verify that we're not building a pointer to pointer to function with
// exception specification.
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -883,9 +982,27 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
D.setInvalidType(true);
// Build the type anyway.
}
+ if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) {
+ const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>();
+ T = Context.getObjCObjectPointerType(T,
+ (ObjCProtocolDecl **)OIT->qual_begin(),
+ OIT->getNumProtocols());
+ break;
+ }
T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
break;
- case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Reference: {
+ Qualifiers Quals;
+ if (DeclType.Ref.HasRestrict) Quals.addRestrict();
+
+ if (ShouldBuildInfo) {
+ if (DeclType.Ref.LValueRef)
+ SourceTy = Context.getLValueReferenceType(SourceTy);
+ else
+ SourceTy = Context.getRValueReferenceType(SourceTy);
+ SourceTy = Context.getQualifiedType(SourceTy, Quals);
+ }
+
// Verify that we're not building a reference to pointer to function with
// exception specification.
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -893,11 +1010,16 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
D.setInvalidType(true);
// Build the type anyway.
}
- T = BuildReferenceType(T, DeclType.Ref.LValueRef,
- DeclType.Ref.HasRestrict ? QualType::Restrict : 0,
+ T = BuildReferenceType(T, DeclType.Ref.LValueRef, Quals,
DeclType.Loc, Name);
break;
+ }
case DeclaratorChunk::Array: {
+ if (ShouldBuildInfo)
+ // We just need to get an array type, the exact type doesn't matter.
+ SourceTy = Context.getIncompleteArrayType(SourceTy, ArrayType::Normal,
+ DeclType.Arr.TypeQuals);
+
// Verify that we're not building an array of pointers to function with
// exception specification.
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -923,10 +1045,30 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
ASM = ArrayType::Normal;
D.setInvalidType(true);
}
- T = BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, DeclType.Loc, Name);
+ T = BuildArrayType(T, ASM, ArraySize,
+ Qualifiers::fromCVRMask(ATI.TypeQuals),
+ SourceRange(DeclType.Loc, DeclType.EndLoc), Name);
break;
}
case DeclaratorChunk::Function: {
+ if (ShouldBuildInfo) {
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+ ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
+ if (Param) {
+ QualType ArgTy = adjustFunctionParamType(Param->getType());
+
+ ArgTys.push_back(ArgTy);
+ }
+ }
+ SourceTy = Context.getFunctionType(SourceTy, ArgTys.data(),
+ ArgTys.size(),
+ FTI.isVariadic,
+ FTI.TypeQuals);
+ }
+
// If the function declarator has a prototype (i.e. it is not () and
// does not have a K&R-style identifier list), then the arguments are part
// of the type, otherwise the argument list is ().
@@ -960,8 +1102,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
// function takes no arguments.
llvm::SmallVector<QualType, 4> Exceptions;
Exceptions.reserve(FTI.NumExceptions);
- for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
- QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
+ for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
+ // FIXME: Preserve type source info.
+ QualType ET = GetTypeFromParser(FTI.Exceptions[ei].Ty);
// Check that the type is valid for an exception spec, and drop it
// if not.
if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
@@ -993,12 +1136,12 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
}
} else if (FTI.ArgInfo[0].Param == 0) {
// C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition.
- Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
+ Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
} else {
// Otherwise, we have a function with an argument list that is
// potentially variadic.
llvm::SmallVector<QualType, 16> ArgTys;
-
+
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
ParmVarDecl *Param =
cast<ParmVarDecl>(FTI.ArgInfo[i].Param.getAs<Decl>());
@@ -1027,28 +1170,29 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
Param->setType(ArgTy);
} else {
// Reject, but continue to parse 'float(const void)'.
- if (ArgTy.getCVRQualifiers())
+ if (ArgTy.hasQualifiers())
Diag(DeclType.Loc, diag::err_void_param_qualified);
-
+
// Do not add 'void' to the ArgTys list.
break;
}
} else if (!FTI.hasPrototype) {
if (ArgTy->isPromotableIntegerType()) {
- ArgTy = Context.IntTy;
- } else if (const BuiltinType* BTy = ArgTy->getAsBuiltinType()) {
+ ArgTy = Context.getPromotedIntegerType(ArgTy);
+ } else if (const BuiltinType* BTy = ArgTy->getAs<BuiltinType>()) {
if (BTy->getKind() == BuiltinType::Float)
ArgTy = Context.DoubleTy;
}
}
-
- ArgTys.push_back(ArgTy);
+
+ ArgTys.push_back(adjustFunctionParamType(ArgTy));
}
llvm::SmallVector<QualType, 4> Exceptions;
Exceptions.reserve(FTI.NumExceptions);
- for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
- QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
+ for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
+ // FIXME: Preserve type source info.
+ QualType ET = GetTypeFromParser(FTI.Exceptions[ei].Ty);
// Check that the type is valid for an exception spec, and drop it if
// not.
if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
@@ -1074,11 +1218,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
// The scope spec must refer to a class, or be dependent.
QualType ClsType;
if (isDependentScopeSpecifier(DeclType.Mem.Scope())) {
- NestedNameSpecifier *NNS
+ NestedNameSpecifier *NNS
= (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep();
assert(NNS->getAsType() && "Nested-name-specifier must name a type");
ClsType = QualType(NNS->getAsType(), 0);
- } else if (CXXRecordDecl *RD
+ } else if (CXXRecordDecl *RD
= dyn_cast_or_null<CXXRecordDecl>(
computeDeclContext(DeclType.Mem.Scope()))) {
ClsType = Context.getTagDeclType(RD);
@@ -1090,6 +1234,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
D.setInvalidType(true);
}
+ if (ShouldBuildInfo) {
+ QualType cls = !ClsType.isNull() ? ClsType : Context.IntTy;
+ SourceTy = Context.getQualifiedType(
+ Context.getMemberPointerType(SourceTy, cls.getTypePtr()),
+ Qualifiers::fromCVRMask(DeclType.Mem.TypeQuals));
+ }
+
if (!ClsType.isNull())
T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals,
DeclType.Loc, D.getIdentifier());
@@ -1111,7 +1262,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
}
if (getLangOptions().CPlusPlus && T->isFunctionType()) {
- const FunctionProtoType *FnTy = T->getAsFunctionProtoType();
+ const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>();
assert(FnTy && "Why oh why is there not a FunctionProtoType here ?");
// C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type
@@ -1122,7 +1273,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
((D.getContext() != Declarator::MemberContext &&
(!D.getCXXScopeSpec().isSet() ||
- !computeDeclContext(D.getCXXScopeSpec())->isRecord())) ||
+ !computeDeclContext(D.getCXXScopeSpec(), /*FIXME:*/true)
+ ->isRecord())) ||
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
if (D.isFunctionDeclarator())
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
@@ -1135,103 +1287,130 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
FnTy->getNumArgs(), FnTy->isVariadic(), 0);
}
}
-
+
// If there were any type attributes applied to the decl itself (not the
// type, apply the type attribute to the type!)
if (const AttributeList *Attrs = D.getAttributes())
ProcessTypeAttributeList(T, Attrs);
-
+
+ if (ShouldBuildInfo)
+ *DInfo = GetDeclaratorInfoForDeclarator(D, SourceTy, Skip);
+
return T;
}
-/// CheckSpecifiedExceptionType - Check if the given type is valid in an
-/// exception specification. Incomplete types, or pointers to incomplete types
-/// other than void are not allowed.
-bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
- // FIXME: This may not correctly work with the fix for core issue 437,
- // where a class's own type is considered complete within its body.
-
- // C++ 15.4p2: A type denoted in an exception-specification shall not denote
- // an incomplete type.
- if (T->isIncompleteType())
- return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
- << Range << T << /*direct*/0;
-
- // C++ 15.4p2: A type denoted in an exception-specification shall not denote
- // an incomplete type a pointer or reference to an incomplete type, other
- // than (cv) void*.
- int kind;
- if (const PointerType* IT = T->getAsPointerType()) {
- T = IT->getPointeeType();
- kind = 1;
- } else if (const ReferenceType* IT = T->getAsReferenceType()) {
- T = IT->getPointeeType();
- kind = 2;
- } else
- return false;
+static void FillTypeSpecLoc(TypeLoc TSL, const DeclSpec &DS) {
+ if (TSL.isNull()) return;
- if (T->isIncompleteType() && !T->isVoidType())
- return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
- << Range << T << /*indirect*/kind;
+ if (TypedefLoc *TL = dyn_cast<TypedefLoc>(&TSL)) {
+ TL->setNameLoc(DS.getTypeSpecTypeLoc());
- return false;
-}
+ } else if (ObjCInterfaceLoc *TL = dyn_cast<ObjCInterfaceLoc>(&TSL)) {
+ TL->setNameLoc(DS.getTypeSpecTypeLoc());
-/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
-/// to member to a function with an exception specification. This means that
-/// it is invalid to add another level of indirection.
-bool Sema::CheckDistantExceptionSpec(QualType T) {
- if (const PointerType *PT = T->getAsPointerType())
- T = PT->getPointeeType();
- else if (const MemberPointerType *PT = T->getAsMemberPointerType())
- T = PT->getPointeeType();
- else
- return false;
+ } else if (ObjCProtocolListLoc *PLL = dyn_cast<ObjCProtocolListLoc>(&TSL)) {
+ assert(PLL->getNumProtocols() == DS.getNumProtocolQualifiers());
+ PLL->setLAngleLoc(DS.getProtocolLAngleLoc());
+ PLL->setRAngleLoc(DS.getSourceRange().getEnd());
+ for (unsigned i = 0; i != DS.getNumProtocolQualifiers(); ++i)
+ PLL->setProtocolLoc(i, DS.getProtocolLocs()[i]);
+ FillTypeSpecLoc(PLL->getBaseTypeLoc(), DS);
- const FunctionProtoType *FnT = T->getAsFunctionProtoType();
- if (!FnT)
- return false;
-
- return FnT->hasExceptionSpec();
+ } else {
+ //FIXME: Other typespecs.
+ DefaultTypeSpecLoc &DTL = cast<DefaultTypeSpecLoc>(TSL);
+ DTL.setStartLoc(DS.getSourceRange().getBegin());
+ }
}
-/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
-/// exception specifications. Exception specifications are equivalent if
-/// they allow exactly the same set of exception types. It does not matter how
-/// that is achieved. See C++ [except.spec]p2.
-bool Sema::CheckEquivalentExceptionSpec(
- const FunctionProtoType *Old, SourceLocation OldLoc,
- const FunctionProtoType *New, SourceLocation NewLoc) {
- bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
- bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
- if (OldAny && NewAny)
- return false;
- if (OldAny || NewAny) {
- Diag(NewLoc, diag::err_mismatched_exception_spec);
- Diag(OldLoc, diag::note_previous_declaration);
- return true;
- }
+/// \brief Create and instantiate a DeclaratorInfo with type source information.
+///
+/// \param T QualType referring to the type as written in source code.
+DeclaratorInfo *
+Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, unsigned Skip) {
+ DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T);
+ TypeLoc CurrTL = DInfo->getTypeLoc();
- bool Success = true;
- // Both have a definite exception spec. Collect the first set, then compare
- // to the second.
- llvm::SmallPtrSet<const Type*, 8> Types;
- for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
- E = Old->exception_end(); I != E; ++I)
- Types.insert(Context.getCanonicalType(*I).getTypePtr());
+ for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) {
+ assert(!CurrTL.isNull());
- for (FunctionProtoType::exception_iterator I = New->exception_begin(),
- E = New->exception_end(); I != E && Success; ++I)
- Success = Types.erase(Context.getCanonicalType(*I).getTypePtr());
+ DeclaratorChunk &DeclType = D.getTypeObject(i);
+ switch (DeclType.Kind) {
+ default: assert(0 && "Unknown decltype!");
+ case DeclaratorChunk::BlockPointer: {
+ BlockPointerLoc &BPL = cast<BlockPointerLoc>(CurrTL);
+ BPL.setCaretLoc(DeclType.Loc);
+ break;
+ }
+ case DeclaratorChunk::Pointer: {
+ //FIXME: ObjCObject pointers.
+ PointerLoc &PL = cast<PointerLoc>(CurrTL);
+ PL.setStarLoc(DeclType.Loc);
+ break;
+ }
+ case DeclaratorChunk::Reference: {
+ ReferenceLoc &RL = cast<ReferenceLoc>(CurrTL);
+ RL.setAmpLoc(DeclType.Loc);
+ break;
+ }
+ case DeclaratorChunk::Array: {
+ DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr;
+ ArrayLoc &AL = cast<ArrayLoc>(CurrTL);
+ AL.setLBracketLoc(DeclType.Loc);
+ AL.setRBracketLoc(DeclType.EndLoc);
+ AL.setSizeExpr(static_cast<Expr*>(ATI.NumElts));
+ //FIXME: Star location for [*].
+ break;
+ }
+ case DeclaratorChunk::Function: {
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ FunctionLoc &FL = cast<FunctionLoc>(CurrTL);
+ FL.setLParenLoc(DeclType.Loc);
+ FL.setRParenLoc(DeclType.EndLoc);
+ for (unsigned i = 0, e = FTI.NumArgs, tpi = 0; i != e; ++i) {
+ ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
+ if (Param) {
+ assert(tpi < FL.getNumArgs());
+ FL.setArg(tpi++, Param);
+ }
+ }
+ break;
+ //FIXME: Exception specs.
+ }
+ case DeclaratorChunk::MemberPointer: {
+ MemberPointerLoc &MPL = cast<MemberPointerLoc>(CurrTL);
+ MPL.setStarLoc(DeclType.Loc);
+ //FIXME: Class location.
+ break;
+ }
- Success = Success && Types.empty();
+ }
- if (Success) {
- return false;
+ CurrTL = CurrTL.getNextTypeLoc();
}
- Diag(NewLoc, diag::err_mismatched_exception_spec);
- Diag(OldLoc, diag::note_previous_declaration);
- return true;
+
+ FillTypeSpecLoc(CurrTL, D.getDeclSpec());
+
+ return DInfo;
+}
+
+/// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo.
+QualType Sema::CreateLocInfoType(QualType T, DeclaratorInfo *DInfo) {
+ // FIXME: LocInfoTypes are "transient", only needed for passing to/from Parser
+ // and Sema during declaration parsing. Try deallocating/caching them when
+ // it's appropriate, instead of allocating them and keeping them around.
+ LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType), 8);
+ new (LocT) LocInfoType(T, DInfo);
+ assert(LocT->getTypeClass() != T->getTypeClass() &&
+ "LocInfoType's TypeClass conflicts with an existing Type class");
+ return QualType(LocT, 0);
+}
+
+void LocInfoType::getAsStringInternal(std::string &Str,
+ const PrintingPolicy &Policy) const {
+ assert(false && "LocInfoType leaked into the type system; an opaque TypeTy*"
+ " was used directly instead of getting the QualType through"
+ " GetTypeFromParser");
}
/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
@@ -1240,7 +1419,7 @@ QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
ObjCMethodDecl *MDecl = cast<ObjCMethodDecl>(D.getAs<Decl>());
QualType T = MDecl->getResultType();
llvm::SmallVector<QualType, 16> ArgTys;
-
+
// Add the first two invisible argument types for self and _cmd.
if (MDecl->isInstanceMethod()) {
QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface());
@@ -1249,7 +1428,7 @@ QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
} else
ArgTys.push_back(Context.getObjCIdType());
ArgTys.push_back(Context.getObjCSelType());
-
+
for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(),
E = MDecl->param_end(); PI != E; ++PI) {
QualType ArgTy = (*PI)->getType();
@@ -1271,16 +1450,16 @@ QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
/// be called in a loop that successively "unwraps" pointer and
/// pointer-to-member types to compare them at each level.
bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) {
- const PointerType *T1PtrType = T1->getAsPointerType(),
- *T2PtrType = T2->getAsPointerType();
+ const PointerType *T1PtrType = T1->getAs<PointerType>(),
+ *T2PtrType = T2->getAs<PointerType>();
if (T1PtrType && T2PtrType) {
T1 = T1PtrType->getPointeeType();
T2 = T2PtrType->getPointeeType();
return true;
}
- const MemberPointerType *T1MPType = T1->getAsMemberPointerType(),
- *T2MPType = T2->getAsMemberPointerType();
+ const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(),
+ *T2MPType = T2->getAs<MemberPointerType>();
if (T1MPType && T2MPType &&
Context.getCanonicalType(T1MPType->getClass()) ==
Context.getCanonicalType(T2MPType->getClass())) {
@@ -1295,9 +1474,10 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// C99 6.7.6: Type names have no identifier. This is already validated by
// the parser.
assert(D.getIdentifier() == 0 && "Type name should have no identifier!");
-
+
+ DeclaratorInfo *DInfo = 0;
TagDecl *OwnedTag = 0;
- QualType T = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedTag);
+ QualType T = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag);
if (D.isInvalidType())
return true;
@@ -1314,6 +1494,9 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
<< Context.getTypeDeclType(OwnedTag);
}
+ if (DInfo)
+ T = CreateLocInfoType(T, DInfo);
+
return T.getAsOpaquePtr();
}
@@ -1326,8 +1509,9 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the
/// specified type. The attribute contains 1 argument, the id of the address
/// space for the type.
-static void HandleAddressSpaceTypeAttribute(QualType &Type,
+static void HandleAddressSpaceTypeAttribute(QualType &Type,
const AttributeList &Attr, Sema &S){
+
// If this type is already address space qualified, reject it.
// Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers
// for two or more different address spaces."
@@ -1335,7 +1519,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers);
return;
}
-
+
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
@@ -1349,43 +1533,76 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
return;
}
- unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue());
+ // Bounds checking.
+ if (addrSpace.isSigned()) {
+ if (addrSpace.isNegative()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative)
+ << ASArgExpr->getSourceRange();
+ return;
+ }
+ addrSpace.setIsSigned(false);
+ }
+ llvm::APSInt max(addrSpace.getBitWidth());
+ max = Qualifiers::MaxAddressSpace;
+ if (addrSpace > max) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
+ << Qualifiers::MaxAddressSpace << ASArgExpr->getSourceRange();
+ return;
+ }
+
+ unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue());
Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
}
/// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the
/// specified type. The attribute contains 1 argument, weak or strong.
-static void HandleObjCGCTypeAttribute(QualType &Type,
+static void HandleObjCGCTypeAttribute(QualType &Type,
const AttributeList &Attr, Sema &S) {
- if (Type.getObjCGCAttr() != QualType::GCNone) {
+ if (Type.getObjCGCAttr() != Qualifiers::GCNone) {
S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc);
return;
}
-
+
// Check the attribute arguments.
- if (!Attr.getParameterName()) {
+ if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "objc_gc" << 1;
return;
}
- QualType::GCAttrTypes GCAttr;
+ Qualifiers::GC GCAttr;
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
- if (Attr.getParameterName()->isStr("weak"))
- GCAttr = QualType::Weak;
+ if (Attr.getParameterName()->isStr("weak"))
+ GCAttr = Qualifiers::Weak;
else if (Attr.getParameterName()->isStr("strong"))
- GCAttr = QualType::Strong;
+ GCAttr = Qualifiers::Strong;
else {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
<< "objc_gc" << Attr.getParameterName();
return;
}
-
+
Type = S.Context.getObjCGCQualType(Type, GCAttr);
}
+/// HandleNoReturnTypeAttribute - Process the noreturn attribute on the
+/// specified type. The attribute contains 0 arguments.
+static void HandleNoReturnTypeAttribute(QualType &Type,
+ const AttributeList &Attr, Sema &S) {
+ if (Attr.getNumArgs() != 0)
+ return;
+
+ // We only apply this to a pointer to function or a pointer to block.
+ if (!Type->isFunctionPointerType()
+ && !Type->isBlockPointerType()
+ && !Type->isFunctionType())
+ return;
+
+ Type = S.Context.getNoReturnType(Type);
+}
+
void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
// Scan through and apply attributes to this type where it makes sense. Some
// attributes (such as __address_space__, __vector_size__, etc) apply to the
@@ -1402,11 +1619,14 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
case AttributeList::AT_objc_gc:
HandleObjCGCTypeAttribute(Result, *AL, *this);
break;
+ case AttributeList::AT_noreturn:
+ HandleNoReturnTypeAttribute(Result, *AL, *this);
+ break;
}
}
}
-/// @brief Ensure that the type T is a complete type.
+/// @brief Ensure that the type T is a complete type.
///
/// This routine checks whether the type @p T is complete in any
/// context where a complete type is required. If @p T is a complete
@@ -1421,31 +1641,21 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
///
/// @param T The type that this routine is examining for completeness.
///
-/// @param diag The diagnostic value (e.g.,
-/// @c diag::err_typecheck_decl_incomplete_type) that will be used
-/// for the error message if @p T is incomplete.
-///
-/// @param Range1 An optional range in the source code that will be a
-/// part of the "incomplete type" error message.
-///
-/// @param Range2 An optional range in the source code that will be a
-/// part of the "incomplete type" error message.
-///
-/// @param PrintType If non-NULL, the type that should be printed
-/// instead of @p T. This parameter should be used when the type that
-/// we're checking for incompleteness isn't the type that should be
-/// displayed to the user, e.g., when T is a type and PrintType is a
-/// pointer to T.
+/// @param PD The partial diagnostic that will be printed out if T is not a
+/// complete type.
///
/// @returns @c true if @p T is incomplete and a diagnostic was emitted,
/// @c false otherwise.
-bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
- SourceRange Range1, SourceRange Range2,
- QualType PrintType) {
+bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ std::pair<SourceLocation,
+ PartialDiagnostic> Note) {
+ unsigned diag = PD.getDiagID();
+
// FIXME: Add this assertion to help us flush out problems with
// checking for dependent types and type-dependent expressions.
//
- // assert(!T->isDependentType() &&
+ // assert(!T->isDependentType() &&
// "Can't ask whether a dependent type is complete");
// If we have a complete type, we're done.
@@ -1454,49 +1664,54 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
// If we have a class template specialization or a class member of a
// class template specialization, try to instantiate it.
- if (const RecordType *Record = T->getAsRecordType()) {
+ if (const RecordType *Record = T->getAs<RecordType>()) {
if (ClassTemplateSpecializationDecl *ClassTemplateSpec
= dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
- // Update the class template specialization's location to
- // refer to the point of instantiation.
if (Loc.isValid())
- ClassTemplateSpec->setLocation(Loc);
+ ClassTemplateSpec->setPointOfInstantiation(Loc);
return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
- /*ExplicitInstantiation=*/false);
+ TSK_ImplicitInstantiation,
+ /*Complain=*/diag != 0);
}
- } else if (CXXRecordDecl *Rec
+ } else if (CXXRecordDecl *Rec
= dyn_cast<CXXRecordDecl>(Record->getDecl())) {
if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) {
- // Find the class template specialization that surrounds this
- // member class.
- ClassTemplateSpecializationDecl *Spec = 0;
- for (DeclContext *Parent = Rec->getDeclContext();
- Parent && !Spec; Parent = Parent->getParent())
- Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent);
- assert(Spec && "Not a member of a class template specialization?");
- return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(),
- /*ExplicitInstantiation=*/false);
+ MemberSpecializationInfo *MSInfo = Rec->getMemberSpecializationInfo();
+ assert(MSInfo && "Missing member specialization information?");
+ // This record was instantiated from a class within a template.
+ if (MSInfo->getTemplateSpecializationKind()
+ != TSK_ExplicitSpecialization) {
+ MSInfo->setPointOfInstantiation(Loc);
+ return InstantiateClass(Loc, Rec, Pattern,
+ getTemplateInstantiationArgs(Rec),
+ TSK_ImplicitInstantiation,
+ /*Complain=*/diag != 0);
+ }
}
}
}
- if (PrintType.isNull())
- PrintType = T;
+ if (diag == 0)
+ return true;
// We have an incomplete type. Produce a diagnostic.
- Diag(Loc, diag) << PrintType << Range1 << Range2;
+ Diag(Loc, PD) << T;
+ // If we have a note, produce it.
+ if (!Note.first.isInvalid())
+ Diag(Note.first, Note.second);
+
// If the type was a forward declaration of a class/struct/union
- // type, produce
+ // type, produce
const TagType *Tag = 0;
- if (const RecordType *Record = T->getAsRecordType())
+ if (const RecordType *Record = T->getAs<RecordType>())
Tag = Record;
- else if (const EnumType *Enum = T->getAsEnumType())
+ else if (const EnumType *Enum = T->getAs<EnumType>())
Tag = Enum;
if (Tag && !Tag->getDecl()->isInvalidDecl())
- Diag(Tag->getDecl()->getLocation(),
+ Diag(Tag->getDecl()->getLocation(),
Tag->isBeingDefined() ? diag::note_type_being_defined
: diag::note_forward_declaration)
<< QualType(Tag, 0);
@@ -1509,7 +1724,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
if (!SS.isSet() || SS.isInvalid() || T.isNull())
return T;
-
+
NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
return Context.getQualifiedNameType(NNS, T);
@@ -1521,7 +1736,7 @@ QualType Sema::BuildTypeofExprType(Expr *E) {
QualType Sema::BuildDecltypeType(Expr *E) {
if (E->getType() == Context.OverloadTy) {
- Diag(E->getLocStart(),
+ Diag(E->getLocStart(),
diag::err_cannot_determine_declared_type_of_overloaded_function);
return QualType();
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
new file mode 100644
index 0000000000000..ec5c6676f5d20
--- /dev/null
+++ b/lib/Sema/TreeTransform.h
@@ -0,0 +1,4829 @@
+//===------- TreeTransform.h - Semantic Tree Transformation ---------------===/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+// This file implements a semantic tree transformation that takes a given
+// AST and rebuilds it, possibly transforming some nodes in the process.
+//
+//===----------------------------------------------------------------------===/
+#ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H
+#define LLVM_CLANG_SEMA_TREETRANSFORM_H
+
+#include "Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/Parse/Ownership.h"
+#include "clang/Parse/Designator.h"
+#include "clang/Lex/Preprocessor.h"
+#include <algorithm>
+
+namespace clang {
+
+/// \brief A semantic tree transformation that allows one to transform one
+/// abstract syntax tree into another.
+///
+/// A new tree transformation is defined by creating a new subclass \c X of
+/// \c TreeTransform<X> and then overriding certain operations to provide
+/// behavior specific to that transformation. For example, template
+/// instantiation is implemented as a tree transformation where the
+/// transformation of TemplateTypeParmType nodes involves substituting the
+/// template arguments for their corresponding template parameters; a similar
+/// transformation is performed for non-type template parameters and
+/// template template parameters.
+///
+/// This tree-transformation template uses static polymorphism to allow
+/// subclasses to customize any of its operations. Thus, a subclass can
+/// override any of the transformation or rebuild operators by providing an
+/// operation with the same signature as the default implementation. The
+/// overridding function should not be virtual.
+///
+/// Semantic tree transformations are split into two stages, either of which
+/// can be replaced by a subclass. The "transform" step transforms an AST node
+/// or the parts of an AST node using the various transformation functions,
+/// then passes the pieces on to the "rebuild" step, which constructs a new AST
+/// node of the appropriate kind from the pieces. The default transformation
+/// routines recursively transform the operands to composite AST nodes (e.g.,
+/// the pointee type of a PointerType node) and, if any of those operand nodes
+/// were changed by the transformation, invokes the rebuild operation to create
+/// a new AST node.
+///
+/// Subclasses can customize the transformation at various levels. The
+/// most coarse-grained transformations involve replacing TransformType(),
+/// TransformExpr(), TransformDecl(), TransformNestedNameSpecifier(),
+/// TransformTemplateName(), or TransformTemplateArgument() with entirely
+/// new implementations.
+///
+/// For more fine-grained transformations, subclasses can replace any of the
+/// \c TransformXXX functions (where XXX is the name of an AST node, e.g.,
+/// PointerType, StmtExpr) to alter the transformation. As mentioned previously,
+/// replacing TransformTemplateTypeParmType() allows template instantiation
+/// to substitute template arguments for their corresponding template
+/// parameters. Additionally, subclasses can override the \c RebuildXXX
+/// functions to control how AST nodes are rebuilt when their operands change.
+/// By default, \c TreeTransform will invoke semantic analysis to rebuild
+/// AST nodes. However, certain other tree transformations (e.g, cloning) may
+/// be able to use more efficient rebuild steps.
+///
+/// There are a handful of other functions that can be overridden, allowing one
+/// to avoid traversing nodes that don't need any transformation
+/// (\c AlreadyTransformed()), force rebuilding AST nodes even when their
+/// operands have not changed (\c AlwaysRebuild()), and customize the
+/// default locations and entity names used for type-checking
+/// (\c getBaseLocation(), \c getBaseEntity()).
+template<typename Derived>
+class TreeTransform {
+protected:
+ Sema &SemaRef;
+
+public:
+ typedef Sema::OwningStmtResult OwningStmtResult;
+ typedef Sema::OwningExprResult OwningExprResult;
+ typedef Sema::StmtArg StmtArg;
+ typedef Sema::ExprArg ExprArg;
+ typedef Sema::MultiExprArg MultiExprArg;
+ typedef Sema::MultiStmtArg MultiStmtArg;
+
+ /// \brief Initializes a new tree transformer.
+ TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { }
+
+ /// \brief Retrieves a reference to the derived class.
+ Derived &getDerived() { return static_cast<Derived&>(*this); }
+
+ /// \brief Retrieves a reference to the derived class.
+ const Derived &getDerived() const {
+ return static_cast<const Derived&>(*this);
+ }
+
+ /// \brief Retrieves a reference to the semantic analysis object used for
+ /// this tree transform.
+ Sema &getSema() const { return SemaRef; }
+
+ /// \brief Whether the transformation should always rebuild AST nodes, even
+ /// if none of the children have changed.
+ ///
+ /// Subclasses may override this function to specify when the transformation
+ /// should rebuild all AST nodes.
+ bool AlwaysRebuild() { return false; }
+
+ /// \brief Returns the location of the entity being transformed, if that
+ /// information was not available elsewhere in the AST.
+ ///
+ /// By default, returns no source-location information. Subclasses can
+ /// provide an alternative implementation that provides better location
+ /// information.
+ SourceLocation getBaseLocation() { return SourceLocation(); }
+
+ /// \brief Returns the name of the entity being transformed, if that
+ /// information was not available elsewhere in the AST.
+ ///
+ /// By default, returns an empty name. Subclasses can provide an alternative
+ /// implementation with a more precise name.
+ DeclarationName getBaseEntity() { return DeclarationName(); }
+
+ /// \brief Sets the "base" location and entity when that
+ /// information is known based on another transformation.
+ ///
+ /// By default, the source location and entity are ignored. Subclasses can
+ /// override this function to provide a customized implementation.
+ void setBase(SourceLocation Loc, DeclarationName Entity) { }
+
+ /// \brief RAII object that temporarily sets the base location and entity
+ /// used for reporting diagnostics in types.
+ class TemporaryBase {
+ TreeTransform &Self;
+ SourceLocation OldLocation;
+ DeclarationName OldEntity;
+
+ public:
+ TemporaryBase(TreeTransform &Self, SourceLocation Location,
+ DeclarationName Entity) : Self(Self) {
+ OldLocation = Self.getDerived().getBaseLocation();
+ OldEntity = Self.getDerived().getBaseEntity();
+ Self.getDerived().setBase(Location, Entity);
+ }
+
+ ~TemporaryBase() {
+ Self.getDerived().setBase(OldLocation, OldEntity);
+ }
+ };
+
+ /// \brief Determine whether the given type \p T has already been
+ /// transformed.
+ ///
+ /// Subclasses can provide an alternative implementation of this routine
+ /// to short-circuit evaluation when it is known that a given type will
+ /// not change. For example, template instantiation need not traverse
+ /// non-dependent types.
+ bool AlreadyTransformed(QualType T) {
+ return T.isNull();
+ }
+
+ /// \brief Transforms the given type into another type.
+ ///
+ /// By default, this routine transforms a type by delegating to the
+ /// appropriate TransformXXXType to build a new type, then applying
+ /// the qualifiers on \p T to the resulting type with AddTypeQualifiers.
+ /// Subclasses may override this function (to take over all type
+ /// transformations), some set of the TransformXXXType functions, or
+ /// the AddTypeQualifiers function to alter the transformation.
+ ///
+ /// \returns the transformed type.
+ QualType TransformType(QualType T);
+
+ /// \brief Transform the given type by adding the given set of qualifiers
+ /// and returning the result.
+ ///
+ /// FIXME: By default, this routine adds type qualifiers only to types that
+ /// can have qualifiers, and silently suppresses those qualifiers that are
+ /// not permitted (e.g., qualifiers on reference or function types). This
+ /// is the right thing for template instantiation, but probably not for
+ /// other clients.
+ QualType AddTypeQualifiers(QualType T, Qualifiers Qs);
+
+ /// \brief Transform the given statement.
+ ///
+ /// By default, this routine transforms a statement by delegating to the
+ /// appropriate TransformXXXStmt function to transform a specific kind of
+ /// statement or the TransformExpr() function to transform an expression.
+ /// Subclasses may override this function to transform statements using some
+ /// other mechanism.
+ ///
+ /// \returns the transformed statement.
+ OwningStmtResult TransformStmt(Stmt *S);
+
+ /// \brief Transform the given expression.
+ ///
+ /// By default, this routine transforms an expression by delegating to the
+ /// appropriate TransformXXXExpr function to build a new expression.
+ /// Subclasses may override this function to transform expressions using some
+ /// other mechanism.
+ ///
+ /// \returns the transformed expression.
+ OwningExprResult TransformExpr(Expr *E) {
+ return getDerived().TransformExpr(E, /*isAddressOfOperand=*/false);
+ }
+
+ /// \brief Transform the given expression.
+ ///
+ /// By default, this routine transforms an expression by delegating to the
+ /// appropriate TransformXXXExpr function to build a new expression.
+ /// Subclasses may override this function to transform expressions using some
+ /// other mechanism.
+ ///
+ /// \returns the transformed expression.
+ OwningExprResult TransformExpr(Expr *E, bool isAddressOfOperand);
+
+ /// \brief Transform the given declaration, which is referenced from a type
+ /// or expression.
+ ///
+ /// By default, acts as the identity function on declarations. Subclasses
+ /// may override this function to provide alternate behavior.
+ Decl *TransformDecl(Decl *D) { return D; }
+
+ /// \brief Transform the definition of the given declaration.
+ ///
+ /// By default, invokes TransformDecl() to transform the declaration.
+ /// Subclasses may override this function to provide alternate behavior.
+ Decl *TransformDefinition(Decl *D) { return getDerived().TransformDecl(D); }
+
+ /// \brief Transform the given nested-name-specifier.
+ ///
+ /// By default, transforms all of the types and declarations within the
+ /// nested-name-specifier. Subclasses may override this function to provide
+ /// alternate behavior.
+ NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ QualType ObjectType = QualType(),
+ NamedDecl *FirstQualifierInScope = 0);
+
+ /// \brief Transform the given declaration name.
+ ///
+ /// By default, transforms the types of conversion function, constructor,
+ /// and destructor names and then (if needed) rebuilds the declaration name.
+ /// Identifiers and selectors are returned unmodified. Sublcasses may
+ /// override this function to provide alternate behavior.
+ DeclarationName TransformDeclarationName(DeclarationName Name,
+ SourceLocation Loc);
+
+ /// \brief Transform the given template name.
+ ///
+ /// By default, transforms the template name by transforming the declarations
+ /// and nested-name-specifiers that occur within the template name.
+ /// Subclasses may override this function to provide alternate behavior.
+ TemplateName TransformTemplateName(TemplateName Name,
+ QualType ObjectType = QualType());
+
+ /// \brief Transform the given template argument.
+ ///
+ /// By default, this operation transforms the type, expression, or
+ /// declaration stored within the template argument and constructs a
+ /// new template argument from the transformed result. Subclasses may
+ /// override this function to provide alternate behavior.
+ TemplateArgument TransformTemplateArgument(const TemplateArgument &Arg);
+
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) \
+ QualType Transform##CLASS##Type(const CLASS##Type *T);
+#include "clang/AST/TypeNodes.def"
+
+ OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
+
+#define STMT(Node, Parent) \
+ OwningStmtResult Transform##Node(Node *S);
+#define EXPR(Node, Parent) \
+ OwningExprResult Transform##Node(Node *E);
+#define ABSTRACT_EXPR(Node, Parent)
+#include "clang/AST/StmtNodes.def"
+
+ /// \brief Build a new pointer type given its pointee type.
+ ///
+ /// By default, performs semantic analysis when building the pointer type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildPointerType(QualType PointeeType);
+
+ /// \brief Build a new block pointer type given its pointee type.
+ ///
+ /// By default, performs semantic analysis when building the block pointer
+ /// type. Subclasses may override this routine to provide different behavior.
+ QualType RebuildBlockPointerType(QualType PointeeType);
+
+ /// \brief Build a new lvalue reference type given the type it references.
+ ///
+ /// By default, performs semantic analysis when building the lvalue reference
+ /// type. Subclasses may override this routine to provide different behavior.
+ QualType RebuildLValueReferenceType(QualType ReferentType);
+
+ /// \brief Build a new rvalue reference type given the type it references.
+ ///
+ /// By default, performs semantic analysis when building the rvalue reference
+ /// type. Subclasses may override this routine to provide different behavior.
+ QualType RebuildRValueReferenceType(QualType ReferentType);
+
+ /// \brief Build a new member pointer type given the pointee type and the
+ /// class type it refers into.
+ ///
+ /// By default, performs semantic analysis when building the member pointer
+ /// type. Subclasses may override this routine to provide different behavior.
+ QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType);
+
+ /// \brief Build a new array type given the element type, size
+ /// modifier, size of the array (if known), size expression, and index type
+ /// qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ /// Also by default, all of the other Rebuild*Array
+ QualType RebuildArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt *Size,
+ Expr *SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange);
+
+ /// \brief Build a new constant array type given the element type, size
+ /// modifier, (known) size of the array, and index type qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildConstantArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ unsigned IndexTypeQuals);
+
+ /// \brief Build a new constant array type given the element type, size
+ /// modifier, (known) size of the array, size expression, and index type
+ /// qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildConstantArrayWithExprType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ Expr *SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange);
+
+ /// \brief Build a new constant array type given the element type, size
+ /// modifier, (known) size of the array, and index type qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildConstantArrayWithoutExprType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ unsigned IndexTypeQuals);
+
+ /// \brief Build a new incomplete array type given the element type, size
+ /// modifier, and index type qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildIncompleteArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ unsigned IndexTypeQuals);
+
+ /// \brief Build a new variable-length array type given the element type,
+ /// size modifier, size expression, and index type qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildVariableArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ ExprArg SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange);
+
+ /// \brief Build a new dependent-sized array type given the element type,
+ /// size modifier, size expression, and index type qualifiers.
+ ///
+ /// By default, performs semantic analysis when building the array type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildDependentSizedArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ ExprArg SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange);
+
+ /// \brief Build a new vector type given the element type and
+ /// number of elements.
+ ///
+ /// By default, performs semantic analysis when building the vector type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildVectorType(QualType ElementType, unsigned NumElements);
+
+ /// \brief Build a new extended vector type given the element type and
+ /// number of elements.
+ ///
+ /// By default, performs semantic analysis when building the vector type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildExtVectorType(QualType ElementType, unsigned NumElements,
+ SourceLocation AttributeLoc);
+
+ /// \brief Build a new potentially dependently-sized extended vector type
+ /// given the element type and number of elements.
+ ///
+ /// By default, performs semantic analysis when building the vector type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildDependentSizedExtVectorType(QualType ElementType,
+ ExprArg SizeExpr,
+ SourceLocation AttributeLoc);
+
+ /// \brief Build a new function type.
+ ///
+ /// By default, performs semantic analysis when building the function type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildFunctionProtoType(QualType T,
+ QualType *ParamTypes,
+ unsigned NumParamTypes,
+ bool Variadic, unsigned Quals);
+
+ /// \brief Build a new typedef type.
+ QualType RebuildTypedefType(TypedefDecl *Typedef) {
+ return SemaRef.Context.getTypeDeclType(Typedef);
+ }
+
+ /// \brief Build a new class/struct/union type.
+ QualType RebuildRecordType(RecordDecl *Record) {
+ return SemaRef.Context.getTypeDeclType(Record);
+ }
+
+ /// \brief Build a new Enum type.
+ QualType RebuildEnumType(EnumDecl *Enum) {
+ return SemaRef.Context.getTypeDeclType(Enum);
+ }
+
+ /// \brief Build a new elaborated type.
+ QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag) {
+ return SemaRef.Context.getElaboratedType(T, Tag);
+ }
+
+ /// \brief Build a new typeof(expr) type.
+ ///
+ /// By default, performs semantic analysis when building the typeof type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildTypeOfExprType(ExprArg Underlying);
+
+ /// \brief Build a new typeof(type) type.
+ ///
+ /// By default, builds a new TypeOfType with the given underlying type.
+ QualType RebuildTypeOfType(QualType Underlying);
+
+ /// \brief Build a new C++0x decltype type.
+ ///
+ /// By default, performs semantic analysis when building the decltype type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildDecltypeType(ExprArg Underlying);
+
+ /// \brief Build a new template specialization type.
+ ///
+ /// By default, performs semantic analysis when building the template
+ /// specialization type. Subclasses may override this routine to provide
+ /// different behavior.
+ QualType RebuildTemplateSpecializationType(TemplateName Template,
+ const TemplateArgument *Args,
+ unsigned NumArgs);
+
+ /// \brief Build a new qualified name type.
+ ///
+ /// By default, builds a new QualifiedNameType type from the
+ /// nested-name-specifier and the named type. Subclasses may override
+ /// this routine to provide different behavior.
+ QualType RebuildQualifiedNameType(NestedNameSpecifier *NNS, QualType Named) {
+ return SemaRef.Context.getQualifiedNameType(NNS, Named);
+ }
+
+ /// \brief Build a new typename type that refers to a template-id.
+ ///
+ /// By default, builds a new TypenameType type from the nested-name-specifier
+ /// and the given type. Subclasses may override this routine to provide
+ /// different behavior.
+ QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) {
+ if (NNS->isDependent())
+ return SemaRef.Context.getTypenameType(NNS,
+ cast<TemplateSpecializationType>(T));
+
+ return SemaRef.Context.getQualifiedNameType(NNS, T);
+ }
+
+ /// \brief Build a new typename type that refers to an identifier.
+ ///
+ /// By default, performs semantic analysis when building the typename type
+ /// (or qualified name type). Subclasses may override this routine to provide
+ /// different behavior.
+ QualType RebuildTypenameType(NestedNameSpecifier *NNS,
+ const IdentifierInfo *Id) {
+ return SemaRef.CheckTypenameType(NNS, *Id,
+ SourceRange(getDerived().getBaseLocation()));
+ }
+
+ /// \brief Build a new nested-name-specifier given the prefix and an
+ /// identifier that names the next step in the nested-name-specifier.
+ ///
+ /// By default, performs semantic analysis when building the new
+ /// nested-name-specifier. Subclasses may override this routine to provide
+ /// different behavior.
+ NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ IdentifierInfo &II,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope);
+
+ /// \brief Build a new nested-name-specifier given the prefix and the
+ /// namespace named in the next step in the nested-name-specifier.
+ ///
+ /// By default, performs semantic analysis when building the new
+ /// nested-name-specifier. Subclasses may override this routine to provide
+ /// different behavior.
+ NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ NamespaceDecl *NS);
+
+ /// \brief Build a new nested-name-specifier given the prefix and the
+ /// type named in the next step in the nested-name-specifier.
+ ///
+ /// By default, performs semantic analysis when building the new
+ /// nested-name-specifier. Subclasses may override this routine to provide
+ /// different behavior.
+ NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ bool TemplateKW,
+ QualType T);
+
+ /// \brief Build a new template name given a nested name specifier, a flag
+ /// indicating whether the "template" keyword was provided, and the template
+ /// that the template name refers to.
+ ///
+ /// By default, builds the new template name directly. Subclasses may override
+ /// this routine to provide different behavior.
+ TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ bool TemplateKW,
+ TemplateDecl *Template);
+
+ /// \brief Build a new template name given a nested name specifier, a flag
+ /// indicating whether the "template" keyword was provided, and a set of
+ /// overloaded function templates.
+ ///
+ /// By default, builds the new template name directly. Subclasses may override
+ /// this routine to provide different behavior.
+ TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ bool TemplateKW,
+ OverloadedFunctionDecl *Ovl);
+
+ /// \brief Build a new template name given a nested name specifier and the
+ /// name that is referred to as a template.
+ ///
+ /// By default, performs semantic analysis to determine whether the name can
+ /// be resolved to a specific template, then builds the appropriate kind of
+ /// template name. Subclasses may override this routine to provide different
+ /// behavior.
+ TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ const IdentifierInfo &II,
+ QualType ObjectType);
+
+
+ /// \brief Build a new compound statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildCompoundStmt(SourceLocation LBraceLoc,
+ MultiStmtArg Statements,
+ SourceLocation RBraceLoc,
+ bool IsStmtExpr) {
+ return getSema().ActOnCompoundStmt(LBraceLoc, RBraceLoc, move(Statements),
+ IsStmtExpr);
+ }
+
+ /// \brief Build a new case statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildCaseStmt(SourceLocation CaseLoc,
+ ExprArg LHS,
+ SourceLocation EllipsisLoc,
+ ExprArg RHS,
+ SourceLocation ColonLoc) {
+ return getSema().ActOnCaseStmt(CaseLoc, move(LHS), EllipsisLoc, move(RHS),
+ ColonLoc);
+ }
+
+ /// \brief Attach the body to a new case statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildCaseStmtBody(StmtArg S, StmtArg Body) {
+ getSema().ActOnCaseStmtBody(S.get(), move(Body));
+ return move(S);
+ }
+
+ /// \brief Build a new default statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt) {
+ return getSema().ActOnDefaultStmt(DefaultLoc, ColonLoc, move(SubStmt),
+ /*CurScope=*/0);
+ }
+
+ /// \brief Build a new label statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildLabelStmt(SourceLocation IdentLoc,
+ IdentifierInfo *Id,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt) {
+ return SemaRef.ActOnLabelStmt(IdentLoc, Id, ColonLoc, move(SubStmt));
+ }
+
+ /// \brief Build a new "if" statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond,
+ StmtArg Then, SourceLocation ElseLoc,
+ StmtArg Else) {
+ return getSema().ActOnIfStmt(IfLoc, Cond, move(Then), ElseLoc, move(Else));
+ }
+
+ /// \brief Start building a new switch statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildSwitchStmtStart(ExprArg Cond) {
+ return getSema().ActOnStartOfSwitchStmt(move(Cond));
+ }
+
+ /// \brief Attach the body to the switch statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildSwitchStmtBody(SourceLocation SwitchLoc,
+ StmtArg Switch, StmtArg Body) {
+ return getSema().ActOnFinishSwitchStmt(SwitchLoc, move(Switch),
+ move(Body));
+ }
+
+ /// \brief Build a new while statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildWhileStmt(SourceLocation WhileLoc,
+ Sema::FullExprArg Cond,
+ StmtArg Body) {
+ return getSema().ActOnWhileStmt(WhileLoc, Cond, move(Body));
+ }
+
+ /// \brief Build a new do-while statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildDoStmt(SourceLocation DoLoc, StmtArg Body,
+ SourceLocation WhileLoc,
+ SourceLocation LParenLoc,
+ ExprArg Cond,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnDoStmt(DoLoc, move(Body), WhileLoc, LParenLoc,
+ move(Cond), RParenLoc);
+ }
+
+ /// \brief Build a new for statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg Init, ExprArg Cond, ExprArg Inc,
+ SourceLocation RParenLoc, StmtArg Body) {
+ return getSema().ActOnForStmt(ForLoc, LParenLoc, move(Init), move(Cond),
+ move(Inc), RParenLoc, move(Body));
+ }
+
+ /// \brief Build a new goto statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildGotoStmt(SourceLocation GotoLoc,
+ SourceLocation LabelLoc,
+ LabelStmt *Label) {
+ return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label->getID());
+ }
+
+ /// \brief Build a new indirect goto statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildIndirectGotoStmt(SourceLocation GotoLoc,
+ SourceLocation StarLoc,
+ ExprArg Target) {
+ return getSema().ActOnIndirectGotoStmt(GotoLoc, StarLoc, move(Target));
+ }
+
+ /// \brief Build a new return statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildReturnStmt(SourceLocation ReturnLoc,
+ ExprArg Result) {
+
+ return getSema().ActOnReturnStmt(ReturnLoc, move(Result));
+ }
+
+ /// \brief Build a new declaration statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildDeclStmt(Decl **Decls, unsigned NumDecls,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return getSema().Owned(
+ new (getSema().Context) DeclStmt(
+ DeclGroupRef::Create(getSema().Context,
+ Decls, NumDecls),
+ StartLoc, EndLoc));
+ }
+
+ /// \brief Build a new C++ exception declaration.
+ ///
+ /// By default, performs semantic analysis to build the new decaration.
+ /// Subclasses may override this routine to provide different behavior.
+ VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T,
+ DeclaratorInfo *Declarator,
+ IdentifierInfo *Name,
+ SourceLocation Loc,
+ SourceRange TypeRange) {
+ return getSema().BuildExceptionDeclaration(0, T, Declarator, Name, Loc,
+ TypeRange);
+ }
+
+ /// \brief Build a new C++ catch statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildCXXCatchStmt(SourceLocation CatchLoc,
+ VarDecl *ExceptionDecl,
+ StmtArg Handler) {
+ return getSema().Owned(
+ new (getSema().Context) CXXCatchStmt(CatchLoc, ExceptionDecl,
+ Handler.takeAs<Stmt>()));
+ }
+
+ /// \brief Build a new C++ try statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildCXXTryStmt(SourceLocation TryLoc,
+ StmtArg TryBlock,
+ MultiStmtArg Handlers) {
+ return getSema().ActOnCXXTryBlock(TryLoc, move(TryBlock), move(Handlers));
+ }
+
+ /// \brief Build a new expression that references a declaration.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildDeclRefExpr(NamedDecl *ND, SourceLocation Loc) {
+ return getSema().BuildDeclarationNameExpr(Loc, ND,
+ /*FIXME:*/false,
+ /*SS=*/0,
+ /*FIXME:*/false);
+ }
+
+ /// \brief Build a new expression in parentheses.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildParenExpr(ExprArg SubExpr, SourceLocation LParen,
+ SourceLocation RParen) {
+ return getSema().ActOnParenExpr(LParen, RParen, move(SubExpr));
+ }
+
+ /// \brief Build a new pseudo-destructor expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base,
+ SourceLocation OperatorLoc,
+ bool isArrow,
+ SourceLocation DestroyedTypeLoc,
+ QualType DestroyedType,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange) {
+ CXXScopeSpec SS;
+ if (Qualifier) {
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(Qualifier);
+ }
+
+ DeclarationName Name
+ = SemaRef.Context.DeclarationNames.getCXXDestructorName(
+ SemaRef.Context.getCanonicalType(DestroyedType));
+
+ return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base),
+ OperatorLoc,
+ isArrow? tok::arrow : tok::period,
+ DestroyedTypeLoc,
+ Name,
+ Sema::DeclPtrTy::make((Decl *)0),
+ &SS);
+ }
+
+ /// \brief Build a new unary operator expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildUnaryOperator(SourceLocation OpLoc,
+ UnaryOperator::Opcode Opc,
+ ExprArg SubExpr) {
+ return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, move(SubExpr));
+ }
+
+ /// \brief Build a new sizeof or alignof expression with a type argument.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildSizeOfAlignOf(QualType T, SourceLocation OpLoc,
+ bool isSizeOf, SourceRange R) {
+ return getSema().CreateSizeOfAlignOfExpr(T, OpLoc, isSizeOf, R);
+ }
+
+ /// \brief Build a new sizeof or alignof expression with an expression
+ /// argument.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildSizeOfAlignOf(ExprArg SubExpr, SourceLocation OpLoc,
+ bool isSizeOf, SourceRange R) {
+ OwningExprResult Result
+ = getSema().CreateSizeOfAlignOfExpr((Expr *)SubExpr.get(),
+ OpLoc, isSizeOf, R);
+ if (Result.isInvalid())
+ return getSema().ExprError();
+
+ SubExpr.release();
+ return move(Result);
+ }
+
+ /// \brief Build a new array subscript expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildArraySubscriptExpr(ExprArg LHS,
+ SourceLocation LBracketLoc,
+ ExprArg RHS,
+ SourceLocation RBracketLoc) {
+ return getSema().ActOnArraySubscriptExpr(/*Scope=*/0, move(LHS),
+ LBracketLoc, move(RHS),
+ RBracketLoc);
+ }
+
+ /// \brief Build a new call expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCallExpr(ExprArg Callee, SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCallExpr(/*Scope=*/0, move(Callee), LParenLoc,
+ move(Args), CommaLocs, RParenLoc);
+ }
+
+ /// \brief Build a new member access expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildMemberExpr(ExprArg Base, SourceLocation OpLoc,
+ bool isArrow,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ SourceLocation MemberLoc,
+ NamedDecl *Member) {
+ if (!Member->getDeclName()) {
+ // We have a reference to an unnamed field.
+ assert(!Qualifier && "Can't have an unnamed field with a qualifier!");
+
+ MemberExpr *ME =
+ new (getSema().Context) MemberExpr(Base.takeAs<Expr>(), isArrow,
+ Member, MemberLoc,
+ cast<FieldDecl>(Member)->getType());
+ return getSema().Owned(ME);
+ }
+
+ CXXScopeSpec SS;
+ if (Qualifier) {
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(Qualifier);
+ }
+
+ return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc,
+ isArrow? tok::arrow : tok::period,
+ MemberLoc,
+ Member->getDeclName(),
+ /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
+ &SS);
+ }
+
+ /// \brief Build a new binary operator expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildBinaryOperator(SourceLocation OpLoc,
+ BinaryOperator::Opcode Opc,
+ ExprArg LHS, ExprArg RHS) {
+ OwningExprResult Result
+ = getSema().CreateBuiltinBinOp(OpLoc, Opc, (Expr *)LHS.get(),
+ (Expr *)RHS.get());
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ LHS.release();
+ RHS.release();
+ return move(Result);
+ }
+
+ /// \brief Build a new conditional operator expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildConditionalOperator(ExprArg Cond,
+ SourceLocation QuestionLoc,
+ ExprArg LHS,
+ SourceLocation ColonLoc,
+ ExprArg RHS) {
+ return getSema().ActOnConditionalOp(QuestionLoc, ColonLoc, move(Cond),
+ move(LHS), move(RHS));
+ }
+
+ /// \brief Build a new implicit cast expression.
+ ///
+ /// By default, builds a new implicit cast without any semantic analysis.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildImplicitCastExpr(QualType T, CastExpr::CastKind Kind,
+ ExprArg SubExpr, bool isLvalue) {
+ ImplicitCastExpr *ICE
+ = new (getSema().Context) ImplicitCastExpr(T, Kind,
+ (Expr *)SubExpr.release(),
+ isLvalue);
+ return getSema().Owned(ICE);
+ }
+
+ /// \brief Build a new C-style cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCStyleCaseExpr(SourceLocation LParenLoc,
+ QualType ExplicitTy,
+ SourceLocation RParenLoc,
+ ExprArg SubExpr) {
+ return getSema().ActOnCastExpr(/*Scope=*/0,
+ LParenLoc,
+ ExplicitTy.getAsOpaquePtr(),
+ RParenLoc,
+ move(SubExpr));
+ }
+
+ /// \brief Build a new compound literal expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCompoundLiteralExpr(SourceLocation LParenLoc,
+ QualType T,
+ SourceLocation RParenLoc,
+ ExprArg Init) {
+ return getSema().ActOnCompoundLiteral(LParenLoc, T.getAsOpaquePtr(),
+ RParenLoc, move(Init));
+ }
+
+ /// \brief Build a new extended vector element access expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildExtVectorElementExpr(ExprArg Base,
+ SourceLocation OpLoc,
+ SourceLocation AccessorLoc,
+ IdentifierInfo &Accessor) {
+ return getSema().ActOnMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc,
+ tok::period, AccessorLoc,
+ Accessor,
+ /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
+ }
+
+ /// \brief Build a new initializer list expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildInitList(SourceLocation LBraceLoc,
+ MultiExprArg Inits,
+ SourceLocation RBraceLoc) {
+ return SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc);
+ }
+
+ /// \brief Build a new designated initializer expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildDesignatedInitExpr(Designation &Desig,
+ MultiExprArg ArrayExprs,
+ SourceLocation EqualOrColonLoc,
+ bool GNUSyntax,
+ ExprArg Init) {
+ OwningExprResult Result
+ = SemaRef.ActOnDesignatedInitializer(Desig, EqualOrColonLoc, GNUSyntax,
+ move(Init));
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ ArrayExprs.release();
+ return move(Result);
+ }
+
+ /// \brief Build a new value-initialized expression.
+ ///
+ /// By default, builds the implicit value initialization without performing
+ /// any semantic analysis. Subclasses may override this routine to provide
+ /// different behavior.
+ OwningExprResult RebuildImplicitValueInitExpr(QualType T) {
+ return SemaRef.Owned(new (SemaRef.Context) ImplicitValueInitExpr(T));
+ }
+
+ /// \brief Build a new \c va_arg expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildVAArgExpr(SourceLocation BuiltinLoc, ExprArg SubExpr,
+ QualType T, SourceLocation RParenLoc) {
+ return getSema().ActOnVAArg(BuiltinLoc, move(SubExpr), T.getAsOpaquePtr(),
+ RParenLoc);
+ }
+
+ /// \brief Build a new expression list in parentheses.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildParenListExpr(SourceLocation LParenLoc,
+ MultiExprArg SubExprs,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, move(SubExprs));
+ }
+
+ /// \brief Build a new address-of-label expression.
+ ///
+ /// By default, performs semantic analysis, using the name of the label
+ /// rather than attempting to map the label statement itself.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildAddrLabelExpr(SourceLocation AmpAmpLoc,
+ SourceLocation LabelLoc,
+ LabelStmt *Label) {
+ return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc, Label->getID());
+ }
+
+ /// \brief Build a new GNU statement expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildStmtExpr(SourceLocation LParenLoc,
+ StmtArg SubStmt,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnStmtExpr(LParenLoc, move(SubStmt), RParenLoc);
+ }
+
+ /// \brief Build a new __builtin_types_compatible_p expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ QualType T1, QualType T2,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnTypesCompatibleExpr(BuiltinLoc,
+ T1.getAsOpaquePtr(),
+ T2.getAsOpaquePtr(),
+ RParenLoc);
+ }
+
+ /// \brief Build a new __builtin_choose_expr expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildChooseExpr(SourceLocation BuiltinLoc,
+ ExprArg Cond, ExprArg LHS, ExprArg RHS,
+ SourceLocation RParenLoc) {
+ return SemaRef.ActOnChooseExpr(BuiltinLoc,
+ move(Cond), move(LHS), move(RHS),
+ RParenLoc);
+ }
+
+ /// \brief Build a new overloaded operator call expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// The semantic analysis provides the behavior of template instantiation,
+ /// copying with transformations that turn what looks like an overloaded
+ /// operator call into a use of a builtin operator, performing
+ /// argument-dependent lookup, etc. Subclasses may override this routine to
+ /// provide different behavior.
+ OwningExprResult RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
+ SourceLocation OpLoc,
+ ExprArg Callee,
+ ExprArg First,
+ ExprArg Second);
+
+ /// \brief Build a new C++ "named" cast expression, such as static_cast or
+ /// reinterpret_cast.
+ ///
+ /// By default, this routine dispatches to one of the more-specific routines
+ /// for a particular named case, e.g., RebuildCXXStaticCastExpr().
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXNamedCastExpr(SourceLocation OpLoc,
+ Stmt::StmtClass Class,
+ SourceLocation LAngleLoc,
+ QualType T,
+ SourceLocation RAngleLoc,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ switch (Class) {
+ case Stmt::CXXStaticCastExprClass:
+ return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, T,
+ RAngleLoc, LParenLoc,
+ move(SubExpr), RParenLoc);
+
+ case Stmt::CXXDynamicCastExprClass:
+ return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, T,
+ RAngleLoc, LParenLoc,
+ move(SubExpr), RParenLoc);
+
+ case Stmt::CXXReinterpretCastExprClass:
+ return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, T,
+ RAngleLoc, LParenLoc,
+ move(SubExpr),
+ RParenLoc);
+
+ case Stmt::CXXConstCastExprClass:
+ return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, T,
+ RAngleLoc, LParenLoc,
+ move(SubExpr), RParenLoc);
+
+ default:
+ assert(false && "Invalid C++ named cast");
+ break;
+ }
+
+ return getSema().ExprError();
+ }
+
+ /// \brief Build a new C++ static_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXStaticCastExpr(SourceLocation OpLoc,
+ SourceLocation LAngleLoc,
+ QualType T,
+ SourceLocation RAngleLoc,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_static_cast,
+ LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
+ LParenLoc, move(SubExpr), RParenLoc);
+ }
+
+ /// \brief Build a new C++ dynamic_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXDynamicCastExpr(SourceLocation OpLoc,
+ SourceLocation LAngleLoc,
+ QualType T,
+ SourceLocation RAngleLoc,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_dynamic_cast,
+ LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
+ LParenLoc, move(SubExpr), RParenLoc);
+ }
+
+ /// \brief Build a new C++ reinterpret_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXReinterpretCastExpr(SourceLocation OpLoc,
+ SourceLocation LAngleLoc,
+ QualType T,
+ SourceLocation RAngleLoc,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_reinterpret_cast,
+ LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
+ LParenLoc, move(SubExpr), RParenLoc);
+ }
+
+ /// \brief Build a new C++ const_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXConstCastExpr(SourceLocation OpLoc,
+ SourceLocation LAngleLoc,
+ QualType T,
+ SourceLocation RAngleLoc,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_const_cast,
+ LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
+ LParenLoc, move(SubExpr), RParenLoc);
+ }
+
+ /// \brief Build a new C++ functional-style cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXFunctionalCastExpr(SourceRange TypeRange,
+ QualType T,
+ SourceLocation LParenLoc,
+ ExprArg SubExpr,
+ SourceLocation RParenLoc) {
+ void *Sub = SubExpr.takeAs<Expr>();
+ return getSema().ActOnCXXTypeConstructExpr(TypeRange,
+ T.getAsOpaquePtr(),
+ LParenLoc,
+ Sema::MultiExprArg(getSema(), &Sub, 1),
+ /*CommaLocs=*/0,
+ RParenLoc);
+ }
+
+ /// \brief Build a new C++ typeid(type) expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc,
+ SourceLocation LParenLoc,
+ QualType T,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, true,
+ T.getAsOpaquePtr(), RParenLoc);
+ }
+
+ /// \brief Build a new C++ typeid(expr) expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc,
+ SourceLocation LParenLoc,
+ ExprArg Operand,
+ SourceLocation RParenLoc) {
+ OwningExprResult Result
+ = getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, false, Operand.get(),
+ RParenLoc);
+ if (Result.isInvalid())
+ return getSema().ExprError();
+
+ Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership
+ return move(Result);
+ }
+
+ /// \brief Build a new C++ "this" expression.
+ ///
+ /// By default, builds a new "this" expression without performing any
+ /// semantic analysis. Subclasses may override this routine to provide
+ /// different behavior.
+ OwningExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
+ QualType ThisType) {
+ return getSema().Owned(
+ new (getSema().Context) CXXThisExpr(ThisLoc, ThisType));
+ }
+
+ /// \brief Build a new C++ throw expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXThrowExpr(SourceLocation ThrowLoc, ExprArg Sub) {
+ return getSema().ActOnCXXThrow(ThrowLoc, move(Sub));
+ }
+
+ /// \brief Build a new C++ default-argument expression.
+ ///
+ /// By default, builds a new default-argument expression, which does not
+ /// require any semantic analysis. Subclasses may override this routine to
+ /// provide different behavior.
+ OwningExprResult RebuildCXXDefaultArgExpr(ParmVarDecl *Param) {
+ return getSema().Owned(CXXDefaultArgExpr::Create(getSema().Context, Param));
+ }
+
+ /// \brief Build a new C++ zero-initialization expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXZeroInitValueExpr(SourceLocation TypeStartLoc,
+ SourceLocation LParenLoc,
+ QualType T,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeStartLoc),
+ T.getAsOpaquePtr(), LParenLoc,
+ MultiExprArg(getSema(), 0, 0),
+ 0, RParenLoc);
+ }
+
+ /// \brief Build a new C++ conditional declaration expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXConditionDeclExpr(SourceLocation StartLoc,
+ SourceLocation EqLoc,
+ VarDecl *Var) {
+ return SemaRef.Owned(new (SemaRef.Context) CXXConditionDeclExpr(StartLoc,
+ EqLoc,
+ Var));
+ }
+
+ /// \brief Build a new C++ "new" expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXNewExpr(SourceLocation StartLoc,
+ bool UseGlobal,
+ SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen,
+ bool ParenTypeId,
+ QualType AllocType,
+ SourceLocation TypeLoc,
+ SourceRange TypeRange,
+ ExprArg ArraySize,
+ SourceLocation ConstructorLParen,
+ MultiExprArg ConstructorArgs,
+ SourceLocation ConstructorRParen) {
+ return getSema().BuildCXXNew(StartLoc, UseGlobal,
+ PlacementLParen,
+ move(PlacementArgs),
+ PlacementRParen,
+ ParenTypeId,
+ AllocType,
+ TypeLoc,
+ TypeRange,
+ move(ArraySize),
+ ConstructorLParen,
+ move(ConstructorArgs),
+ ConstructorRParen);
+ }
+
+ /// \brief Build a new C++ "delete" expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXDeleteExpr(SourceLocation StartLoc,
+ bool IsGlobalDelete,
+ bool IsArrayForm,
+ ExprArg Operand) {
+ return getSema().ActOnCXXDelete(StartLoc, IsGlobalDelete, IsArrayForm,
+ move(Operand));
+ }
+
+ /// \brief Build a new unary type trait expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildUnaryTypeTrait(UnaryTypeTrait Trait,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ QualType T,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnUnaryTypeTrait(Trait, StartLoc, LParenLoc,
+ T.getAsOpaquePtr(), RParenLoc);
+ }
+
+ /// \brief Build a new qualified declaration reference expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildQualifiedDeclRefExpr(NestedNameSpecifier *NNS,
+ SourceRange QualifierRange,
+ NamedDecl *ND,
+ SourceLocation Location,
+ bool IsAddressOfOperand) {
+ CXXScopeSpec SS;
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(NNS);
+ return getSema().ActOnDeclarationNameExpr(/*Scope=*/0,
+ Location,
+ ND->getDeclName(),
+ /*Trailing lparen=*/false,
+ &SS,
+ IsAddressOfOperand);
+ }
+
+ /// \brief Build a new (previously unresolved) declaration reference
+ /// expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildUnresolvedDeclRefExpr(NestedNameSpecifier *NNS,
+ SourceRange QualifierRange,
+ DeclarationName Name,
+ SourceLocation Location,
+ bool IsAddressOfOperand) {
+ CXXScopeSpec SS;
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(NNS);
+ return getSema().ActOnDeclarationNameExpr(/*Scope=*/0,
+ Location,
+ Name,
+ /*Trailing lparen=*/false,
+ &SS,
+ IsAddressOfOperand);
+ }
+
+ /// \brief Build a new template-id expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildTemplateIdExpr(TemplateName Template,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc) {
+ return getSema().BuildTemplateIdExpr(Template, TemplateLoc,
+ LAngleLoc,
+ TemplateArgs, NumTemplateArgs,
+ RAngleLoc);
+ }
+
+ /// \brief Build a new object-construction expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXConstructExpr(QualType T,
+ CXXConstructorDecl *Constructor,
+ bool IsElidable,
+ MultiExprArg Args) {
+ return getSema().BuildCXXConstructExpr(/*FIXME:ConstructLoc*/
+ SourceLocation(),
+ T, Constructor, IsElidable,
+ move(Args));
+ }
+
+ /// \brief Build a new object-construction expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXTemporaryObjectExpr(SourceLocation TypeBeginLoc,
+ QualType T,
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *Commas,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeBeginLoc),
+ T.getAsOpaquePtr(),
+ LParenLoc,
+ move(Args),
+ Commas,
+ RParenLoc);
+ }
+
+ /// \brief Build a new object-construction expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXUnresolvedConstructExpr(SourceLocation TypeBeginLoc,
+ QualType T,
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *Commas,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnCXXTypeConstructExpr(SourceRange(TypeBeginLoc,
+ /*FIXME*/LParenLoc),
+ T.getAsOpaquePtr(),
+ LParenLoc,
+ move(Args),
+ Commas,
+ RParenLoc);
+ }
+
+ /// \brief Build a new member reference expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE,
+ bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ DeclarationName Name,
+ SourceLocation MemberLoc,
+ NamedDecl *FirstQualifierInScope) {
+ OwningExprResult Base = move(BaseE);
+ tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
+
+ CXXScopeSpec SS;
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(Qualifier);
+
+ return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0,
+ move(Base), OperatorLoc, OpKind,
+ MemberLoc,
+ Name,
+ /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
+ &SS,
+ FirstQualifierInScope);
+ }
+
+ /// \brief Build a new member reference expression with explicit template
+ /// arguments.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE,
+ bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ TemplateName Template,
+ SourceLocation TemplateNameLoc,
+ NamedDecl *FirstQualifierInScope,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc) {
+ OwningExprResult Base = move(BaseE);
+ tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
+
+ CXXScopeSpec SS;
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(Qualifier);
+
+ // FIXME: We're going to end up looking up the template based on its name,
+ // twice! Also, duplicates part of Sema::ActOnMemberTemplateIdReferenceExpr.
+ DeclarationName Name;
+ if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
+ Name = ActualTemplate->getDeclName();
+ else if (OverloadedFunctionDecl *Ovl
+ = Template.getAsOverloadedFunctionDecl())
+ Name = Ovl->getDeclName();
+ else
+ Name = Template.getAsDependentTemplateName()->getName();
+
+ return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base),
+ OperatorLoc, OpKind,
+ TemplateNameLoc, Name, true,
+ LAngleLoc, TemplateArgs,
+ NumTemplateArgs, RAngleLoc,
+ Sema::DeclPtrTy(), &SS);
+ }
+
+ /// \brief Build a new Objective-C @encode expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildObjCEncodeExpr(SourceLocation AtLoc,
+ QualType T,
+ SourceLocation RParenLoc) {
+ return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, T,
+ RParenLoc));
+ }
+
+ /// \brief Build a new Objective-C protocol expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildObjCProtocolExpr(ObjCProtocolDecl *Protocol,
+ SourceLocation AtLoc,
+ SourceLocation ProtoLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ return SemaRef.Owned(SemaRef.ParseObjCProtocolExpression(
+ Protocol->getIdentifier(),
+ AtLoc,
+ ProtoLoc,
+ LParenLoc,
+ RParenLoc));
+ }
+
+ /// \brief Build a new shuffle vector expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildShuffleVectorExpr(SourceLocation BuiltinLoc,
+ MultiExprArg SubExprs,
+ SourceLocation RParenLoc) {
+ // Find the declaration for __builtin_shufflevector
+ const IdentifierInfo &Name
+ = SemaRef.Context.Idents.get("__builtin_shufflevector");
+ TranslationUnitDecl *TUDecl = SemaRef.Context.getTranslationUnitDecl();
+ DeclContext::lookup_result Lookup = TUDecl->lookup(DeclarationName(&Name));
+ assert(Lookup.first != Lookup.second && "No __builtin_shufflevector?");
+
+ // Build a reference to the __builtin_shufflevector builtin
+ FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
+ Expr *Callee
+ = new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(),
+ BuiltinLoc, false, false);
+ SemaRef.UsualUnaryConversions(Callee);
+
+ // Build the CallExpr
+ unsigned NumSubExprs = SubExprs.size();
+ Expr **Subs = (Expr **)SubExprs.release();
+ CallExpr *TheCall = new (SemaRef.Context) CallExpr(SemaRef.Context, Callee,
+ Subs, NumSubExprs,
+ Builtin->getResultType(),
+ RParenLoc);
+ OwningExprResult OwnedCall(SemaRef.Owned(TheCall));
+
+ // Type-check the __builtin_shufflevector expression.
+ OwningExprResult Result = SemaRef.SemaBuiltinShuffleVector(TheCall);
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ OwnedCall.release();
+ return move(Result);
+ }
+};
+
+template<typename Derived>
+Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
+ if (!S)
+ return SemaRef.Owned(S);
+
+ switch (S->getStmtClass()) {
+ case Stmt::NoStmtClass: break;
+
+ // Transform individual statement nodes
+#define STMT(Node, Parent) \
+ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S));
+#define EXPR(Node, Parent)
+#include "clang/AST/StmtNodes.def"
+
+ // Transform expressions by calling TransformExpr.
+#define STMT(Node, Parent)
+#define EXPR(Node, Parent) case Stmt::Node##Class:
+#include "clang/AST/StmtNodes.def"
+ {
+ Sema::OwningExprResult E = getDerived().TransformExpr(cast<Expr>(S));
+ if (E.isInvalid())
+ return getSema().StmtError();
+
+ return getSema().Owned(E.takeAs<Stmt>());
+ }
+ }
+
+ return SemaRef.Owned(S->Retain());
+}
+
+
+template<typename Derived>
+Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E,
+ bool isAddressOfOperand) {
+ if (!E)
+ return SemaRef.Owned(E);
+
+ switch (E->getStmtClass()) {
+ case Stmt::NoStmtClass: break;
+#define STMT(Node, Parent) case Stmt::Node##Class: break;
+#define EXPR(Node, Parent) \
+ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E));
+#include "clang/AST/StmtNodes.def"
+ }
+
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope) {
+ if (!NNS)
+ return 0;
+
+ // Transform the prefix of this nested name specifier.
+ NestedNameSpecifier *Prefix = NNS->getPrefix();
+ if (Prefix) {
+ Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range,
+ ObjectType,
+ FirstQualifierInScope);
+ if (!Prefix)
+ return 0;
+
+ // Clear out the object type and the first qualifier in scope; they only
+ // apply to the first element in the nested-name-specifier.
+ ObjectType = QualType();
+ FirstQualifierInScope = 0;
+ }
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ assert((Prefix || !ObjectType.isNull()) &&
+ "Identifier nested-name-specifier with no prefix or object type");
+ if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() &&
+ ObjectType.isNull())
+ return NNS;
+
+ return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
+ *NNS->getAsIdentifier(),
+ ObjectType,
+ FirstQualifierInScope);
+
+ case NestedNameSpecifier::Namespace: {
+ NamespaceDecl *NS
+ = cast_or_null<NamespaceDecl>(
+ getDerived().TransformDecl(NNS->getAsNamespace()));
+ if (!getDerived().AlwaysRebuild() &&
+ Prefix == NNS->getPrefix() &&
+ NS == NNS->getAsNamespace())
+ return NNS;
+
+ return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NS);
+ }
+
+ case NestedNameSpecifier::Global:
+ // There is no meaningful transformation that one could perform on the
+ // global scope.
+ return NNS;
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::TypeSpec: {
+ QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0));
+ if (T.isNull())
+ return 0;
+
+ if (!getDerived().AlwaysRebuild() &&
+ Prefix == NNS->getPrefix() &&
+ T == QualType(NNS->getAsType(), 0))
+ return NNS;
+
+ return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
+ NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
+ T);
+ }
+ }
+
+ // Required to silence a GCC warning
+ return 0;
+}
+
+template<typename Derived>
+DeclarationName
+TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name,
+ SourceLocation Loc) {
+ if (!Name)
+ return Name;
+
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXUsingDirective:
+ return Name;
+
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName: {
+ TemporaryBase Rebase(*this, Loc, Name);
+ QualType T = getDerived().TransformType(Name.getCXXNameType());
+ if (T.isNull())
+ return DeclarationName();
+
+ return SemaRef.Context.DeclarationNames.getCXXSpecialName(
+ Name.getNameKind(),
+ SemaRef.Context.getCanonicalType(T));
+ }
+ }
+
+ return DeclarationName();
+}
+
+template<typename Derived>
+TemplateName
+TreeTransform<Derived>::TransformTemplateName(TemplateName Name,
+ QualType ObjectType) {
+ if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(),
+ /*FIXME:*/SourceRange(getDerived().getBaseLocation()));
+ if (!NNS)
+ return TemplateName();
+
+ if (TemplateDecl *Template = QTN->getTemplateDecl()) {
+ TemplateDecl *TransTemplate
+ = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template));
+ if (!TransTemplate)
+ return TemplateName();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == QTN->getQualifier() &&
+ TransTemplate == Template)
+ return Name;
+
+ return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(),
+ TransTemplate);
+ }
+
+ OverloadedFunctionDecl *Ovl = QTN->getOverloadedFunctionDecl();
+ assert(Ovl && "Not a template name or an overload set?");
+ OverloadedFunctionDecl *TransOvl
+ = cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl));
+ if (!TransOvl)
+ return TemplateName();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == QTN->getQualifier() &&
+ TransOvl == Ovl)
+ return Name;
+
+ return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(),
+ TransOvl);
+ }
+
+ if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(DTN->getQualifier(),
+ /*FIXME:*/SourceRange(getDerived().getBaseLocation()));
+ if (!NNS && DTN->getQualifier())
+ return TemplateName();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == DTN->getQualifier())
+ return Name;
+
+ return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType);
+ }
+
+ if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
+ TemplateDecl *TransTemplate
+ = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template));
+ if (!TransTemplate)
+ return TemplateName();
+
+ if (!getDerived().AlwaysRebuild() &&
+ TransTemplate == Template)
+ return Name;
+
+ return TemplateName(TransTemplate);
+ }
+
+ OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl();
+ assert(Ovl && "Not a template name or an overload set?");
+ OverloadedFunctionDecl *TransOvl
+ = cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl));
+ if (!TransOvl)
+ return TemplateName();
+
+ if (!getDerived().AlwaysRebuild() &&
+ TransOvl == Ovl)
+ return Name;
+
+ return TemplateName(TransOvl);
+}
+
+template<typename Derived>
+TemplateArgument
+TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ return Arg;
+
+ case TemplateArgument::Type: {
+ QualType T = getDerived().TransformType(Arg.getAsType());
+ if (T.isNull())
+ return TemplateArgument();
+ return TemplateArgument(Arg.getLocation(), T);
+ }
+
+ case TemplateArgument::Declaration: {
+ Decl *D = getDerived().TransformDecl(Arg.getAsDecl());
+ if (!D)
+ return TemplateArgument();
+ return TemplateArgument(Arg.getLocation(), D);
+ }
+
+ case TemplateArgument::Expression: {
+ // Template argument expressions are not potentially evaluated.
+ EnterExpressionEvaluationContext Unevaluated(getSema(),
+ Action::Unevaluated);
+
+ Sema::OwningExprResult E = getDerived().TransformExpr(Arg.getAsExpr());
+ if (E.isInvalid())
+ return TemplateArgument();
+ return TemplateArgument(E.takeAs<Expr>());
+ }
+
+ case TemplateArgument::Pack: {
+ llvm::SmallVector<TemplateArgument, 4> TransformedArgs;
+ TransformedArgs.reserve(Arg.pack_size());
+ for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
+ AEnd = Arg.pack_end();
+ A != AEnd; ++A) {
+ TemplateArgument TA = getDerived().TransformTemplateArgument(*A);
+ if (TA.isNull())
+ return TA;
+
+ TransformedArgs.push_back(TA);
+ }
+ TemplateArgument Result;
+ Result.setArgumentPack(TransformedArgs.data(), TransformedArgs.size(),
+ true);
+ return Result;
+ }
+ }
+
+ // Work around bogus GCC warning
+ return TemplateArgument();
+}
+
+//===----------------------------------------------------------------------===//
+// Type transformation
+//===----------------------------------------------------------------------===//
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformType(QualType T) {
+ if (getDerived().AlreadyTransformed(T))
+ return T;
+
+ QualifierCollector Qs;
+ const Type *Ty = Qs.strip(T);
+
+ QualType Result;
+ switch (Ty->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) \
+ case Type::CLASS: \
+ Result = getDerived().Transform##CLASS##Type( \
+ static_cast<const CLASS##Type*>(Ty)); \
+ break;
+#include "clang/AST/TypeNodes.def"
+ }
+
+ if (Result.isNull() || T == Result)
+ return Result;
+
+ return getDerived().AddTypeQualifiers(Result, Qs);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::AddTypeQualifiers(QualType T, Qualifiers Quals) {
+ if (!Quals.empty() && !T->isFunctionType() && !T->isReferenceType())
+ return SemaRef.Context.getQualifiedType(T, Quals);
+
+ return T;
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformBuiltinType(const BuiltinType *T) {
+ // Nothing to do
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformFixedWidthIntType(
+ const FixedWidthIntType *T) {
+ // FIXME: Implement
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformComplexType(const ComplexType *T) {
+ // FIXME: Implement
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformPointerType(const PointerType *T) {
+ QualType PointeeType = getDerived().TransformType(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ PointeeType == T->getPointeeType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildPointerType(PointeeType);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformBlockPointerType(const BlockPointerType *T) {
+ QualType PointeeType = getDerived().TransformType(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ PointeeType == T->getPointeeType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildBlockPointerType(PointeeType);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformLValueReferenceType(
+ const LValueReferenceType *T) {
+ QualType PointeeType = getDerived().TransformType(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ PointeeType == T->getPointeeType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildLValueReferenceType(PointeeType);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformRValueReferenceType(
+ const RValueReferenceType *T) {
+ QualType PointeeType = getDerived().TransformType(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ PointeeType == T->getPointeeType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildRValueReferenceType(PointeeType);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformMemberPointerType(const MemberPointerType *T) {
+ QualType PointeeType = getDerived().TransformType(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ QualType ClassType = getDerived().TransformType(QualType(T->getClass(), 0));
+ if (ClassType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ PointeeType == T->getPointeeType() &&
+ ClassType == QualType(T->getClass(), 0))
+ return QualType(T, 0);
+
+ return getDerived().RebuildMemberPointerType(PointeeType, ClassType);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformConstantArrayType(const ConstantArrayType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildConstantArrayType(ElementType,
+ T->getSizeModifier(),
+ T->getSize(),
+ T->getIndexTypeCVRQualifiers());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformConstantArrayWithExprType(
+ const ConstantArrayWithExprType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ // Array bounds are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
+ if (Size.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType() &&
+ Size.get() == T->getSizeExpr())
+ return QualType(T, 0);
+
+ return getDerived().RebuildConstantArrayWithExprType(ElementType,
+ T->getSizeModifier(),
+ T->getSize(),
+ Size.takeAs<Expr>(),
+ T->getIndexTypeCVRQualifiers(),
+ T->getBracketsRange());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformConstantArrayWithoutExprType(
+ const ConstantArrayWithoutExprType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildConstantArrayWithoutExprType(ElementType,
+ T->getSizeModifier(),
+ T->getSize(),
+ T->getIndexTypeCVRQualifiers());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformIncompleteArrayType(
+ const IncompleteArrayType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildIncompleteArrayType(ElementType,
+ T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformVariableArrayType(
+ const VariableArrayType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ // Array bounds are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
+ if (Size.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType() &&
+ Size.get() == T->getSizeExpr()) {
+ Size.take();
+ return QualType(T, 0);
+ }
+
+ return getDerived().RebuildVariableArrayType(ElementType,
+ T->getSizeModifier(),
+ move(Size),
+ T->getIndexTypeCVRQualifiers(),
+ T->getBracketsRange());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformDependentSizedArrayType(
+ const DependentSizedArrayType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ // Array bounds are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
+ if (Size.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType() &&
+ Size.get() == T->getSizeExpr()) {
+ Size.take();
+ return QualType(T, 0);
+ }
+
+ return getDerived().RebuildDependentSizedArrayType(ElementType,
+ T->getSizeModifier(),
+ move(Size),
+ T->getIndexTypeCVRQualifiers(),
+ T->getBracketsRange());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ // Vector sizes are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
+ if (Size.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType() &&
+ Size.get() == T->getSizeExpr()) {
+ Size.take();
+ return QualType(T, 0);
+ }
+
+ return getDerived().RebuildDependentSizedExtVectorType(ElementType,
+ move(Size),
+ T->getAttributeLoc());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformVectorType(const VectorType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildVectorType(ElementType, T->getNumElements());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformExtVectorType(const ExtVectorType *T) {
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ElementType == T->getElementType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildExtVectorType(ElementType, T->getNumElements(),
+ /*FIXME*/SourceLocation());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformFunctionProtoType(
+ const FunctionProtoType *T) {
+ QualType ResultType = getDerived().TransformType(T->getResultType());
+ if (ResultType.isNull())
+ return QualType();
+
+ llvm::SmallVector<QualType, 4> ParamTypes;
+ for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(),
+ ParamEnd = T->arg_type_end();
+ Param != ParamEnd; ++Param) {
+ QualType P = getDerived().TransformType(*Param);
+ if (P.isNull())
+ return QualType();
+
+ ParamTypes.push_back(P);
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ ResultType == T->getResultType() &&
+ std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin()))
+ return QualType(T, 0);
+
+ return getDerived().RebuildFunctionProtoType(ResultType, ParamTypes.data(),
+ ParamTypes.size(), T->isVariadic(),
+ T->getTypeQuals());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
+ const FunctionNoProtoType *T) {
+ // FIXME: Implement
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTypedefType(const TypedefType *T) {
+ TypedefDecl *Typedef
+ = cast_or_null<TypedefDecl>(getDerived().TransformDecl(T->getDecl()));
+ if (!Typedef)
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Typedef == T->getDecl())
+ return QualType(T, 0);
+
+ return getDerived().RebuildTypedefType(Typedef);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTypeOfExprType(
+ const TypeOfExprType *T) {
+ // typeof expressions are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
+ if (E.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ E.get() == T->getUnderlyingExpr()) {
+ E.take();
+ return QualType(T, 0);
+ }
+
+ return getDerived().RebuildTypeOfExprType(move(E));
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTypeOfType(const TypeOfType *T) {
+ QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
+ if (Underlying.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Underlying == T->getUnderlyingType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildTypeOfType(Underlying);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformDecltypeType(const DecltypeType *T) {
+ // decltype expressions are not potentially evaluated contexts
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
+ if (E.isInvalid())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ E.get() == T->getUnderlyingExpr()) {
+ E.take();
+ return QualType(T, 0);
+ }
+
+ return getDerived().RebuildDecltypeType(move(E));
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformRecordType(const RecordType *T) {
+ RecordDecl *Record
+ = cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl()));
+ if (!Record)
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Record == T->getDecl())
+ return QualType(T, 0);
+
+ return getDerived().RebuildRecordType(Record);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformEnumType(const EnumType *T) {
+ EnumDecl *Enum
+ = cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl()));
+ if (!Enum)
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Enum == T->getDecl())
+ return QualType(T, 0);
+
+ return getDerived().RebuildEnumType(Enum);
+}
+
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformElaboratedType(
+ const ElaboratedType *T) {
+ QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
+ if (Underlying.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Underlying == T->getUnderlyingType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildElaboratedType(Underlying, T->getTagKind());
+}
+
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
+ const TemplateTypeParmType *T) {
+ // Nothing to do
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
+ const TemplateSpecializationType *T) {
+ TemplateName Template
+ = getDerived().TransformTemplateName(T->getTemplateName());
+ if (Template.isNull())
+ return QualType();
+
+ llvm::SmallVector<TemplateArgument, 4> NewTemplateArgs;
+ NewTemplateArgs.reserve(T->getNumArgs());
+ for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
+ Arg != ArgEnd; ++Arg) {
+ TemplateArgument NewArg = getDerived().TransformTemplateArgument(*Arg);
+ if (NewArg.isNull())
+ return QualType();
+
+ NewTemplateArgs.push_back(NewArg);
+ }
+
+ // FIXME: early abort if all of the template arguments and such are the
+ // same.
+
+ // FIXME: We're missing the locations of the template name, '<', and '>'.
+ return getDerived().RebuildTemplateSpecializationType(Template,
+ NewTemplateArgs.data(),
+ NewTemplateArgs.size());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformQualifiedNameType(
+ const QualifiedNameType *T) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
+ SourceRange());
+ if (!NNS)
+ return QualType();
+
+ QualType Named = getDerived().TransformType(T->getNamedType());
+ if (Named.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == T->getQualifier() &&
+ Named == T->getNamedType())
+ return QualType(T, 0);
+
+ return getDerived().RebuildQualifiedNameType(NNS, Named);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTypenameType(const TypenameType *T) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
+ SourceRange(/*FIXME:*/getDerived().getBaseLocation()));
+ if (!NNS)
+ return QualType();
+
+ if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
+ QualType NewTemplateId
+ = getDerived().TransformType(QualType(TemplateId, 0));
+ if (NewTemplateId.isNull())
+ return QualType();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == T->getQualifier() &&
+ NewTemplateId == QualType(TemplateId, 0))
+ return QualType(T, 0);
+
+ return getDerived().RebuildTypenameType(NNS, NewTemplateId);
+ }
+
+ return getDerived().RebuildTypenameType(NNS, T->getIdentifier());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformObjCInterfaceType(
+ const ObjCInterfaceType *T) {
+ // FIXME: Implement
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformObjCObjectPointerType(
+ const ObjCObjectPointerType *T) {
+ // FIXME: Implement
+ return QualType(T, 0);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformObjCProtocolListType(
+ const ObjCProtocolListType *T) {
+ assert(false && "Should not see ObjCProtocolList types");
+ return QualType(T, 0);
+}
+
+//===----------------------------------------------------------------------===//
+// Statement transformation
+//===----------------------------------------------------------------------===//
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformNullStmt(NullStmt *S) {
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S) {
+ return getDerived().TransformCompoundStmt(S, false);
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
+ bool IsStmtExpr) {
+ bool SubStmtChanged = false;
+ ASTOwningVector<&ActionBase::DeleteStmt> Statements(getSema());
+ for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end();
+ B != BEnd; ++B) {
+ OwningStmtResult Result = getDerived().TransformStmt(*B);
+ if (Result.isInvalid())
+ return getSema().StmtError();
+
+ SubStmtChanged = SubStmtChanged || Result.get() != *B;
+ Statements.push_back(Result.takeAs<Stmt>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ !SubStmtChanged)
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildCompoundStmt(S->getLBracLoc(),
+ move_arg(Statements),
+ S->getRBracLoc(),
+ IsStmtExpr);
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) {
+ // The case value expressions are not potentially evaluated.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ // Transform the left-hand case value.
+ OwningExprResult LHS = getDerived().TransformExpr(S->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the right-hand case value (for the GNU case-range extension).
+ OwningExprResult RHS = getDerived().TransformExpr(S->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.StmtError();
+
+ // Build the case statement.
+ // Case statements are always rebuilt so that they will attached to their
+ // transformed switch statement.
+ OwningStmtResult Case = getDerived().RebuildCaseStmt(S->getCaseLoc(),
+ move(LHS),
+ S->getEllipsisLoc(),
+ move(RHS),
+ S->getColonLoc());
+ if (Case.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the statement following the case
+ OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+ if (SubStmt.isInvalid())
+ return SemaRef.StmtError();
+
+ // Attach the body to the case statement
+ return getDerived().RebuildCaseStmtBody(move(Case), move(SubStmt));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformDefaultStmt(DefaultStmt *S) {
+ // Transform the statement following the default case
+ OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+ if (SubStmt.isInvalid())
+ return SemaRef.StmtError();
+
+ // Default statements are always rebuilt
+ return getDerived().RebuildDefaultStmt(S->getDefaultLoc(), S->getColonLoc(),
+ move(SubStmt));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) {
+ OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+ if (SubStmt.isInvalid())
+ return SemaRef.StmtError();
+
+ // FIXME: Pass the real colon location in.
+ SourceLocation ColonLoc = SemaRef.PP.getLocForEndOfToken(S->getIdentLoc());
+ return getDerived().RebuildLabelStmt(S->getIdentLoc(), S->getID(), ColonLoc,
+ move(SubStmt));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
+ // Transform the condition
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
+
+ // Transform the "then" branch.
+ OwningStmtResult Then = getDerived().TransformStmt(S->getThen());
+ if (Then.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the "else" branch.
+ OwningStmtResult Else = getDerived().TransformStmt(S->getElse());
+ if (Else.isInvalid())
+ return SemaRef.StmtError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ FullCond->get() == S->getCond() &&
+ Then.get() == S->getThen() &&
+ Else.get() == S->getElse())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, move(Then),
+ S->getElseLoc(), move(Else));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
+ // Transform the condition.
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Rebuild the switch statement.
+ OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(move(Cond));
+ if (Switch.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body of the switch statement.
+ OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ // Complete the switch statement.
+ return getDerived().RebuildSwitchStmtBody(S->getSwitchLoc(), move(Switch),
+ move(Body));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
+ // Transform the condition
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
+
+ // Transform the body
+ OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ FullCond->get() == S->getCond() &&
+ Body.get() == S->getBody())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, move(Body));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformDoStmt(DoStmt *S) {
+ // Transform the condition
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body
+ OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Cond.get() == S->getCond() &&
+ Body.get() == S->getBody())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildDoStmt(S->getDoLoc(), move(Body), S->getWhileLoc(),
+ /*FIXME:*/S->getWhileLoc(), move(Cond),
+ S->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
+ // Transform the initialization statement
+ OwningStmtResult Init = getDerived().TransformStmt(S->getInit());
+ if (Init.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the condition
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the increment
+ OwningExprResult Inc = getDerived().TransformExpr(S->getInc());
+ if (Inc.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body
+ OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Init.get() == S->getInit() &&
+ Cond.get() == S->getCond() &&
+ Inc.get() == S->getInc() &&
+ Body.get() == S->getBody())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
+ move(Init), move(Cond), move(Inc),
+ S->getRParenLoc(), move(Body));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformGotoStmt(GotoStmt *S) {
+ // Goto statements must always be rebuilt, to resolve the label.
+ return getDerived().RebuildGotoStmt(S->getGotoLoc(), S->getLabelLoc(),
+ S->getLabel());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) {
+ OwningExprResult Target = getDerived().TransformExpr(S->getTarget());
+ if (Target.isInvalid())
+ return SemaRef.StmtError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Target.get() == S->getTarget())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(),
+ move(Target));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformContinueStmt(ContinueStmt *S) {
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) {
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformReturnStmt(ReturnStmt *S) {
+ Sema::OwningExprResult Result = getDerived().TransformExpr(S->getRetValue());
+ if (Result.isInvalid())
+ return SemaRef.StmtError();
+
+ // FIXME: We always rebuild the return statement because there is no way
+ // to tell whether the return type of the function has changed.
+ return getDerived().RebuildReturnStmt(S->getReturnLoc(), move(Result));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) {
+ bool DeclChanged = false;
+ llvm::SmallVector<Decl *, 4> Decls;
+ for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D) {
+ Decl *Transformed = getDerived().TransformDefinition(*D);
+ if (!Transformed)
+ return SemaRef.StmtError();
+
+ if (Transformed != *D)
+ DeclChanged = true;
+
+ Decls.push_back(Transformed);
+ }
+
+ if (!getDerived().AlwaysRebuild() && !DeclChanged)
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildDeclStmt(Decls.data(), Decls.size(),
+ S->getStartLoc(), S->getEndLoc());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformSwitchCase(SwitchCase *S) {
+ assert(false && "SwitchCase is abstract and cannot be transformed");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
+ // FIXME: Implement!
+ assert(false && "Inline assembly cannot be transformed");
+ return SemaRef.Owned(S->Retain());
+}
+
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C @try statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C @catch statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C @finally statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C @throw statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
+ ObjCAtSynchronizedStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C @synchronized statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCForCollectionStmt(
+ ObjCForCollectionStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot transform an Objective-C for-each statement");
+ return SemaRef.Owned(S->Retain());
+}
+
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) {
+ // Transform the exception declaration, if any.
+ VarDecl *Var = 0;
+ if (S->getExceptionDecl()) {
+ VarDecl *ExceptionDecl = S->getExceptionDecl();
+ TemporaryBase Rebase(*this, ExceptionDecl->getLocation(),
+ ExceptionDecl->getDeclName());
+
+ QualType T = getDerived().TransformType(ExceptionDecl->getType());
+ if (T.isNull())
+ return SemaRef.StmtError();
+
+ Var = getDerived().RebuildExceptionDecl(ExceptionDecl,
+ T,
+ ExceptionDecl->getDeclaratorInfo(),
+ ExceptionDecl->getIdentifier(),
+ ExceptionDecl->getLocation(),
+ /*FIXME: Inaccurate*/
+ SourceRange(ExceptionDecl->getLocation()));
+ if (!Var || Var->isInvalidDecl()) {
+ if (Var)
+ Var->Destroy(SemaRef.Context);
+ return SemaRef.StmtError();
+ }
+ }
+
+ // Transform the actual exception handler.
+ OwningStmtResult Handler = getDerived().TransformStmt(S->getHandlerBlock());
+ if (Handler.isInvalid()) {
+ if (Var)
+ Var->Destroy(SemaRef.Context);
+ return SemaRef.StmtError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ !Var &&
+ Handler.get() == S->getHandlerBlock())
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildCXXCatchStmt(S->getCatchLoc(),
+ Var,
+ move(Handler));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
+ // Transform the try block itself.
+ OwningStmtResult TryBlock
+ = getDerived().TransformCompoundStmt(S->getTryBlock());
+ if (TryBlock.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the handlers.
+ bool HandlerChanged = false;
+ ASTOwningVector<&ActionBase::DeleteStmt> Handlers(SemaRef);
+ for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) {
+ OwningStmtResult Handler
+ = getDerived().TransformCXXCatchStmt(S->getHandler(I));
+ if (Handler.isInvalid())
+ return SemaRef.StmtError();
+
+ HandlerChanged = HandlerChanged || Handler.get() != S->getHandler(I);
+ Handlers.push_back(Handler.takeAs<Stmt>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ TryBlock.get() == S->getTryBlock() &&
+ !HandlerChanged)
+ return SemaRef.Owned(S->Retain());
+
+ return getDerived().RebuildCXXTryStmt(S->getTryLoc(), move(TryBlock),
+ move_arg(Handlers));
+}
+
+//===----------------------------------------------------------------------===//
+// Expression transformation
+//===----------------------------------------------------------------------===//
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
+ NamedDecl *ND
+ = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl()));
+ if (!ND)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() && ND == E->getDecl())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildDeclRefExpr(ND, E->getLocation());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildParenExpr(move(SubExpr), E->getLParen(),
+ E->getRParen());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildUnaryOperator(E->getOperatorLoc(),
+ E->getOpcode(),
+ move(SubExpr));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ if (E->isArgumentType()) {
+ QualType T = getDerived().TransformType(E->getArgumentType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() && T == E->getArgumentType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildSizeOfAlignOf(T, E->getOperatorLoc(),
+ E->isSizeOf(),
+ E->getSourceRange());
+ }
+
+ Sema::OwningExprResult SubExpr(SemaRef);
+ {
+ // C++0x [expr.sizeof]p1:
+ // The operand is either an expression, which is an unevaluated operand
+ // [...]
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
+ SubExpr = getDerived().TransformExpr(E->getArgumentExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getArgumentExpr())
+ return SemaRef.Owned(E->Retain());
+ }
+
+ return getDerived().RebuildSizeOfAlignOf(move(SubExpr), E->getOperatorLoc(),
+ E->isSizeOf(),
+ E->getSourceRange());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) {
+ OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult RHS = getDerived().TransformExpr(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+
+ if (!getDerived().AlwaysRebuild() &&
+ LHS.get() == E->getLHS() &&
+ RHS.get() == E->getRHS())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildArraySubscriptExpr(move(LHS),
+ /*FIXME:*/E->getLHS()->getLocStart(),
+ move(RHS),
+ E->getRBracketLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {
+ // Transform the callee.
+ OwningExprResult Callee = getDerived().TransformExpr(E->getCallee());
+ if (Callee.isInvalid())
+ return SemaRef.ExprError();
+
+ // Transform arguments.
+ bool ArgChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
+ OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ // FIXME: Wrong source location information for the ','.
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken(E->getArg(I)->getSourceRange().getEnd()));
+
+ ArgChanged = ArgChanged || Arg.get() != E->getArg(I);
+ Args.push_back(Arg.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Callee.get() == E->getCallee() &&
+ !ArgChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Wrong source location information for the '('.
+ SourceLocation FakeLParenLoc
+ = ((Expr *)Callee.get())->getSourceRange().getBegin();
+ return getDerived().RebuildCallExpr(move(Callee), FakeLParenLoc,
+ move_arg(Args),
+ FakeCommaLocs.data(),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ NestedNameSpecifier *Qualifier = 0;
+ if (E->hasQualifier()) {
+ Qualifier
+ = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange());
+ if (Qualifier == 0)
+ return SemaRef.ExprError();
+ }
+
+ NamedDecl *Member
+ = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getMemberDecl()));
+ if (!Member)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase() &&
+ Qualifier == E->getQualifier() &&
+ Member == E->getMemberDecl())
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Bogus source location for the operator
+ SourceLocation FakeOperatorLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
+
+ return getDerived().RebuildMemberExpr(move(Base), FakeOperatorLoc,
+ E->isArrow(),
+ Qualifier,
+ E->getQualifierRange(),
+ E->getMemberLoc(),
+ Member);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCastExpr(CastExpr *E) {
+ assert(false && "Cannot transform abstract class");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
+ OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult RHS = getDerived().TransformExpr(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ LHS.get() == E->getLHS() &&
+ RHS.get() == E->getRHS())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
+ move(LHS), move(RHS));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCompoundAssignOperator(
+ CompoundAssignOperator *E) {
+ return getDerived().TransformBinaryOperator(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) {
+ OwningExprResult Cond = getDerived().TransformExpr(E->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult RHS = getDerived().TransformExpr(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Cond.get() == E->getCond() &&
+ LHS.get() == E->getLHS() &&
+ RHS.get() == E->getRHS())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildConditionalOperator(move(Cond),
+ E->getQuestionLoc(),
+ move(LHS),
+ E->getColonLoc(),
+ move(RHS));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) {
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildImplicitCastExpr(T, E->getCastKind(),
+ move(SubExpr),
+ E->isLvalueCast());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) {
+ assert(false && "Cannot transform abstract class");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
+ QualType T;
+ {
+ // FIXME: Source location isn't quite accurate.
+ SourceLocation TypeStartLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
+ TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName());
+
+ T = getDerived().TransformType(E->getTypeAsWritten());
+ if (T.isNull())
+ return SemaRef.ExprError();
+ }
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getTypeAsWritten() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCStyleCaseExpr(E->getLParenLoc(), T,
+ E->getRParenLoc(),
+ move(SubExpr));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ QualType T;
+ {
+ // FIXME: Source location isn't quite accurate.
+ SourceLocation FakeTypeLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
+ TemporaryBase Rebase(*this, FakeTypeLoc, DeclarationName());
+
+ T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+ }
+
+ OwningExprResult Init = getDerived().TransformExpr(E->getInitializer());
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ Init.get() == E->getInitializer())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), T,
+ /*FIXME:*/E->getInitializer()->getLocEnd(),
+ move(Init));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) {
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase())
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Bad source location
+ SourceLocation FakeOperatorLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getBase()->getLocEnd());
+ return getDerived().RebuildExtVectorElementExpr(move(Base), FakeOperatorLoc,
+ E->getAccessorLoc(),
+ E->getAccessor());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) {
+ bool InitChanged = false;
+
+ ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef);
+ for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) {
+ OwningExprResult Init = getDerived().TransformExpr(E->getInit(I));
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+
+ InitChanged = InitChanged || Init.get() != E->getInit(I);
+ Inits.push_back(Init.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() && !InitChanged)
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildInitList(E->getLBraceLoc(), move_arg(Inits),
+ E->getRBraceLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
+ Designation Desig;
+
+ // transform the initializer value
+ OwningExprResult Init = getDerived().TransformExpr(E->getInit());
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+
+ // transform the designators.
+ ASTOwningVector<&ActionBase::DeleteExpr, 4> ArrayExprs(SemaRef);
+ bool ExprChanged = false;
+ for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
+ DEnd = E->designators_end();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator()) {
+ Desig.AddDesignator(Designator::getField(D->getFieldName(),
+ D->getDotLoc(),
+ D->getFieldLoc()));
+ continue;
+ }
+
+ if (D->isArrayDesignator()) {
+ OwningExprResult Index = getDerived().TransformExpr(E->getArrayIndex(*D));
+ if (Index.isInvalid())
+ return SemaRef.ExprError();
+
+ Desig.AddDesignator(Designator::getArray(Index.get(),
+ D->getLBracketLoc()));
+
+ ExprChanged = ExprChanged || Init.get() != E->getArrayIndex(*D);
+ ArrayExprs.push_back(Index.release());
+ continue;
+ }
+
+ assert(D->isArrayRangeDesignator() && "New kind of designator?");
+ OwningExprResult Start
+ = getDerived().TransformExpr(E->getArrayRangeStart(*D));
+ if (Start.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult End = getDerived().TransformExpr(E->getArrayRangeEnd(*D));
+ if (End.isInvalid())
+ return SemaRef.ExprError();
+
+ Desig.AddDesignator(Designator::getArrayRange(Start.get(),
+ End.get(),
+ D->getLBracketLoc(),
+ D->getEllipsisLoc()));
+
+ ExprChanged = ExprChanged || Start.get() != E->getArrayRangeStart(*D) ||
+ End.get() != E->getArrayRangeEnd(*D);
+
+ ArrayExprs.push_back(Start.release());
+ ArrayExprs.push_back(End.release());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Init.get() == E->getInit() &&
+ !ExprChanged)
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildDesignatedInitExpr(Desig, move_arg(ArrayExprs),
+ E->getEqualOrColonLoc(),
+ E->usesGNUSyntax(), move(Init));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformImplicitValueInitExpr(
+ ImplicitValueInitExpr *E) {
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildImplicitValueInitExpr(T);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) {
+ // FIXME: Do we want the type as written?
+ QualType T;
+
+ {
+ // FIXME: Source location isn't quite accurate.
+ TemporaryBase Rebase(*this, E->getBuiltinLoc(), DeclarationName());
+ T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+ }
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildVAArgExpr(E->getBuiltinLoc(), move(SubExpr),
+ T, E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) {
+ bool ArgumentChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef);
+ for (unsigned I = 0, N = E->getNumExprs(); I != N; ++I) {
+ OwningExprResult Init = getDerived().TransformExpr(E->getExpr(I));
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || Init.get() != E->getExpr(I);
+ Inits.push_back(Init.takeAs<Expr>());
+ }
+
+ return getDerived().RebuildParenListExpr(E->getLParenLoc(),
+ move_arg(Inits),
+ E->getRParenLoc());
+}
+
+/// \brief Transform an address-of-label expression.
+///
+/// By default, the transformation of an address-of-label expression always
+/// rebuilds the expression, so that the label identifier can be resolved to
+/// the corresponding label statement by semantic analysis.
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) {
+ return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(),
+ E->getLabel());
+}
+
+template<typename Derived>
+Sema::OwningExprResult TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) {
+ OwningStmtResult SubStmt
+ = getDerived().TransformCompoundStmt(E->getSubStmt(), true);
+ if (SubStmt.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ SubStmt.get() == E->getSubStmt())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildStmtExpr(E->getLParenLoc(),
+ move(SubStmt),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) {
+ QualType T1, T2;
+ {
+ // FIXME: Source location isn't quite accurate.
+ TemporaryBase Rebase(*this, E->getBuiltinLoc(), DeclarationName());
+
+ T1 = getDerived().TransformType(E->getArgType1());
+ if (T1.isNull())
+ return SemaRef.ExprError();
+
+ T2 = getDerived().TransformType(E->getArgType2());
+ if (T2.isNull())
+ return SemaRef.ExprError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ T1 == E->getArgType1() &&
+ T2 == E->getArgType2())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildTypesCompatibleExpr(E->getBuiltinLoc(),
+ T1, T2, E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) {
+ OwningExprResult Cond = getDerived().TransformExpr(E->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult RHS = getDerived().TransformExpr(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Cond.get() == E->getCond() &&
+ LHS.get() == E->getLHS() &&
+ RHS.get() == E->getRHS())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildChooseExpr(E->getBuiltinLoc(),
+ move(Cond), move(LHS), move(RHS),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ OwningExprResult Callee = getDerived().TransformExpr(E->getCallee());
+ if (Callee.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult First = getDerived().TransformExpr(E->getArg(0));
+ if (First.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult Second(SemaRef);
+ if (E->getNumArgs() == 2) {
+ Second = getDerived().TransformExpr(E->getArg(1));
+ if (Second.isInvalid())
+ return SemaRef.ExprError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Callee.get() == E->getCallee() &&
+ First.get() == E->getArg(0) &&
+ (E->getNumArgs() != 2 || Second.get() == E->getArg(1)))
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
+ E->getOperatorLoc(),
+ move(Callee),
+ move(First),
+ move(Second));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ return getDerived().TransformCallExpr(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
+ QualType ExplicitTy;
+ {
+ // FIXME: Source location isn't quite accurate.
+ SourceLocation TypeStartLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
+ TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName());
+
+ ExplicitTy = getDerived().TransformType(E->getTypeAsWritten());
+ if (ExplicitTy.isNull())
+ return SemaRef.ExprError();
+ }
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ExplicitTy == E->getTypeAsWritten() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Poor source location information here.
+ SourceLocation FakeLAngleLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
+ SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin();
+ SourceLocation FakeRParenLoc
+ = SemaRef.PP.getLocForEndOfToken(
+ E->getSubExpr()->getSourceRange().getEnd());
+ return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
+ E->getStmtClass(),
+ FakeLAngleLoc,
+ ExplicitTy,
+ FakeRAngleLoc,
+ FakeRAngleLoc,
+ move(SubExpr),
+ FakeRParenLoc);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXReinterpretCastExpr(
+ CXXReinterpretCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
+ CXXFunctionalCastExpr *E) {
+ QualType ExplicitTy;
+ {
+ TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
+
+ ExplicitTy = getDerived().TransformType(E->getTypeAsWritten());
+ if (ExplicitTy.isNull())
+ return SemaRef.ExprError();
+ }
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ ExplicitTy == E->getTypeAsWritten() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: The end of the type's source range is wrong
+ return getDerived().RebuildCXXFunctionalCastExpr(
+ /*FIXME:*/SourceRange(E->getTypeBeginLoc()),
+ ExplicitTy,
+ /*FIXME:*/E->getSubExpr()->getLocStart(),
+ move(SubExpr),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
+ if (E->isTypeOperand()) {
+ TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
+
+ QualType T = getDerived().TransformType(E->getTypeOperand());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getTypeOperand())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXTypeidExpr(E->getLocStart(),
+ /*FIXME:*/E->getLocStart(),
+ T,
+ E->getLocEnd());
+ }
+
+ // We don't know whether the expression is potentially evaluated until
+ // after we perform semantic analysis, so the expression is potentially
+ // potentially evaluated.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Action::PotentiallyPotentiallyEvaluated);
+
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ SubExpr.get() == E->getExprOperand())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXTypeidExpr(E->getLocStart(),
+ /*FIXME:*/E->getLocStart(),
+ move(SubExpr),
+ E->getLocEnd());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr(
+ CXXNullPtrLiteralExpr *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
+ TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
+
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXThisExpr(E->getLocStart(), T);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), move(SubExpr));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ ParmVarDecl *Param
+ = cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getParam()));
+ if (!Param)
+ return SemaRef.ExprError();
+
+ if (getDerived().AlwaysRebuild() &&
+ Param == E->getParam())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXDefaultArgExpr(Param);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
+ TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
+
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXZeroInitValueExpr(E->getTypeBeginLoc(),
+ /*FIXME:*/E->getTypeBeginLoc(),
+ T,
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E) {
+ VarDecl *Var
+ = cast_or_null<VarDecl>(getDerived().TransformDefinition(E->getVarDecl()));
+ if (!Var)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Var == E->getVarDecl())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXConditionDeclExpr(E->getStartLoc(),
+ /*FIXME:*/E->getStartLoc(),
+ Var);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
+ // Transform the type that we're allocating
+ TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
+ QualType AllocType = getDerived().TransformType(E->getAllocatedType());
+ if (AllocType.isNull())
+ return SemaRef.ExprError();
+
+ // Transform the size of the array we're allocating (if any).
+ OwningExprResult ArraySize = getDerived().TransformExpr(E->getArraySize());
+ if (ArraySize.isInvalid())
+ return SemaRef.ExprError();
+
+ // Transform the placement arguments (if any).
+ bool ArgumentChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> PlacementArgs(SemaRef);
+ for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) {
+ OwningExprResult Arg = getDerived().TransformExpr(E->getPlacementArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || Arg.get() != E->getPlacementArg(I);
+ PlacementArgs.push_back(Arg.take());
+ }
+
+ // transform the constructor arguments (if any).
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef);
+ for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) {
+ OwningExprResult Arg = getDerived().TransformExpr(E->getConstructorArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || Arg.get() != E->getConstructorArg(I);
+ ConstructorArgs.push_back(Arg.take());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ AllocType == E->getAllocatedType() &&
+ ArraySize.get() == E->getArraySize() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXNewExpr(E->getLocStart(),
+ E->isGlobalNew(),
+ /*FIXME:*/E->getLocStart(),
+ move_arg(PlacementArgs),
+ /*FIXME:*/E->getLocStart(),
+ E->isParenTypeId(),
+ AllocType,
+ /*FIXME:*/E->getLocStart(),
+ /*FIXME:*/SourceRange(),
+ move(ArraySize),
+ /*FIXME:*/E->getLocStart(),
+ move_arg(ConstructorArgs),
+ E->getLocEnd());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
+ OwningExprResult Operand = getDerived().TransformExpr(E->getArgument());
+ if (Operand.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Operand.get() == E->getArgument())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXDeleteExpr(E->getLocStart(),
+ E->isGlobalDelete(),
+ E->isArrayForm(),
+ move(Operand));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
+ CXXPseudoDestructorExpr *E) {
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ NestedNameSpecifier *Qualifier
+ = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange());
+ if (E->getQualifier() && !Qualifier)
+ return SemaRef.ExprError();
+
+ QualType DestroyedType;
+ {
+ TemporaryBase Rebase(*this, E->getDestroyedTypeLoc(), DeclarationName());
+ DestroyedType = getDerived().TransformType(E->getDestroyedType());
+ if (DestroyedType.isNull())
+ return SemaRef.ExprError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase() &&
+ Qualifier == E->getQualifier() &&
+ DestroyedType == E->getDestroyedType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXPseudoDestructorExpr(move(Base),
+ E->getOperatorLoc(),
+ E->isArrow(),
+ E->getDestroyedTypeLoc(),
+ DestroyedType,
+ Qualifier,
+ E->getQualifierRange());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformUnresolvedFunctionNameExpr(
+ UnresolvedFunctionNameExpr *E) {
+ // There is no transformation we can apply to an unresolved function name.
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
+ TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
+
+ QualType T = getDerived().TransformType(E->getQueriedType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getQueriedType())
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Bad location information
+ SourceLocation FakeLParenLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getLocStart());
+
+ return getDerived().RebuildUnaryTypeTrait(E->getTrait(),
+ E->getLocStart(),
+ /*FIXME:*/FakeLParenLoc,
+ T,
+ E->getLocEnd());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformQualifiedDeclRefExpr(QualifiedDeclRefExpr *E) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange());
+ if (!NNS)
+ return SemaRef.ExprError();
+
+ NamedDecl *ND
+ = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl()));
+ if (!ND)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == E->getQualifier() &&
+ ND == E->getDecl())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildQualifiedDeclRefExpr(NNS,
+ E->getQualifierRange(),
+ ND,
+ E->getLocation(),
+ /*FIXME:*/false);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformUnresolvedDeclRefExpr(
+ UnresolvedDeclRefExpr *E) {
+ NestedNameSpecifier *NNS
+ = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange());
+ if (!NNS)
+ return SemaRef.ExprError();
+
+ DeclarationName Name
+ = getDerived().TransformDeclarationName(E->getDeclName(), E->getLocation());
+ if (!Name)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ NNS == E->getQualifier() &&
+ Name == E->getDeclName())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildUnresolvedDeclRefExpr(NNS,
+ E->getQualifierRange(),
+ Name,
+ E->getLocation(),
+ /*FIXME:*/false);
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) {
+ TemplateName Template
+ = getDerived().TransformTemplateName(E->getTemplateName());
+ if (Template.isNull())
+ return SemaRef.ExprError();
+
+ llvm::SmallVector<TemplateArgument, 4> TransArgs;
+ for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
+ TemplateArgument TransArg
+ = getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]);
+ if (TransArg.isNull())
+ return SemaRef.ExprError();
+
+ TransArgs.push_back(TransArg);
+ }
+
+ // FIXME: Would like to avoid rebuilding if nothing changed, but we can't
+ // compare template arguments (yet).
+
+ // FIXME: It's possible that we'll find out now that the template name
+ // actually refers to a type, in which case the caller is actually dealing
+ // with a functional cast. Give a reasonable error message!
+ return getDerived().RebuildTemplateIdExpr(Template, E->getTemplateNameLoc(),
+ E->getLAngleLoc(),
+ TransArgs.data(),
+ TransArgs.size(),
+ E->getRAngleLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
+ TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
+
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ CXXConstructorDecl *Constructor
+ = cast_or_null<CXXConstructorDecl>(
+ getDerived().TransformDecl(E->getConstructor()));
+ if (!Constructor)
+ return SemaRef.ExprError();
+
+ bool ArgumentChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(),
+ ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg) {
+ OwningExprResult TransArg = getDerived().TransformExpr(*Arg);
+ if (TransArg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg;
+ Args.push_back(TransArg.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ Constructor == E->getConstructor() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXConstructExpr(T, Constructor, E->isElidable(),
+ move_arg(Args));
+}
+
+/// \brief Transform a C++ temporary-binding expression.
+///
+/// The transformation of a temporary-binding expression always attempts to
+/// bind a new temporary variable to its subexpression, even if the
+/// subexpression itself did not change, because the temporary variable itself
+/// must be unique.
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.MaybeBindToTemporary(SubExpr.takeAs<Expr>());
+}
+
+/// \brief Transform a C++ expression that contains temporaries that should
+/// be destroyed after the expression is evaluated.
+///
+/// The transformation of a full expression always attempts to build a new
+/// CXXExprWithTemporaries expression, even if the
+/// subexpression itself did not change, because it will need to capture the
+/// the new temporary variables introduced in the subexpression.
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXExprWithTemporaries(
+ CXXExprWithTemporaries *E) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.Owned(
+ SemaRef.MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs<Expr>(),
+ E->shouldDestroyTemporaries()));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
+ CXXTemporaryObjectExpr *E) {
+ TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ CXXConstructorDecl *Constructor
+ = cast_or_null<CXXConstructorDecl>(
+ getDerived().TransformDecl(E->getConstructor()));
+ if (!Constructor)
+ return SemaRef.ExprError();
+
+ bool ArgumentChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ Args.reserve(E->getNumArgs());
+ for (CXXTemporaryObjectExpr::arg_iterator Arg = E->arg_begin(),
+ ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg) {
+ OwningExprResult TransArg = getDerived().TransformExpr(*Arg);
+ if (TransArg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg;
+ Args.push_back((Expr *)TransArg.release());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ Constructor == E->getConstructor() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: Bogus location information
+ SourceLocation CommaLoc;
+ if (Args.size() > 1) {
+ Expr *First = (Expr *)Args[0];
+ CommaLoc
+ = SemaRef.PP.getLocForEndOfToken(First->getSourceRange().getEnd());
+ }
+ return getDerived().RebuildCXXTemporaryObjectExpr(E->getTypeBeginLoc(),
+ T,
+ /*FIXME:*/E->getTypeBeginLoc(),
+ move_arg(Args),
+ &CommaLoc,
+ E->getLocEnd());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
+ CXXUnresolvedConstructExpr *E) {
+ TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
+ QualType T = getDerived().TransformType(E->getTypeAsWritten());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ bool ArgumentChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ llvm::SmallVector<SourceLocation, 8> FakeCommaLocs;
+ for (CXXUnresolvedConstructExpr::arg_iterator Arg = E->arg_begin(),
+ ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg) {
+ OwningExprResult TransArg = getDerived().TransformExpr(*Arg);
+ if (TransArg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || TransArg.get() != *Arg;
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken((*Arg)->getLocEnd()));
+ Args.push_back(TransArg.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getTypeAsWritten() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // FIXME: we're faking the locations of the commas
+ return getDerived().RebuildCXXUnresolvedConstructExpr(E->getTypeBeginLoc(),
+ T,
+ E->getLParenLoc(),
+ move_arg(Args),
+ FakeCommaLocs.data(),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
+ CXXUnresolvedMemberExpr *E) {
+ // Transform the base of the expression.
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ Sema::TypeTy *ObjectType = 0;
+ Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
+ E->getOperatorLoc(),
+ E->isArrow()? tok::arrow : tok::period,
+ ObjectType);
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // FIXME: The first qualifier found might be a template type parameter,
+ // in which case there is no transformed declaration to refer to (it might
+ // refer to a built-in type!).
+ NamedDecl *FirstQualifierInScope
+ = cast_or_null<NamedDecl>(
+ getDerived().TransformDecl(E->getFirstQualifierFoundInScope()));
+
+ NestedNameSpecifier *Qualifier = 0;
+ if (E->getQualifier()) {
+ Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange(),
+ QualType::getFromOpaquePtr(ObjectType),
+ FirstQualifierInScope);
+ if (!Qualifier)
+ return SemaRef.ExprError();
+ }
+
+ DeclarationName Name
+ = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc());
+ if (!Name)
+ return SemaRef.ExprError();
+
+ if (!E->hasExplicitTemplateArgumentList()) {
+ // This is a reference to a member without an explicitly-specified
+ // template argument list. Optimize for this common case.
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase() &&
+ Qualifier == E->getQualifier() &&
+ Name == E->getMember() &&
+ FirstQualifierInScope == E->getFirstQualifierFoundInScope())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
+ E->isArrow(),
+ E->getOperatorLoc(),
+ Qualifier,
+ E->getQualifierRange(),
+ Name,
+ E->getMemberLoc(),
+ FirstQualifierInScope);
+ }
+
+ // FIXME: This is an ugly hack, which forces the same template name to
+ // be looked up multiple times. Yuck!
+ // FIXME: This also won't work for, e.g., x->template operator+<int>
+ TemplateName OrigTemplateName
+ = SemaRef.Context.getDependentTemplateName(0, Name.getAsIdentifierInfo());
+
+ TemplateName Template
+ = getDerived().TransformTemplateName(OrigTemplateName,
+ QualType::getFromOpaquePtr(ObjectType));
+ if (Template.isNull())
+ return SemaRef.ExprError();
+
+ llvm::SmallVector<TemplateArgument, 4> TransArgs;
+ for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
+ TemplateArgument TransArg
+ = getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]);
+ if (TransArg.isNull())
+ return SemaRef.ExprError();
+
+ TransArgs.push_back(TransArg);
+ }
+
+ return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
+ E->isArrow(),
+ E->getOperatorLoc(),
+ Qualifier,
+ E->getQualifierRange(),
+ Template,
+ E->getMemberLoc(),
+ FirstQualifierInScope,
+ E->getLAngleLoc(),
+ TransArgs.data(),
+ TransArgs.size(),
+ E->getRAngleLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) {
+ // FIXME: poor source location
+ TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName());
+ QualType EncodedType = getDerived().TransformType(E->getEncodedType());
+ if (EncodedType.isNull())
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ EncodedType == E->getEncodedType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCEncodeExpr(E->getAtLoc(),
+ EncodedType,
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) {
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) {
+ ObjCProtocolDecl *Protocol
+ = cast_or_null<ObjCProtocolDecl>(
+ getDerived().TransformDecl(E->getProtocol()));
+ if (!Protocol)
+ return SemaRef.ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ Protocol == E->getProtocol())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCProtocolExpr(Protocol,
+ E->getAtLoc(),
+ /*FIXME:*/E->getAtLoc(),
+ /*FIXME:*/E->getAtLoc(),
+ E->getRParenLoc());
+
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform Objective-C expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
+ bool ArgumentChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef);
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) {
+ OwningExprResult SubExpr = getDerived().TransformExpr(E->getExpr(I));
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgumentChanged = ArgumentChanged || SubExpr.get() != E->getExpr(I);
+ SubExprs.push_back(SubExpr.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ !ArgumentChanged)
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildShuffleVectorExpr(E->getBuiltinLoc(),
+ move_arg(SubExprs),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform block expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ // FIXME: Implement this!
+ assert(false && "Cannot transform block-related expressions yet");
+ return SemaRef.Owned(E->Retain());
+}
+
+//===----------------------------------------------------------------------===//
+// Type reconstruction
+//===----------------------------------------------------------------------===//
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildPointerType(QualType PointeeType) {
+ return SemaRef.BuildPointerType(PointeeType, Qualifiers(),
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildBlockPointerType(QualType PointeeType) {
+ return SemaRef.BuildBlockPointerType(PointeeType, Qualifiers(),
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildLValueReferenceType(QualType ReferentType) {
+ return SemaRef.BuildReferenceType(ReferentType, true, Qualifiers(),
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildRValueReferenceType(QualType ReferentType) {
+ return SemaRef.BuildReferenceType(ReferentType, false, Qualifiers(),
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
+ QualType ClassType) {
+ return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Qualifiers(),
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt *Size,
+ Expr *SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange) {
+ if (SizeExpr || !Size)
+ return SemaRef.BuildArrayType(ElementType, SizeMod, SizeExpr,
+ IndexTypeQuals, BracketsRange,
+ getDerived().getBaseEntity());
+
+ QualType Types[] = {
+ SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy,
+ SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy,
+ SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty
+ };
+ const unsigned NumTypes = sizeof(Types) / sizeof(QualType);
+ QualType SizeType;
+ for (unsigned I = 0; I != NumTypes; ++I)
+ if (Size->getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) {
+ SizeType = Types[I];
+ break;
+ }
+
+ if (SizeType.isNull())
+ SizeType = SemaRef.Context.getFixedWidthIntType(Size->getBitWidth(), false);
+
+ IntegerLiteral ArraySize(*Size, SizeType, /*FIXME*/BracketsRange.getBegin());
+ return SemaRef.BuildArrayType(ElementType, SizeMod, &ArraySize,
+ IndexTypeQuals, BracketsRange,
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ unsigned IndexTypeQuals) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0,
+ IndexTypeQuals, SourceRange());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildConstantArrayWithExprType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ Expr *SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr,
+ IndexTypeQuals, BracketsRange);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildConstantArrayWithoutExprType(
+ QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ const llvm::APInt &Size,
+ unsigned IndexTypeQuals) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0,
+ IndexTypeQuals, SourceRange());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildIncompleteArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ unsigned IndexTypeQuals) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, 0, 0,
+ IndexTypeQuals, SourceRange());
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildVariableArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ ExprArg SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, 0,
+ SizeExpr.takeAs<Expr>(),
+ IndexTypeQuals, BracketsRange);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType,
+ ArrayType::ArraySizeModifier SizeMod,
+ ExprArg SizeExpr,
+ unsigned IndexTypeQuals,
+ SourceRange BracketsRange) {
+ return getDerived().RebuildArrayType(ElementType, SizeMod, 0,
+ SizeExpr.takeAs<Expr>(),
+ IndexTypeQuals, BracketsRange);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType,
+ unsigned NumElements) {
+ // FIXME: semantic checking!
+ return SemaRef.Context.getVectorType(ElementType, NumElements);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildExtVectorType(QualType ElementType,
+ unsigned NumElements,
+ SourceLocation AttributeLoc) {
+ llvm::APInt numElements(SemaRef.Context.getIntWidth(SemaRef.Context.IntTy),
+ NumElements, true);
+ IntegerLiteral *VectorSize
+ = new (SemaRef.Context) IntegerLiteral(numElements, SemaRef.Context.IntTy,
+ AttributeLoc);
+ return SemaRef.BuildExtVectorType(ElementType, SemaRef.Owned(VectorSize),
+ AttributeLoc);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::RebuildDependentSizedExtVectorType(QualType ElementType,
+ ExprArg SizeExpr,
+ SourceLocation AttributeLoc) {
+ return SemaRef.BuildExtVectorType(ElementType, move(SizeExpr), AttributeLoc);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T,
+ QualType *ParamTypes,
+ unsigned NumParamTypes,
+ bool Variadic,
+ unsigned Quals) {
+ return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic,
+ Quals,
+ getDerived().getBaseLocation(),
+ getDerived().getBaseEntity());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildTypeOfExprType(ExprArg E) {
+ return SemaRef.BuildTypeofExprType(E.takeAs<Expr>());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) {
+ return SemaRef.Context.getTypeOfType(Underlying);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildDecltypeType(ExprArg E) {
+ return SemaRef.BuildDecltypeType(E.takeAs<Expr>());
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildTemplateSpecializationType(
+ TemplateName Template,
+ const TemplateArgument *Args,
+ unsigned NumArgs) {
+ // FIXME: Missing source locations for the template name, <, >.
+ return SemaRef.CheckTemplateIdType(Template, getDerived().getBaseLocation(),
+ SourceLocation(), Args, NumArgs,
+ SourceLocation());
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ IdentifierInfo &II,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope) {
+ CXXScopeSpec SS;
+ // FIXME: The source location information is all wrong.
+ SS.setRange(Range);
+ SS.setScopeRep(Prefix);
+ return static_cast<NestedNameSpecifier *>(
+ SemaRef.BuildCXXNestedNameSpecifier(0, SS, Range.getEnd(),
+ Range.getEnd(), II,
+ ObjectType,
+ FirstQualifierInScope,
+ false));
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ NamespaceDecl *NS) {
+ return NestedNameSpecifier::Create(SemaRef.Context, Prefix, NS);
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ bool TemplateKW,
+ QualType T) {
+ if (T->isDependentType() || T->isRecordType() ||
+ (SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) {
+ assert(!T.hasQualifiers() && "Can't get cv-qualifiers here");
+ return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW,
+ T.getTypePtr());
+ }
+
+ SemaRef.Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T;
+ return 0;
+}
+
+template<typename Derived>
+TemplateName
+TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ bool TemplateKW,
+ TemplateDecl *Template) {
+ return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW,
+ Template);
+}
+
+template<typename Derived>
+TemplateName
+TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ bool TemplateKW,
+ OverloadedFunctionDecl *Ovl) {
+ return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, Ovl);
+}
+
+template<typename Derived>
+TemplateName
+TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ const IdentifierInfo &II,
+ QualType ObjectType) {
+ CXXScopeSpec SS;
+ SS.setRange(SourceRange(getDerived().getBaseLocation()));
+ SS.setScopeRep(Qualifier);
+ return getSema().ActOnDependentTemplateName(
+ /*FIXME:*/getDerived().getBaseLocation(),
+ II,
+ /*FIXME:*/getDerived().getBaseLocation(),
+ SS,
+ ObjectType.getAsOpaquePtr())
+ .template getAsVal<TemplateName>();
+}
+
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
+ SourceLocation OpLoc,
+ ExprArg Callee,
+ ExprArg First,
+ ExprArg Second) {
+ Expr *FirstExpr = (Expr *)First.get();
+ Expr *SecondExpr = (Expr *)Second.get();
+ bool isPostIncDec = SecondExpr && (Op == OO_PlusPlus || Op == OO_MinusMinus);
+
+ // Determine whether this should be a builtin operation.
+ if (SecondExpr == 0 || isPostIncDec) {
+ if (!FirstExpr->getType()->isOverloadableType()) {
+ // The argument is not of overloadable type, so try to create a
+ // built-in unary operation.
+ UnaryOperator::Opcode Opc
+ = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec);
+
+ return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, move(First));
+ }
+ } else {
+ if (!FirstExpr->getType()->isOverloadableType() &&
+ !SecondExpr->getType()->isOverloadableType()) {
+ // Neither of the arguments is an overloadable type, so try to
+ // create a built-in binary operation.
+ BinaryOperator::Opcode Opc = BinaryOperator::getOverloadedOpcode(Op);
+ OwningExprResult Result
+ = SemaRef.CreateBuiltinBinOp(OpLoc, Opc, FirstExpr, SecondExpr);
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ First.release();
+ Second.release();
+ return move(Result);
+ }
+ }
+
+ // Compute the transformed set of functions (and function templates) to be
+ // used during overload resolution.
+ Sema::FunctionSet Functions;
+
+ DeclRefExpr *DRE
+ = cast<DeclRefExpr>(((Expr *)Callee.get())->IgnoreParenCasts());
+
+ // FIXME: Do we have to check
+ // IsAcceptableNonMemberOperatorCandidate for each of these?
+ for (OverloadIterator F(DRE->getDecl()), FEnd; F != FEnd; ++F)
+ Functions.insert(*F);
+
+ // Add any functions found via argument-dependent lookup.
+ Expr *Args[2] = { FirstExpr, SecondExpr };
+ unsigned NumArgs = 1 + (SecondExpr != 0);
+ DeclarationName OpName
+ = SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
+ SemaRef.ArgumentDependentLookup(OpName, Args, NumArgs, Functions);
+
+ // Create the overloaded operator invocation for unary operators.
+ if (NumArgs == 1 || isPostIncDec) {
+ UnaryOperator::Opcode Opc
+ = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec);
+ return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(First));
+ }
+
+ // Create the overloaded operator invocation for binary operators.
+ BinaryOperator::Opcode Opc =
+ BinaryOperator::getOverloadedOpcode(Op);
+ OwningExprResult Result
+ = SemaRef.CreateOverloadedBinOp(OpLoc, Opc, Functions, Args[0], Args[1]);
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ First.release();
+ Second.release();
+ return move(Result);
+}
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_SEMA_TREETRANSFORM_H