summaryrefslogtreecommitdiffstats
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp29
-rw-r--r--lib/Sema/CMakeLists.txt2
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp67
-rw-r--r--lib/Sema/JumpDiagnostics.cpp378
-rw-r--r--lib/Sema/Sema.cpp43
-rw-r--r--lib/Sema/Sema.h146
-rw-r--r--lib/Sema/SemaAttr.cpp98
-rw-r--r--lib/Sema/SemaCXXCast.cpp25
-rw-r--r--lib/Sema/SemaChecking.cpp406
-rw-r--r--lib/Sema/SemaCodeComplete.cpp555
-rw-r--r--lib/Sema/SemaDecl.cpp263
-rw-r--r--lib/Sema/SemaDeclAttr.cpp68
-rw-r--r--lib/Sema/SemaDeclCXX.cpp605
-rw-r--r--lib/Sema/SemaDeclObjC.cpp52
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp2
-rw-r--r--lib/Sema/SemaExpr.cpp258
-rw-r--r--lib/Sema/SemaExprCXX.cpp153
-rw-r--r--lib/Sema/SemaExprObjC.cpp59
-rw-r--r--lib/Sema/SemaInit.cpp87
-rw-r--r--lib/Sema/SemaInit.h44
-rw-r--r--lib/Sema/SemaLookup.cpp97
-rw-r--r--lib/Sema/SemaObjCProperty.cpp184
-rw-r--r--lib/Sema/SemaOverload.cpp588
-rw-r--r--lib/Sema/SemaOverload.h45
-rw-r--r--lib/Sema/SemaStmt.cpp397
-rw-r--r--lib/Sema/SemaTemplate.cpp286
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp33
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp85
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp87
-rw-r--r--lib/Sema/SemaType.cpp242
-rw-r--r--lib/Sema/TreeTransform.h328
31 files changed, 3866 insertions, 1846 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 6ded0a3..448d161 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -54,8 +54,13 @@ static void CheckUnreachable(Sema &S, AnalysisContext &AC) {
// Check for missing return value.
//===----------------------------------------------------------------------===//
-enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
- AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 };
+enum ControlFlowKind {
+ UnknownFallThrough,
+ NeverFallThrough,
+ MaybeFallThrough,
+ AlwaysFallThrough,
+ NeverFallThroughOrReturn
+};
/// CheckFallThrough - Check that we don't fall off the end of a
/// Statement that should return a value.
@@ -68,9 +73,7 @@ enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
/// will return.
static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
CFG *cfg = AC.getCFG();
- if (cfg == 0)
- // FIXME: This should be NeverFallThrough
- return NeverFallThroughOrReturn;
+ if (cfg == 0) return UnknownFallThrough;
// The CFG leaves in dead things, and we don't want the dead code paths to
// confuse us, so we mark all live things first.
@@ -164,6 +167,19 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
}
}
}
+ // FIXME: Remove this hack once temporaries and their destructors are
+ // modeled correctly by the CFG.
+ if (CXXExprWithTemporaries *E = dyn_cast<CXXExprWithTemporaries>(S)) {
+ for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) {
+ const FunctionDecl *FD = E->getTemporary(I)->getDestructor();
+ if (FD->hasAttr<NoReturnAttr>() ||
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ break;
+ }
+ }
+ }
// FIXME: Add noreturn message sends.
if (NoReturnEdge == false)
HasPlainEdge = true;
@@ -290,6 +306,9 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
// FIXME: Function try block
if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
switch (CheckFallThrough(AC)) {
+ case UnknownFallThrough:
+ break;
+
case MaybeFallThrough:
if (HasNoReturn)
S.Diag(Compound->getRBracLoc(),
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index ac0dfd6..b54e8eb 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -34,4 +34,4 @@ add_clang_library(clangSema
TargetAttributesSema.cpp
)
-add_dependencies(clangSema ClangDiagnosticSema)
+add_dependencies(clangSema ClangDiagnosticSema ClangStmtNodes)
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 0ef9a15..6cefc61 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -210,9 +210,10 @@ CodeCompletionString::Chunk::Destroy() {
}
}
-CodeCompletionString::~CodeCompletionString() {
+void CodeCompletionString::clear() {
std::for_each(Chunks.begin(), Chunks.end(),
std::mem_fun_ref(&Chunk::Destroy));
+ Chunks.clear();
}
std::string CodeCompletionString::getAsString() const {
@@ -310,15 +311,13 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
}
}
-CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
- const char *StrEnd) {
+bool CodeCompletionString::Deserialize(const char *&Str, const char *StrEnd) {
if (Str == StrEnd || *Str == 0)
- return 0;
+ return false;
- CodeCompletionString *Result = new CodeCompletionString;
unsigned NumBlocks;
if (ReadUnsigned(Str, StrEnd, NumBlocks))
- return Result;
+ return false;
for (unsigned I = 0; I != NumBlocks; ++I) {
if (Str + 1 >= StrEnd)
@@ -327,7 +326,7 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
// Parse the next kind.
unsigned KindValue;
if (ReadUnsigned(Str, StrEnd, KindValue))
- return Result;
+ return false;
switch (ChunkKind Kind = (ChunkKind)KindValue) {
case CK_TypedText:
@@ -338,16 +337,17 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
case CK_CurrentParameter: {
unsigned StrLen;
if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd))
- return Result;
+ return false;
- Result->AddChunk(Chunk(Kind, StringRef(Str, StrLen)));
+ AddChunk(Chunk(Kind, StringRef(Str, StrLen)));
Str += StrLen;
break;
}
case CK_Optional: {
- std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str, StrEnd));
- Result->AddOptionalChunk(Optional);
+ std::auto_ptr<CodeCompletionString> Optional(new CodeCompletionString());
+ if (Optional->Deserialize(Str, StrEnd))
+ AddOptionalChunk(Optional);
break;
}
@@ -365,12 +365,12 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
case CK_Equal:
case CK_HorizontalSpace:
case CK_VerticalSpace:
- Result->AddChunk(Chunk(Kind));
+ AddChunk(Chunk(Kind));
break;
}
};
- return Result;
+ return true;
}
void CodeCompleteConsumer::Result::Destroy() {
@@ -380,6 +380,25 @@ void CodeCompleteConsumer::Result::Destroy() {
}
}
+unsigned CodeCompleteConsumer::Result::getPriorityFromDecl(NamedDecl *ND) {
+ if (!ND)
+ return CCP_Unlikely;
+
+ // Context-based decisions.
+ DeclContext *DC = ND->getDeclContext()->getLookupContext();
+ if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC))
+ return CCP_LocalDeclaration;
+ if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
+ return CCP_MemberDeclaration;
+
+ // Content-based decisions.
+ if (isa<EnumConstantDecl>(ND))
+ return CCP_Constant;
+ if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND))
+ return CCP_Type;
+ return CCP_Declaration;
+}
+
//===----------------------------------------------------------------------===//
// Code completion overload candidate implementation
//===----------------------------------------------------------------------===//
@@ -459,11 +478,6 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
}
}
}
-
- // Once we've printed the code-completion results, suppress remaining
- // diagnostics.
- // FIXME: Move this somewhere else!
- SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
}
void
@@ -478,11 +492,6 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
delete CCS;
}
}
-
- // Once we've printed the code-completion results, suppress remaining
- // diagnostics.
- // FIXME: Move this somewhere else!
- SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
}
void
@@ -594,16 +603,12 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
}
WriteUnsigned(OS, Kind);
+ WriteUnsigned(OS, Results[I].Priority);
CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef);
assert(CCS && "No code-completion string?");
CCS->Serialize(OS);
delete CCS;
}
-
- // Once we've printed the code-completion results, suppress remaining
- // diagnostics.
- // FIXME: Move this somewhere else!
- SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
}
void
@@ -613,15 +618,11 @@ CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
unsigned NumCandidates) {
for (unsigned I = 0; I != NumCandidates; ++I) {
WriteUnsigned(OS, CXCursor_NotImplemented);
+ WriteUnsigned(OS, /*Priority=*/0);
CodeCompletionString *CCS
= Candidates[I].CreateSignatureString(CurrentArg, SemaRef);
assert(CCS && "No code-completion string?");
CCS->Serialize(OS);
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/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 0694294..543c1b6 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/BitVector.h"
#include "Sema.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtObjC.h"
@@ -39,33 +40,47 @@ class JumpScopeChecker {
/// the parent scope is the function body.
unsigned ParentScope;
- /// Diag - The diagnostic to emit if there is a jump into this scope.
- unsigned Diag;
+ /// InDiag - The diagnostic to emit if there is a jump into this scope.
+ unsigned InDiag;
+
+ /// OutDiag - The diagnostic to emit if there is an indirect jump out
+ /// of this scope. Direct jumps always clean up their current scope
+ /// in an orderly way.
+ unsigned OutDiag;
/// Loc - Location to emit the diagnostic.
SourceLocation Loc;
- GotoScope(unsigned parentScope, unsigned diag, SourceLocation L)
- : ParentScope(parentScope), Diag(diag), Loc(L) {}
+ GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag,
+ SourceLocation L)
+ : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {}
};
llvm::SmallVector<GotoScope, 48> Scopes;
llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
llvm::SmallVector<Stmt*, 16> Jumps;
+
+ llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
+ llvm::SmallVector<LabelStmt*, 4> IndirectJumpTargets;
public:
JumpScopeChecker(Stmt *Body, Sema &S);
private:
void BuildScopeInformation(Stmt *S, unsigned ParentScope);
void VerifyJumps();
+ void VerifyIndirectJumps();
+ void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
+ LabelStmt *Target, unsigned TargetScope);
void CheckJump(Stmt *From, Stmt *To,
SourceLocation DiagLoc, unsigned JumpDiag);
+
+ unsigned GetDeepestCommonScope(unsigned A, unsigned B);
};
} // end anonymous namespace
JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
// Add a scope entry for function scope.
- Scopes.push_back(GotoScope(~0U, ~0U, SourceLocation()));
+ Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation()));
// Build information for the top level compound statement, so that we have a
// defined scope record for every "goto" and label.
@@ -73,29 +88,64 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
// Check that all jumps we saw are kosher.
VerifyJumps();
+ VerifyIndirectJumps();
+}
+
+/// GetDeepestCommonScope - Finds the innermost scope enclosing the
+/// two scopes.
+unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) {
+ while (A != B) {
+ // Inner scopes are created after outer scopes and therefore have
+ // higher indices.
+ if (A < B) {
+ assert(Scopes[B].ParentScope < B);
+ B = Scopes[B].ParentScope;
+ } else {
+ assert(Scopes[A].ParentScope < A);
+ A = Scopes[A].ParentScope;
+ }
+ }
+ return A;
}
/// 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, bool isCPlusPlus) {
+static std::pair<unsigned,unsigned>
+ GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ unsigned InDiag = 0, OutDiag = 0;
if (VD->getType()->isVariablyModifiedType())
- 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;
- // FIXME: In C++0x, we have to check more conditions than "did we
- // just give it an initializer?". See 6.7p3.
- if (isCPlusPlus && VD->hasLocalStorage() && VD->hasInit())
- return diag::note_protected_by_variable_init;
+ InDiag = diag::note_protected_by_vla;
+
+ if (VD->hasAttr<BlocksAttr>()) {
+ InDiag = diag::note_protected_by___block;
+ OutDiag = diag::note_exits___block;
+ } else if (VD->hasAttr<CleanupAttr>()) {
+ InDiag = diag::note_protected_by_cleanup;
+ OutDiag = diag::note_exits_cleanup;
+ } else if (isCPlusPlus) {
+ // FIXME: In C++0x, we have to check more conditions than "did we
+ // just give it an initializer?". See 6.7p3.
+ if (VD->hasLocalStorage() && VD->hasInit())
+ InDiag = diag::note_protected_by_variable_init;
+
+ CanQualType T = VD->getType()->getCanonicalTypeUnqualified();
+ while (CanQual<ArrayType> AT = T->getAs<ArrayType>())
+ T = AT->getElementType();
+ if (CanQual<RecordType> RT = T->getAs<RecordType>())
+ if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor())
+ OutDiag = diag::note_exits_dtor;
+ }
- } else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ return std::make_pair(InDiag, OutDiag);
+ }
+
+ if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
- return diag::note_protected_by_vla_typedef;
+ return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0);
}
- return 0;
+ return std::make_pair(0U, 0U);
}
@@ -106,14 +156,32 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
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)) {
+ switch (S->getStmtClass()) {
+ case Stmt::LabelStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::CaseStmtClass:
+ LabelAndGotoScopes[S] = ParentScope;
+ break;
+
+ case Stmt::AddrLabelExprClass:
+ IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel());
+ break;
+
+ case Stmt::IndirectGotoStmtClass:
LabelAndGotoScopes[S] = ParentScope;
- } else if (isa<GotoStmt>(S) || isa<SwitchStmt>(S) ||
- isa<IndirectGotoStmt>(S) || isa<AddrLabelExpr>(S)) {
+ IndirectJumps.push_back(cast<IndirectGotoStmt>(S));
+ break;
+
+ case Stmt::GotoStmtClass:
+ case Stmt::SwitchStmtClass:
// Remember both what scope a goto is in as well as the fact that we have
// it. This makes the second scan not have to walk the AST again.
LabelAndGotoScopes[S] = ParentScope;
Jumps.push_back(S);
+ break;
+
+ default:
+ break;
}
for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E;
@@ -131,8 +199,11 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
I != E; ++I) {
// If this decl causes a new scope, push and switch to it.
- if (unsigned Diag = GetDiagForGotoScopeDecl(*I, isCPlusPlus)) {
- Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation()));
+ std::pair<unsigned,unsigned> Diags
+ = GetDiagForGotoScopeDecl(*I, isCPlusPlus);
+ if (Diags.first || Diags.second) {
+ Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,
+ (*I)->getLocation()));
ParentScope = Scopes.size()-1;
}
@@ -149,7 +220,9 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
// walking all sub-stmts in that scope.
if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) {
// Recursively walk the AST for the @try part.
- Scopes.push_back(GotoScope(ParentScope,diag::note_protected_by_objc_try,
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_try,
+ diag::note_exits_objc_try,
AT->getAtTryLoc()));
if (Stmt *TryPart = AT->getTryBody())
BuildScopeInformation(TryPart, Scopes.size()-1);
@@ -159,6 +232,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
ObjCAtCatchStmt *AC = AT->getCatchStmt(I);
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_catch,
+ diag::note_exits_objc_catch,
AC->getAtCatchLoc()));
// @catches are nested and it isn't
BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1);
@@ -168,6 +242,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) {
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_finally,
+ diag::note_exits_objc_finally,
AF->getAtFinallyLoc()));
BuildScopeInformation(AF, Scopes.size()-1);
}
@@ -186,6 +261,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
// scope.
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_synchronized,
+ diag::note_exits_objc_synchronized,
AS->getAtSynchronizedLoc()));
BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1);
continue;
@@ -194,7 +270,9 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
// Disallow jumps into any part of a C++ try statement. This is pretty
// much the same as for Obj-C.
if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) {
- Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_try,
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_cxx_try,
+ diag::note_exits_cxx_try,
TS->getSourceRange().getBegin()));
if (Stmt *TryBlock = TS->getTryBlock())
BuildScopeInformation(TryBlock, Scopes.size()-1);
@@ -204,6 +282,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
CXXCatchStmt *CS = TS->getHandler(I);
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_cxx_catch,
+ diag::note_exits_cxx_catch,
CS->getSourceRange().getBegin()));
BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1);
}
@@ -229,54 +308,178 @@ void JumpScopeChecker::VerifyJumps() {
continue;
}
- if (SwitchStmt *SS = dyn_cast<SwitchStmt>(Jump)) {
- for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
- SC = SC->getNextSwitchCase()) {
- assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
- CheckJump(SS, SC, SC->getLocStart(),
- diag::err_switch_into_protected_scope);
- }
- continue;
+ SwitchStmt *SS = cast<SwitchStmt>(Jump);
+ for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
+ CheckJump(SS, SC, SC->getLocStart(),
+ diag::err_switch_into_protected_scope);
}
+ }
+}
- 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)) {
- assert(LabelAndGotoScopes.count(Jump) &&
- "Jump didn't get added to scopes?");
- unsigned GotoScope = LabelAndGotoScopes[IG];
- if (GotoScope == 0) continue; // indirect jump is ok.
- S.Diag(IG->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
- DiagnosticScope = GotoScope;
- } else {
- // We model &&Label as a jump for purposes of scope tracking. We actually
- // don't care *where* the address of label is, but we require the *label
- // itself* to be in scope 0. If it is nested inside of a VLA scope, then
- // it is possible for an indirect goto to illegally enter the VLA scope by
- // 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;
+/// VerifyIndirectJumps - Verify whether any possible indirect jump
+/// might cross a protection boundary. Unlike direct jumps, indirect
+/// jumps count cleanups as protection boundaries: since there's no
+/// way to know where the jump is going, we can't implicitly run the
+/// right cleanups the way we can with direct jumps.
+///
+/// Thus, an indirect jump is "trivial" if it bypasses no
+/// initializations and no teardowns. More formally, an indirect jump
+/// from A to B is trivial if the path out from A to DCA(A,B) is
+/// trivial and the path in from DCA(A,B) to B is trivial, where
+/// DCA(A,B) is the deepest common ancestor of A and B.
+/// Jump-triviality is transitive but asymmetric.
+///
+/// A path in is trivial if none of the entered scopes have an InDiag.
+/// A path out is trivial is none of the exited scopes have an OutDiag.
+///
+/// Under these definitions, this function checks that the indirect
+/// jump between A and B is trivial for every indirect goto statement A
+/// and every label B whose address was taken in the function.
+void JumpScopeChecker::VerifyIndirectJumps() {
+ if (IndirectJumps.empty()) return;
+
+ // If there aren't any address-of-label expressions in this function,
+ // complain about the first indirect goto.
+ if (IndirectJumpTargets.empty()) {
+ S.Diag(IndirectJumps[0]->getGotoLoc(),
+ diag::err_indirect_goto_without_addrlabel);
+ return;
+ }
+
+ // Collect a single representative of every scope containing an
+ // indirect goto. For most code bases, this substantially cuts
+ // down on the number of jump sites we'll have to consider later.
+ typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope;
+ llvm::SmallVector<JumpScope, 32> JumpScopes;
+ {
+ llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap;
+ for (llvm::SmallVectorImpl<IndirectGotoStmt*>::iterator
+ I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) {
+ IndirectGotoStmt *IG = *I;
+ assert(LabelAndGotoScopes.count(IG) &&
+ "indirect jump didn't get added to scopes?");
+ unsigned IGScope = LabelAndGotoScopes[IG];
+ IndirectGotoStmt *&Entry = JumpScopesMap[IGScope];
+ if (!Entry) Entry = IG;
+ }
+ JumpScopes.reserve(JumpScopesMap.size());
+ for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator
+ I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I)
+ JumpScopes.push_back(*I);
+ }
+
+ // Collect a single representative of every scope containing a
+ // label whose address was taken somewhere in the function.
+ // For most code bases, there will be only one such scope.
+ llvm::DenseMap<unsigned, LabelStmt*> TargetScopes;
+ for (llvm::SmallVectorImpl<LabelStmt*>::iterator
+ I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end();
+ I != E; ++I) {
+ LabelStmt *TheLabel = *I;
+ assert(LabelAndGotoScopes.count(TheLabel) &&
+ "Referenced label didn't get added to scopes?");
+ unsigned LabelScope = LabelAndGotoScopes[TheLabel];
+ LabelStmt *&Target = TargetScopes[LabelScope];
+ if (!Target) Target = TheLabel;
+ }
+
+ // For each target scope, make sure it's trivially reachable from
+ // every scope containing a jump site.
+ //
+ // A path between scopes always consists of exitting zero or more
+ // scopes, then entering zero or more scopes. We build a set of
+ // of scopes S from which the target scope can be trivially
+ // entered, then verify that every jump scope can be trivially
+ // exitted to reach a scope in S.
+ llvm::BitVector Reachable(Scopes.size(), false);
+ for (llvm::DenseMap<unsigned,LabelStmt*>::iterator
+ TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) {
+ unsigned TargetScope = TI->first;
+ LabelStmt *TargetLabel = TI->second;
+
+ Reachable.reset();
+
+ // Mark all the enclosing scopes from which you can safely jump
+ // into the target scope. 'Min' will end up being the index of
+ // the shallowest such scope.
+ unsigned Min = TargetScope;
+ while (true) {
+ Reachable.set(Min);
+
+ // Don't go beyond the outermost scope.
+ if (Min == 0) break;
+
+ // Stop if we can't trivially enter the current scope.
+ if (Scopes[Min].InDiag) break;
+
+ Min = Scopes[Min].ParentScope;
}
- // Report all the things that would be skipped over by this &&label or
- // indirect goto.
- while (DiagnosticScope != 0) {
- S.Diag(Scopes[DiagnosticScope].Loc, Scopes[DiagnosticScope].Diag);
- DiagnosticScope = Scopes[DiagnosticScope].ParentScope;
+ // Walk through all the jump sites, checking that they can trivially
+ // reach this label scope.
+ for (llvm::SmallVectorImpl<JumpScope>::iterator
+ I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) {
+ unsigned Scope = I->first;
+
+ // Walk out the "scope chain" for this scope, looking for a scope
+ // we've marked reachable. For well-formed code this amortizes
+ // to O(JumpScopes.size() / Scopes.size()): we only iterate
+ // when we see something unmarked, and in well-formed code we
+ // mark everything we iterate past.
+ bool IsReachable = false;
+ while (true) {
+ if (Reachable.test(Scope)) {
+ // If we find something reachable, mark all the scopes we just
+ // walked through as reachable.
+ for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope)
+ Reachable.set(S);
+ IsReachable = true;
+ break;
+ }
+
+ // Don't walk out if we've reached the top-level scope or we've
+ // gotten shallower than the shallowest reachable scope.
+ if (Scope == 0 || Scope < Min) break;
+
+ // Don't walk out through an out-diagnostic.
+ if (Scopes[Scope].OutDiag) break;
+
+ Scope = Scopes[Scope].ParentScope;
+ }
+
+ // Only diagnose if we didn't find something.
+ if (IsReachable) continue;
+
+ DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope);
}
}
}
+/// Diagnose an indirect jump which is known to cross scopes.
+void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
+ unsigned JumpScope,
+ LabelStmt *Target,
+ unsigned TargetScope) {
+ assert(JumpScope != TargetScope);
+
+ S.Diag(Jump->getGotoLoc(), diag::warn_indirect_goto_in_protected_scope);
+ S.Diag(Target->getIdentLoc(), diag::note_indirect_goto_target);
+
+ unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope);
+
+ // Walk out the scope chain until we reach the common ancestor.
+ for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)
+ if (Scopes[I].OutDiag)
+ S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
+
+ // Now walk into the scopes containing the label whose address was taken.
+ for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope)
+ if (Scopes[I].InDiag)
+ S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
+}
+
/// CheckJump - Validate that the specified jump statement is valid: that it is
/// jumping within or out of its current scope, not into a deeper one.
void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
@@ -290,42 +493,25 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *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.
- unsigned TestScope = Scopes[FromScope].ParentScope;
- while (TestScope != ~0U) {
- // 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;
- }
+ unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope);
- // 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);
+ // It's okay to jump out from a nested scope.
+ if (CommonScope == ToScope) return;
- // Eliminate the common prefix of the jump and the target. Start by
- // linearizing both scopes, reversing them as we go.
- std::vector<unsigned> FromScopes, ToScopes;
- for (TestScope = FromScope; TestScope != ~0U;
- TestScope = Scopes[TestScope].ParentScope)
- FromScopes.push_back(TestScope);
- for (TestScope = ToScope; TestScope != ~0U;
- TestScope = Scopes[TestScope].ParentScope)
- ToScopes.push_back(TestScope);
-
- // Remove any common entries (such as the top-level function scope).
- while (!FromScopes.empty() && FromScopes.back() == ToScopes.back()) {
- FromScopes.pop_back();
- ToScopes.pop_back();
- }
+ // Pull out (and reverse) any scopes we might need to diagnose skipping.
+ llvm::SmallVector<unsigned, 10> ToScopes;
+ for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope)
+ if (Scopes[I].InDiag)
+ ToScopes.push_back(I);
+
+ // If the only scopes present are cleanup scopes, we're okay.
+ if (ToScopes.empty()) return;
+
+ S.Diag(DiagLoc, JumpDiag);
// 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);
+ S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].InDiag);
}
void Sema::DiagnoseInvalidJumps(Stmt *Body) {
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 755af84..523b196 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -33,22 +33,12 @@ void FunctionScopeInfo::Clear(unsigned NumErrors) {
NeedsScopeChecking = false;
LabelMap.clear();
SwitchStack.clear();
+ Returns.clear();
NumErrorsAtStartOfFunction = NumErrors;
}
BlockScopeInfo::~BlockScopeInfo() { }
-static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
- if (C.getLangOptions().CPlusPlus)
- return CXXRecordDecl::Create(C, TagDecl::TK_struct,
- C.getTranslationUnitDecl(),
- SourceLocation(), &C.Idents.get(Name));
-
- return RecordDecl::Create(C, TagDecl::TK_struct,
- C.getTranslationUnitDecl(),
- SourceLocation(), &C.Idents.get(Name));
-}
-
void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
TUScope = S;
PushDeclContext(S, Context.getTranslationUnitDecl());
@@ -97,8 +87,9 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
}
// Create the built-in typedef for 'id'.
if (Context.getObjCIdType().isNull()) {
- QualType IdT = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy);
- TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(IdT);
+ QualType T = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, 0, 0);
+ T = Context.getObjCObjectPointerType(T);
+ TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(T);
TypedefDecl *IdTypedef
= TypedefDecl::Create(Context, CurContext, SourceLocation(),
&Context.Idents.get("id"), IdInfo);
@@ -108,9 +99,9 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
}
// Create the built-in typedef for 'Class'.
if (Context.getObjCClassType().isNull()) {
- QualType ClassType
- = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy);
- TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(ClassType);
+ QualType T = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, 0, 0);
+ T = Context.getObjCObjectPointerType(T);
+ TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(T);
TypedefDecl *ClassTypedef
= TypedefDecl::Create(Context, CurContext, SourceLocation(),
&Context.Idents.get("Class"), ClassInfo);
@@ -175,7 +166,17 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
}
}
- CheckImplicitConversion(Expr, Ty);
+ // If this is a derived-to-base cast to a through a virtual base, we
+ // need a vtable.
+ if (Kind == CastExpr::CK_DerivedToBase &&
+ BasePathInvolvesVirtualBase(BasePath)) {
+ QualType T = Expr->getType();
+ if (const PointerType *Pointer = T->getAs<PointerType>())
+ T = Pointer->getPointeeType();
+ if (const RecordType *RecordTy = T->getAs<RecordType>())
+ MarkVTableUsed(Expr->getLocStart(),
+ cast<CXXRecordDecl>(RecordTy->getDecl()));
+ }
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
if (ImpCast->getCastKind() == Kind && BasePath.empty()) {
@@ -212,10 +213,10 @@ void Sema::ActOnEndOfTranslationUnit() {
// template instantiations earlier.
PerformPendingImplicitInstantiations();
- /// If ProcessPendingClassesWithUnmarkedVirtualMembers ends up marking
- /// any virtual member functions it might lead to more pending template
+ /// If DefinedUsedVTables ends up marking any virtual member
+ /// functions it might lead to more pending template
/// instantiations, which is why we need to loop here.
- if (!ProcessPendingClassesWithUnmarkedVirtualMembers())
+ if (!DefineUsedVTables())
break;
}
@@ -304,7 +305,7 @@ void Sema::ActOnEndOfTranslationUnit() {
DeclContext *Sema::getFunctionLevelDeclContext() {
DeclContext *DC = CurContext;
- while (isa<BlockDecl>(DC))
+ while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC))
DC = DC->getParent();
return DC;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index f146c85..dfc45ac 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -134,6 +134,11 @@ struct FunctionScopeInfo {
/// block.
llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
+ /// \brief The list of return statements that occur within the function or
+ /// block, if there is any chance of applying the named return value
+ /// optimization.
+ llvm::SmallVector<ReturnStmt *, 4> Returns;
+
FunctionScopeInfo(unsigned NumErrors)
: IsBlockInfo(false), NeedsScopeChecking(false),
NumErrorsAtStartOfFunction(NumErrors) { }
@@ -768,7 +773,8 @@ public:
bool RequireCompleteType(SourceLocation Loc, QualType T,
unsigned DiagID);
- QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T);
+ QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
+ const CXXScopeSpec &SS, QualType T);
QualType BuildTypeofExprType(Expr *E);
QualType BuildDecltypeType(Expr *E);
@@ -901,11 +907,11 @@ 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);
+ virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS);
- bool InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
- RecordDecl *AnonRecord);
virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
+ AccessSpecifier AS,
RecordDecl *Record);
bool isAcceptableTagRedeclaration(const TagDecl *Previous,
@@ -1161,6 +1167,9 @@ public:
ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
bool PerformContextuallyConvertToBool(Expr *&From);
+ ImplicitConversionSequence TryContextuallyConvertToObjCId(Expr *From);
+ bool PerformContextuallyConvertToObjCId(Expr *&From);
+
bool PerformObjectMemberConversion(Expr *&From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
@@ -1528,16 +1537,21 @@ public:
/// ImplMethodsVsClassMethods - This is main routine to warn if any method
/// remains unimplemented in the class or category @implementation.
- void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
+ void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl,
bool IncompleteImpl = false);
/// DiagnoseUnimplementedProperties - This routine warns on those properties
/// which must be implemented by this implementation.
- void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
+ void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const llvm::DenseSet<Selector>& InsMap);
+ /// DefaultSynthesizeProperties - This routine default synthesizes all
+ /// properties which must be synthesized in class's @implementation.
+ void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
+ ObjCInterfaceDecl *IDecl);
+
/// CollectImmediateProperties - This routine collects all properties in
/// the class and its conforming protocols; but not those it its super class.
void CollectImmediateProperties(ObjCContainerDecl *CDecl,
@@ -1583,7 +1597,8 @@ public:
const bool isAssign,
const bool isReadWrite,
const unsigned Attributes, QualType T,
- tok::ObjCKeywordKind MethodImplKind);
+ tok::ObjCKeywordKind MethodImplKind,
+ DeclContext *lexicalDC = 0);
/// AtomicPropertySetterGetterRules - This routine enforces the rule (via
/// warning) when atomic property has one but not the other user-declared
@@ -1661,10 +1676,9 @@ public:
FullExprArg CondVal, DeclPtrTy CondVar,
StmtArg ThenVal,
SourceLocation ElseLoc, StmtArg ElseVal);
- virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
+ ExprArg Cond,
DeclPtrTy CondVar);
- virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
- StmtArg Body);
virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
StmtArg Switch, StmtArg Body);
virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
@@ -1762,7 +1776,8 @@ public:
/// DiagnoseUnusedExprResult - If the statement passed in is an expression
/// whose result is unused, warn.
void DiagnoseUnusedExprResult(const Stmt *S);
-
+ void DiagnoseUnusedDecl(const NamedDecl *ND);
+
ParsingDeclStackState PushParsingDeclaration();
void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D);
void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc);
@@ -1785,6 +1800,7 @@ public:
virtual void PopExpressionEvaluationContext();
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
+ void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD);
// Primary Expressions.
@@ -1796,7 +1812,8 @@ public:
bool HasTrailingLParen,
bool IsAddressOfOperand);
- bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R);
+ bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
+ CorrectTypoContext CTC = CTC_Unknown);
OwningExprResult LookupInObjCMethod(LookupResult &R,
Scope *S,
@@ -2321,7 +2338,9 @@ public:
virtual DeclResult ActOnCXXConditionDeclaration(Scope *S,
Declarator &D);
- OwningExprResult CheckConditionVariable(VarDecl *ConditionVar);
+ OwningExprResult CheckConditionVariable(VarDecl *ConditionVar,
+ SourceLocation StmtLoc,
+ bool ConvertToBoolean);
/// ActOnUnaryTypeTrait - Parsed one of the unary type trait support
/// pseudo-functions.
@@ -2553,27 +2572,38 @@ public:
void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc,
CXXRecordDecl *Record);
- /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual
- /// members need to be marked as referenced at the end of the translation
- /// unit. It will contain polymorphic classes that do not have a key
- /// function or have a key function that has been defined.
- llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 4>
- ClassesWithUnmarkedVirtualMembers;
+ /// \brief The list of classes whose vtables have been used within
+ /// this translation unit, and the source locations at which the
+ /// first use occurred.
+ llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 16>
+ VTableUses;
- /// MaybeMarkVirtualMembersReferenced - If the passed in method is the
- /// key function of the record decl, will mark virtual member functions as
- /// referenced.
- void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD);
+ /// \brief The set of classes whose vtables have been used within
+ /// this translation unit, and a bit that will be true if the vtable is
+ /// required to be emitted (otherwise, it should be emitted only if needed
+ /// by code generation).
+ llvm::DenseMap<CXXRecordDecl *, bool> VTablesUsed;
+
+ /// \brief A list of all of the dynamic classes in this translation
+ /// unit.
+ llvm::SmallVector<CXXRecordDecl *, 16> DynamicClasses;
+
+ /// \brief Note that the vtable for the given class was used at the
+ /// given location.
+ void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
+ bool DefinitionRequired = false);
/// MarkVirtualMembersReferenced - Will mark all virtual members of the given
/// CXXRecordDecl referenced.
void MarkVirtualMembersReferenced(SourceLocation Loc,
const CXXRecordDecl *RD);
- /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes
- /// that might need to have their virtual members marked as referenced.
- /// Returns false if no work was done.
- bool ProcessPendingClassesWithUnmarkedVirtualMembers();
+ /// \brief Define all of the vtables that have been used in this
+ /// translation unit and reference any virtual members used by those
+ /// vtables.
+ ///
+ /// \returns true if any work was done, false otherwise.
+ bool DefineUsedVTables();
void AddImplicitlyDeclaredMembersToClass(Scope *S, CXXRecordDecl *ClassDecl);
@@ -2657,6 +2687,8 @@ public:
void BuildBasePathArray(const CXXBasePaths &Paths,
CXXBaseSpecifierArray &BasePath);
+ bool BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath);
+
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
CXXBaseSpecifierArray *BasePath = 0,
@@ -2768,14 +2800,16 @@ public:
// C++ Templates [C++ 14]
//
void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
- QualType ObjectType, bool EnteringContext);
+ QualType ObjectType, bool EnteringContext,
+ bool &MemberOfUnknownSpecialization);
virtual TemplateNameKind isTemplateName(Scope *S,
CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
- TemplateTy &Template);
+ TemplateTy &Template,
+ bool &MemberOfUnknownSpecialization);
virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
SourceLocation IILoc,
@@ -3085,7 +3119,9 @@ public:
QualType CheckTypenameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo &II,
- SourceRange Range);
+ SourceLocation KeywordLoc,
+ SourceRange NNSRange,
+ SourceLocation IILoc);
TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
SourceLocation Loc,
@@ -3568,6 +3604,24 @@ public:
}
};
+ /// \brief RAII class that determines when any errors have occurred
+ /// between the time the instance was created and the time it was
+ /// queried.
+ class ErrorTrap {
+ Sema &SemaRef;
+ unsigned PrevErrors;
+
+ public:
+ explicit ErrorTrap(Sema &SemaRef)
+ : SemaRef(SemaRef), PrevErrors(SemaRef.getDiagnostics().getNumErrors()) {}
+
+ /// \brief Determine whether any errors have occurred since this
+ /// object instance was created.
+ bool hasErrorOccurred() const {
+ return SemaRef.getDiagnostics().getNumErrors() > PrevErrors;
+ }
+ };
+
/// \brief A stack-allocated class that identifies which local
/// variable declaration instantiations are present in this scope.
///
@@ -3858,7 +3912,7 @@ public:
void MatchOneProtocolPropertiesInClass(Decl *CDecl,
ObjCProtocolDecl *PDecl);
- virtual void ActOnAtEnd(SourceRange AtEnd,
+ virtual void ActOnAtEnd(Scope *S, SourceRange AtEnd,
DeclPtrTy classDecl,
DeclPtrTy *allMethods = 0, unsigned allNum = 0,
DeclPtrTy *allProperties = 0, unsigned pNum = 0,
@@ -3871,7 +3925,8 @@ public:
bool *OverridingProperty,
tok::ObjCKeywordKind MethodImplKind);
- virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc,
+ virtual DeclPtrTy ActOnPropertyImplDecl(Scope *S,
+ SourceLocation AtLoc,
SourceLocation PropertyLoc,
bool ImplKind,DeclPtrTy ClassImplDecl,
IdentifierInfo *PropertyId,
@@ -3960,6 +4015,11 @@ public:
MultiExprArg Args);
+ /// ActOnPragmaOptionsAlign - Called on well formed #pragma options align.
+ virtual void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
+ SourceLocation PragmaLoc,
+ SourceLocation KindLoc);
+
/// ActOnPragmaPack - Called on well formed #pragma pack(...).
virtual void ActOnPragmaPack(PragmaPackKind Kind,
IdentifierInfo *Name,
@@ -3990,9 +4050,9 @@ public:
SourceLocation WeakNameLoc,
SourceLocation AliasNameLoc);
- /// getPragmaPackAlignment() - Return the current alignment as specified by
- /// the current #pragma pack directive, or 0 if none is currently active.
- unsigned getPragmaPackAlignment() const;
+ /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to
+ /// a the record decl, to handle '#pragma pack' and '#pragma options align'.
+ void AddAlignmentAttributesForRecord(RecordDecl *RD);
/// FreePackedContext - Deallocate and null out PackContext.
void FreePackedContext();
@@ -4044,7 +4104,8 @@ public:
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
// will warn if the resulting type is not a POD type.
- bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT);
+ bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT,
+ FunctionDecl *FDecl);
// UsualArithmeticConversions - performs the UsualUnaryConversions on it's
// operands and then handles various conversions that are common to binary
@@ -4215,9 +4276,9 @@ public:
SourceLocation questionLoc);
/// type checking for vector binary operators.
- inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
- inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx,
- SourceLocation l, bool isRel);
+ QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
+ 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
@@ -4311,6 +4372,9 @@ public:
/// \return true iff there were any errors
bool CheckBooleanCondition(Expr *&CondExpr, SourceLocation Loc);
+ virtual OwningExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc,
+ ExprArg SubExpr);
+
/// DiagnoseAssignmentAsCondition - Given that an expression is
/// being used as a boolean condition, warn if it's an assignment.
void DiagnoseAssignmentAsCondition(Expr *E);
@@ -4455,9 +4519,7 @@ private:
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
- void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc,
- const BinaryOperator::Opcode* BinOpc = 0);
- void CheckImplicitConversion(Expr *E, QualType Target);
+ void CheckImplicitConversions(Expr *E);
};
//===--------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 095f537..82978c9 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -15,17 +15,28 @@
#include "Sema.h"
#include "Lookup.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
using namespace clang;
//===----------------------------------------------------------------------===//
-// Pragma Packed
+// Pragma 'pack' and 'options align'
//===----------------------------------------------------------------------===//
namespace {
+ struct PackStackEntry {
+ // We just use a sentinel to represent when the stack is set to mac68k
+ // alignment.
+ static const unsigned kMac68kAlignmentSentinel = ~0U;
+
+ unsigned Alignment;
+ IdentifierInfo *Name;
+ };
+
/// PragmaPackStack - Simple class to wrap the stack used by #pragma
/// pack.
class PragmaPackStack {
- typedef std::vector< std::pair<unsigned, IdentifierInfo*> > stack_ty;
+ typedef std::vector<PackStackEntry> stack_ty;
/// Alignment - The current user specified alignment.
unsigned Alignment;
@@ -43,7 +54,8 @@ namespace {
/// push - Push the current alignment onto the stack, optionally
/// using the given \arg Name for the record, if non-zero.
void push(IdentifierInfo *Name) {
- Stack.push_back(std::make_pair(Alignment, Name));
+ PackStackEntry PSE = { Alignment, Name };
+ Stack.push_back(PSE);
}
/// pop - Pop a record from the stack and restore the current
@@ -60,7 +72,7 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) {
// If name is empty just pop top.
if (!Name) {
- Alignment = Stack.back().first;
+ Alignment = Stack.back().Alignment;
Stack.pop_back();
return true;
}
@@ -68,9 +80,9 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) {
// Otherwise, find the named record.
for (unsigned i = Stack.size(); i != 0; ) {
--i;
- if (Stack[i].second == Name) {
+ if (Stack[i].Name == Name) {
// Found it, pop up to and including this record.
- Alignment = Stack[i].first;
+ Alignment = Stack[i].Alignment;
Stack.erase(Stack.begin() + i, Stack.end());
return true;
}
@@ -86,12 +98,65 @@ void Sema::FreePackedContext() {
PackContext = 0;
}
-/// getPragmaPackAlignment() - Return the current alignment as specified by
-/// the current #pragma pack directive, or 0 if none is currently active.
-unsigned Sema::getPragmaPackAlignment() const {
- if (PackContext)
- return static_cast<PragmaPackStack*>(PackContext)->getAlignment();
- return 0;
+void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
+ // If there is no pack context, we don't need any attributes.
+ if (!PackContext)
+ return;
+
+ PragmaPackStack *Stack = static_cast<PragmaPackStack*>(PackContext);
+
+ // Otherwise, check to see if we need a max field alignment attribute.
+ if (unsigned Alignment = Stack->getAlignment()) {
+ if (Alignment == PackStackEntry::kMac68kAlignmentSentinel)
+ RD->addAttr(::new (Context) AlignMac68kAttr());
+ else
+ RD->addAttr(::new (Context) MaxFieldAlignmentAttr(Alignment * 8));
+ }
+}
+
+void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
+ SourceLocation PragmaLoc,
+ SourceLocation KindLoc) {
+ if (PackContext == 0)
+ PackContext = new PragmaPackStack();
+
+ PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
+
+ // Reset just pops the top of the stack.
+ if (Kind == Action::POAK_Reset) {
+ // Do the pop.
+ if (!Context->pop(0)) {
+ // If a name was specified then failure indicates the name
+ // wasn't found. Otherwise failure indicates the stack was
+ // empty.
+ Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
+ << "stack empty";
+ }
+ return;
+ }
+
+ // We don't support #pragma options align=power.
+ switch (Kind) {
+ case POAK_Natural:
+ Context->push(0);
+ Context->setAlignment(0);
+ break;
+
+ case POAK_Mac68k:
+ // Check if the target supports this.
+ if (!PP.getTargetInfo().hasAlignMac68kSupport()) {
+ Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported);
+ return;
+ }
+ Context->push(0);
+ Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel);
+ break;
+
+ default:
+ Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option)
+ << KindLoc;
+ break;
+ }
}
void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
@@ -106,7 +171,9 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
// pack(0) is like pack(), which just works out since that is what
// we use 0 for in PackAttr.
- if (!Alignment->isIntegerConstantExpr(Val, Context) ||
+ if (Alignment->isTypeDependent() ||
+ Alignment->isValueDependent() ||
+ !Alignment->isIntegerConstantExpr(Val, Context) ||
!(Val == 0 || Val.isPowerOf2()) ||
Val.getZExtValue() > 16) {
Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment);
@@ -134,7 +201,10 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
// FIXME: This should come from the target.
if (AlignmentVal == 0)
AlignmentVal = 8;
- Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
+ if (AlignmentVal == PackStackEntry::kMac68kAlignmentSentinel)
+ Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k";
+ else
+ Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
break;
case Action::PPK_Push: // pack(push [, id] [, [n])
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index ba7e1ff..9b95552 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -388,6 +388,12 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
return;
Kind = CastExpr::CK_DerivedToBase;
+
+ // If we are casting to or through a virtual base class, we need a
+ // vtable.
+ if (Self.BasePathInvolvesVirtualBase(BasePath))
+ Self.MarkVTableUsed(OpRange.getBegin(),
+ cast<CXXRecordDecl>(SrcRecord->getDecl()));
return;
}
@@ -398,6 +404,8 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
<< SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
}
+ Self.MarkVTableUsed(OpRange.getBegin(),
+ cast<CXXRecordDecl>(SrcRecord->getDecl()));
// Done. Everything else is run-time checks.
Kind = CastExpr::CK_Dynamic;
@@ -578,8 +586,9 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
return TC_Success;
}
}
- else if (CStyle && DestType->isObjCObjectPointerType()) {
- // allow c-style cast of objective-c pointers as they are pervasive.
+ else if (DestType->isObjCObjectPointerType()) {
+ // allow both c-style cast and static_cast of objective-c pointers as
+ // they are pervasive.
Kind = CastExpr::CK_AnyPointerToObjCPointerCast;
return TC_Success;
}
@@ -590,7 +599,11 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
}
}
}
-
+ // Allow arbitray objective-c pointer conversion with static casts.
+ if (SrcType->isObjCObjectPointerType() &&
+ DestType->isObjCObjectPointerType())
+ return TC_Success;
+
// We tried everything. Everything! Nothing works! :-(
return TC_NotApplicable;
}
@@ -846,7 +859,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
}
// B is a base of D. But is it an allowed base? If not, it's a hard error.
- if (Paths.isAmbiguous(DestClass)) {
+ if (Paths.isAmbiguous(Self.Context.getCanonicalType(DestClass))) {
Paths.clear();
Paths.setRecordingPaths(true);
bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths);
@@ -970,7 +983,9 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
// 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()) {
+ if (!DestType->isPointerType() &&
+ !DestType->isMemberPointerType() &&
+ !DestType->isObjCObjectPointerType()) {
// 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
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 7029711..4f3f41b 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -75,14 +75,15 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
TheLexer.LexFromRawLexer(TheTok);
// Use the StringLiteralParser to compute the length of the string in bytes.
- StringLiteralParser SLP(&TheTok, 1, PP);
+ StringLiteralParser SLP(&TheTok, 1, PP, /*Complain=*/false);
unsigned TokNumBytes = SLP.GetStringLength();
// If the byte is in this token, return the location of the byte.
if (ByteNo < TokNumBytes ||
(ByteNo == TokNumBytes && TokNo == SL->getNumConcatenated())) {
unsigned Offset =
- StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP);
+ StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP,
+ /*Complain=*/false);
// Now that we know the offset of the token in the spelling, use the
// preprocessor to get the offset in the original source.
@@ -607,12 +608,25 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
if (OrigArg->isTypeDependent())
return false;
- // This operation requires a floating-point number
+ // This operation requires a non-_Complex floating-point number.
if (!OrigArg->getType()->isRealFloatingType())
return Diag(OrigArg->getLocStart(),
diag::err_typecheck_call_invalid_unary_fp)
<< OrigArg->getType() << OrigArg->getSourceRange();
+ // If this is an implicit conversion from float -> double, remove it.
+ if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) {
+ Expr *CastArg = Cast->getSubExpr();
+ if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) {
+ assert(Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) &&
+ "promotion from float to double is the only expected cast here");
+ Cast->setSubExpr(0);
+ Cast->Destroy(Context);
+ TheCall->setArg(NumArgs-1, CastArg);
+ OrigArg = CastArg;
+ }
+ }
+
return false;
}
@@ -1718,8 +1732,14 @@ struct IntRange {
T = VT->getElementType().getTypePtr();
if (const ComplexType *CT = dyn_cast<ComplexType>(T))
T = CT->getElementType().getTypePtr();
- if (const EnumType *ET = dyn_cast<EnumType>(T))
- T = ET->getDecl()->getIntegerType().getTypePtr();
+
+ if (const EnumType *ET = dyn_cast<EnumType>(T)) {
+ EnumDecl *Enum = ET->getDecl();
+ unsigned NumPositive = Enum->getNumPositiveBits();
+ unsigned NumNegative = Enum->getNumNegativeBits();
+
+ return IntRange(std::max(NumPositive, NumNegative), NumNegative == 0);
+ }
const BuiltinType *BT = cast<BuiltinType>(T);
assert(BT->isInteger());
@@ -1961,6 +1981,10 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
return IntRange::forType(C, E->getType());
}
+IntRange GetExprRange(ASTContext &C, Expr *E) {
+ return GetExprRange(C, E, C.getIntWidth(E->getType()));
+}
+
/// Checks whether the given value, which currently has the given
/// source semantics, has the same value when coerced through the
/// target semantics.
@@ -1999,7 +2023,40 @@ bool IsSameFloatAfterCast(const APValue &value,
IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
}
-} // end anonymous namespace
+void AnalyzeImplicitConversions(Sema &S, Expr *E);
+
+bool IsZero(Sema &S, Expr *E) {
+ llvm::APSInt Value;
+ return E->isIntegerConstantExpr(Value, S.Context) && Value == 0;
+}
+
+void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
+ BinaryOperator::Opcode op = E->getOpcode();
+ if (op == BinaryOperator::LT && IsZero(S, E->getRHS())) {
+ S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
+ << "< 0" << "false"
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ } else if (op == BinaryOperator::GE && IsZero(S, E->getRHS())) {
+ S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
+ << ">= 0" << "true"
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ } else if (op == BinaryOperator::GT && IsZero(S, E->getLHS())) {
+ S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
+ << "0 >" << "false"
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ } else if (op == BinaryOperator::LE && IsZero(S, E->getLHS())) {
+ S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
+ << "0 <=" << "true"
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ }
+}
+
+/// Analyze the operands of the given comparison. Implements the
+/// fallback case from AnalyzeComparison.
+void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
+ AnalyzeImplicitConversions(S, E->getLHS());
+ AnalyzeImplicitConversions(S, E->getRHS());
+}
/// \brief Implements -Wsign-compare.
///
@@ -2007,138 +2064,85 @@ bool IsSameFloatAfterCast(const APValue &value,
/// \param rex the right-hand expression
/// \param OpLoc the location of the joining operator
/// \param BinOpc binary opcode or 0
-void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
- const BinaryOperator::Opcode* BinOpc) {
- // Don't warn if we're in an unevaluated context.
- if (ExprEvalContexts.back().Context == Unevaluated)
- return;
-
- // If either expression is value-dependent, don't warn. We'll get another
- // chance at instantiation time.
- if (lex->isValueDependent() || rex->isValueDependent())
- return;
-
- QualType lt = lex->getType(), rt = rex->getType();
-
- // Only warn if both operands are integral.
- if (!lt->isIntegerType() || !rt->isIntegerType())
- return;
-
- // In C, the width of a bitfield determines its type, and the
- // declared type only contributes the signedness. This duplicates
- // the work that will later be done by UsualUnaryConversions.
- // Eventually, this check will be reorganized in a way that avoids
- // this duplication.
- if (!getLangOptions().CPlusPlus) {
- QualType tmp;
- tmp = Context.isPromotableBitField(lex);
- if (!tmp.isNull()) lt = tmp;
- tmp = Context.isPromotableBitField(rex);
- if (!tmp.isNull()) rt = tmp;
- }
-
- if (const EnumType *E = lt->getAs<EnumType>())
- lt = E->getDecl()->getPromotionType();
- if (const EnumType *E = rt->getAs<EnumType>())
- rt = E->getDecl()->getPromotionType();
-
- // The rule is that the signed operand becomes unsigned, so isolate the
- // signed operand.
- Expr *signedOperand = lex, *unsignedOperand = rex;
- QualType signedType = lt, unsignedType = rt;
- if (lt->isSignedIntegerType()) {
- if (rt->isSignedIntegerType()) return;
+void AnalyzeComparison(Sema &S, BinaryOperator *E) {
+ // The type the comparison is being performed in.
+ QualType T = E->getLHS()->getType();
+ assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())
+ && "comparison with mismatched types");
+
+ // We don't do anything special if this isn't an unsigned integral
+ // comparison: we're only interested in integral comparisons, and
+ // signed comparisons only happen in cases we don't care to warn about.
+ if (!T->isUnsignedIntegerType())
+ return AnalyzeImpConvsInComparison(S, E);
+
+ Expr *lex = E->getLHS()->IgnoreParenImpCasts();
+ Expr *rex = E->getRHS()->IgnoreParenImpCasts();
+
+ // Check to see if one of the (unmodified) operands is of different
+ // signedness.
+ Expr *signedOperand, *unsignedOperand;
+ if (lex->getType()->isSignedIntegerType()) {
+ assert(!rex->getType()->isSignedIntegerType() &&
+ "unsigned comparison between two signed integer expressions?");
+ signedOperand = lex;
+ unsignedOperand = rex;
+ } else if (rex->getType()->isSignedIntegerType()) {
+ signedOperand = rex;
+ unsignedOperand = lex;
} else {
- if (!rt->isSignedIntegerType()) return;
- std::swap(signedOperand, unsignedOperand);
- std::swap(signedType, unsignedType);
+ CheckTrivialUnsignedComparison(S, E);
+ return AnalyzeImpConvsInComparison(S, E);
}
- unsigned unsignedWidth = Context.getIntWidth(unsignedType);
- unsigned signedWidth = Context.getIntWidth(signedType);
+ // Otherwise, calculate the effective range of the signed operand.
+ IntRange signedRange = GetExprRange(S.Context, signedOperand);
- // If the unsigned type is strictly smaller than the signed type,
- // then (1) the result type will be signed and (2) the unsigned
- // value will fit fully within the signed type, and thus the result
- // of the comparison will be exact.
- if (signedWidth > unsignedWidth)
- return;
+ // Go ahead and analyze implicit conversions in the operands. Note
+ // that we skip the implicit conversions on both sides.
+ AnalyzeImplicitConversions(S, lex);
+ AnalyzeImplicitConversions(S, rex);
- // Otherwise, calculate the effective ranges.
- IntRange signedRange = GetExprRange(Context, signedOperand, signedWidth);
- IntRange unsignedRange = GetExprRange(Context, unsignedOperand, unsignedWidth);
-
- // We should never be unable to prove that the unsigned operand is
- // non-negative.
- assert(unsignedRange.NonNegative && "unsigned range includes negative?");
-
- // If the signed operand is non-negative, then the signed->unsigned
- // conversion won't change it.
- if (signedRange.NonNegative) {
- // Emit warnings for comparisons of unsigned to integer constant 0.
- // always false: x < 0 (or 0 > x)
- // always true: x >= 0 (or 0 <= x)
- llvm::APSInt X;
- if (BinOpc && signedOperand->isIntegerConstantExpr(X, Context) && X == 0) {
- if (signedOperand != lex) {
- if (*BinOpc == BinaryOperator::LT) {
- Diag(OpLoc, diag::warn_lunsigned_always_true_comparison)
- << "< 0" << "false"
- << lex->getSourceRange() << rex->getSourceRange();
- }
- else if (*BinOpc == BinaryOperator::GE) {
- Diag(OpLoc, diag::warn_lunsigned_always_true_comparison)
- << ">= 0" << "true"
- << lex->getSourceRange() << rex->getSourceRange();
- }
- }
- else {
- if (*BinOpc == BinaryOperator::GT) {
- Diag(OpLoc, diag::warn_runsigned_always_true_comparison)
- << "0 >" << "false"
- << lex->getSourceRange() << rex->getSourceRange();
- }
- else if (*BinOpc == BinaryOperator::LE) {
- Diag(OpLoc, diag::warn_runsigned_always_true_comparison)
- << "0 <=" << "true"
- << lex->getSourceRange() << rex->getSourceRange();
- }
- }
- }
- return;
- }
+ // If the signed range is non-negative, -Wsign-compare won't fire,
+ // but we should still check for comparisons which are always true
+ // or false.
+ if (signedRange.NonNegative)
+ return CheckTrivialUnsignedComparison(S, E);
// For (in)equality comparisons, if the unsigned operand is a
// constant which cannot collide with a overflowed signed operand,
// then reinterpreting the signed operand as unsigned will not
// change the result of the comparison.
- if (BinOpc &&
- (*BinOpc == BinaryOperator::EQ || *BinOpc == BinaryOperator::NE) &&
- unsignedRange.Width < unsignedWidth)
- return;
+ if (E->isEqualityOp()) {
+ unsigned comparisonWidth = S.Context.getIntWidth(T);
+ IntRange unsignedRange = GetExprRange(S.Context, unsignedOperand);
+
+ // We should never be unable to prove that the unsigned operand is
+ // non-negative.
+ assert(unsignedRange.NonNegative && "unsigned range includes negative?");
+
+ if (unsignedRange.Width < comparisonWidth)
+ return;
+ }
- Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison
- : diag::warn_mixed_sign_conditional)
- << lt << rt << lex->getSourceRange() << rex->getSourceRange();
+ S.Diag(E->getOperatorLoc(), diag::warn_mixed_sign_comparison)
+ << lex->getType() << rex->getType()
+ << lex->getSourceRange() << rex->getSourceRange();
}
/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
-static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
+void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange();
}
-/// Implements -Wconversion.
-void Sema::CheckImplicitConversion(Expr *E, QualType T) {
- // Don't diagnose in unevaluated contexts.
- if (ExprEvalContexts.back().Context == Sema::Unevaluated)
- return;
+void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
+ bool *ICContext = 0) {
+ if (E->isTypeDependent() || E->isValueDependent()) return;
- // Don't diagnose for value-dependent expressions.
- if (E->isValueDependent())
- return;
-
- const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr();
- const Type *Target = Context.getCanonicalType(T).getTypePtr();
+ const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
+ const Type *Target = S.Context.getCanonicalType(T).getTypePtr();
+ if (Source == Target) return;
+ if (Target->isDependentType()) return;
// Never diagnose implicit casts to bool.
if (Target->isSpecificBuiltinType(BuiltinType::Bool))
@@ -2147,7 +2151,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
// Strip vector types.
if (isa<VectorType>(Source)) {
if (!isa<VectorType>(Target))
- return DiagnoseImpCast(*this, E, T, diag::warn_impcast_vector_scalar);
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar);
Source = cast<VectorType>(Source)->getElementType().getTypePtr();
Target = cast<VectorType>(Target)->getElementType().getTypePtr();
@@ -2156,7 +2160,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
// Strip complex types.
if (isa<ComplexType>(Source)) {
if (!isa<ComplexType>(Target))
- return DiagnoseImpCast(*this, E, T, diag::warn_impcast_complex_scalar);
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar);
Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
@@ -2176,15 +2180,15 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
// Don't warn about float constants that are precisely
// representable in the target type.
Expr::EvalResult result;
- if (E->Evaluate(result, Context)) {
+ if (E->Evaluate(result, S.Context)) {
// Value might be a float, a float vector, or a float complex.
if (IsSameFloatAfterCast(result.Val,
- Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
- Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
+ S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
+ S.Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
return;
}
- DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_precision);
+ DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision);
}
return;
}
@@ -2192,7 +2196,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
// If the target is integral, always warn.
if ((TargetBT && TargetBT->isInteger()))
// TODO: don't warn for integer values?
- return DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_integer);
+ DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer);
return;
}
@@ -2200,22 +2204,158 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
if (!Source->isIntegerType() || !Target->isIntegerType())
return;
- IntRange SourceRange = GetExprRange(Context, E, Context.getIntWidth(E->getType()));
- IntRange TargetRange = IntRange::forCanonicalType(Context, Target);
-
- // FIXME: also signed<->unsigned?
+ IntRange SourceRange = GetExprRange(S.Context, E);
+ IntRange TargetRange = IntRange::forCanonicalType(S.Context, Target);
if (SourceRange.Width > TargetRange.Width) {
// People want to build with -Wshorten-64-to-32 and not -Wconversion
// and by god we'll let them.
if (SourceRange.Width == 64 && TargetRange.Width == 32)
- return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_64_32);
- return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_precision);
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32);
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision);
+ }
+
+ if ((TargetRange.NonNegative && !SourceRange.NonNegative) ||
+ (!TargetRange.NonNegative && SourceRange.NonNegative &&
+ SourceRange.Width == TargetRange.Width)) {
+ unsigned DiagID = diag::warn_impcast_integer_sign;
+
+ // Traditionally, gcc has warned about this under -Wsign-compare.
+ // We also want to warn about it in -Wconversion.
+ // So if -Wconversion is off, use a completely identical diagnostic
+ // in the sign-compare group.
+ // The conditional-checking code will
+ if (ICContext) {
+ DiagID = diag::warn_impcast_integer_sign_conditional;
+ *ICContext = true;
+ }
+
+ return DiagnoseImpCast(S, E, T, DiagID);
}
return;
}
+void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T);
+
+void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
+ bool &ICContext) {
+ E = E->IgnoreParenImpCasts();
+
+ if (isa<ConditionalOperator>(E))
+ return CheckConditionalOperator(S, cast<ConditionalOperator>(E), T);
+
+ AnalyzeImplicitConversions(S, E);
+ if (E->getType() != T)
+ return CheckImplicitConversion(S, E, T, &ICContext);
+ return;
+}
+
+void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) {
+ AnalyzeImplicitConversions(S, E->getCond());
+
+ bool Suspicious = false;
+ CheckConditionalOperand(S, E->getTrueExpr(), T, Suspicious);
+ CheckConditionalOperand(S, E->getFalseExpr(), T, Suspicious);
+
+ // If -Wconversion would have warned about either of the candidates
+ // for a signedness conversion to the context type...
+ if (!Suspicious) return;
+
+ // ...but it's currently ignored...
+ if (S.Diags.getDiagnosticLevel(diag::warn_impcast_integer_sign_conditional))
+ return;
+
+ // ...and -Wsign-compare isn't...
+ if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional))
+ return;
+
+ // ...then check whether it would have warned about either of the
+ // candidates for a signedness conversion to the condition type.
+ if (E->getType() != T) {
+ Suspicious = false;
+ CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(),
+ E->getType(), &Suspicious);
+ if (!Suspicious)
+ CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(),
+ E->getType(), &Suspicious);
+ if (!Suspicious)
+ return;
+ }
+
+ // If so, emit a diagnostic under -Wsign-compare.
+ Expr *lex = E->getTrueExpr()->IgnoreParenImpCasts();
+ Expr *rex = E->getFalseExpr()->IgnoreParenImpCasts();
+ S.Diag(E->getQuestionLoc(), diag::warn_mixed_sign_conditional)
+ << lex->getType() << rex->getType()
+ << lex->getSourceRange() << rex->getSourceRange();
+}
+
+/// AnalyzeImplicitConversions - Find and report any interesting
+/// implicit conversions in the given expression. There are a couple
+/// of competing diagnostics here, -Wconversion and -Wsign-compare.
+void AnalyzeImplicitConversions(Sema &S, Expr *OrigE) {
+ QualType T = OrigE->getType();
+ Expr *E = OrigE->IgnoreParenImpCasts();
+
+ // For conditional operators, we analyze the arguments as if they
+ // were being fed directly into the output.
+ if (isa<ConditionalOperator>(E)) {
+ ConditionalOperator *CO = cast<ConditionalOperator>(E);
+ CheckConditionalOperator(S, CO, T);
+ return;
+ }
+
+ // Go ahead and check any implicit conversions we might have skipped.
+ // The non-canonical typecheck is just an optimization;
+ // CheckImplicitConversion will filter out dead implicit conversions.
+ if (E->getType() != T)
+ CheckImplicitConversion(S, E, T);
+
+ // Now continue drilling into this expression.
+
+ // Skip past explicit casts.
+ if (isa<ExplicitCastExpr>(E)) {
+ E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts();
+ return AnalyzeImplicitConversions(S, E);
+ }
+
+ // Do a somewhat different check with comparison operators.
+ if (isa<BinaryOperator>(E) && cast<BinaryOperator>(E)->isComparisonOp())
+ return AnalyzeComparison(S, cast<BinaryOperator>(E));
+
+ // These break the otherwise-useful invariant below. Fortunately,
+ // we don't really need to recurse into them, because any internal
+ // expressions should have been analyzed already when they were
+ // built into statements.
+ if (isa<StmtExpr>(E)) return;
+
+ // Don't descend into unevaluated contexts.
+ if (isa<SizeOfAlignOfExpr>(E)) return;
+
+ // Now just recurse over the expression's children.
+ for (Stmt::child_iterator I = E->child_begin(), IE = E->child_end();
+ I != IE; ++I)
+ AnalyzeImplicitConversions(S, cast<Expr>(*I));
+}
+
+} // end anonymous namespace
+
+/// Diagnoses "dangerous" implicit conversions within the given
+/// expression (which is a full expression). Implements -Wconversion
+/// and -Wsign-compare.
+void Sema::CheckImplicitConversions(Expr *E) {
+ // Don't diagnose in unevaluated contexts.
+ if (ExprEvalContexts.back().Context == Sema::Unevaluated)
+ return;
+
+ // Don't diagnose for value- or type-dependent expressions.
+ if (E->isTypeDependent() || E->isValueDependent())
+ return;
+
+ AnalyzeImplicitConversions(*this, E);
+}
+
/// 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
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index c075d16..d8c1a5c 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -127,6 +127,13 @@ namespace {
explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0)
: SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { }
+ /// \brief Whether we should include code patterns in the completion
+ /// results.
+ bool includeCodePatterns() const {
+ return SemaRef.CodeCompleter &&
+ SemaRef.CodeCompleter->includeCodePatterns();
+ }
+
/// \brief Set the filter used for code-completion results.
void setFilter(LookupFilter Filter) {
this->Filter = Filter;
@@ -532,8 +539,10 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
// If the filter is for nested-name-specifiers, then this result starts a
// nested-name-specifier.
- if (AsNestedNameSpecifier)
+ if (AsNestedNameSpecifier) {
R.StartsNestedNameSpecifier = true;
+ R.Priority = CCP_NestedNameSpecifier;
+ }
// If this result is supposed to have an informative qualifier, add one.
if (R.QualifierIsInformative && !R.Qualifier &&
@@ -581,8 +590,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
// If the filter is for nested-name-specifiers, then this result starts a
// nested-name-specifier.
- if (AsNestedNameSpecifier)
+ if (AsNestedNameSpecifier) {
R.StartsNestedNameSpecifier = true;
+ R.Priority = CCP_NestedNameSpecifier;
+ }
else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass &&
isa<CXXRecordDecl>(R.Declaration->getDeclContext()
->getLookupContext()))
@@ -601,6 +612,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
R.QualifierIsInformative = false;
}
+ // Adjust the priority if this result comes from a base class.
+ if (InBaseClass)
+ R.Priority += CCD_InBaseClass;
+
// Insert this result into the set of results.
Results.push_back(R);
}
@@ -672,8 +687,8 @@ bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const {
ND = ClassTemplate->getTemplatedDecl();
if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
- return RD->getTagKind() == TagDecl::TK_class ||
- RD->getTagKind() == TagDecl::TK_struct;
+ return RD->getTagKind() == TTK_Class ||
+ RD->getTagKind() == TTK_Struct;
return false;
}
@@ -685,7 +700,7 @@ bool ResultBuilder::IsUnion(NamedDecl *ND) const {
ND = ClassTemplate->getTemplatedDecl();
if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
- return RD->getTagKind() == TagDecl::TK_union;
+ return RD->getTagKind() == TTK_Union;
return false;
}
@@ -744,47 +759,56 @@ namespace {
static void AddTypeSpecifierResults(const LangOptions &LangOpts,
ResultBuilder &Results) {
typedef CodeCompleteConsumer::Result Result;
- Results.AddResult(Result("short"));
- Results.AddResult(Result("long"));
- Results.AddResult(Result("signed"));
- Results.AddResult(Result("unsigned"));
- Results.AddResult(Result("void"));
- Results.AddResult(Result("char"));
- Results.AddResult(Result("int"));
- Results.AddResult(Result("float"));
- Results.AddResult(Result("double"));
- Results.AddResult(Result("enum"));
- Results.AddResult(Result("struct"));
- Results.AddResult(Result("union"));
- Results.AddResult(Result("const"));
- Results.AddResult(Result("volatile"));
+ Results.AddResult(Result("short", CCP_Type));
+ Results.AddResult(Result("long", CCP_Type));
+ Results.AddResult(Result("signed", CCP_Type));
+ Results.AddResult(Result("unsigned", CCP_Type));
+ Results.AddResult(Result("void", CCP_Type));
+ Results.AddResult(Result("char", CCP_Type));
+ Results.AddResult(Result("int", CCP_Type));
+ Results.AddResult(Result("float", CCP_Type));
+ Results.AddResult(Result("double", CCP_Type));
+ Results.AddResult(Result("enum", CCP_Type));
+ Results.AddResult(Result("struct", CCP_Type));
+ Results.AddResult(Result("union", CCP_Type));
+ Results.AddResult(Result("const", CCP_Type));
+ Results.AddResult(Result("volatile", CCP_Type));
if (LangOpts.C99) {
// C99-specific
- Results.AddResult(Result("_Complex"));
- Results.AddResult(Result("_Imaginary"));
- Results.AddResult(Result("_Bool"));
- Results.AddResult(Result("restrict"));
+ Results.AddResult(Result("_Complex", CCP_Type));
+ Results.AddResult(Result("_Imaginary", CCP_Type));
+ Results.AddResult(Result("_Bool", CCP_Type));
+ Results.AddResult(Result("restrict", CCP_Type));
}
if (LangOpts.CPlusPlus) {
// C++-specific
- Results.AddResult(Result("bool"));
- Results.AddResult(Result("class"));
- Results.AddResult(Result("wchar_t"));
+ Results.AddResult(Result("bool", CCP_Type));
+ Results.AddResult(Result("class", CCP_Type));
+ Results.AddResult(Result("wchar_t", CCP_Type));
+
+ if (Results.includeCodePatterns()) {
+ // typename qualified-id
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typename");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("qualified-id");
+ Results.AddResult(Result(Pattern));
+ }
- // typename qualified-id
- CodeCompletionString *Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("typename");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("qualified-id");
- Results.AddResult(Result(Pattern));
-
if (LangOpts.CPlusPlus0x) {
- Results.AddResult(Result("auto"));
- Results.AddResult(Result("char16_t"));
- Results.AddResult(Result("char32_t"));
- Results.AddResult(Result("decltype"));
+ Results.AddResult(Result("auto", CCP_Type));
+ Results.AddResult(Result("char16_t", CCP_Type));
+ Results.AddResult(Result("char32_t", CCP_Type));
+ if (Results.includeCodePatterns()) {
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("decltype");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+ }
}
}
@@ -795,12 +819,14 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
// Results.AddResult(Result("_Decimal64"));
// Results.AddResult(Result("_Decimal128"));
- CodeCompletionString *Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("typeof");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression-or-type");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typeof");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+ }
}
}
@@ -843,6 +869,7 @@ static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC,
case Action::CCC_Statement:
case Action::CCC_ForInit:
case Action::CCC_Condition:
+ case Action::CCC_RecoveryInFunction:
break;
}
}
@@ -868,7 +895,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
typedef CodeCompleteConsumer::Result Result;
switch (CCC) {
case Action::CCC_Namespace:
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) {
// namespace <identifier> { }
CodeCompletionString *Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("namespace");
@@ -920,8 +947,10 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
// Fall through
case Action::CCC_Class:
- Results.AddResult(Result("typedef"));
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (Results.includeCodePatterns())
+ Results.AddResult(Result("typedef"));
+
+ if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) {
// Using declaration
CodeCompletionString *Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("using");
@@ -964,7 +993,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
case Action::CCC_Template:
case Action::CCC_MemberTemplate:
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) {
// template < parameters >
CodeCompletionString *Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("template");
@@ -994,11 +1023,13 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true);
break;
+ case Action::CCC_RecoveryInFunction:
case Action::CCC_Statement: {
- Results.AddResult(Result("typedef"));
+ if (Results.includeCodePatterns())
+ Results.AddResult(Result("typedef"));
CodeCompletionString *Pattern = 0;
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) {
Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("try");
Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
@@ -1018,37 +1049,39 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
if (SemaRef.getLangOptions().ObjC1)
AddObjCStatementResults(Results, true);
- // if (condition) { statements }
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("if");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus)
- Pattern->AddPlaceholderChunk("condition");
- else
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
- Pattern->AddPlaceholderChunk("statements");
- Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
- Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.AddResult(Result(Pattern));
-
- // switch (condition) { }
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("switch");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus)
- Pattern->AddPlaceholderChunk("condition");
- else
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
- Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
- Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ // if (condition) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("if");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+ // switch (condition) { }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("switch");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+ }
+
// Switch-specific statements.
- if (!SemaRef.getSwitchStack().empty()) {
+ if (!SemaRef.getSwitchStack().empty() && Results.includeCodePatterns()) {
// case expression:
Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("case");
@@ -1063,52 +1096,54 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Results.AddResult(Result(Pattern));
}
- /// while (condition) { statements }
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("while");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus)
- Pattern->AddPlaceholderChunk("condition");
- else
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
- Pattern->AddPlaceholderChunk("statements");
- Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
- Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ /// while (condition) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("while");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
- // do { statements } while ( expression );
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("do");
- Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
- Pattern->AddPlaceholderChunk("statements");
- Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
- Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Pattern->AddTextChunk("while");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ // do { statements } while ( expression );
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("do");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Pattern->AddTextChunk("while");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // for ( for-init-statement ; condition ; expression ) { statements }
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("for");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99)
- Pattern->AddPlaceholderChunk("init-statement");
- else
- Pattern->AddPlaceholderChunk("init-expression");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
- Pattern->AddPlaceholderChunk("condition");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
- Pattern->AddPlaceholderChunk("inc-expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
- Pattern->AddPlaceholderChunk("statements");
- Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
- Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.AddResult(Result(Pattern));
+ // for ( for-init-statement ; condition ; expression ) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("for");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99)
+ Pattern->AddPlaceholderChunk("init-statement");
+ else
+ Pattern->AddPlaceholderChunk("init-expression");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Pattern->AddPlaceholderChunk("condition");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Pattern->AddPlaceholderChunk("inc-expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+ }
if (S->getContinueParent()) {
// continue ;
@@ -1143,21 +1178,23 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
}
Results.AddResult(Result(Pattern));
- // goto identifier ;
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("goto");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("identifier");
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ // goto identifier ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("goto");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Results.AddResult(Result(Pattern));
- // Using directives
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("using");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddTextChunk("namespace");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("identifier");
- Results.AddResult(Result(Pattern));
+ // Using directives
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("using");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("namespace");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Results.AddResult(Result(Pattern));
+ }
}
// Fall through (for statement expressions).
@@ -1178,103 +1215,107 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Results.AddResult(Result("true"));
Results.AddResult(Result("false"));
- // dynamic_cast < type-id > ( expression )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("dynamic_cast");
- Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
-
- // static_cast < type-id > ( expression )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("static_cast");
- Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
-
- // reinterpret_cast < type-id > ( expression )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("reinterpret_cast");
- Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ // dynamic_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("dynamic_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // static_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("static_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // const_cast < type-id > ( expression )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("const_cast");
- Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ // reinterpret_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("reinterpret_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // typeid ( expression-or-type )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("typeid");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression-or-type");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ // const_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("const_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // new T ( ... )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("new");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expressions");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ // typeid ( expression-or-type )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typeid");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // new T [ ] ( ... )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("new");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
- Pattern->AddPlaceholderChunk("size");
- Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expressions");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ // new T ( ... )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("new");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expressions");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // delete expression
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("delete");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("expression");
- Results.AddResult(Result(Pattern));
+ // new T [ ] ( ... )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("new");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
+ Pattern->AddPlaceholderChunk("size");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expressions");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // delete expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("delete");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
- // delete [] expression
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("delete");
- Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
- Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("expression");
- Results.AddResult(Result(Pattern));
+ // delete [] expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("delete");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
- // throw expression
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("throw");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("expression");
- Results.AddResult(Result(Pattern));
+ // throw expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("throw");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
+ }
+
+ // FIXME: Rethrow?
}
if (SemaRef.getLangOptions().ObjC1) {
@@ -1286,13 +1327,15 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
AddObjCExpressionResults(Results, true);
}
- // sizeof expression
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("sizeof");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression-or-type");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ // sizeof expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("sizeof");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+ }
break;
}
}
@@ -1543,7 +1586,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
return Result;
}
- assert(Kind == RK_Declaration && "Missed a macro kind?");
+ assert(Kind == RK_Declaration && "Missed a result kind?");
NamedDecl *ND = Declaration;
if (StartsNestedNameSpecifier) {
@@ -1925,6 +1968,10 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
case CCC_Condition:
Results.setFilter(&ResultBuilder::IsOrdinaryName);
break;
+
+ case CCC_RecoveryInFunction:
+ // Unfiltered
+ break;
}
CodeCompletionDeclConsumer Consumer(Results, CurContext);
@@ -2047,14 +2094,14 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
I != E; ++I)
AddObjCProperties(*I, true, CurContext, Results);
} else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
- (!IsArrow && BaseType->isObjCInterfaceType())) {
+ (!IsArrow && BaseType->isObjCObjectType())) {
// Objective-C instance variable access.
ObjCInterfaceDecl *Class = 0;
if (const ObjCObjectPointerType *ObjCPtr
= BaseType->getAs<ObjCObjectPointerType>())
Class = ObjCPtr->getInterfaceDecl();
else
- Class = BaseType->getAs<ObjCInterfaceType>()->getDecl();
+ Class = BaseType->getAs<ObjCObjectType>()->getInterface();
// Add all ivars from this class and its superclasses.
if (Class) {
@@ -2413,6 +2460,9 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
static void AddObjCImplementationResults(const LangOptions &LangOpts,
ResultBuilder &Results,
bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
// Since we have an implementation, we can end it.
Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end)));
@@ -2438,6 +2488,9 @@ static void AddObjCImplementationResults(const LangOptions &LangOpts,
static void AddObjCInterfaceResults(const LangOptions &LangOpts,
ResultBuilder &Results,
bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
// Since we have an interface or protocol, we can end it.
@@ -2456,6 +2509,9 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts,
}
static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
CodeCompletionString *Pattern = 0;
@@ -2515,6 +2571,9 @@ void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
}
static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
CodeCompletionString *Pattern = 0;
@@ -2544,6 +2603,9 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
}
static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
CodeCompletionString *Pattern = 0;
@@ -2590,6 +2652,9 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
static void AddObjCVisibilityResults(const LangOptions &LangOpts,
ResultBuilder &Results,
bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,private)));
Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,protected)));
@@ -2911,9 +2976,9 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
ObjCInterfaceDecl *IFace = 0;
switch (Msg->getReceiverKind()) {
case ObjCMessageExpr::Class:
- if (const ObjCInterfaceType *IFaceType
- = Msg->getClassReceiver()->getAs<ObjCInterfaceType>())
- IFace = IFaceType->getDecl();
+ if (const ObjCObjectType *ObjType
+ = Msg->getClassReceiver()->getAs<ObjCObjectType>())
+ IFace = ObjType->getInterface();
break;
case ObjCMessageExpr::Instance: {
@@ -2994,9 +3059,9 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) {
// "super" names an interface. Use it.
} else if (TypeDecl *TD = dyn_cast_or_null<TypeDecl>(ND)) {
- if (const ObjCInterfaceType *Iface
- = Context.getTypeDeclType(TD)->getAs<ObjCInterfaceType>())
- CDecl = Iface->getDecl();
+ if (const ObjCObjectType *Iface
+ = Context.getTypeDeclType(TD)->getAs<ObjCObjectType>())
+ CDecl = Iface->getInterface();
} else if (ND && isa<UnresolvedUsingTypenameDecl>(ND)) {
// "super" names an unresolved type; we can't be more specific.
} else {
@@ -3030,8 +3095,8 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver,
if (Receiver) {
QualType T = GetTypeFromParser(Receiver, 0);
if (!T.isNull())
- if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>())
- CDecl = Interface->getDecl();
+ if (const ObjCObjectType *Interface = T->getAs<ObjCObjectType>())
+ CDecl = Interface->getInterface();
}
// Add all of the factory methods in this Objective-C class, its protocols,
@@ -3079,8 +3144,6 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver,
}
Results.ExitScope();
-
- // This also suppresses remaining diagnostics.
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a802679..af02099 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -90,8 +90,9 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// We know from the grammar that this name refers to a type, so build a
// DependentNameType node to describe the type.
return CheckTypenameType(ETK_None,
- (NestedNameSpecifier *)SS->getScopeRep(),
- II, SS->getRange()).getAsOpaquePtr();
+ (NestedNameSpecifier *)SS->getScopeRep(), II,
+ SourceLocation(), SS->getRange(), NameLoc
+ ).getAsOpaquePtr();
}
return 0;
@@ -191,7 +192,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
T = Context.getTypeDeclType(TD);
if (SS)
- T = getQualifiedNameType(*SS, T);
+ T = getElaboratedType(ETK_None, *SS, T);
} else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
T = Context.getObjCInterfaceType(IDecl);
@@ -223,10 +224,11 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
if (R.getResultKind() == LookupResult::Found)
if (const TagDecl *TD = R.getAsSingle<TagDecl>()) {
switch (TD->getTagKind()) {
- case TagDecl::TK_struct: return DeclSpec::TST_struct;
- case TagDecl::TK_union: return DeclSpec::TST_union;
- case TagDecl::TK_class: return DeclSpec::TST_class;
- case TagDecl::TK_enum: return DeclSpec::TST_enum;
+ default: return DeclSpec::TST_unspecified;
+ case TTK_Struct: return DeclSpec::TST_struct;
+ case TTK_Union: return DeclSpec::TST_union;
+ case TTK_Class: return DeclSpec::TST_class;
+ case TTK_Enum: return DeclSpec::TST_enum;
}
}
@@ -285,8 +287,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
Name.setIdentifier(&II, IILoc);
CXXScopeSpec EmptySS;
TemplateTy TemplateResult;
- if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult)
- == TNK_Type_template) {
+ bool MemberOfUnknownSpecialization;
+ if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult,
+ MemberOfUnknownSpecialization) == TNK_Type_template) {
TemplateName TplName = TemplateResult.getAsVal<TemplateName>();
Diag(IILoc, diag::err_template_missing_args) << TplName;
if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) {
@@ -544,9 +547,9 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
}
- // If we failed to complete the type for some reason, don't
- // diagnose the variable.
- if (Ty->isIncompleteType())
+ // If we failed to complete the type for some reason, or if the type is
+ // dependent, don't diagnose the variable.
+ if (Ty->isIncompleteType() || Ty->isDependentType())
return false;
if (const TagType *TT = Ty->getAs<TagType>()) {
@@ -555,9 +558,10 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
- if (!RD->hasTrivialConstructor())
- return false;
- if (!RD->hasTrivialDestructor())
+ // FIXME: Checking for the presence of a user-declared constructor
+ // isn't completely accurate; we'd prefer to check that the initializer
+ // has no side effects.
+ if (RD->hasUserDeclaredConstructor() || !RD->hasTrivialDestructor())
return false;
}
}
@@ -568,6 +572,18 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return true;
}
+void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
+ if (!ShouldDiagnoseUnusedDecl(D))
+ return;
+
+ if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable())
+ Diag(D->getLocation(), diag::warn_unused_exception_param)
+ << D->getDeclName();
+ else
+ Diag(D->getLocation(), diag::warn_unused_variable)
+ << D->getDeclName();
+}
+
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
@@ -584,15 +600,9 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (!D->getDeclName()) continue;
// Diagnose unused variables in this scope.
- if (ShouldDiagnoseUnusedDecl(D) &&
- S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) {
- if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable())
- Diag(D->getLocation(), diag::warn_unused_exception_param)
- << D->getDeclName();
- else
- Diag(D->getLocation(), diag::warn_unused_variable)
- << D->getDeclName();
- }
+ if (S->getNumErrorsAtStart() == getDiagnostics().getNumErrors())
+ DiagnoseUnusedDecl(D);
+
// Remove this name from our lexical scope.
IdResolver.RemoveDecl(D);
}
@@ -1069,10 +1079,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
= cast<FunctionType>(OldQType.getTypePtr())->getResultType();
QualType NewReturnType
= cast<FunctionType>(NewQType.getTypePtr())->getResultType();
+ QualType ResQT;
if (OldReturnType != NewReturnType) {
- Diag(New->getLocation(), diag::err_ovl_diff_return_type);
- Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
- return true;
+ if (NewReturnType->isObjCObjectPointerType()
+ && OldReturnType->isObjCObjectPointerType())
+ ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
+ if (ResQT.isNull()) {
+ Diag(New->getLocation(), diag::err_ovl_diff_return_type);
+ Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ return true;
+ }
+ else
+ NewQType = ResQT;
}
const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
@@ -1356,6 +1374,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
= Context.getCanonicalType(New->getType())->getAs<ArrayType>();
if (OldArray->getElementType() == NewArray->getElementType())
MergedT = Old->getType();
+ } else if (New->getType()->isObjCObjectPointerType()
+ && Old->getType()->isObjCObjectPointerType()) {
+ MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType());
}
} else {
MergedT = Context.mergeTypes(New->getType(), Old->getType());
@@ -1435,7 +1456,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
-Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
+Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS) {
// FIXME: Error on auto/register at file scope
// FIXME: Error on inline/virtual/explicit
// FIXME: Warn on useless __thread
@@ -1485,7 +1507,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
if (getLangOptions().CPlusPlus ||
Record->getDeclContext()->isRecord())
- return BuildAnonymousStructOrUnion(S, DS, Record);
+ return BuildAnonymousStructOrUnion(S, DS, AS, Record);
Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
<< DS.getSourceRange();
@@ -1563,8 +1585,10 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
///
/// This routine is recursive, injecting the names of nested anonymous
/// structs/unions into the owning context and scope as well.
-bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
- RecordDecl *AnonRecord) {
+static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S,
+ DeclContext *Owner,
+ RecordDecl *AnonRecord,
+ AccessSpecifier AS) {
unsigned diagKind
= AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl
: diag::err_anonymous_struct_member_redecl;
@@ -1574,7 +1598,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
FEnd = AnonRecord->field_end();
F != FEnd; ++F) {
if ((*F)->getDeclName()) {
- if (CheckAnonMemberRedeclaration(*this, S, Owner, (*F)->getDeclName(),
+ if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, (*F)->getDeclName(),
(*F)->getLocation(), diagKind)) {
// C++ [class.union]p2:
// The names of the members of an anonymous union shall be
@@ -1588,15 +1612,19 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
// considered to have been defined in the scope in which the
// anonymous union is declared.
Owner->makeDeclVisibleInContext(*F);
- S->AddDecl(DeclPtrTy::make(*F));
- IdResolver.AddDecl(*F);
+ S->AddDecl(Sema::DeclPtrTy::make(*F));
+ SemaRef.IdResolver.AddDecl(*F);
+
+ // That includes picking up the appropriate access specifier.
+ if (AS != AS_none) (*F)->setAccess(AS);
}
} else if (const RecordType *InnerRecordType
= (*F)->getType()->getAs<RecordType>()) {
RecordDecl *InnerRecord = InnerRecordType->getDecl();
if (InnerRecord->isAnonymousStructOrUnion())
Invalid = Invalid ||
- InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord);
+ InjectAnonymousStructOrUnionMembers(SemaRef, S, Owner,
+ InnerRecord, AS);
}
}
@@ -1666,6 +1694,7 @@ StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec,
/// (C++ [class.union]) and a GNU C extension; anonymous structures
/// are a GNU C and GNU C++ extension.
Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
+ AccessSpecifier AS,
RecordDecl *Record) {
DeclContext *Owner = Record->getDeclContext();
@@ -1720,7 +1749,8 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// C++ [class.union]p3:
// An anonymous union shall not have private or protected
// members (clause 11).
- if (FD->getAccess() == AS_protected || FD->getAccess() == AS_private) {
+ assert(FD->getAccess() != AS_none);
+ if (FD->getAccess() != AS_public) {
Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member)
<< (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected);
Invalid = true;
@@ -1777,7 +1807,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Context.getTypeDeclType(Record),
TInfo,
/*BitWidth=*/0, /*Mutable=*/false);
- Anon->setAccess(AS_public);
+ Anon->setAccess(AS);
if (getLangOptions().CPlusPlus) {
FieldCollector->Add(cast<FieldDecl>(Anon));
if (!cast<CXXRecordDecl>(Record)->isEmpty())
@@ -1814,7 +1844,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// Inject the members of the anonymous struct/union into the owning
// context and into the identifier resolver chain for name lookup
// purposes.
- if (InjectAnonymousStructOrUnionMembers(S, Owner, Record))
+ if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS))
Invalid = true;
// Mark this as an anonymous struct/union type. Note that we do not
@@ -2711,7 +2741,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
QualType T = NewVD->getType();
- if (T->isObjCInterfaceType()) {
+ if (T->isObjCObjectType()) {
Diag(NewVD->getLocation(), diag::err_statically_allocated_object);
return NewVD->setInvalidDecl();
}
@@ -2929,7 +2959,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
D.setInvalidType();
// Do not allow returning a objc interface by-value.
- if (R->getAs<FunctionType>()->getResultType()->isObjCInterfaceType()) {
+ if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) {
Diag(D.getIdentifierLoc(),
diag::err_object_cannot_be_passed_returned_by_value) << 0
<< R->getAs<FunctionType>()->getResultType();
@@ -4322,7 +4352,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC,
// Parameter declarators cannot be interface types. All ObjC objects are
// passed by reference.
- if (T->isObjCInterfaceType()) {
+ if (T->isObjCObjectType()) {
Diag(NameLoc,
diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
New->setInvalidDecl();
@@ -4540,6 +4570,38 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
return DeclPtrTy::make(FD);
}
+/// \brief Given the set of return statements within a function body,
+/// compute the variables that are subject to the named return value
+/// optimization.
+///
+/// Each of the variables that is subject to the named return value
+/// optimization will be marked as NRVO variables in the AST, and any
+/// return statement that has a marked NRVO variable as its NRVO candidate can
+/// use the named return value optimization.
+///
+/// This function applies a very simplistic algorithm for NRVO: if every return
+/// statement in the function has the same NRVO candidate, that candidate is
+/// the NRVO variable.
+///
+/// FIXME: Employ a smarter algorithm that accounts for multiple return
+/// statements and the lifetimes of the NRVO candidates. We should be able to
+/// find a maximal set of NRVO variables.
+static void ComputeNRVO(Stmt *Body, ReturnStmt **Returns, unsigned NumReturns) {
+ const VarDecl *NRVOCandidate = 0;
+ for (unsigned I = 0; I != NumReturns; ++I) {
+ if (!Returns[I]->getNRVOCandidate())
+ return;
+
+ if (!NRVOCandidate)
+ NRVOCandidate = Returns[I]->getNRVOCandidate();
+ else if (NRVOCandidate != Returns[I]->getNRVOCandidate())
+ return;
+ }
+
+ if (NRVOCandidate)
+ const_cast<VarDecl*>(NRVOCandidate)->setNRVOVariable(true);
+}
+
Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg) {
return ActOnFinishFunctionBody(D, move(BodyArg), false);
}
@@ -4567,12 +4629,17 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
WP.disableCheckFallThrough();
}
- if (!FD->isInvalidDecl())
+ if (!FD->isInvalidDecl()) {
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
-
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
- MaybeMarkVirtualMembersReferenced(Method->getLocation(), Method);
-
+
+ // If this is a constructor, we need a vtable.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD))
+ MarkVTableUsed(FD->getLocation(), Constructor->getParent());
+
+ ComputeNRVO(Body, FunctionScopes.back()->Returns.data(),
+ FunctionScopes.back()->Returns.size());
+ }
+
assert(FD == getCurFunctionDecl() && "Function parsing confused");
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
@@ -4636,7 +4703,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
// Verify that that gotos and switch cases don't jump into scopes illegally.
// Verify that that gotos and switch cases don't jump into scopes illegally.
- if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction())
+ if (FunctionNeedsScopeChecking() &&
+ !dcl->isInvalidDecl() &&
+ !hasAnyErrorsInThisFunction())
DiagnoseInvalidJumps(Body);
if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
@@ -4838,38 +4907,38 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
///
/// \returns true if the new tag kind is acceptable, false otherwise.
bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
- TagDecl::TagKind NewTag,
+ TagTypeKind NewTag,
SourceLocation NewTagLoc,
const IdentifierInfo &Name) {
// C++ [dcl.type.elab]p3:
// The class-key or enum keyword present in the
// elaborated-type-specifier shall agree in kind with the
- // declaration to which the name in theelaborated-type-specifier
+ // declaration to which the name in the elaborated-type-specifier
// refers. This rule also applies to the form of
// elaborated-type-specifier that declares a class-name or
// friend class since it can be construed as referring to the
// definition of the class. Thus, in any
// elaborated-type-specifier, the enum keyword shall be used to
- // refer to an enumeration (7.2), the union class-keyshall be
+ // refer to an enumeration (7.2), the union class-key shall be
// used to refer to a union (clause 9), and either the class or
// struct class-key shall be used to refer to a class (clause 9)
// declared using the class or struct class-key.
- TagDecl::TagKind OldTag = Previous->getTagKind();
+ TagTypeKind 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)) {
+ if ((OldTag == TTK_Struct || OldTag == TTK_Class) &&
+ (NewTag == TTK_Struct || NewTag == TTK_Class)) {
// Warn about the struct/class tag mismatch.
bool isTemplate = false;
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
isTemplate = Record->getDescribedClassTemplate();
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
- << (NewTag == TagDecl::TK_class)
+ << (NewTag == TTK_Class)
<< isTemplate << &Name
<< FixItHint::CreateReplacement(SourceRange(NewTagLoc),
- OldTag == TagDecl::TK_class? "class" : "struct");
+ OldTag == TTK_Class? "class" : "struct");
Diag(Previous->getLocation(), diag::note_previous_use);
return true;
}
@@ -4891,7 +4960,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
"Nameless record must be a definition!");
OwnedDecl = false;
- TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
// FIXME: Check explicit specializations more carefully.
bool isExplicitSpecialization = false;
@@ -4915,7 +4984,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
} else {
// The "template<>" header is extraneous.
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
- << ElaboratedType::getNameForTagKind(Kind) << Name;
+ << TypeWithKeyword::getTagTypeKindName(Kind) << Name;
isExplicitSpecialization = true;
}
}
@@ -5134,8 +5203,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// struct or something similar.
if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
bool SafeToContinue
- = (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
- Kind != TagDecl::TK_enum);
+ = (PrevTagDecl->getTagKind() != TTK_Enum &&
+ Kind != TTK_Enum);
if (SafeToContinue)
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
@@ -5289,7 +5358,7 @@ CreateNewDecl:
// PrevDecl.
TagDecl *New;
- if (Kind == TagDecl::TK_enum) {
+ if (Kind == TTK_Enum) {
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
// enum X { A, B, C } D; D should chain to X.
New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc,
@@ -5319,16 +5388,18 @@ CreateNewDecl:
// Maybe add qualifier info.
if (SS.isNotEmpty()) {
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
- New->setQualifierInfo(NNS, SS.getRange());
+ if (SS.isSet()) {
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ New->setQualifierInfo(NNS, SS.getRange());
+ }
+ else
+ Invalid = true;
}
- if (Kind != TagDecl::TK_enum) {
- // Handle #pragma pack: if the #pragma pack stack has non-default
- // alignment, make up a packed attribute for this decl. These
- // attributes are checked when the ASTContext lays out the
- // structure.
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(New)) {
+ // Add alignment attributes if necessary; these attributes are checked when
+ // the ASTContext lays out the structure.
//
// It is important for implementing the correct semantics that this
// happen here (in act on tag decl). The #pragma pack stack is
@@ -5336,15 +5407,14 @@ CreateNewDecl:
// many points during the parsing of a struct declaration (because
// the #pragma tokens are effectively skipped over during the
// parsing of the struct).
- if (unsigned Alignment = getPragmaPackAlignment())
- New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8));
+ AddAlignmentAttributesForRecord(RD);
}
// If this is a specialization of a member class (of a class template),
// check the specialization.
if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
Invalid = true;
-
+
if (Invalid)
New->setInvalidDecl();
@@ -5439,37 +5509,6 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD,
"Broken injected-class-name");
}
-// Traverses the class and any nested classes, making a note of any
-// dynamic classes that have no key function so that we can mark all of
-// their virtual member functions as "used" at the end of the translation
-// unit. This ensures that all functions needed by the vtable will get
-// instantiated/synthesized.
-static void
-RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record,
- SourceLocation Loc) {
- // We don't look at dependent or undefined classes.
- if (Record->isDependentContext() || !Record->isDefinition())
- return;
-
- if (Record->isDynamicClass()) {
- const CXXMethodDecl *KeyFunction = S.Context.getKeyFunction(Record);
-
- if (!KeyFunction)
- S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record,
- Loc));
-
- if ((!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined()))
- && Record->getLinkage() == ExternalLinkage)
- S.Diag(Record->getLocation(), diag::warn_weak_vtable) << Record;
- }
- for (DeclContext::decl_iterator D = Record->decls_begin(),
- DEnd = Record->decls_end();
- D != DEnd; ++D) {
- if (CXXRecordDecl *Nested = dyn_cast<CXXRecordDecl>(*D))
- RecordDynamicClassesWithNoKeyFunction(S, Nested, Loc);
- }
-}
-
void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
SourceLocation RBraceLoc) {
AdjustDeclIfTemplate(TagD);
@@ -5481,10 +5520,6 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
// Exit this scope of this tag's definition.
PopDeclContext();
-
- if (isa<CXXRecordDecl>(Tag) && !Tag->getLexicalDeclContext()->isRecord())
- RecordDynamicClassesWithNoKeyFunction(*this, cast<CXXRecordDecl>(Tag),
- RBraceLoc);
// Notify the consumer that we've defined a tag.
Consumer.HandleTagDeclDefinition(Tag);
@@ -6098,6 +6133,15 @@ void Sema::ActOnFields(Scope* S,
EnclosingDecl->setInvalidDecl();
continue;
}
+ if (!FD->getType()->isDependentType() &&
+ !Context.getBaseElementType(FD->getType())->isPODType()) {
+ Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type)
+ << FD->getDeclName() << FD->getType();
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+
// Okay, we have a legal flexible array member at the end of the struct.
if (Record)
Record->setHasFlexibleArrayMember(true);
@@ -6132,7 +6176,7 @@ void Sema::ActOnFields(Scope* S,
}
if (Record && FDTTy->getDecl()->hasObjectMember())
Record->setHasObjectMember(true);
- } else if (FDTy->isObjCInterfaceType()) {
+ } else if (FDTy->isObjCObjectType()) {
/// A field cannot be an Objective-c object
Diag(FD->getLocation(), diag::err_statically_allocated_object);
FD->setInvalidDecl();
@@ -6435,7 +6479,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(EnumType);
}
- Enum->completeDefinition(Context.DependentTy, Context.DependentTy);
+ Enum->completeDefinition(Context.DependentTy, Context.DependentTy, 0, 0);
return;
}
@@ -6616,7 +6660,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(NewTy);
}
- Enum->completeDefinition(BestType, BestPromotionType);
+ Enum->completeDefinition(BestType, BestPromotionType,
+ NumPositiveBits, NumNegativeBits);
}
Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 90aa9c1..c6dcc3b 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -129,11 +129,11 @@ static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
if (!PT)
return false;
- const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAs<ObjCInterfaceType>();
- if (!ClsT)
+ ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface();
+ if (!Cls)
return false;
- IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier();
+ IdentifierInfo* ClsName = Cls->getIdentifier();
// FIXME: Should we walk the chain of classes?
return ClsName == &Ctx.Idents.get("NSString") ||
@@ -150,7 +150,7 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
return false;
const RecordDecl *RD = RT->getDecl();
- if (RD->getTagKind() != TagDecl::TK_struct)
+ if (RD->getTagKind() != TTK_Struct)
return false;
return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
@@ -259,6 +259,26 @@ static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName();
}
+static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
+ Sema &S) {
+
+ // The iboutletcollection attribute can have zero or one arguments.
+ if (Attr.getNumArgs() > 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ // The IBOutletCollection attributes only apply to instance variables of
+ // Objective-C classes.
+ if (!(isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName();
+ return;
+ }
+
+ // FIXME: Eventually accept the type argument.
+ d->addAttr(::new (S.Context) IBOutletCollectionAttr());
+}
+
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
@@ -280,7 +300,8 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// The argument must be an integer constant expression.
Expr *Ex = static_cast<Expr *>(*I);
llvm::APSInt ArgNum(32);
- if (!Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
+ if (Ex->isTypeDependent() || Ex->isValueDependent() ||
+ !Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "nonnull" << Ex->getSourceRange();
return;
@@ -560,7 +581,8 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() > 0) {
Expr *E = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Idx(32);
- if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "constructor" << 1 << E->getSourceRange();
return;
@@ -589,7 +611,8 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() > 0) {
Expr *E = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Idx(32);
- if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "destructor" << 1 << E->getSourceRange();
return;
@@ -745,7 +768,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() > 0) {
Expr *E = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Idx(32);
- if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "sentinel" << 1 << E->getSourceRange();
return;
@@ -763,7 +787,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() > 1) {
Expr *E = static_cast<Expr *>(Attr.getArg(1));
llvm::APSInt Idx(32);
- if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "sentinel" << 2 << E->getSourceRange();
return;
@@ -924,7 +949,8 @@ static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
for (unsigned i = 0; i < 3; ++i) {
Expr *E = static_cast<Expr *>(Attr.getArg(i));
llvm::APSInt ArgNum(32);
- if (!E->isIntegerConstantExpr(ArgNum, S.Context)) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(ArgNum, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "reqd_work_group_size" << E->getSourceRange();
return;
@@ -1076,7 +1102,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// checks for the 2nd argument
Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Idx(32);
- if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
+ if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
+ !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "format" << 2 << IdxExpr->getSourceRange();
return;
@@ -1198,7 +1225,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// checks for the 2nd argument
Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Idx(32);
- if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
+ if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
+ !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "format" << 2 << IdxExpr->getSourceRange();
return;
@@ -1261,7 +1289,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the 3rd argument
Expr *FirstArgExpr = static_cast<Expr *>(Attr.getArg(1));
llvm::APSInt FirstArg(32);
- if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
+ if (FirstArgExpr->isTypeDependent() || FirstArgExpr->isValueDependent() ||
+ !FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "format" << 3 << FirstArgExpr->getSourceRange();
return;
@@ -1403,7 +1432,8 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Alignment(32);
- if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) {
+ if (alignmentExpr->isTypeDependent() || alignmentExpr->isValueDependent() ||
+ !alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "aligned" << alignmentExpr->getSourceRange();
return;
@@ -1654,6 +1684,8 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) {
case AttributeList::AT_stdcall:
d->addAttr(::new (S.Context) StdCallAttr());
return;
+ case AttributeList::AT_thiscall:
+ d->addAttr(::new (S.Context) ThisCallAttr());
case AttributeList::AT_cdecl:
d->addAttr(::new (S.Context) CDeclAttr());
return;
@@ -1678,7 +1710,8 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt NumParams(32);
- if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
+ if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
+ !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "regparm" << NumParamsExpr->getSourceRange();
return;
@@ -1871,7 +1904,9 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
return;
switch (Attr.getKind()) {
case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break;
- case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break;
+ case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break;
+ case AttributeList::AT_IBOutletCollection:
+ HandleIBOutletCollection(D, Attr, S); break;
case AttributeList::AT_address_space:
case AttributeList::AT_objc_gc:
case AttributeList::AT_vector_size:
@@ -1950,6 +1985,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_stdcall:
case AttributeList::AT_cdecl:
case AttributeList::AT_fastcall:
+ case AttributeList::AT_thiscall:
HandleCallConvAttr(D, Attr, S);
break;
default:
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b9c7d79..148d146 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -461,7 +461,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
if (BaseType->isDependentType())
return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
- Class->getTagKind() == RecordDecl::TK_class,
+ Class->getTagKind() == TTK_Class,
Access, BaseType);
// Base specifiers must be record types.
@@ -504,9 +504,8 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
SetClassDeclAttributesFromBase(Class, CXXBaseDecl, Virtual);
// Create the base specifier.
- // FIXME: Allocate via ASTContext?
return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
- Class->getTagKind() == RecordDecl::TK_class,
+ Class->getTagKind() == TTK_Class,
Access, BaseType);
}
@@ -623,7 +622,13 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
QualType NewBaseType
= Context.getCanonicalType(Bases[idx]->getType());
NewBaseType = NewBaseType.getLocalUnqualifiedType();
-
+ if (!Class->hasObjectMember()) {
+ if (const RecordType *FDTTy =
+ NewBaseType.getTypePtr()->getAs<RecordType>())
+ if (FDTTy->getDecl()->hasObjectMember())
+ Class->setHasObjectMember(true);
+ }
+
if (KnownBaseTypes[NewBaseType]) {
// C++ [class.mi]p3:
// A class shall not be specified as a direct base class of a
@@ -736,6 +741,18 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
BasePathArray.push_back(Path[I].Base);
}
+/// \brief Determine whether the given base path includes a virtual
+/// base class.
+bool Sema::BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath) {
+ for (CXXBaseSpecifierArray::iterator B = BasePath.begin(),
+ BEnd = BasePath.end();
+ B != BEnd; ++B)
+ if ((*B)->isVirtual())
+ return true;
+
+ return false;
+}
+
/// 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
@@ -1125,7 +1142,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// specialization, we take it as a type name.
BaseType = CheckTypenameType(ETK_None,
(NestedNameSpecifier *)SS.getScopeRep(),
- *MemberOrBase, SS.getRange());
+ *MemberOrBase, SourceLocation(),
+ SS.getRange(), IdLoc);
if (BaseType.isNull())
return true;
@@ -1192,7 +1210,7 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
static_cast<NestedNameSpecifier*>(SS.getScopeRep());
// FIXME: preserve source range information
- BaseType = Context.getQualifiedNameType(Qualifier, BaseType);
+ BaseType = Context.getElaboratedType(ETK_None, Qualifier, BaseType);
}
}
}
@@ -1357,7 +1375,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
for (unsigned i = 0; i < NumArgs; i++)
HasDependentArg |= Args[i]->isTypeDependent();
- SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin();
+ SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin();
if (BaseType->isDependentType() || HasDependentArg) {
// Can't check initialization for a base of dependent type or when
// any of the arguments are type-dependent expressions.
@@ -1381,7 +1399,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (!BaseType->isRecordType())
return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
- << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
+ << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange();
// C++ [class.base.init]p2:
// [...] Unless the mem-initializer-id names a nonstatic data
@@ -1402,7 +1420,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// class, the mem-initializer is ill-formed.
if (DirectBaseSpec && VirtualBaseSpec)
return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
- << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
+ << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange();
// 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
@@ -1410,7 +1428,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (!DirectBaseSpec && !VirtualBaseSpec)
return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
<< BaseType << Context.getTypeDeclType(ClassDecl)
- << BaseTInfo->getTypeLoc().getSourceRange();
+ << BaseTInfo->getTypeLoc().getLocalSourceRange();
CXXBaseSpecifier *BaseSpec
= const_cast<CXXBaseSpecifier *>(DirectBaseSpec);
@@ -1550,42 +1568,107 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ImplicitInitializerKind ImplicitInitKind,
FieldDecl *Field,
CXXBaseOrMemberInitializer *&CXXMemberInit) {
+ if (Field->isInvalidDecl())
+ return true;
+
if (ImplicitInitKind == IIK_Copy) {
- // FIXME: We should not return early here, but will do so until
- // we know how to handle copy initialization of arrays.
- CXXMemberInit = 0;
- return false;
-
+ SourceLocation Loc = Constructor->getLocation();
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
Expr *MemberExprBase =
DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param,
- SourceLocation(), ParamType, 0);
+ Loc, ParamType, 0);
+
+ // Build a reference to this field within the parameter.
+ CXXScopeSpec SS;
+ LookupResult MemberLookup(SemaRef, Field->getDeclName(), Loc,
+ Sema::LookupMemberName);
+ MemberLookup.addDecl(Field, AS_public);
+ MemberLookup.resolveKind();
+ Sema::OwningExprResult CopyCtorArg
+ = SemaRef.BuildMemberReferenceExpr(SemaRef.Owned(MemberExprBase),
+ ParamType, Loc,
+ /*IsArrow=*/false,
+ SS,
+ /*FirstQualifierInScope=*/0,
+ MemberLookup,
+ /*TemplateArgs=*/0);
+ if (CopyCtorArg.isInvalid())
+ return true;
+ // When the field we are copying is an array, create index variables for
+ // each dimension of the array. We use these index variables to subscript
+ // the source array, and other clients (e.g., CodeGen) will perform the
+ // necessary iteration with these index variables.
+ llvm::SmallVector<VarDecl *, 4> IndexVariables;
+ QualType BaseType = Field->getType();
+ QualType SizeType = SemaRef.Context.getSizeType();
+ while (const ConstantArrayType *Array
+ = SemaRef.Context.getAsConstantArrayType(BaseType)) {
+ // Create the iteration variable for this array index.
+ IdentifierInfo *IterationVarName = 0;
+ {
+ llvm::SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "__i" << IndexVariables.size();
+ IterationVarName = &SemaRef.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar
+ = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc,
+ IterationVarName, SizeType,
+ SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc),
+ VarDecl::None, VarDecl::None);
+ IndexVariables.push_back(IterationVar);
+
+ // Create a reference to the iteration variable.
+ Sema::OwningExprResult IterationVarRef
+ = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, Loc);
+ assert(!IterationVarRef.isInvalid() &&
+ "Reference to invented variable cannot fail!");
+
+ // Subscript the array with this iteration variable.
+ CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(move(CopyCtorArg),
+ Loc,
+ move(IterationVarRef),
+ Loc);
+ if (CopyCtorArg.isInvalid())
+ return true;
+
+ BaseType = Array->getElementType();
+ }
- Expr *CopyCtorArg =
- MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false,
- 0, SourceRange(), Field,
- DeclAccessPair::make(Field, Field->getAccess()),
- SourceLocation(), 0,
- Field->getType().getNonReferenceType());
+ // Construct the entity that we will be initializing. For an array, this
+ // will be first element in the array, which may require several levels
+ // of array-subscript entities.
+ llvm::SmallVector<InitializedEntity, 4> Entities;
+ Entities.reserve(1 + IndexVariables.size());
+ Entities.push_back(InitializedEntity::InitializeMember(Field));
+ for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
+ Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context,
+ 0,
+ Entities.back()));
- InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ // Direct-initialize to use the copy constructor.
InitializationKind InitKind =
- InitializationKind::CreateDirect(Constructor->getLocation(),
- SourceLocation(), SourceLocation());
+ InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
- InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
- &CopyCtorArg, 1);
+ Expr *CopyCtorArgE = CopyCtorArg.takeAs<Expr>();
+ InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind,
+ &CopyCtorArgE, 1);
- Sema::OwningExprResult MemberInit =
- InitSeq.Perform(SemaRef, InitEntity, InitKind,
- Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0);
+ Sema::OwningExprResult MemberInit
+ = InitSeq.Perform(SemaRef, Entities.back(), InitKind,
+ Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArgE, 1));
+ MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit));
if (MemberInit.isInvalid())
return true;
-
- CXXMemberInit = 0;
+
+ CXXMemberInit
+ = CXXBaseOrMemberInitializer::Create(SemaRef.Context, Field, Loc, Loc,
+ MemberInit.takeAs<Expr>(), Loc,
+ IndexVariables.data(),
+ IndexVariables.size());
return false;
}
@@ -1640,6 +1723,81 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
CXXMemberInit = 0;
return false;
}
+
+namespace {
+struct BaseAndFieldInfo {
+ Sema &S;
+ CXXConstructorDecl *Ctor;
+ bool AnyErrorsInInits;
+ ImplicitInitializerKind IIK;
+ llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
+ llvm::SmallVector<CXXBaseOrMemberInitializer*, 8> AllToInit;
+
+ BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits)
+ : S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) {
+ // FIXME: Handle implicit move constructors.
+ if (Ctor->isImplicit() && Ctor->isCopyConstructor())
+ IIK = IIK_Copy;
+ else
+ IIK = IIK_Default;
+ }
+};
+}
+
+static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
+ FieldDecl *Top, FieldDecl *Field) {
+
+ // Overwhelmingly common case: we have a direct initializer for this field.
+ if (CXXBaseOrMemberInitializer *Init = Info.AllBaseFields.lookup(Field)) {
+ Info.AllToInit.push_back(Init);
+
+ if (Field != Top) {
+ Init->setMember(Top);
+ Init->setAnonUnionMember(Field);
+ }
+ return false;
+ }
+
+ if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) {
+ const RecordType *FieldClassType = Field->getType()->getAs<RecordType>();
+ assert(FieldClassType && "anonymous struct/union without record type");
+
+ // Walk through the members, tying in any initializers for fields
+ // we find. The earlier semantic checks should prevent redundant
+ // initialization of union members, given the requirement that
+ // union members never have non-trivial default constructors.
+
+ // TODO: in C++0x, it might be legal to have union members with
+ // non-trivial default constructors in unions. Revise this
+ // implementation then with the appropriate semantics.
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
+ EA = FieldClassDecl->field_end(); FA != EA; FA++)
+ if (CollectFieldInitializer(Info, Top, *FA))
+ return true;
+ }
+
+ // Don't try to build an implicit initializer if there were semantic
+ // errors in any of the initializers (and therefore we might be
+ // missing some that the user actually wrote).
+ if (Info.AnyErrorsInInits)
+ return false;
+
+ CXXBaseOrMemberInitializer *Init = 0;
+ if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Init))
+ return true;
+
+ // If the member doesn't need to be initialized, Init will still be null.
+ if (!Init) return false;
+
+ Info.AllToInit.push_back(Init);
+ if (Top != Field) {
+ Init->setMember(Top);
+ Init->setAnonUnionMember(Field);
+ }
+ return false;
+}
bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
@@ -1661,11 +1819,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
return false;
}
- ImplicitInitializerKind ImplicitInitKind = IIK_Default;
-
- // FIXME: Handle implicit move constructors.
- if (Constructor->isImplicit() && Constructor->isCopyConstructor())
- ImplicitInitKind = IIK_Copy;
+ BaseAndFieldInfo Info(*this, Constructor, AnyErrors);
// We need to build the initializer AST according to order of construction
// and not what user specified in the Initializers list.
@@ -1673,17 +1827,15 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
if (!ClassDecl)
return true;
- llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
- llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
bool HadError = false;
for (unsigned i = 0; i < NumInitializers; i++) {
CXXBaseOrMemberInitializer *Member = Initializers[i];
if (Member->isBaseInitializer())
- AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
+ Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
else
- AllBaseFields[Member->getMember()] = Member;
+ Info.AllBaseFields[Member->getMember()] = Member;
}
// Keep track of the direct virtual bases.
@@ -1699,22 +1851,23 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
if (CXXBaseOrMemberInitializer *Value
- = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
- AllToInit.push_back(Value);
+ = Info.AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
+ Info.AllToInit.push_back(Value);
} else if (!AnyErrors) {
bool IsInheritedVirtualBase = !DirectVBases.count(VBase);
CXXBaseOrMemberInitializer *CXXBaseInit;
- if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind,
+ if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK,
VBase, IsInheritedVirtualBase,
CXXBaseInit)) {
HadError = true;
continue;
}
- AllToInit.push_back(CXXBaseInit);
+ Info.AllToInit.push_back(CXXBaseInit);
}
}
+ // Non-virtual bases.
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.
@@ -1722,70 +1875,39 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
continue;
if (CXXBaseOrMemberInitializer *Value
- = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
- AllToInit.push_back(Value);
+ = Info.AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
+ Info.AllToInit.push_back(Value);
} else if (!AnyErrors) {
CXXBaseOrMemberInitializer *CXXBaseInit;
- if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind,
+ if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK,
Base, /*IsInheritedVirtualBase=*/false,
CXXBaseInit)) {
HadError = true;
continue;
}
- AllToInit.push_back(CXXBaseInit);
+ Info.AllToInit.push_back(CXXBaseInit);
}
}
- // non-static data members.
+ // Fields.
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)) {
- AllToInit.push_back(Value);
+ if ((*Field)->getType()->isIncompleteArrayType()) {
+ assert(ClassDecl->hasFlexibleArrayMember() &&
+ "Incomplete array type is not valid");
continue;
}
-
- if (AnyErrors)
- continue;
-
- CXXBaseOrMemberInitializer *Member;
- if (BuildImplicitMemberInitializer(*this, Constructor, ImplicitInitKind,
- *Field, Member)) {
+ if (CollectFieldInitializer(Info, *Field, *Field))
HadError = true;
- continue;
- }
-
- // If the member doesn't need to be initialized, it will be null.
- if (Member)
- AllToInit.push_back(Member);
}
- NumInitializers = AllToInit.size();
+ NumInitializers = Info.AllToInit.size();
if (NumInitializers > 0) {
Constructor->setNumBaseOrMemberInitializers(NumInitializers);
CXXBaseOrMemberInitializer **baseOrMemberInitializers =
new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
- memcpy(baseOrMemberInitializers, AllToInit.data(),
+ memcpy(baseOrMemberInitializers, Info.AllToInit.data(),
NumInitializers * sizeof(CXXBaseOrMemberInitializer*));
Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
@@ -1900,9 +2022,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
// If we didn't find this initializer, it must be because we
// scanned past it on a previous iteration. That can only
// happen if we're out of order; emit a warning.
- if (IdealIndex == NumIdealInits) {
- assert(PrevInit && "initializer not found in initializer list");
-
+ if (IdealIndex == NumIdealInits && PrevInit) {
Sema::SemaDiagnosticBuilder D =
SemaRef.Diag(PrevInit->getSourceLocation(),
diag::warn_initializer_out_of_order);
@@ -2028,6 +2148,9 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
for (unsigned i = 0; i < NumMemInits; i++) {
CXXBaseOrMemberInitializer *Init = MemInits[i];
+ // Set the source order index.
+ Init->setSourceOrder(i);
+
if (Init->isMemberInitializer()) {
FieldDecl *Field = Init->getMember();
if (CheckRedundantInit(*this, Init, Members[Field]) ||
@@ -2064,7 +2187,8 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
E = ClassDecl->field_end(); I != E; ++I) {
FieldDecl *Field = *I;
-
+ if (Field->isInvalidDecl())
+ continue;
QualType FieldType = Context.getBaseElementType(Field->getType());
const RecordType* RT = FieldType->getAs<RecordType>();
@@ -2403,6 +2527,9 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
}
}
}
+
+ if (Record->isDynamicClass())
+ DynamicClasses.push_back(Record);
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
@@ -2530,7 +2657,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S,
Context.getFunctionType(Context.VoidTy,
&ArgType, 1,
false, 0,
- /*FIXME:*/false,
+ /*FIXME: hasExceptionSpec*/false,
false, 0, 0,
FunctionType::ExtInfo()),
/*TInfo=*/0,
@@ -2623,7 +2750,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S,
CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name,
Context.getFunctionType(RetType, &ArgType, 1,
false, 0,
- /*FIXME:*/false,
+ /*FIXME: hasExceptionSpec*/false,
false, 0, 0,
FunctionType::ExtInfo()),
/*TInfo=*/0, /*isStatic=*/false,
@@ -2659,7 +2786,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S,
// inline public member of its class.
QualType Ty = Context.getFunctionType(Context.VoidTy,
0, 0, false, 0,
- /*FIXME:*/false,
+ /*FIXME: hasExceptionSpec*/false,
false, 0, 0, FunctionType::ExtInfo());
DeclarationName Name
@@ -3817,8 +3944,9 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
// A using-declaration is a declaration and can therefore be used
// repeatedly where (and only where) multiple declarations are
// allowed.
- // That's only in file contexts.
- if (CurContext->getLookupContext()->isFileContext())
+ //
+ // That's in non-member contexts.
+ if (!CurContext->getLookupContext()->isRecord())
return false;
NestedNameSpecifier *Qual
@@ -4082,12 +4210,15 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
ImplicitlyDefinedFunctionScope Scope(*this, Constructor);
- if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) {
+ ErrorTrap Trap(*this);
+ if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false) ||
+ Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
+ MarkVTableUsed(CurrentLocation, ClassDecl);
}
}
@@ -4098,14 +4229,16 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
+ if (Destructor->isInvalidDecl())
+ return;
+
ImplicitlyDefinedFunctionScope Scope(*this, Destructor);
+ ErrorTrap Trap(*this);
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
Destructor->getParent());
- // FIXME: If CheckDestructor fails, we should emit a note about where the
- // implicit destructor was needed.
- if (CheckDestructor(Destructor)) {
+ if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDestructor << Context.getTagDeclType(ClassDecl);
@@ -4114,6 +4247,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
Destructor->setUsed();
+ MarkVTableUsed(CurrentLocation, ClassDecl);
}
/// \brief Builds a statement that copies the given entity from \p From to
@@ -4332,6 +4466,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CopyAssignOperator->setUsed();
ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator);
+ ErrorTrap Trap(*this);
// C++0x [class.copy]p30:
// The implicitly-defined or explicitly-defaulted copy assignment operator
@@ -4407,8 +4542,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
move(To), Owned(From),
/*CopyingBaseSubobject=*/true);
if (Copy.isInvalid()) {
- Invalid = true;
- continue;
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
+ CopyAssignOperator->setInvalidDecl();
+ return;
}
// Success! Record the copy.
@@ -4427,7 +4564,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(Loc, diag::note_first_required_here);
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
Invalid = true;
continue;
}
@@ -4438,12 +4576,18 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(Loc, diag::note_first_required_here);
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
Invalid = true;
continue;
}
QualType FieldType = Field->getType().getNonReferenceType();
+ if (FieldType->isIncompleteArrayType()) {
+ assert(ClassDecl->hasFlexibleArrayMember() &&
+ "Incomplete array type is not valid");
+ continue;
+ }
// Build references to the field in the object we're copying from and to.
CXXScopeSpec SS; // Intentionally empty
@@ -4528,8 +4672,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
move(To), move(From),
/*CopyingBaseSubobject=*/false);
if (Copy.isInvalid()) {
- Invalid = true;
- continue;
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
+ CopyAssignOperator->setInvalidDecl();
+ return;
}
// Success! Record the copy.
@@ -4546,6 +4692,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Invalid = true;
else {
Statements.push_back(Return.takeAs<Stmt>());
+
+ if (Trap.hasErrorOccurred()) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
+ Invalid = true;
+ }
}
}
@@ -4572,37 +4724,22 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor);
+ ErrorTrap Trap(*this);
- if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) {
+ if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) ||
+ Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
+ << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
CopyConstructor->setInvalidDecl();
- } else {
- CopyConstructor->setUsed();
- }
-
- // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of
- // fields, this code below should be removed.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXConstructorDecl *FieldCopyCtor =
- FieldClassDecl->getCopyConstructor(Context, TypeQuals)) {
- CheckDirectMemberAccess(Field->getLocation(),
- FieldCopyCtor,
- PDiag(diag::err_access_copy_field)
- << Field->getDeclName() << Field->getType());
-
- MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
- }
- }
+ } else {
+ CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(),
+ CopyConstructor->getLocation(),
+ MultiStmtArg(*this, 0, 0),
+ /*isStmtExpr=*/false)
+ .takeAs<Stmt>());
}
+
+ CopyConstructor->setUsed();
}
Sema::OwningExprResult
@@ -4672,7 +4809,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl());
if (!ClassDecl->isInvalidDecl() && !VD->isInvalidDecl() &&
- !ClassDecl->hasTrivialDestructor()) {
+ !ClassDecl->hasTrivialDestructor() && !ClassDecl->isDependentContext()) {
CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
MarkDeclarationReferenced(VD->getLocation(), Destructor);
CheckDestructorAccess(VD->getLocation(), Destructor,
@@ -5419,7 +5556,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc,
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
QualType T = TSInfo->getType();
- SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();
+ SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange();
if (!getLangOptions().CPlusPlus0x) {
// C++03 [class.friend]p2:
@@ -5948,90 +6085,125 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
return Dcl;
}
-static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) {
- // Ignore dependent types.
- if (MD->isDependentContext())
- return false;
-
- // Ignore declarations that are not definitions.
- if (!MD->isThisDeclarationADefinition())
- return false;
-
- CXXRecordDecl *RD = MD->getParent();
-
- // Ignore classes without a vtable.
- if (!RD->isDynamicClass())
- return false;
-
- switch (MD->getParent()->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- // Classes that aren't instantiations of templates don't need their
- // virtual methods marked until we see the definition of the key
- // function.
- break;
+void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
+ bool DefinitionRequired) {
+ // Ignore any vtable uses in unevaluated operands or for classes that do
+ // not have a vtable.
+ if (!Class->isDynamicClass() || Class->isDependentContext() ||
+ CurContext->isDependentContext() ||
+ ExprEvalContexts.back().Context == Unevaluated)
+ return;
- case TSK_ImplicitInstantiation:
- // This is a constructor of a class template; mark all of the virtual
- // members as referenced to ensure that they get instantiatied.
- if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
- return true;
- break;
+ // Try to insert this class into the map.
+ Class = cast<CXXRecordDecl>(Class->getCanonicalDecl());
+ std::pair<llvm::DenseMap<CXXRecordDecl *, bool>::iterator, bool>
+ Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired));
+ if (!Pos.second) {
+ // If we already had an entry, check to see if we are promoting this vtable
+ // to required a definition. If so, we need to reappend to the VTableUses
+ // list, since we may have already processed the first entry.
+ if (DefinitionRequired && !Pos.first->second) {
+ Pos.first->second = true;
+ } else {
+ // Otherwise, we can early exit.
+ return;
+ }
+ }
- case TSK_ExplicitInstantiationDeclaration:
- return false;
+ // Local classes need to have their virtual members marked
+ // immediately. For all other classes, we mark their virtual members
+ // at the end of the translation unit.
+ if (Class->isLocalClass())
+ MarkVirtualMembersReferenced(Loc, Class);
+ else
+ VTableUses.push_back(std::make_pair(Class, Loc));
+}
- case TSK_ExplicitInstantiationDefinition:
- // This is method of a explicit instantiation; mark all of the virtual
- // members as referenced to ensure that they get instantiatied.
- return true;
+bool Sema::DefineUsedVTables() {
+ // If any dynamic classes have their key function defined within
+ // this translation unit, then those vtables are considered "used" and must
+ // be emitted.
+ for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) {
+ if (const CXXMethodDecl *KeyFunction
+ = Context.getKeyFunction(DynamicClasses[I])) {
+ const FunctionDecl *Definition = 0;
+ if (KeyFunction->getBody(Definition))
+ MarkVTableUsed(Definition->getLocation(), DynamicClasses[I], true);
+ }
}
- // Consider only out-of-line definitions of member functions. When we see
- // an inline definition, it's too early to compute the key function.
- if (!MD->isOutOfLine())
+ if (VTableUses.empty())
return false;
+
+ // Note: The VTableUses vector could grow as a result of marking
+ // the members of a class as "used", so we check the size each
+ // time through the loop and prefer indices (with are stable) to
+ // iterators (which are not).
+ for (unsigned I = 0; I != VTableUses.size(); ++I) {
+ CXXRecordDecl *Class = VTableUses[I].first->getDefinition();
+ if (!Class)
+ continue;
- const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
-
- // If there is no key function, we will need a copy of the vtable.
- if (!KeyFunction)
- return true;
-
- // If this is the key function, we need to mark virtual members.
- if (KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl())
- return true;
-
- return false;
-}
-
-void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
- CXXMethodDecl *MD) {
- CXXRecordDecl *RD = MD->getParent();
+ SourceLocation Loc = VTableUses[I].second;
+
+ // If this class has a key function, but that key function is
+ // defined in another translation unit, we don't need to emit the
+ // vtable even though we're using it.
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(Class);
+ if (KeyFunction && !KeyFunction->getBody()) {
+ switch (KeyFunction->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ // The key function is in another translation unit.
+ continue;
- // We will need to mark all of the virtual members as referenced to build the
- // vtable.
- if (!needsVTable(MD, Context))
- return;
+ case TSK_ExplicitInstantiationDefinition:
+ case TSK_ImplicitInstantiation:
+ // We will be instantiating the key function.
+ break;
+ }
+ } else if (!KeyFunction) {
+ // If we have a class with no key function that is the subject
+ // of an explicit instantiation declaration, suppress the
+ // vtable; it will live with the explicit instantiation
+ // definition.
+ bool IsExplicitInstantiationDeclaration
+ = Class->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration;
+ for (TagDecl::redecl_iterator R = Class->redecls_begin(),
+ REnd = Class->redecls_end();
+ R != REnd; ++R) {
+ TemplateSpecializationKind TSK
+ = cast<CXXRecordDecl>(*R)->getTemplateSpecializationKind();
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
+ IsExplicitInstantiationDeclaration = true;
+ else if (TSK == TSK_ExplicitInstantiationDefinition) {
+ IsExplicitInstantiationDeclaration = false;
+ break;
+ }
+ }
- TemplateSpecializationKind kind = RD->getTemplateSpecializationKind();
- if (kind == TSK_ImplicitInstantiation)
- ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc));
- else
- MarkVirtualMembersReferenced(Loc, RD);
-}
+ if (IsExplicitInstantiationDeclaration)
+ continue;
+ }
-bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
- if (ClassesWithUnmarkedVirtualMembers.empty())
- return false;
-
- while (!ClassesWithUnmarkedVirtualMembers.empty()) {
- CXXRecordDecl *RD = ClassesWithUnmarkedVirtualMembers.back().first;
- SourceLocation Loc = ClassesWithUnmarkedVirtualMembers.back().second;
- ClassesWithUnmarkedVirtualMembers.pop_back();
- MarkVirtualMembersReferenced(Loc, RD);
+ // Mark all of the virtual members of this class as referenced, so
+ // that we can build a vtable. Then, tell the AST consumer that a
+ // vtable for this class is required.
+ MarkVirtualMembersReferenced(Loc, Class);
+ CXXRecordDecl *Canonical = cast<CXXRecordDecl>(Class->getCanonicalDecl());
+ Consumer.HandleVTable(Class, VTablesUsed[Canonical]);
+
+ // Optionally warn if we're emitting a weak vtable.
+ if (Class->getLinkage() == ExternalLinkage &&
+ Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
+ if (!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined()))
+ Diag(Class->getLocation(), diag::warn_weak_vtable) << Class;
+ }
}
-
+ VTableUses.clear();
+
return true;
}
@@ -6076,6 +6248,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
for (unsigned i = 0; i < ivars.size(); i++) {
FieldDecl *Field = ivars[i];
+ if (Field->isInvalidDecl())
+ continue;
+
CXXBaseOrMemberInitializer *Member;
InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
InitializationKind InitKind =
@@ -6098,6 +6273,20 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
MemberInit.takeAs<Expr>(),
SourceLocation());
AllToInit.push_back(Member);
+
+ // Be sure that the destructor is accessible and is marked as referenced.
+ if (const RecordType *RecordTy
+ = Context.getBaseElementType(Field->getType())
+ ->getAs<RecordType>()) {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (CXXDestructorDecl *Destructor
+ = const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) {
+ MarkDeclarationReferenced(Field->getLocation(), Destructor);
+ CheckDestructorAccess(Field->getLocation(), Destructor,
+ PDiag(diag::err_access_dtor_ivar)
+ << Context.getBaseElementType(Field->getType()));
+ }
+ }
}
ObjCImplementation->setIvarInitializers(Context,
AllToInit.data(), AllToInit.size());
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index d446cc1..3b05f5a 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -142,8 +142,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
// 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())
+ if (T->isObjCObjectType()) {
+ if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface())
SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
}
}
@@ -210,8 +210,8 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
LookupOrdinaryName, ForRedeclaration);
if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) {
QualType T = TDecl->getUnderlyingType();
- if (T->isObjCInterfaceType()) {
- if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) {
+ if (T->isObjCObjectType()) {
+ if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
ClassName = IDecl->getIdentifier();
CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
LookupOrdinaryName, ForRedeclaration);
@@ -763,6 +763,10 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
<< (*IM)->getType();
Diag((*IF)->getLocation(), diag::note_previous_definition);
}
+ if (ImpMethodDecl->isVariadic() != IntfMethodDecl->isVariadic()) {
+ Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic);
+ Diag(IntfMethodDecl->getLocation(), diag::note_previous_declaration);
+ }
}
/// FIXME: Type hierarchies in Objective-C can be deep. We could most likely
@@ -925,7 +929,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
}
}
-void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
+void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool IncompleteImpl) {
llvm::DenseSet<Selector> InsMap;
@@ -938,8 +942,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
// Check and see if properties declared in the interface have either 1)
// an implementation or 2) there is a @synthesize/@dynamic implementation
// of the property in the @implementation.
- if (isa<ObjCInterfaceDecl>(CDecl))
- DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap);
+ if (isa<ObjCInterfaceDecl>(CDecl) && !LangOpts.ObjCNonFragileABI2)
+ DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
llvm::DenseSet<Selector> ClsMap;
for (ObjCImplementationDecl::classmeth_iterator
@@ -968,7 +972,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
for (ObjCCategoryDecl *Categories = I->getCategoryList();
Categories; Categories = Categories->getNextClassCategory()) {
if (Categories->IsClassExtension()) {
- ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl);
+ ImplMethodsVsClassMethods(S, IMPDecl, Categories, IncompleteImpl);
break;
}
}
@@ -990,7 +994,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I)
InsMap.insert((*I)->getSelector());
}
- DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap);
+ DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
}
} else
assert(false && "invalid ObjCContainerDecl type.");
@@ -1024,15 +1028,15 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
//
// FIXME: Make an extension?
TypedefDecl *TDD = dyn_cast<TypedefDecl>(PrevDecl);
- if (!TDD || !isa<ObjCInterfaceType>(TDD->getUnderlyingType())) {
+ if (!TDD || !TDD->getUnderlyingType()->isObjCObjectType()) {
Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i];
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- } else if (TDD) {
+ } else {
// 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();
+ if (const ObjCObjectType *OI =
+ TDD->getUnderlyingType()->getAs<ObjCObjectType>())
+ PrevDecl = OI->getInterface();
}
}
ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
@@ -1326,7 +1330,7 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
// Note: For class/category implemenations, allMethods/allProperties is
// always null.
-void Sema::ActOnAtEnd(SourceRange AtEnd,
+void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
DeclPtrTy classDecl,
DeclPtrTy *allMethods, unsigned allNum,
DeclPtrTy *allProperties, unsigned pNum,
@@ -1433,7 +1437,9 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
IC->setAtEndRange(AtEnd);
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) {
- ImplMethodsVsClassMethods(IC, IDecl);
+ if (LangOpts.ObjCNonFragileABI2)
+ DefaultSynthesizeProperties(S, IC, IDecl);
+ ImplMethodsVsClassMethods(S, IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
if (LangOpts.ObjCNonFragileABI2)
while (IDecl->getSuperClass()) {
@@ -1452,7 +1458,7 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
for (ObjCCategoryDecl *Categories = IDecl->getCategoryList();
Categories; Categories = Categories->getNextClassCategory()) {
if (Categories->getIdentifier() == CatImplClass->getIdentifier()) {
- ImplMethodsVsClassMethods(CatImplClass, Categories);
+ ImplMethodsVsClassMethods(S, CatImplClass, Categories);
break;
}
}
@@ -1530,7 +1536,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
// Methods cannot return interface types. All ObjC objects are
// passed by reference.
- if (resultDeclType->isObjCInterfaceType()) {
+ if (resultDeclType->isObjCObjectType()) {
Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value)
<< 0 << resultDeclType;
return DeclPtrTy();
@@ -1568,7 +1574,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
ArgInfo[i].Name, ArgType, DI,
VarDecl::None, VarDecl::None, 0);
- if (ArgType->isObjCInterfaceType()) {
+ if (ArgType->isObjCObjectType()) {
Diag(ArgInfo[i].NameLoc,
diag::err_object_cannot_be_passed_returned_by_value)
<< 1 << ArgType;
@@ -1592,7 +1598,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
else
// Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
ArgType = adjustParameterType(ArgType);
- if (ArgType->isObjCInterfaceType()) {
+ if (ArgType->isObjCObjectType()) {
Diag(Param->getLocation(),
diag::err_object_cannot_be_passed_returned_by_value)
<< 1 << ArgType;
@@ -1810,7 +1816,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI,
E = OI->ivar_end(); I != E; ++I) {
ObjCIvarDecl *Iv = (*I);
QualType QT = Context.getBaseElementType(Iv->getType());
- if (isa<RecordType>(QT))
+ if (QT->isRecordType())
Ivars.push_back(*I);
}
@@ -1820,7 +1826,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI,
E = CDecl->ivar_end(); I != E; ++I) {
ObjCIvarDecl *Iv = (*I);
QualType QT = Context.getBaseElementType(Iv->getType());
- if (isa<RecordType>(QT))
+ if (QT->isRecordType())
Ivars.push_back(*I);
}
}
@@ -1832,7 +1838,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI,
E = ImplDecl->ivar_end(); I != E; ++I) {
ObjCIvarDecl *Iv = (*I);
QualType QT = Context.getBaseElementType(Iv->getType());
- if (isa<RecordType>(QT))
+ if (QT->isRecordType())
Ivars.push_back(*I);
}
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 53e9385..7d73fe4 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -389,7 +389,7 @@ bool Sema::CheckExceptionSpecSubset(
if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
continue;
- if (Paths.isAmbiguous(CanonicalSuperT))
+ if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT)))
continue;
// Do this check from a context without privileges.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 869d6df..f745352 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -160,16 +161,19 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
++sentinel;
}
Expr *sentinelExpr = Args[sentinel];
- if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) &&
- !sentinelExpr->isTypeDependent() &&
- !sentinelExpr->isValueDependent() &&
- (!sentinelExpr->getType()->isPointerType() ||
- !sentinelExpr->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull)))) {
- Diag(Loc, diag::warn_missing_sentinel) << isMethod;
- Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
- }
- return;
+ if (!sentinelExpr) return;
+ if (sentinelExpr->isTypeDependent()) return;
+ if (sentinelExpr->isValueDependent()) return;
+ if (sentinelExpr->getType()->isPointerType() &&
+ sentinelExpr->IgnoreParenCasts()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull))
+ return;
+
+ // Unfortunately, __null has type 'int'.
+ if (isa<GNUNullExpr>(sentinelExpr)) return;
+
+ Diag(Loc, diag::warn_missing_sentinel) << isMethod;
+ Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
}
SourceRange Sema::getExprRange(ExprTy *E) const {
@@ -275,10 +279,9 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) {
assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type");
// If this is a 'float' (CVR qualified or typedef) promote to double.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
- if (BT->getKind() == BuiltinType::Float)
- return ImpCastExprToType(Expr, Context.DoubleTy,
- CastExpr::CK_FloatingCast);
+ if (Ty->isSpecificBuiltinType(BuiltinType::Float))
+ return ImpCastExprToType(Expr, Context.DoubleTy,
+ CastExpr::CK_FloatingCast);
UsualUnaryConversions(Expr);
}
@@ -287,10 +290,17 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) {
/// will warn if the resulting type is not a POD type, and rejects ObjC
/// interfaces passed by value. This returns true if the argument type is
/// completely illegal.
-bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
+bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT,
+ FunctionDecl *FDecl) {
DefaultArgumentPromotion(Expr);
- if (Expr->getType()->isObjCInterfaceType() &&
+ // __builtin_va_start takes the second argument as a "varargs" argument, but
+ // it doesn't actually do anything with it. It doesn't need to be non-pod
+ // etc.
+ if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start)
+ return false;
+
+ if (Expr->getType()->isObjCObjectType() &&
DiagRuntimeBehavior(Expr->getLocStart(),
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
<< Expr->getType() << CT))
@@ -486,35 +496,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc,
D, Loc, Ty));
}
-/// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or
-/// variable corresponding to the anonymous union or struct whose type
-/// is Record.
-static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context,
- RecordDecl *Record) {
- 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(),
- DEnd = Ctx->decls_end();
- D != DEnd; ++D) {
- if (*D == Record) {
- // The object for the anonymous struct/union directly
- // follows its type in the list of declarations.
- ++D;
- assert(D != DEnd && "Missing object for anonymous record");
- assert(!cast<NamedDecl>(*D)->getDeclName() && "Decl should be unnamed");
- return *D;
- }
- }
-
- assert(false && "Missing object for anonymous record");
- return 0;
-}
-
/// \brief Given a field that represents a member of an anonymous
/// struct/union, build the path from that field's context to the
/// actual member.
@@ -539,7 +520,7 @@ VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
DeclContext *Ctx = Field->getDeclContext();
do {
RecordDecl *Record = cast<RecordDecl>(Ctx);
- Decl *AnonObject = getObjectForAnonymousRecordDecl(Context, Record);
+ ValueDecl *AnonObject = Record->getAnonymousStructOrUnionObject();
if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject))
Path.push_back(AnonField);
else {
@@ -592,7 +573,8 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
// 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)) {
+ DeclContext *DC = getFunctionLevelDeclContext();
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
if (!MD->isStatic()) {
QualType AnonFieldType
= Context.getTagDeclType(
@@ -828,9 +810,10 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
const LookupResult &R) {
assert(!R.empty() && (*R.begin())->isCXXClassMember());
+ DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
bool isStaticContext =
- (!isa<CXXMethodDecl>(SemaRef.CurContext) ||
- cast<CXXMethodDecl>(SemaRef.CurContext)->isStatic());
+ (!isa<CXXMethodDecl>(DC) ||
+ cast<CXXMethodDecl>(DC)->isStatic());
if (R.isUnresolvableResult())
return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
@@ -870,7 +853,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
// declaring classes, it can't be an implicit member reference (in
// which case it's an error if any of those members are selected).
if (IsProvablyNotDerivedFrom(SemaRef,
- cast<CXXMethodDecl>(SemaRef.CurContext)->getParent(),
+ cast<CXXMethodDecl>(DC)->getParent(),
Classes))
return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
@@ -907,7 +890,7 @@ static void DiagnoseInstanceReference(Sema &SemaRef,
///
/// \return false if new lookup candidates were found
bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS,
- LookupResult &R) {
+ LookupResult &R, CorrectTypoContext CTC) {
DeclarationName Name = R.getLookupName();
unsigned diagnostic = diag::err_undeclared_var_use;
@@ -958,7 +941,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS,
// We didn't find anything, so try to correct for a typo.
DeclarationName Corrected;
- if (S && (Corrected = CorrectTypo(R, S, &SS))) {
+ if (S && (Corrected = CorrectTypo(R, S, &SS, false, CTC))) {
if (!R.empty()) {
if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
if (SS.isEmpty())
@@ -1067,17 +1050,14 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// Perform the required lookup.
LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
if (TemplateArgs) {
- // Just re-use the lookup done by isTemplateName.
- DecomposeTemplateName(R, Id);
-
- // Re-derive the naming class.
- if (SS.isSet()) {
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- if (const Type *Ty = Qualifier->getAsType())
- if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl())
- R.setNamingClass(NamingClass);
- }
+ // Lookup the template name again to correctly establish the context in
+ // which it was found. This is really unfortunate as we already did the
+ // lookup to determine that it was a template name in the first place. If
+ // this becomes a performance hit, we can work harder to preserve those
+ // results until we get here but it's likely not worth it.
+ bool MemberOfUnknownSpecialization;
+ LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
+ MemberOfUnknownSpecialization);
} else {
bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl());
LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
@@ -1112,7 +1092,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// If this name wasn't predeclared and if this is not a function
// call, diagnose the problem.
if (R.empty()) {
- if (DiagnoseEmptyLookup(S, SS, R))
+ if (DiagnoseEmptyLookup(S, SS, R, CTC_Unknown))
return ExprError();
assert(!R.empty() &&
@@ -1166,7 +1146,8 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
QualType T = Func->getType();
QualType NoProtoType = T;
if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>())
- NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
+ NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType(),
+ Proto->getExtInfo());
return BuildDeclRefExpr(Func, NoProtoType, NameLoc, &SS);
}
}
@@ -1423,6 +1404,9 @@ Sema::PerformObjectMemberConversion(Expr *&From,
SourceRange FromRange = From->getSourceRange();
SourceLocation FromLoc = FromRange.getBegin();
+ bool isLvalue
+ = (From->isLvalue(Context) == Expr::LV_Valid) && !PointerConversions;
+
// C++ [class.member.lookup]p8:
// [...] Ambiguities can often be resolved by qualifying a name with its
// class name.
@@ -1460,7 +1444,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
if (PointerConversions)
QType = Context.getPointerType(QType);
ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue=*/!PointerConversions, BasePath);
+ isLvalue, BasePath);
FromType = QType;
FromRecordType = QRecordType;
@@ -1497,7 +1481,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
if (PointerConversions)
UType = Context.getPointerType(UType);
ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue=*/!PointerConversions, BasePath);
+ isLvalue, BasePath);
FromType = UType;
FromRecordType = URecordType;
}
@@ -1514,7 +1498,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
return true;
ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue=*/!PointerConversions, BasePath);
+ isLvalue, BasePath);
return false;
}
@@ -1558,7 +1542,8 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
// If this is known to be an instance access, go ahead and build a
// 'this' expression now.
- QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context);
+ DeclContext *DC = getFunctionLevelDeclContext();
+ QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context);
Expr *This = 0; // null signifies implicit access
if (IsKnownInstance) {
SourceLocation Loc = R.getNameLoc();
@@ -1682,8 +1667,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
(NestedNameSpecifier*) SS.getScopeRep(),
SS.getRange(),
R.getLookupName(), R.getNameLoc(),
- NeedsADL, R.isOverloadedResult());
- ULE->addDecls(R.begin(), R.end());
+ NeedsADL, R.isOverloadedResult(),
+ R.begin(), R.end());
return Owned(ULE);
}
@@ -2036,12 +2021,18 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
return true;
// Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
- if (LangOpts.ObjCNonFragileABI && exprType->isObjCInterfaceType()) {
+ if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) {
Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
<< exprType << isSizeof << ExprRange;
return true;
}
+ if (Context.hasSameUnqualifiedType(exprType, Context.OverloadTy)) {
+ Diag(OpLoc, diag::err_sizeof_alignof_overloaded_function_type)
+ << !isSizeof << ExprRange;
+ return true;
+ }
+
return false;
}
@@ -2312,7 +2303,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc,
return ExprError();
// Diagnose bad cases where we step over interface counts.
- if (ResultType->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ if (ResultType->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(LLoc, diag::err_subscript_nonfragile_interface)
<< ResultType << BaseExpr->getSourceRange();
return ExprError();
@@ -2665,6 +2656,9 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
if (Result.get())
return move(Result);
+
+ // LookupMemberExpr can modify Base, and thus change BaseType
+ BaseType = Base->getType();
}
return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType,
@@ -2741,8 +2735,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
IsArrow, OpLoc,
Qualifier, SS.getRange(),
MemberName, MemberLoc,
- TemplateArgs);
- MemExpr->addDecls(R.begin(), R.end());
+ TemplateArgs, R.begin(), R.end());
return Owned(MemExpr);
}
@@ -2917,7 +2910,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Handle the following exceptional case PObj->isa.
if (const ObjCObjectPointerType *OPT =
BaseType->getAs<ObjCObjectPointerType>()) {
- if (OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) &&
+ if (OPT->getObjectType()->isObjCId() &&
MemberName.getAsIdentifierInfo()->isStr("isa"))
return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc,
Context.getObjCClassType()));
@@ -3041,8 +3034,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
}
}
- // Handle field access to simple records. This also handles access
- // to fields of the ObjC 'id' struct.
+ // Handle field access to simple records.
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(),
RTy, OpLoc, SS))
@@ -3053,14 +3045,14 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
// (*Obj).ivar.
if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
- (!IsArrow && BaseType->isObjCInterfaceType())) {
+ (!IsArrow && BaseType->isObjCObjectType())) {
const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>();
- const ObjCInterfaceType *IFaceT =
- OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>();
- if (IFaceT) {
+ ObjCInterfaceDecl *IDecl =
+ OPT ? OPT->getInterfaceDecl()
+ : BaseType->getAs<ObjCObjectType>()->getInterface();
+ if (IDecl) {
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
ObjCInterfaceDecl *ClassDeclared;
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
@@ -3173,7 +3165,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Handle the following exceptional case (*Obj).isa.
if (!IsArrow &&
- BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) &&
+ BaseType->isObjCObjectType() &&
+ BaseType->getAs<ObjCObjectType>()->isObjCId() &&
MemberName.getAsIdentifierInfo()->isStr("isa"))
return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc,
Context.getObjCClassType()));
@@ -3471,9 +3464,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
// If this is a variadic call, handle args passed through "...".
if (CallType != VariadicDoesNotApply) {
// Promote the arguments (C99 6.5.2.2p7).
- for (unsigned i = ArgIx; i < NumArgs; i++) {
+ for (unsigned i = ArgIx; i != NumArgs; ++i) {
Expr *Arg = Args[i];
- Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType);
+ Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType, FDecl);
AllArgs.push_back(Arg);
}
}
@@ -4081,8 +4074,6 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (getLangOptions().CPlusPlus)
return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc);
- CheckSignCompare(LHS, RHS, QuestionLoc);
-
UsualUnaryConversions(Cond);
UsualUnaryConversions(LHS);
UsualUnaryConversions(RHS);
@@ -4659,7 +4650,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
return Incompatible;
}
- if (lhsType->isArithmeticType() && rhsType->isArithmeticType())
+ if (lhsType->isArithmeticType() && rhsType->isArithmeticType() &&
+ !(getLangOptions().CPlusPlus && lhsType->isEnumeralType()))
return Compatible;
if (isa<PointerType>(lhsType)) {
@@ -4917,7 +4909,13 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
if (const VectorType *RV = rhsType->getAs<VectorType>())
if (LV->getElementType() == RV->getElementType() &&
LV->getNumElements() == RV->getNumElements()) {
- return lhsType->isExtVectorType() ? lhsType : rhsType;
+ if (lhsType->isExtVectorType()) {
+ ImpCastExprToType(rex, lhsType, CastExpr::CK_BitCast);
+ return lhsType;
+ }
+
+ ImpCastExprToType(lex, rhsType, CastExpr::CK_BitCast);
+ return rhsType;
}
}
}
@@ -5059,7 +5057,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
return QualType();
}
// Diagnose bad cases where we step over interface counts.
- if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
<< PointeeTy << PExp->getSourceRange();
return QualType();
@@ -5135,7 +5133,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
return QualType();
// Diagnose bad cases where we step over interface counts.
- if (lpointee->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
<< lpointee << lex->getSourceRange();
return QualType();
@@ -5274,8 +5272,6 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
- CheckSignCompare(lex, rex, Loc, &Opc);
-
// C99 6.5.8p3 / C99 6.5.9p4
if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
UsualArithmeticConversions(lex, rex);
@@ -5904,7 +5900,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
<< ResType))
return QualType();
// Diagnose bad cases where we step over interface counts.
- else if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ else if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
<< PointeeTy << Op->getSourceRange();
return QualType();
@@ -6626,7 +6622,7 @@ Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
SourceLocation RParenLoc) {
QualType ArgTy = TInfo->getType();
bool Dependent = ArgTy->isDependentType();
- SourceRange TypeRange = TInfo->getTypeLoc().getSourceRange();
+ SourceRange TypeRange = TInfo->getTypeLoc().getLocalSourceRange();
// We must have at least one component that refers to the type, and the first
// one is known to be a field designator. Verify that the ArgTy represents
@@ -7018,7 +7014,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
QualType RetTy = T.getTypePtr()->getAs<FunctionType>()->getResultType();
// Do not allow returning a objc interface by-value.
- if (RetTy->isObjCInterfaceType()) {
+ if (RetTy->isObjCObjectType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
return;
@@ -7090,7 +7086,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
QualType RetTy = T->getAs<FunctionType>()->getResultType();
// Do not allow returning a objc interface by-value.
- if (RetTy->isObjCInterfaceType()) {
+ if (RetTy->isObjCObjectType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
} else if (!RetTy->isDependentType())
@@ -7500,22 +7496,24 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
}
- MaybeMarkVirtualMembersReferenced(Loc, Constructor);
+ MarkVTableUsed(Loc, Constructor->getParent());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
if (Destructor->isImplicit() && !Destructor->isUsed())
DefineImplicitDestructor(Loc, Destructor);
-
+ if (Destructor->isVirtual())
+ MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
if (!MethodDecl->isUsed())
DefineImplicitCopyAssignment(Loc, MethodDecl);
- }
+ } else if (MethodDecl->isVirtual())
+ MarkVTableUsed(Loc, MethodDecl->getParent());
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
// Implicit instantiation of function templates and member functions of
// class templates.
- if (!Function->getBody() && Function->isImplicitlyInstantiable()) {
+ if (Function->isImplicitlyInstantiable()) {
bool AlreadyInstantiated = false;
if (FunctionTemplateSpecializationInfo *SpecInfo
= Function->getTemplateSpecializationInfo()) {
@@ -7570,6 +7568,48 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
}
}
+namespace {
+ // Mark all of the declarations referenced
+ // FIXME: Not fully implemented yet! We need to have a better understanding
+ // of when we're entering
+ class MarkReferencedDecls : public RecursiveASTVisitor<MarkReferencedDecls> {
+ Sema &S;
+ SourceLocation Loc;
+
+ public:
+ typedef RecursiveASTVisitor<MarkReferencedDecls> Inherited;
+
+ MarkReferencedDecls(Sema &S, SourceLocation Loc) : S(S), Loc(Loc) { }
+
+ bool VisitTemplateArgument(const TemplateArgument &Arg);
+ bool VisitRecordType(RecordType *T);
+ };
+}
+
+bool MarkReferencedDecls::VisitTemplateArgument(const TemplateArgument &Arg) {
+ if (Arg.getKind() == TemplateArgument::Declaration) {
+ S.MarkDeclarationReferenced(Loc, Arg.getAsDecl());
+ }
+
+ return Inherited::VisitTemplateArgument(Arg);
+}
+
+bool MarkReferencedDecls::VisitRecordType(RecordType *T) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) {
+ const TemplateArgumentList &Args = Spec->getTemplateArgs();
+ return VisitTemplateArguments(Args.getFlatArgumentList(),
+ Args.flat_size());
+ }
+
+ return false;
+}
+
+void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) {
+ MarkReferencedDecls Marker(*this, Loc);
+ Marker.Visit(Context.getCanonicalType(T));
+}
+
/// \brief Emit a diagnostic that describes an effect on the run-time behavior
/// of the program being compiled.
///
@@ -7698,3 +7738,17 @@ bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
return false;
}
+
+Sema::OwningExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc,
+ ExprArg SubExpr) {
+ Expr *Sub = SubExpr.takeAs<Expr>();
+ if (!Sub)
+ return ExprError();
+
+ if (CheckBooleanCondition(Sub, Loc)) {
+ Sub->Destroy(Context);
+ return ExprError();
+ }
+
+ return Owned(Sub);
+}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 425fc2d..97de96a 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -261,7 +261,8 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
Range = SourceRange(NameLoc);
}
- return CheckTypenameType(ETK_None, NNS, II, Range).getAsOpaquePtr();
+ return CheckTypenameType(ETK_None, NNS, II, SourceLocation(),
+ Range, NameLoc).getAsOpaquePtr();
}
if (ObjectTypePtr)
@@ -314,8 +315,12 @@ Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
// When typeid is applied to an expression other than an lvalue of a
// polymorphic class type [...] [the] expression is an unevaluated
// operand. [...]
- if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid)
+ if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) {
isUnevaluatedOperand = false;
+
+ // We require a vtable to query the type at run time.
+ MarkVTableUsed(TypeidLoc, RecordD);
+ }
}
// C++ [expr.typeid]p4:
@@ -437,14 +442,22 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
// Initialize the exception result. This implicitly weeds out
// abstract types or types with inaccessible copy constructors.
+ // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p34.
InitializedEntity Entity =
- InitializedEntity::InitializeException(ThrowLoc, E->getType());
+ InitializedEntity::InitializeException(ThrowLoc, E->getType(),
+ /*NRVO=*/false);
OwningExprResult Res = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(E));
if (Res.isInvalid())
return true;
E = Res.takeAs<Expr>();
+
+ // If we are throwing a polymorphic class type or pointer thereof,
+ // exception handling will make use of the vtable.
+ if (const RecordType *RecordTy = Ty->getAs<RecordType>())
+ MarkVTableUsed(ThrowLoc, cast<CXXRecordDecl>(RecordTy->getDecl()));
+
return false;
}
@@ -453,10 +466,8 @@ Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) {
/// is a non-lvalue expression whose value is the address of the object for
/// which the function is called.
- if (!isa<FunctionDecl>(CurContext))
- return ExprError(Diag(ThisLoc, diag::err_invalid_this_use));
-
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext))
+ DeclContext *DC = getFunctionLevelDeclContext();
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
if (MD->isInstance())
return Owned(new (Context) CXXThisExpr(ThisLoc,
MD->getThisType(Context),
@@ -668,10 +679,19 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeLoc, TypeRange))
return ExprError();
- QualType ResultType = Context.getPointerType(AllocType);
+ // Per C++0x [expr.new]p5, the type being constructed may be a
+ // typedef of an array type.
+ if (!ArraySizeE.get()) {
+ if (const ConstantArrayType *Array
+ = Context.getAsConstantArrayType(AllocType)) {
+ ArraySizeE = Owned(new (Context) IntegerLiteral(Array->getSize(),
+ Context.getSizeType(),
+ TypeRange.getEnd()));
+ AllocType = Array->getElementType();
+ }
+ }
- // That every array dimension except the first is constant was already
- // checked by the type check above.
+ QualType ResultType = Context.getPointerType(AllocType);
// C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
// or enumeration type with a non-negative value."
@@ -739,7 +759,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
// Array 'new' can't have any initializers.
- if (NumConsArgs && ArraySize) {
+ if (NumConsArgs && (ResultType->isArrayType() || ArraySize)) {
SourceRange InitRange(ConsArgs[0]->getLocStart(),
ConsArgs[NumConsArgs - 1]->getLocEnd());
@@ -1173,7 +1193,7 @@ void Sema::DeclareGlobalNewDelete() {
if (!StdBadAlloc) {
// The "std::bad_alloc" class has not yet been declared, so build it
// implicitly.
- StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class,
+ StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class,
StdNamespace,
SourceLocation(),
&PP.getIdentifierTable().get("bad_alloc"),
@@ -1378,7 +1398,13 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
<< Type << Ex->getSourceRange());
QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
- if (Pointee->isFunctionType() || Pointee->isVoidType())
+ if (Pointee->isVoidType() && !isSFINAEContext()) {
+ // The C++ standard bans deleting a pointer to a non-object type, which
+ // effectively bans deletion of "void*". However, most compilers support
+ // this, so we treat it as a warning unless we're in a SFINAE context.
+ Diag(StartLoc, diag::ext_delete_void_ptr_operand)
+ << Type << Ex->getSourceRange();
+ } else if (Pointee->isFunctionType() || Pointee->isVoidType())
return ExprError(Diag(StartLoc, diag::err_delete_operand)
<< Type << Ex->getSourceRange());
else if (!Pointee->isDependentType() &&
@@ -1437,7 +1463,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
/// \brief Check the use of the given variable as a C++ condition in an if,
/// while, do-while, or switch statement.
-Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) {
+Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
+ SourceLocation StmtLoc,
+ bool ConvertToBoolean) {
QualType T = ConditionVar->getType();
// C++ [stmt.select]p2:
@@ -1451,9 +1479,15 @@ Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) {
diag::err_invalid_use_of_array_type)
<< ConditionVar->getSourceRange());
- return Owned(DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar,
- ConditionVar->getLocation(),
- ConditionVar->getType().getNonReferenceType()));
+ Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar,
+ ConditionVar->getLocation(),
+ ConditionVar->getType().getNonReferenceType());
+ if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) {
+ Condition->Destroy(Context);
+ return ExprError();
+ }
+
+ return Owned(Condition);
}
/// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
@@ -1748,10 +1782,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
ImpCastExprToType(From, ToType, CastExpr::CK_FloatingToIntegral);
break;
- case ICK_Complex_Real:
- ImpCastExprToType(From, ToType, CastExpr::CK_Unknown);
- break;
-
case ICK_Compatible_Conversion:
ImpCastExprToType(From, ToType, CastExpr::CK_NoOp);
break;
@@ -1794,18 +1824,41 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break;
}
- case ICK_Derived_To_Base:
+ case ICK_Derived_To_Base: {
+ CXXBaseSpecifierArray BasePath;
if (CheckDerivedToBaseConversion(From->getType(),
ToType.getNonReferenceType(),
From->getLocStart(),
- From->getSourceRange(), 0,
+ From->getSourceRange(),
+ &BasePath,
IgnoreBaseAccess))
return true;
+
ImpCastExprToType(From, ToType.getNonReferenceType(),
- CastExpr::CK_DerivedToBase);
+ CastExpr::CK_DerivedToBase,
+ /*isLvalue=*/(From->getType()->isRecordType() &&
+ From->isLvalue(Context) == Expr::LV_Valid),
+ BasePath);
+ break;
+ }
+
+ case ICK_Vector_Conversion:
+ ImpCastExprToType(From, ToType, CastExpr::CK_BitCast);
+ break;
+
+ case ICK_Vector_Splat:
+ ImpCastExprToType(From, ToType, CastExpr::CK_VectorSplat);
break;
- default:
+ case ICK_Complex_Real:
+ ImpCastExprToType(From, ToType, CastExpr::CK_Unknown);
+ break;
+
+ case ICK_Lvalue_To_Rvalue:
+ case ICK_Array_To_Pointer:
+ case ICK_Function_To_Pointer:
+ case ICK_Qualification:
+ case ICK_Num_Conversion_Kinds:
assert(false && "Improper second standard conversion");
break;
}
@@ -1828,7 +1881,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break;
default:
- assert(false && "Improper second standard conversion");
+ assert(false && "Improper third standard conversion");
break;
}
@@ -2113,8 +2166,6 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (LHS->isTypeDependent() || RHS->isTypeDependent())
return Context.DependentTy;
- CheckSignCompare(LHS, RHS, QuestionLoc);
-
// C++0x 5.16p2
// If either the second or the third operand has type (cv) void, ...
QualType LTy = LHS->getType();
@@ -2218,9 +2269,36 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// After those conversions, one of the following shall hold:
// -- The second and third operands have the same type; the result
- // is of that type.
- if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy))
+ // is of that type. If the operands have class type, the result
+ // is a prvalue temporary of the result type, which is
+ // copy-initialized from either the second operand or the third
+ // operand depending on the value of the first operand.
+ if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) {
+ if (LTy->isRecordType()) {
+ // The operands have class type. Make a temporary copy.
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy);
+ OwningExprResult LHSCopy = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(LHS));
+ if (LHSCopy.isInvalid())
+ return QualType();
+
+ OwningExprResult RHSCopy = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(RHS));
+ if (RHSCopy.isInvalid())
+ return QualType();
+
+ LHS = LHSCopy.takeAs<Expr>();
+ RHS = RHSCopy.takeAs<Expr>();
+ }
+
return LTy;
+ }
+
+ // Extension: conditional operator involving vector types.
+ if (LTy->isVectorType() || RTy->isVectorType())
+ return CheckVectorOperands(QuestionLoc, LHS, RHS);
// -- The second and third operands have arithmetic or enumeration type;
// the usual arithmetic conversions are performed to bring them to a
@@ -2529,6 +2607,9 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr) {
assert(SubExpr && "sub expression can't be null!");
+ // Check any implicit conversions within the expression.
+ CheckImplicitConversions(SubExpr);
+
unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
assert(ExprTemporaries.size() >= FirstTemporary);
if (ExprTemporaries.size() == FirstTemporary)
@@ -2713,12 +2794,12 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
if (DestructedTypeInfo) {
QualType DestructedType = DestructedTypeInfo->getType();
SourceLocation DestructedTypeStart
- = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin();
+ = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
<< ObjectType << DestructedType << BaseE->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getSourceRange();
+ << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
// Recover by setting the destructed type to the object type.
DestructedType = ObjectType;
@@ -2740,10 +2821,10 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
if (!ScopeType->isDependentType() && !ObjectType->isDependentType() &&
!Context.hasSameType(ScopeType, ObjectType)) {
- Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(),
+ Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(),
diag::err_pseudo_dtor_type_mismatch)
<< ObjectType << ScopeType << BaseE->getSourceRange()
- << ScopeTypeInfo->getTypeLoc().getSourceRange();
+ << ScopeTypeInfo->getTypeLoc().getLocalSourceRange();
ScopeType = QualType();
ScopeTypeInfo = 0;
@@ -2943,6 +3024,8 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
Expr *FullExpr = Arg.takeAs<Expr>();
if (FullExpr)
FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr);
-
+ else
+ return ExprError();
+
return Owned(FullExpr);
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index db9a2e2..695a1be 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -254,7 +254,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
if (Args[i]->isTypeDependent())
continue;
- IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod);
+ IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0);
}
} else {
// Check for extra arguments to non-variadic methods.
@@ -718,14 +718,12 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
}
SourceLocation Loc = SuperLoc.isValid()? SuperLoc
- : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin();
+ : ReceiverTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
// Find the class to which we are sending this message.
ObjCInterfaceDecl *Class = 0;
- if (const ObjCInterfaceType *ClassType
- = ReceiverType->getAs<ObjCInterfaceType>())
- Class = ClassType->getDecl();
- else {
+ const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>();
+ if (!ClassType || !(Class = ClassType->getInterface())) {
Diag(Loc, diag::err_invalid_receiver_class_message)
<< ReceiverType;
return ExprError();
@@ -766,15 +764,17 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
}
// Construct the appropriate ObjCMessageExpr.
+ Expr *Result;
if (SuperLoc.isValid())
- return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
- SuperLoc, /*IsInstanceSuper=*/false,
- ReceiverType, Sel, Method, Args,
- NumArgs, RBracLoc));
-
- return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
- ReceiverTypeInfo, Sel, Method, Args,
- NumArgs, RBracLoc));
+ Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ SuperLoc, /*IsInstanceSuper=*/false,
+ ReceiverType, Sel, Method, Args,
+ NumArgs, RBracLoc);
+ else
+ Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ ReceiverTypeInfo, Sel, Method, Args,
+ NumArgs, RBracLoc);
+ return MaybeBindToTemporary(Result);
}
// ActOnClassMessage - used for both unary and keyword messages.
@@ -976,6 +976,21 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE,
ImpCastExprToType(Receiver, Context.getObjCIdType(),
CastExpr::CK_IntegralToPointer);
ReceiverType = Receiver->getType();
+ }
+ else if (getLangOptions().CPlusPlus &&
+ !PerformContextuallyConvertToObjCId(Receiver)) {
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) {
+ Receiver = ICE->getSubExpr();
+ ReceiverType = Receiver->getType();
+ }
+ return BuildInstanceMessage(Owned(Receiver),
+ ReceiverType,
+ SuperLoc,
+ Sel,
+ Method,
+ LBracLoc,
+ RBracLoc,
+ move(ArgsIn));
} else {
// Reject other random receiver types (e.g. structs).
Diag(Loc, diag::err_bad_receiver_type)
@@ -994,14 +1009,16 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE,
return ExprError();
// Construct the appropriate ObjCMessageExpr instance.
+ Expr *Result;
if (SuperLoc.isValid())
- return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
- SuperLoc, /*IsInstanceSuper=*/true,
- ReceiverType, Sel, Method,
- Args, NumArgs, RBracLoc));
-
- return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver,
- Sel, Method, Args, NumArgs, RBracLoc));
+ Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ SuperLoc, /*IsInstanceSuper=*/true,
+ ReceiverType, Sel, Method,
+ Args, NumArgs, RBracLoc);
+ else
+ Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver,
+ Sel, Method, Args, NumArgs, RBracLoc);
+ return MaybeBindToTemporary(Result);
}
// ActOnInstanceMessage - used for both unary and keyword messages.
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 0aa3446..20f0c79 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -624,7 +624,7 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isReferenceType()) {
CheckReferenceType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
- } else if (DeclType->isObjCInterfaceType()) {
+ } else if (DeclType->isObjCObjectType()) {
SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class)
<< DeclType;
hadError = true;
@@ -1984,6 +1984,26 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
return 0;
}
+bool InitializedEntity::allowsNRVO() const {
+ switch (getKind()) {
+ case EK_Result:
+ case EK_Exception:
+ return LocAndNRVO.NRVO;
+
+ case EK_Variable:
+ case EK_Parameter:
+ case EK_Member:
+ case EK_New:
+ case EK_Temporary:
+ case EK_Base:
+ case EK_ArrayElement:
+ case EK_VectorElement:
+ break;
+ }
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Initialization sequence
//===----------------------------------------------------------------------===//
@@ -2034,6 +2054,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_ReferenceBindingToInitList:
case FK_InitListBadDestinationType:
case FK_DefaultInitOfConst:
+ case FK_Incomplete:
return false;
case FK_ReferenceInitOverloadFailed:
@@ -2245,11 +2266,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct;
const RecordType *T1RecordType = 0;
- if (AllowRValues && (T1RecordType = T1->getAs<RecordType>())) {
+ if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
+ !S.RequireCompleteType(Kind.getLocation(), T1, 0)) {
// The type we're converting to is a class type. Enumerate its constructors
// to see if there is a suitable conversion.
CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl());
-
DeclarationName ConstructorName
= S.Context.DeclarationNames.getCXXConstructorName(
S.Context.getCanonicalType(T1).getUnqualifiedType());
@@ -2281,7 +2302,9 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
}
}
- if (const RecordType *T2RecordType = T2->getAs<RecordType>()) {
+ const RecordType *T2RecordType = 0;
+ if ((T2RecordType = T2->getAs<RecordType>()) &&
+ !S.RequireCompleteType(Kind.getLocation(), T2, 0)) {
// The type we're converting from is a class type, enumerate its conversion
// functions.
CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl());
@@ -2627,7 +2650,7 @@ static void TryConstructorInitialization(Sema &S,
// The type we're constructing needs to be complete.
if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
- Sequence.SetFailed(InitializationSequence::FK_ConversionFailed);
+ Sequence.SetFailed(InitializationSequence::FK_Incomplete);
return;
}
@@ -2740,8 +2763,8 @@ static void TryValueInitialization(Sema &S,
// without a user-provided constructor, then the object is
// zero-initialized and, if T’s implicitly-declared default
// constructor is non-trivial, that constructor is called.
- if ((ClassDecl->getTagKind() == TagDecl::TK_class ||
- ClassDecl->getTagKind() == TagDecl::TK_struct) &&
+ if ((ClassDecl->getTagKind() == TTK_Class ||
+ ClassDecl->getTagKind() == TTK_Struct) &&
!ClassDecl->hasTrivialConstructor()) {
Sequence.AddZeroInitializationStep(Entity.getType());
return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
@@ -3240,9 +3263,9 @@ static Sema::OwningExprResult CopyObject(Sema &S,
// directly into the target of the omitted copy/move
//
// Note that the other three bullets are handled elsewhere. Copy
- // elision for return statements and throw expressions are (FIXME:
- // not yet) handled as part of constructor initialization, while
- // copy elision for exception handlers is handled by the run-time.
+ // elision for return statements and throw expressions are handled as part
+ // of constructor initialization, while copy elision for exception handlers
+ // is handled by the run-time.
bool Elidable = CurInitExpr->isTemporaryObject() &&
S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType());
SourceLocation Loc;
@@ -3517,6 +3540,7 @@ InitializationSequence::Perform(Sema &S,
// Overload resolution determined which function invoke; update the
// initializer to reflect that choice.
S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl);
+ S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation());
CurInit = S.FixOverloadedFunctionReference(move(CurInit),
Step->Function.FoundDecl,
Step->Function.Function);
@@ -3537,6 +3561,15 @@ InitializationSequence::Perform(Sema &S,
&BasePath, IgnoreBaseAccess))
return S.ExprError();
+ if (S.BasePathInvolvesVirtualBase(BasePath)) {
+ QualType T = SourceType;
+ if (const PointerType *Pointer = T->getAs<PointerType>())
+ T = Pointer->getPointeeType();
+ if (const RecordType *RecordTy = T->getAs<RecordType>())
+ S.MarkVTableUsed(CurInitExpr->getLocStart(),
+ cast<CXXRecordDecl>(RecordTy->getDecl()));
+ }
+
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type,
CastExpr::CK_DerivedToBase,
(Expr*)CurInit.release(),
@@ -3619,6 +3652,7 @@ InitializationSequence::Perform(Sema &S,
S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity,
FoundFn.getAccess());
+ S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation());
CastKind = CastExpr::CK_ConstructorConversion;
QualType Class = S.Context.getTypeDeclType(Constructor->getParent());
@@ -3633,6 +3667,7 @@ InitializationSequence::Perform(Sema &S,
IsLvalue = Conversion->getResultType()->isLValueReferenceType();
S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0,
FoundFn);
+ S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation());
// FIXME: Should we move this initialization into a separate
// derived-to-base conversion? I believe the answer is "no", because
@@ -3723,7 +3758,7 @@ InitializationSequence::Perform(Sema &S,
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step->Function.Function);
-
+
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
SourceLocation Loc = Kind.getLocation();
@@ -3760,11 +3795,21 @@ InitializationSequence::Perform(Sema &S,
CXXConstructExpr::CK_VirtualBase :
CXXConstructExpr::CK_NonVirtualBase;
}
- CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
- Constructor,
- move_arg(ConstructorArgs),
- ConstructorInitRequiresZeroInit,
- ConstructKind);
+
+ // If the entity allows NRVO, mark the construction as elidable
+ // unconditionally.
+ if (Entity.allowsNRVO())
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor, /*Elidable=*/true,
+ move_arg(ConstructorArgs),
+ ConstructorInitRequiresZeroInit,
+ ConstructKind);
+ else
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor,
+ move_arg(ConstructorArgs),
+ ConstructorInitRequiresZeroInit,
+ ConstructKind);
}
if (CurInit.isInvalid())
return S.ExprError();
@@ -3772,6 +3817,7 @@ InitializationSequence::Perform(Sema &S,
// Only check access if all of that succeeded.
S.CheckConstructorAccess(Loc, Constructor, Entity,
Step->Function.FoundDecl.getAccess());
+ S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Loc);
if (shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
@@ -4092,6 +4138,11 @@ bool InitializationSequence::Diagnose(Sema &S,
<< DestType << (bool)DestType->getAs<RecordType>();
}
break;
+
+ case FK_Incomplete:
+ S.RequireCompleteType(Kind.getLocation(), DestType,
+ diag::err_init_incomplete_type);
+ break;
}
PrintInitLocationNote(S, Entity);
@@ -4170,6 +4221,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
case FK_DefaultInitOfConst:
OS << "default initialization of a const variable";
break;
+
+ case FK_Incomplete:
+ OS << "initialization of incomplete type";
+ break;
}
OS << '\n';
return;
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 5f2592f..a9064ed 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -85,11 +85,16 @@ private:
/// the VarDecl, ParmVarDecl, or FieldDecl, respectively.
DeclaratorDecl *VariableOrMember;
- /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the
- /// location of the 'return', 'throw', or 'new' keyword,
- /// respectively. When Kind == EK_Temporary, the location where
- /// the temporary is being created.
- unsigned Location;
+ struct {
+ /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the
+ /// location of the 'return', 'throw', or 'new' keyword,
+ /// respectively. When Kind == EK_Temporary, the location where
+ /// the temporary is being created.
+ unsigned Location;
+
+ /// \brief Whether the
+ bool NRVO;
+ } LocAndNRVO;
/// \brief When Kind == EK_Base, the base specifier that provides the
/// base class. The lower bit specifies whether the base is an inherited
@@ -116,8 +121,13 @@ private:
/// \brief Create the initialization entity for the result of a
/// function, throwing an object, performing an explicit cast, or
/// initializing a parameter for which there is no declaration.
- InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type)
- : Kind(Kind), Parent(0), Type(Type), Location(Loc.getRawEncoding()) { }
+ InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type,
+ bool NRVO = false)
+ : Kind(Kind), Parent(0), Type(Type)
+ {
+ LocAndNRVO.Location = Loc.getRawEncoding();
+ LocAndNRVO.NRVO = NRVO;
+ }
/// \brief Create the initialization entity for a member subobject.
InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent)
@@ -152,14 +162,14 @@ public:
/// \brief Create the initialization entity for the result of a function.
static InitializedEntity InitializeResult(SourceLocation ReturnLoc,
- QualType Type) {
- return InitializedEntity(EK_Result, ReturnLoc, Type);
+ QualType Type, bool NRVO) {
+ return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO);
}
/// \brief Create the initialization entity for an exception object.
static InitializedEntity InitializeException(SourceLocation ThrowLoc,
- QualType Type) {
- return InitializedEntity(EK_Exception, ThrowLoc, Type);
+ QualType Type, bool NRVO) {
+ return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO);
}
/// \brief Create the initialization entity for an object allocated via new.
@@ -208,6 +218,10 @@ public:
/// initialized.
DeclaratorDecl *getDecl() const;
+ /// \brief Determine whether this initialization allows the named return
+ /// value optimization, which also applies to thrown objects.
+ bool allowsNRVO() const;
+
/// \brief Retrieve the base specifier.
CXXBaseSpecifier *getBaseSpecifier() const {
assert(getKind() == EK_Base && "Not a base specifier");
@@ -224,14 +238,14 @@ public:
/// the result of a function call.
SourceLocation getReturnLoc() const {
assert(getKind() == EK_Result && "No 'return' location!");
- return SourceLocation::getFromRawEncoding(Location);
+ return SourceLocation::getFromRawEncoding(LocAndNRVO.Location);
}
/// \brief Determine the location of the 'throw' keyword when initializing
/// an exception object.
SourceLocation getThrowLoc() const {
assert(getKind() == EK_Exception && "No 'throw' location!");
- return SourceLocation::getFromRawEncoding(Location);
+ return SourceLocation::getFromRawEncoding(LocAndNRVO.Location);
}
/// \brief If this is already the initializer for an array or vector
@@ -530,7 +544,9 @@ public:
/// \brief Overloaded for initialization by constructor failed.
FK_ConstructorOverloadFailed,
/// \brief Default-initialization of a 'const' object.
- FK_DefaultInitOfConst
+ FK_DefaultInitOfConst,
+ /// \brief Initialization of an incomplete type.
+ FK_Incomplete
};
private:
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 337a4a3..4555a86 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -665,6 +665,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
//
DeclContext *OutsideOfTemplateParamDC = 0;
for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
+ DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
@@ -675,10 +677,12 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
}
if (Found) {
R.resolveKind();
+ if (S->isClassScope())
+ if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(Ctx))
+ R.setNamingClass(Record);
return true;
}
- DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
S->getParent() && !S->getParent()->isTemplateParamScope()) {
// We've just searched the last template parameter scope and
@@ -761,10 +765,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// context as well as walking through the scopes.
for (; S; S = S->getParent()) {
- DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
- if (Ctx && Ctx->isTransparentContext())
- continue;
-
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
@@ -778,21 +778,57 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
}
}
- // If we have a context, and it's not a context stashed in the
- // template parameter scope for an out-of-line definition, also
- // look into that context.
- if (Ctx && !(Found && S && S->isTemplateParamScope())) {
- assert(Ctx->isFileContext() &&
- "We should have been looking only at file context here already.");
+ if (Found && S->isTemplateParamScope()) {
+ R.resolveKind();
+ return true;
+ }
- // Look into context considering using-directives.
- if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs))
- Found = true;
+ DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
+ if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
+ S->getParent() && !S->getParent()->isTemplateParamScope()) {
+ // We've just searched the last template parameter scope and
+ // found nothing, so look into the the contexts between the
+ // lexical and semantic declaration contexts returned by
+ // findOuterContext(). This implements the name lookup behavior
+ // of C++ [temp.local]p8.
+ Ctx = OutsideOfTemplateParamDC;
+ OutsideOfTemplateParamDC = 0;
}
+
+ if (Ctx) {
+ DeclContext *OuterCtx;
+ bool SearchAfterTemplateScope;
+ llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
+ if (SearchAfterTemplateScope)
+ OutsideOfTemplateParamDC = OuterCtx;
- if (Found) {
- R.resolveKind();
- return true;
+ for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) {
+ // We do not directly look into transparent contexts, since
+ // those entities will be found in the nearest enclosing
+ // non-transparent context.
+ if (Ctx->isTransparentContext())
+ continue;
+
+ // If we have a context, and it's not a context stashed in the
+ // template parameter scope for an out-of-line definition, also
+ // look into that context.
+ if (!(Found && S && S->isTemplateParamScope())) {
+ assert(Ctx->isFileContext() &&
+ "We should have been looking only at file context here already.");
+
+ // Look into context considering using-directives.
+ if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs))
+ Found = true;
+ }
+
+ if (Found) {
+ R.resolveKind();
+ return true;
+ }
+
+ if (R.isForRedeclaration() && !Ctx->isTransparentContext())
+ return false;
+ }
}
if (R.isForRedeclaration() && Ctx && !Ctx->isTransparentContext())
@@ -2580,6 +2616,12 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
WantExpressionKeywords = true;
WantCXXNamedCasts = true;
WantRemainingKeywords = true;
+
+ if (ObjCMethodDecl *Method = getCurMethodDecl())
+ if (Method->getClassInterface() &&
+ Method->getClassInterface()->getSuperClass())
+ Consumer.addKeywordResult(Context, "super");
+
break;
case CTC_NoKeywords:
@@ -2646,7 +2688,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
Consumer.addKeywordResult(Context, "typeof");
}
- if (WantCXXNamedCasts) {
+ if (WantCXXNamedCasts && getLangOptions().CPlusPlus) {
Consumer.addKeywordResult(Context, "const_cast");
Consumer.addKeywordResult(Context, "dynamic_cast");
Consumer.addKeywordResult(Context, "reinterpret_cast");
@@ -2776,6 +2818,25 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
BestIvarOrPropertyDecl = 0;
FoundIvarOrPropertyDecl = false;
Consumer.clear_decls();
+ } else if (CTC == CTC_ObjCMessageReceiver &&
+ (*Consumer.keyword_begin())->isStr("super")) {
+ // In an Objective-C message send, give the "super" keyword a slight
+ // edge over entities not in function or method scope.
+ for (TypoCorrectionConsumer::iterator I = Consumer.begin(),
+ IEnd = Consumer.end();
+ I != IEnd; ++I) {
+ if ((*I)->getDeclName() == BestName) {
+ if ((*I)->getDeclContext()->isFunctionOrMethod())
+ return DeclarationName();
+ }
+ }
+
+ // Everything found was outside a function or method; the 'super'
+ // keyword takes precedence.
+ BestIvarOrPropertyDecl = 0;
+ FoundIvarOrPropertyDecl = false;
+ Consumer.clear_decls();
+ BestName = *Consumer.keyword_begin();
} else {
// Name collision; we will not correct typos.
return DeclarationName();
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index b73739f..4c89a11 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
+#include "clang/AST/ExprObjC.h"
using namespace clang;
@@ -119,7 +121,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
ObjCPropertyDecl *PDecl =
CreatePropertyDecl(S, CCPrimary, AtLoc,
FD, GetterSel, SetterSel, isAssign, isReadWrite,
- Attributes, T, MethodImplKind);
+ Attributes, T, MethodImplKind, DC);
// A case of continuation class adding a new property in the class. This
// is not what it was meant for. However, gcc supports it and so should we.
@@ -189,7 +191,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
const bool isReadWrite,
const unsigned Attributes,
QualType T,
- tok::ObjCKeywordKind MethodImplKind){
+ tok::ObjCKeywordKind MethodImplKind,
+ DeclContext *lexicalDC){
IdentifierInfo *PropertyId = FD.D.getIdentifier();
@@ -197,19 +200,16 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
// 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"), AtLoc))
- if (IDecl->ClassImplementsProtocol(PNSCopying, true))
- Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
- }
+ if (const ObjCObjectPointerType *ObjPtrTy =
+ T->getAs<ObjCObjectPointerType>()) {
+ ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
+ if (IDecl)
+ if (ObjCProtocolDecl* PNSCopying =
+ LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc))
+ if (IDecl->ClassImplementsProtocol(PNSCopying, true))
+ Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
}
- if (T->isObjCInterfaceType())
+ if (T->isObjCObjectType())
Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object);
DeclContext *DC = cast<DeclContext>(CDecl);
@@ -223,8 +223,11 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
Diag(prevDecl->getLocation(), diag::note_property_declare);
PDecl->setInvalidDecl();
}
- else
+ else {
DC->addDecl(PDecl);
+ if (lexicalDC)
+ PDecl->setLexicalDeclContext(lexicalDC);
+ }
if (T->isArrayType() || T->isFunctionType()) {
Diag(AtLoc, diag::err_property_type) << T;
@@ -275,7 +278,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
/// builds the AST node for a property implementation declaration; declared
/// as @synthesize or @dynamic.
///
-Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
+Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S,
+ SourceLocation AtLoc,
SourceLocation PropertyLoc,
bool Synthesize,
DeclPtrTy ClassCatImpDecl,
@@ -379,7 +383,16 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
// Check that type of property and its ivar are type compatible.
if (PropType != IvarType) {
- if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
+ bool compat = false;
+ if (isa<ObjCObjectPointerType>(PropType)
+ && isa<ObjCObjectPointerType>(IvarType))
+ compat =
+ Context.canAssignObjCInterfaces(
+ PropType->getAs<ObjCObjectPointerType>(),
+ IvarType->getAs<ObjCObjectPointerType>());
+ else
+ compat = (CheckAssignmentConstraints(PropType, IvarType) == Compatible);
+ if (!compat) {
Diag(PropertyLoc, diag::error_property_ivar_type)
<< property->getDeclName() << PropType
<< Ivar->getDeclName() << IvarType;
@@ -427,6 +440,55 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
ObjCPropertyImplDecl::Synthesize
: ObjCPropertyImplDecl::Dynamic),
Ivar);
+ if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
+ getterMethod->createImplicitParams(Context, IDecl);
+ if (getLangOptions().CPlusPlus && Synthesize) {
+ // For Objective-C++, need to synthesize the AST for the IVAR object to be
+ // returned by the getter as it must conform to C++'s copy-return rules.
+ // FIXME. Eventually we want to do this for Objective-C as well.
+ ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();
+ DeclRefExpr *SelfExpr =
+ new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(),
+ SourceLocation());
+ Expr *IvarRefExpr =
+ new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc,
+ SelfExpr, true, true);
+ OwningExprResult Res =
+ PerformCopyInitialization(InitializedEntity::InitializeResult(
+ SourceLocation(),
+ getterMethod->getResultType(),
+ /*NRVO=*/false),
+ SourceLocation(),
+ Owned(IvarRefExpr));
+ if (!Res.isInvalid()) {
+ Expr *ResExpr = Res.takeAs<Expr>();
+ if (ResExpr)
+ ResExpr = MaybeCreateCXXExprWithTemporaries(ResExpr);
+ PIDecl->setGetterCXXConstructor(ResExpr);
+ }
+ }
+ }
+ if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
+ setterMethod->createImplicitParams(Context, IDecl);
+ if (getLangOptions().CPlusPlus && Synthesize) {
+ // FIXME. Eventually we want to do this for Objective-C as well.
+ ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
+ DeclRefExpr *SelfExpr =
+ new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(),
+ SourceLocation());
+ Expr *lhs =
+ new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc,
+ SelfExpr, true, true);
+ ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
+ ParmVarDecl *Param = (*P);
+ Expr *rhs = new (Context) DeclRefExpr(Param,Param->getType(),
+ SourceLocation());
+ OwningExprResult Res = BuildBinOp(S, SourceLocation(),
+ BinaryOperator::Assign, lhs, rhs);
+ PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>());
+ }
+ }
+
if (IC) {
if (Synthesize)
if (ObjCPropertyImplDecl *PPIDecl =
@@ -751,6 +813,47 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
}
}
+/// CollectClassPropertyImplementations - This routine collects list of
+/// properties to be implemented in the class. This includes, class's
+/// and its conforming protocols' properties.
+static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl,
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
+ if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
+ E = IDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); PI != E; ++PI)
+ CollectClassPropertyImplementations((*PI), PropMap);
+ }
+ else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ CollectClassPropertyImplementations((*PI), PropMap);
+ }
+}
+
+/// CollectSuperClassPropertyImplementations - This routine collects list of
+/// properties to be implemented in super class(s) and also coming from their
+/// conforming protocols.
+static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
+ if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
+ while (SDecl) {
+ CollectClassPropertyImplementations(SDecl, PropMap);
+ SDecl = SDecl->getSuperClass();
+ }
+ }
+}
+
/// ProtocolConformsToSuperClass - Returns true if class's given protocol
/// conforms to one of its super class's protocols.
bool Sema::ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl,
@@ -817,8 +920,36 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
return 0;
}
+/// DefaultSynthesizeProperties - This routine default synthesizes all
+/// properties which must be synthesized in class's @implementation.
+void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
+ ObjCInterfaceDecl *IDecl) {
+
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
+ CollectClassPropertyImplementations(IDecl, PropMap);
+ if (PropMap.empty())
+ return;
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap;
+ CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
+
+ for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
+ P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = P->second;
+ // If property to be implemented in the super class, ignore.
+ if (SuperPropMap[Prop->getIdentifier()])
+ continue;
+ // Is there a matching propery synthesize/dynamic?
+ if (Prop->isInvalidDecl() ||
+ Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
+ IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier()))
+ continue;
+ ActOnPropertyImplDecl(S, IMPDecl->getLocation(), IMPDecl->getLocation(),
+ true, DeclPtrTy::make(IMPDecl),
+ Prop->getIdentifier(), Prop->getIdentifier());
+ }
+}
-void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
+void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const llvm::DenseSet<Selector>& InsMap) {
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
@@ -840,14 +971,6 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
PropImplMap.count(Prop))
continue;
- if (LangOpts.ObjCNonFragileABI2 && !isa<ObjCCategoryImplDecl>(IMPDecl)) {
- ActOnPropertyImplDecl(IMPDecl->getLocation(),
- IMPDecl->getLocation(),
- true, DeclPtrTy::make(IMPDecl),
- Prop->getIdentifier(),
- Prop->getIdentifier());
- continue;
- }
if (!InsMap.count(Prop->getGetterName())) {
Diag(Prop->getLocation(),
isa<ObjCCategoryDecl>(CDecl) ?
@@ -954,6 +1077,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ObjCMethodDecl::Optional :
ObjCMethodDecl::Required);
CD->addDecl(GetterMethod);
+ // FIXME: Eventually this shouldn't be needed, as the lexical context
+ // and the real context should be the same.
+ if (DeclContext *lexicalDC = property->getLexicalDeclContext())
+ GetterMethod->setLexicalDeclContext(lexicalDC);
+
} else
// A user declared getter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
@@ -987,6 +1115,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
0);
SetterMethod->setMethodParams(Context, &Argument, 1, 1);
CD->addDecl(SetterMethod);
+ // FIXME: Eventually this shouldn't be needed, as the lexical context
+ // and the real context should be the same.
+ if (DeclContext *lexicalDC = property->getLexicalDeclContext())
+ SetterMethod->setLexicalDeclContext(lexicalDC);
} else
// A user declared setter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index b87fa7d..2754d44 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -52,6 +52,8 @@ GetConversionCategory(ImplicitConversionKind Kind) {
ICC_Conversion,
ICC_Conversion,
ICC_Conversion,
+ ICC_Conversion,
+ ICC_Conversion,
ICC_Conversion
};
return Category[(int)Kind];
@@ -80,6 +82,8 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
+ ICR_Conversion,
+ ICR_Conversion,
ICR_Complex_Real_Conversion
};
return Rank[(int)Kind];
@@ -102,12 +106,14 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
"Floating conversion",
"Complex conversion",
"Floating-integral conversion",
- "Complex-real conversion",
"Pointer conversion",
"Pointer-to-member conversion",
"Boolean conversion",
"Compatible-types conversion",
- "Derived-to-base conversion"
+ "Derived-to-base conversion",
+ "Vector conversion",
+ "Vector splat",
+ "Complex-real conversion"
};
return Name[Kind];
}
@@ -275,7 +281,194 @@ AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) {
new (&conversions()) ConversionSet(O.conversions());
}
+namespace {
+ // Structure used by OverloadCandidate::DeductionFailureInfo to store
+ // template parameter and template argument information.
+ struct DFIParamWithArguments {
+ TemplateParameter Param;
+ TemplateArgument FirstArg;
+ TemplateArgument SecondArg;
+ };
+}
+
+/// \brief Convert from Sema's representation of template deduction information
+/// to the form used in overload-candidate information.
+OverloadCandidate::DeductionFailureInfo
+static MakeDeductionFailureInfo(ASTContext &Context,
+ Sema::TemplateDeductionResult TDK,
+ Sema::TemplateDeductionInfo &Info) {
+ OverloadCandidate::DeductionFailureInfo Result;
+ Result.Result = static_cast<unsigned>(TDK);
+ Result.Data = 0;
+ switch (TDK) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ break;
+
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_InvalidExplicitArguments:
+ Result.Data = Info.Param.getOpaqueValue();
+ break;
+
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals: {
+ // FIXME: Should allocate from normal heap so that we can free this later.
+ DFIParamWithArguments *Saved = new (Context) DFIParamWithArguments;
+ Saved->Param = Info.Param;
+ Saved->FirstArg = Info.FirstArg;
+ Saved->SecondArg = Info.SecondArg;
+ Result.Data = Saved;
+ break;
+ }
+
+ case Sema::TDK_SubstitutionFailure:
+ Result.Data = Info.take();
+ break;
+
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+
+ return Result;
+}
+
+void OverloadCandidate::DeductionFailureInfo::Destroy() {
+ switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_InvalidExplicitArguments:
+ break;
+
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ // FIXME: Destroy the data?
+ Data = 0;
+ break;
+ case Sema::TDK_SubstitutionFailure:
+ // FIXME: Destroy the template arugment list?
+ Data = 0;
+ break;
+
+ // Unhandled
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+}
+
+TemplateParameter
+OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
+ switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_SubstitutionFailure:
+ return TemplateParameter();
+
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_InvalidExplicitArguments:
+ return TemplateParameter::getFromOpaqueValue(Data);
+
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ return static_cast<DFIParamWithArguments*>(Data)->Param;
+
+ // Unhandled
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+
+ return TemplateParameter();
+}
+
+TemplateArgumentList *
+OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() {
+ switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ return 0;
+
+ case Sema::TDK_SubstitutionFailure:
+ return static_cast<TemplateArgumentList*>(Data);
+
+ // Unhandled
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+
+ return 0;
+}
+
+const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() {
+ switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_SubstitutionFailure:
+ return 0;
+
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ return &static_cast<DFIParamWithArguments*>(Data)->FirstArg;
+
+ // Unhandled
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+
+ return 0;
+}
+
+const TemplateArgument *
+OverloadCandidate::DeductionFailureInfo::getSecondArg() {
+ switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_SubstitutionFailure:
+ return 0;
+
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ return &static_cast<DFIParamWithArguments*>(Data)->SecondArg;
+
+ // Unhandled
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+
+ return 0;
+}
+
+void OverloadCandidateSet::clear() {
+ inherited::clear();
+ Functions.clear();
+}
+
// IsOverload - Determine whether the given New declaration is an
// overload of the declarations in Old. This routine returns false if
// New and Old cannot be overloaded, e.g., if New has the same
@@ -586,6 +779,48 @@ static bool IsNoReturnConversion(ASTContext &Context, QualType FromType,
ResultTy = FromType;
return true;
}
+
+/// \brief Determine whether the conversion from FromType to ToType is a valid
+/// vector conversion.
+///
+/// \param ICK Will be set to the vector conversion kind, if this is a vector
+/// conversion.
+static bool IsVectorConversion(ASTContext &Context, QualType FromType,
+ QualType ToType, ImplicitConversionKind &ICK) {
+ // We need at least one of these types to be a vector type to have a vector
+ // conversion.
+ if (!ToType->isVectorType() && !FromType->isVectorType())
+ return false;
+
+ // Identical types require no conversions.
+ if (Context.hasSameUnqualifiedType(FromType, ToType))
+ return false;
+
+ // There are no conversions between extended vector types, only identity.
+ if (ToType->isExtVectorType()) {
+ // There are no conversions between extended vector types other than the
+ // identity conversion.
+ if (FromType->isExtVectorType())
+ return false;
+
+ // Vector splat from any arithmetic type to a vector.
+ if (!FromType->isVectorType() && FromType->isArithmeticType()) {
+ ICK = ICK_Vector_Splat;
+ return true;
+ }
+ }
+
+ // If lax vector conversions are permitted and the vector types are of the
+ // same size, we can perform the conversion.
+ if (Context.getLangOptions().LaxVectorConversions &&
+ FromType->isVectorType() && ToType->isVectorType() &&
+ Context.getTypeSize(FromType) == Context.getTypeSize(ToType)) {
+ ICK = ICK_Vector_Conversion;
+ return true;
+ }
+
+ return false;
+}
/// IsStandardConversion - Determines whether there is a standard
/// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the
@@ -708,6 +943,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// For overloading in C, this can also be a "compatible-type"
// conversion.
bool IncompatibleObjC = false;
+ ImplicitConversionKind SecondICK = ICK_Identity;
if (Context.hasSameUnqualifiedType(FromType, ToType)) {
// The unqualified versions of the types are the same: there's no
// conversion to do.
@@ -769,10 +1005,14 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// Boolean conversions (C++ 4.12).
SCS.Second = ICK_Boolean_Conversion;
FromType = Context.BoolTy;
+ } else if (IsVectorConversion(Context, FromType, ToType, SecondICK)) {
+ SCS.Second = SecondICK;
+ FromType = ToType.getUnqualifiedType();
} else if (!getLangOptions().CPlusPlus &&
Context.typesAreCompatible(ToType, FromType)) {
// Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
+ FromType = ToType.getUnqualifiedType();
} else if (IsNoReturnConversion(Context, FromType, ToType, FromType)) {
// Treat a conversion that strips "noreturn" as an identity conversion.
SCS.Second = ICK_NoReturn_Adjustment;
@@ -802,7 +1042,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
CanonTo = Context.getCanonicalType(ToType);
if (CanonFrom.getLocalUnqualifiedType()
== CanonTo.getLocalUnqualifiedType() &&
- CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()) {
+ (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()
+ || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr())) {
FromType = ToType;
CanonFrom = CanonTo;
}
@@ -992,7 +1233,7 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
if (CanonToPointee.getLocalQualifiers() == Quals) {
// ToType is exactly what we need. Return it.
if (!ToType.isNull())
- return ToType;
+ return ToType.getUnqualifiedType();
// Build a pointer to ToPointee. It has the right qualifiers
// already.
@@ -1350,22 +1591,18 @@ bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType,
if (ToType != FromType) {
if (const PointerType *PTTo = ToType->getAs<PointerType>()) {
if (const PointerType *PTFr = FromType->getAs<PointerType>())
- if (PTTo->getPointeeType()->isObjCQualifiedIdType() &&
- PTFr->getPointeeType()->isObjCQualifiedIdType() ||
- PTTo->getPointeeType()->isObjCQualifiedClassType() &&
- PTFr->getPointeeType()->isObjCQualifiedClassType())
+ if ((PTTo->getPointeeType()->isObjCQualifiedIdType() &&
+ PTFr->getPointeeType()->isObjCQualifiedIdType()) ||
+ (PTTo->getPointeeType()->isObjCQualifiedClassType() &&
+ PTFr->getPointeeType()->isObjCQualifiedClassType()))
continue;
}
- else if (ToType->isObjCObjectPointerType() &&
- FromType->isObjCObjectPointerType()) {
- QualType ToInterfaceTy = ToType->getPointeeType();
- QualType FromInterfaceTy = FromType->getPointeeType();
- if (const ObjCInterfaceType *OITTo =
- ToInterfaceTy->getAs<ObjCInterfaceType>())
- if (const ObjCInterfaceType *OITFr =
- FromInterfaceTy->getAs<ObjCInterfaceType>())
- if (OITTo->getDecl() == OITFr->getDecl())
- continue;
+ else if (const ObjCObjectPointerType *PTTo =
+ ToType->getAs<ObjCObjectPointerType>()) {
+ if (const ObjCObjectPointerType *PTFr =
+ FromType->getAs<ObjCObjectPointerType>())
+ if (PTTo->getInterfaceDecl() == PTFr->getInterfaceDecl())
+ continue;
}
return false;
}
@@ -1839,6 +2076,15 @@ compareStandardConversionSubsets(ASTContext &Context,
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
+ // the identity conversion sequence is considered to be a subsequence of
+ // any non-identity conversion sequence
+ if (SCS1.ReferenceBinding == SCS2.ReferenceBinding) {
+ if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion())
+ return ImplicitConversionSequence::Better;
+ else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion())
+ return ImplicitConversionSequence::Worse;
+ }
+
if (SCS1.Second != SCS2.Second) {
if (SCS1.Second == ICK_Identity)
Result = ImplicitConversionSequence::Better;
@@ -1954,8 +2200,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->getAs<ObjCInterfaceType>();
- const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>();
+ const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>();
+ const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>();
if (FromIface1 && FromIface1) {
if (Context.canAssignObjCInterfaces(FromIface2, FromIface1))
return ImplicitConversionSequence::Better;
@@ -2161,10 +2407,10 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
QualType ToPointee2
= ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>();
- const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>();
- const ObjCInterfaceType* ToIface1 = ToPointee1->getAs<ObjCInterfaceType>();
- const ObjCInterfaceType* ToIface2 = ToPointee2->getAs<ObjCInterfaceType>();
+ const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>();
+ const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>();
+ const ObjCObjectType* ToIface1 = ToPointee1->getAs<ObjCObjectType>();
+ const ObjCObjectType* ToIface2 = ToPointee2->getAs<ObjCObjectType>();
// -- conversion of C* to B* is better than conversion of C* to A*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
@@ -2289,8 +2535,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// T1 is a base class of T2.
if (UnqualT1 == UnqualT2)
DerivedToBase = false;
- else if (!RequireCompleteType(Loc, OrigT1, PDiag()) &&
- !RequireCompleteType(Loc, OrigT2, PDiag()) &&
+ else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&
IsDerivedFrom(UnqualT2, UnqualT1))
DerivedToBase = true;
else
@@ -2724,6 +2969,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From,
/// TryContextuallyConvertToBool - Attempt to contextually convert the
/// expression From to bool (C++0x [conv]p3).
ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
+ // FIXME: This is pretty broken.
return TryImplicitConversion(From, Context.BoolTy,
// FIXME: Are these flags correct?
/*SuppressUserConversions=*/false,
@@ -2744,6 +2990,27 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
<< From->getType() << From->getSourceRange();
return true;
}
+
+/// TryContextuallyConvertToObjCId - Attempt to contextually convert the
+/// expression From to 'id'.
+ImplicitConversionSequence Sema::TryContextuallyConvertToObjCId(Expr *From) {
+ QualType Ty = Context.getObjCIdType();
+ return TryImplicitConversion(From, Ty,
+ // FIXME: Are these flags correct?
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/true,
+ /*InOverloadResolution=*/false);
+}
+
+/// PerformContextuallyConvertToObjCId - Perform a contextual conversion
+/// of the expression From to 'id'.
+bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) {
+ QualType Ty = Context.getObjCIdType();
+ ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(From);
+ if (!ICS.isBad())
+ return PerformImplicitConversion(From, Ty, ICS, AA_Converting);
+ return true;
+}
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments. If
@@ -3029,7 +3296,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
}
}
}
-
+
/// \brief Add a C++ member function template as a candidate to the candidate
/// set, using template argument deduction to produce an appropriate member
/// function template specialization.
@@ -3059,11 +3326,18 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
if (TemplateDeductionResult Result
= DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs,
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;
- }
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate &Candidate = CandidateSet.back();
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = MethodTmpl->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_deduction;
+ Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
+ Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
+ Info);
+ return;
+ }
// Add the function template specialization produced by template argument
// deduction as a candidate.
@@ -3110,10 +3384,8 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
-
- // TODO: record more information about failed template arguments
- Candidate.DeductionFailure.Result = Result;
- Candidate.DeductionFailure.TemplateParameter = Info.Param.getOpaqueValue();
+ Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
+ Info);
return;
}
@@ -3260,9 +3532,16 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
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;
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate &Candidate = CandidateSet.back();
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_deduction;
+ Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
+ Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
+ Info);
return;
}
@@ -3504,6 +3783,10 @@ class BuiltinCandidateTypeSet {
/// used in the built-in candidates.
TypeSet EnumerationTypes;
+ /// \brief The set of vector types that will be used in the built-in
+ /// candidates.
+ TypeSet VectorTypes;
+
/// Sema - The semantic analysis instance where we are building the
/// candidate type set.
Sema &SemaRef;
@@ -3545,6 +3828,9 @@ public:
/// enumeration_end - Past the last enumeration type found;
iterator enumeration_end() { return EnumerationTypes.end(); }
+
+ iterator vector_begin() { return VectorTypes.begin(); }
+ iterator vector_end() { return VectorTypes.end(); }
};
/// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to
@@ -3677,6 +3963,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
return;
} else if (Ty->isEnumeralType()) {
EnumerationTypes.insert(Ty);
+ } else if (Ty->isVectorType()) {
+ VectorTypes.insert(Ty);
} else if (AllowUserConversions) {
if (const RecordType *TyRec = Ty->getAs<RecordType>()) {
if (SemaRef.RequireCompleteType(Loc, Ty, 0)) {
@@ -3841,21 +4129,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]);
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 ||
- Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript ||
- Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus ||
- (Op == OO_Star && NumArgs == 1) || Op == OO_Conditional) {
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
- CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(),
- OpLoc,
- true,
- (Op == OO_Exclaim ||
- Op == OO_AmpAmp ||
- Op == OO_PipePipe),
- VisibleTypeConversionsQuals);
- }
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
+ CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(),
+ OpLoc,
+ true,
+ (Op == OO_Exclaim ||
+ Op == OO_AmpAmp ||
+ Op == OO_PipePipe),
+ VisibleTypeConversionsQuals);
bool isComparison = false;
switch (Op) {
@@ -4019,6 +4300,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
QualType ArithTy = ArithmeticTypes[Arith];
AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet);
}
+
+ // Extension: We also add these operators for vector types.
+ for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(),
+ VecEnd = CandidateTypes.vector_end();
+ Vec != VecEnd; ++Vec) {
+ QualType VecTy = *Vec;
+ AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet);
+ }
break;
case OO_Tilde:
@@ -4032,6 +4321,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
QualType IntTy = ArithmeticTypes[Int];
AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet);
}
+
+ // Extension: We also add this operator for vector types.
+ for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(),
+ VecEnd = CandidateTypes.vector_end();
+ Vec != VecEnd; ++Vec) {
+ QualType VecTy = *Vec;
+ AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet);
+ }
break;
case OO_New:
@@ -4188,6 +4485,30 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
}
+
+ // Extension: Add the binary operators ==, !=, <, <=, >=, >, *, /, and the
+ // conditional operator for vector types.
+ for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(),
+ Vec1End = CandidateTypes.vector_end();
+ Vec1 != Vec1End; ++Vec1)
+ for (BuiltinCandidateTypeSet::iterator
+ Vec2 = CandidateTypes.vector_begin(),
+ Vec2End = CandidateTypes.vector_end();
+ Vec2 != Vec2End; ++Vec2) {
+ QualType LandR[2] = { *Vec1, *Vec2 };
+ QualType Result;
+ if (isComparison)
+ Result = Context.BoolTy;
+ else {
+ if ((*Vec1)->isExtVectorType() || !(*Vec2)->isExtVectorType())
+ Result = *Vec1;
+ else
+ Result = *Vec2;
+ }
+
+ AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
+ }
+
break;
case OO_Percent:
@@ -4243,7 +4564,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
MemPtr != MemPtrEnd; ++MemPtr)
AddBuiltinAssignmentOperatorCandidates(*this, *MemPtr, Args, 2,
CandidateSet);
- // Fall through.
+
+ // Fall through.
case OO_PlusEqual:
case OO_MinusEqual:
@@ -4318,6 +4640,30 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
}
}
}
+
+ // Extension: Add the binary operators =, +=, -=, *=, /= for vector types.
+ for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(),
+ Vec1End = CandidateTypes.vector_end();
+ Vec1 != Vec1End; ++Vec1)
+ for (BuiltinCandidateTypeSet::iterator
+ Vec2 = CandidateTypes.vector_begin(),
+ Vec2End = CandidateTypes.vector_end();
+ Vec2 != Vec2End; ++Vec2) {
+ QualType ParamTypes[2];
+ ParamTypes[1] = *Vec2;
+ // Add this built-in operator as a candidate (VQ is empty).
+ ParamTypes[0] = Context.getLValueReferenceType(*Vec1);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/Op == OO_Equal);
+
+ // Add this built-in operator as a candidate (VQ is 'volatile').
+ if (VisibleTypeConversionsQuals.hasVolatile()) {
+ ParamTypes[0] = Context.getVolatileType(*Vec1);
+ ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/Op == OO_Equal);
+ }
+ }
break;
case OO_PercentEqual:
@@ -4413,7 +4759,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
ParamTypes[0] = ParamTypes[1];
ParamTypes[1] = *Ptr;
AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
- }
+ }
break;
case OO_ArrowStar:
@@ -4901,16 +5247,21 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned MinParams = Fn->getMinRequiredArguments();
// at least / at most / exactly
+ // FIXME: variadic templates "at most" should account for parameter packs
unsigned mode, modeCount;
if (NumFormalArgs < MinParams) {
- assert(Cand->FailureKind == ovl_fail_too_few_arguments);
+ assert((Cand->FailureKind == ovl_fail_too_few_arguments) ||
+ (Cand->FailureKind == ovl_fail_bad_deduction &&
+ Cand->DeductionFailure.Result == Sema::TDK_TooFewArguments));
if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic())
mode = 0; // "at least"
else
mode = 2; // "exactly"
modeCount = MinParams;
} else {
- assert(Cand->FailureKind == ovl_fail_too_many_arguments);
+ assert((Cand->FailureKind == ovl_fail_too_many_arguments) ||
+ (Cand->FailureKind == ovl_fail_bad_deduction &&
+ Cand->DeductionFailure.Result == Sema::TDK_TooManyArguments));
if (MinParams != FnTy->getNumArgs())
mode = 1; // "at most"
else
@@ -4922,7 +5273,8 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
- << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs;
+ << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode
+ << modeCount << NumFormalArgs;
}
/// Diagnose a failed template-argument deduction.
@@ -4930,34 +5282,86 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
Expr **Args, unsigned NumArgs) {
FunctionDecl *Fn = Cand->Function; // pattern
- TemplateParameter Param = TemplateParameter::getFromOpaqueValue(
- Cand->DeductionFailure.TemplateParameter);
-
+ TemplateParameter Param = Cand->DeductionFailure.getTemplateParameter();
+ NamedDecl *ParamD;
+ (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
+ (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) ||
+ (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>());
switch (Cand->DeductionFailure.Result) {
case Sema::TDK_Success:
llvm_unreachable("TDK_success while diagnosing bad deduction");
case Sema::TDK_Incomplete: {
- NamedDecl *ParamD;
- (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
- (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) ||
- (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>());
assert(ParamD && "no parameter found for incomplete deduction result");
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction)
<< ParamD->getDeclName();
return;
}
- // TODO: diagnose these individually, then kill off
- // note_ovl_candidate_bad_deduction, which is uselessly vague.
- case Sema::TDK_InstantiationDepth:
case Sema::TDK_Inconsistent:
- case Sema::TDK_InconsistentQuals:
- case Sema::TDK_SubstitutionFailure:
- case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_InconsistentQuals: {
+ assert(ParamD && "no parameter found for inconsistent deduction result");
+ int which = 0;
+ if (isa<TemplateTypeParmDecl>(ParamD))
+ which = 0;
+ else if (isa<NonTypeTemplateParmDecl>(ParamD))
+ which = 1;
+ else {
+ which = 2;
+ }
+
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_inconsistent_deduction)
+ << which << ParamD->getDeclName()
+ << *Cand->DeductionFailure.getFirstArg()
+ << *Cand->DeductionFailure.getSecondArg();
+ return;
+ }
+
+ case Sema::TDK_InvalidExplicitArguments:
+ assert(ParamD && "no parameter found for invalid explicit arguments");
+ if (ParamD->getDeclName())
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_explicit_arg_mismatch_named)
+ << ParamD->getDeclName();
+ else {
+ int index = 0;
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ParamD))
+ index = TTP->getIndex();
+ else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(ParamD))
+ index = NTTP->getIndex();
+ else
+ index = cast<TemplateTemplateParmDecl>(ParamD)->getIndex();
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_explicit_arg_mismatch_unnamed)
+ << (index + 1);
+ }
+ return;
+
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
- case Sema::TDK_InvalidExplicitArguments:
+ DiagnoseArityMismatch(S, Cand, NumArgs);
+ return;
+
+ case Sema::TDK_InstantiationDepth:
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_instantiation_depth);
+ return;
+
+ case Sema::TDK_SubstitutionFailure: {
+ std::string ArgString;
+ if (TemplateArgumentList *Args
+ = Cand->DeductionFailure.getTemplateArgumentList())
+ ArgString = S.getTemplateArgumentBindingsText(
+ Fn->getDescribedFunctionTemplate()->getTemplateParameters(),
+ *Args);
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure)
+ << ArgString;
+ return;
+ }
+
+ // TODO: diagnose these individually, then kill off
+ // note_ovl_candidate_bad_deduction, which is uselessly vague.
+ case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_FailedOverloadResolution:
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction);
return;
@@ -5500,8 +5904,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
assert(Result != MatchesCopy.end() && "no most-specialized template");
MarkDeclarationReferenced(From->getLocStart(), *Result);
FoundResult = Matches[Result - MatchesCopy.begin()].first;
- if (Complain)
+ if (Complain) {
CheckUnresolvedAccess(*this, OvlExpr, FoundResult);
+ DiagnoseUseOfDecl(FoundResult, OvlExpr->getNameLoc());
+ }
return cast<FunctionDecl>(*Result);
}
@@ -5521,8 +5927,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
if (Matches.size() == 1) {
MarkDeclarationReferenced(From->getLocStart(), Matches[0].second);
FoundResult = Matches[0].first;
- if (Complain)
+ if (Complain) {
CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
+ DiagnoseUseOfDecl(Matches[0].first, OvlExpr->getNameLoc());
+ }
return cast<FunctionDecl>(Matches[0].second);
}
@@ -5724,7 +6132,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
- if (SemaRef.DiagnoseEmptyLookup(S, SS, R))
+ if (SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression))
return Destroy(SemaRef, Fn, Args, NumArgs);
assert(!R.empty() && "lookup results empty despite recovery");
@@ -5801,6 +6209,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
case OR_Success: {
FunctionDecl *FDecl = Best->Function;
CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, ULE->getNameLoc());
Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc);
}
@@ -5885,9 +6294,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, OpLoc,
- /*ADL*/ true, IsOverloaded(Fns));
- Fn->addDecls(Fns.begin(), Fns.end());
-
+ /*ADL*/ true, IsOverloaded(Fns),
+ Fns.begin(), Fns.end());
input.release();
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
&Args[0], NumArgs,
@@ -5945,6 +6353,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
Input = (Expr *)input.get();
}
+ DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
+
// Determine the result type
QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
@@ -5958,7 +6368,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
ExprOwningPtr<CallExpr> TheCall(this,
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
Args, NumArgs, ResultTy, OpLoc));
-
+
if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
FnDecl))
return ExprError();
@@ -6056,9 +6466,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, OpLoc,
- /*ADL*/ true, IsOverloaded(Fns));
-
- Fn->addDecls(Fns.begin(), Fns.end());
+ /*ADL*/ true, IsOverloaded(Fns),
+ Fns.begin(), Fns.end());
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
Args, 2,
Context.DependentTy,
@@ -6150,6 +6559,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Args[1] = RHS = Arg1.takeAs<Expr>();
}
+ DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
+
// Determine the result type
QualType ResultTy
= FnDecl->getType()->getAs<FunctionType>()->getResultType();
@@ -6252,7 +6663,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, LLoc,
- /*ADL*/ true, /*Overloaded*/ false);
+ /*ADL*/ true, /*Overloaded*/ false,
+ UnresolvedSetIterator(),
+ UnresolvedSetIterator());
// Can't add any actual overloads yet
Base.release();
@@ -6286,6 +6699,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// operator.
CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, LLoc);
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
@@ -6452,6 +6866,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Method = cast<CXXMethodDecl>(Best->Function);
FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc());
break;
case OR_No_Viable_Function:
@@ -6661,6 +7076,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
Best->Conversions[0].UserDefined.ConversionFunction);
CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
@@ -6677,6 +7093,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
}
CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
// We found an overloaded operator(). Build a CXXOperatorCallExpr
// that calls this method, using Object for the implicit object
@@ -6767,7 +7184,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// Promote the arguments (C99 6.5.2.2p7).
for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
Expr *Arg = Args[i];
- IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod);
+ IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod, 0);
TheCall->setArg(i + 1, Arg);
}
}
@@ -6847,6 +7264,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
}
CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 5e61111..eb4fc65 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -16,7 +16,9 @@
#define LLVM_CLANG_SEMA_OVERLOAD_H
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "clang/AST/UnresolvedSet.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -60,6 +62,8 @@ namespace clang {
ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12)
ICK_Compatible_Conversion, ///< Conversions between compatible types in C99
ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics])
+ ICK_Vector_Conversion, ///< Vector conversions
+ ICK_Vector_Splat, ///< A vector splat from an arithmetic type
ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7)
ICK_Num_Conversion_Kinds ///< The number of conversion kinds
};
@@ -173,6 +177,12 @@ namespace clang {
}
void setAsIdentityConversion();
+
+ bool isIdentityConversion() const {
+ return First == ICK_Identity && Second == ICK_Identity &&
+ Third == ICK_Identity;
+ }
+
ImplicitConversionRank getRank() const;
bool isPointerConversionToBool() const;
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
@@ -529,8 +539,28 @@ namespace clang {
// A Sema::TemplateDeductionResult.
unsigned Result;
- // A TemplateParameter.
- void *TemplateParameter;
+ /// \brief Opaque pointer containing additional data about
+ /// this deduction failure.
+ void *Data;
+
+ /// \brief Retrieve the template parameter this deduction failure
+ /// refers to, if any.
+ TemplateParameter getTemplateParameter();
+
+ /// \brief Retrieve the template argument list associated with this
+ /// deduction failure, if any.
+ TemplateArgumentList *getTemplateArgumentList();
+
+ /// \brief Return the first template argument this deduction failure
+ /// refers to, if any.
+ const TemplateArgument *getFirstArg();
+
+ /// \brief Return the second template argument this deduction failure
+ /// refers to, if any.
+ const TemplateArgument *getSecondArg();
+
+ /// \brief Free any memory associated with this deduction failure.
+ void Destroy();
};
union {
@@ -562,6 +592,10 @@ namespace clang {
llvm::SmallPtrSet<Decl *, 16> Functions;
SourceLocation Loc;
+
+ OverloadCandidateSet(const OverloadCandidateSet &);
+ OverloadCandidateSet &operator=(const OverloadCandidateSet &);
+
public:
OverloadCandidateSet(SourceLocation Loc) : Loc(Loc) {}
@@ -574,10 +608,9 @@ namespace clang {
}
/// \brief Clear out all of the candidates.
- void clear() {
- inherited::clear();
- Functions.clear();
- }
+ void clear();
+
+ ~OverloadCandidateSet() { clear(); }
};
} // end namespace clang
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 9d6132d..875b160 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -30,7 +30,7 @@ using namespace clang;
Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) {
Expr *E = expr->takeAs<Expr>();
assert(E && "ActOnExprStmt(): missing expression");
- if (E->getType()->isObjCInterfaceType()) {
+ if (E->getType()->isObjCObjectType()) {
if (LangOpts.ObjCNonFragileABI)
Diag(E->getLocEnd(), diag::err_indirection_requires_nonfragile_object)
<< E->getType();
@@ -280,7 +280,7 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar,
VarDecl *ConditionVar = 0;
if (CondVar.get()) {
ConditionVar = CondVar.getAs<VarDecl>();
- CondResult = CheckConditionVariable(ConditionVar);
+ CondResult = CheckConditionVariable(ConditionVar, IfLoc, true);
if (CondResult.isInvalid())
return StmtError();
}
@@ -288,11 +288,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar,
if (!ConditionExpr)
return StmtError();
- if (CheckBooleanCondition(ConditionExpr, IfLoc)) {
- CondResult = ConditionExpr;
- return StmtError();
- }
-
Stmt *thenStmt = ThenVal.takeAs<Stmt>();
DiagnoseUnusedExprResult(thenStmt);
@@ -313,23 +308,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar,
thenStmt, ElseLoc, elseStmt));
}
-Action::OwningStmtResult
-Sema::ActOnStartOfSwitchStmt(FullExprArg cond, DeclPtrTy CondVar) {
- OwningExprResult CondResult(cond.release());
-
- VarDecl *ConditionVar = 0;
- if (CondVar.get()) {
- ConditionVar = CondVar.getAs<VarDecl>();
- CondResult = CheckConditionVariable(ConditionVar);
- if (CondResult.isInvalid())
- return StmtError();
- }
- SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar,
- CondResult.takeAs<Expr>());
- getSwitchStack().push_back(SS);
- return Owned(SS);
-}
-
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
/// the specified width and sign. If an overflow occurs, detect it and emit
/// the specified diagnostic.
@@ -540,14 +518,36 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
return false;
}
-/// ActOnSwitchBodyError - This is called if there is an error parsing the
-/// body of the switch stmt instead of ActOnFinishSwitchStmt.
-void Sema::ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
- StmtArg Body) {
- // Keep the switch stack balanced.
- assert(getSwitchStack().back() == (SwitchStmt*)Switch.get() &&
- "switch stack missing push/pop!");
- getSwitchStack().pop_back();
+Action::OwningStmtResult
+Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, ExprArg Cond,
+ DeclPtrTy CondVar) {
+ VarDecl *ConditionVar = 0;
+ if (CondVar.get()) {
+ ConditionVar = CondVar.getAs<VarDecl>();
+ OwningExprResult CondE = CheckConditionVariable(ConditionVar, SourceLocation(), false);
+ if (CondE.isInvalid())
+ return StmtError();
+
+ Cond = move(CondE);
+ }
+
+ Expr *CondExpr = Cond.takeAs<Expr>();
+ if (!CondExpr)
+ return StmtError();
+
+ if (getLangOptions().CPlusPlus &&
+ CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr))
+ return StmtError();
+
+ if (!CondVar.get()) {
+ CondExpr = MaybeCreateCXXExprWithTemporaries(CondExpr);
+ if (!CondExpr)
+ return StmtError();
+ }
+
+ SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, CondExpr);
+ getSwitchStack().push_back(SS);
+ return Owned(SS);
}
Action::OwningStmtResult
@@ -567,13 +567,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
Expr *CondExpr = SS->getCond();
+ Expr *CondExprBeforePromotion = CondExpr;
QualType CondTypeBeforePromotion =
GetTypeBeforeIntegralPromotion(CondExpr);
- if (getLangOptions().CPlusPlus &&
- CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr))
- return StmtError();
-
// C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
UsualUnaryConversions(CondExpr);
QualType CondType = CondExpr->getType();
@@ -679,16 +676,38 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
if (!HasDependentValue) {
+ // If we don't have a default statement, check whether the
+ // condition is constant.
+ llvm::APSInt ConstantCondValue;
+ bool HasConstantCond = false;
+ bool ShouldCheckConstantCond = false;
+ if (!HasDependentValue && !TheDefaultStmt) {
+ Expr::EvalResult Result;
+ HasConstantCond = CondExprBeforePromotion->Evaluate(Result, Context);
+ if (HasConstantCond) {
+ assert(Result.Val.isInt() && "switch condition evaluated to non-int");
+ ConstantCondValue = Result.Val.getInt();
+ ShouldCheckConstantCond = true;
+
+ assert(ConstantCondValue.getBitWidth() == CondWidth &&
+ ConstantCondValue.isSigned() == CondIsSigned);
+ }
+ }
+
// Sort all the scalar case values so we can easily detect duplicates.
std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals);
if (!CaseVals.empty()) {
- for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) {
- if (CaseVals[i].first == CaseVals[i+1].first) {
+ for (unsigned i = 0, e = CaseVals.size(); i != e; ++i) {
+ if (ShouldCheckConstantCond &&
+ CaseVals[i].first == ConstantCondValue)
+ ShouldCheckConstantCond = false;
+
+ if (i != 0 && CaseVals[i].first == CaseVals[i-1].first) {
// 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::err_duplicate_case) << CaseVals[i].first.toString(10);
+ Diag(CaseVals[i-1].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.
@@ -707,6 +726,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
// 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) {
+ llvm::APSInt &LoVal = CaseRanges[i].first;
CaseStmt *CR = CaseRanges[i].second;
Expr *Hi = CR->getRHS();
llvm::APSInt HiVal = Hi->EvaluateAsInt(Context);
@@ -722,7 +742,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
CR->setRHS(Hi);
// If the low value is bigger than the high value, the case is empty.
- if (CaseRanges[i].first > HiVal) {
+ if (LoVal > HiVal) {
Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range)
<< SourceRange(CR->getLHS()->getLocStart(),
CR->getRHS()->getLocEnd());
@@ -730,6 +750,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
--i, --e;
continue;
}
+
+ if (ShouldCheckConstantCond &&
+ LoVal <= ConstantCondValue &&
+ ConstantCondValue <= HiVal)
+ ShouldCheckConstantCond = false;
+
HiVals.push_back(HiVal);
}
@@ -783,18 +809,32 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
}
- // Check to see if switch is over an Enum and handles all of its
- // values
+ // Complain if we have a constant condition and we didn't find a match.
+ if (!CaseListIsErroneous && ShouldCheckConstantCond) {
+ // TODO: it would be nice if we printed enums as enums, chars as
+ // chars, etc.
+ Diag(CondExpr->getExprLoc(), diag::warn_missing_case_for_condition)
+ << ConstantCondValue.toString(10)
+ << CondExpr->getSourceRange();
+ }
+
+ // Check to see if switch is over an Enum and handles all of its
+ // values. We don't need to do this if there's a default
+ // statement or if we have a constant condition.
+ //
+ // TODO: we might want to check whether case values are out of the
+ // enum even if we don't want to check whether all cases are handled.
const EnumType* ET = CondTypeBeforePromotion->getAs<EnumType>();
// If switch has default case, then ignore it.
- if (!CaseListIsErroneous && !TheDefaultStmt && ET) {
+ if (!CaseListIsErroneous && !TheDefaultStmt && !HasConstantCond && ET) {
const EnumDecl *ED = ET->getDecl();
typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
EnumValsTy EnumVals;
- // Gather all enum values, set their type and sort them, allowing easier comparison
- // with CaseVals.
- for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); EDI != ED->enumerator_end(); EDI++) {
+ // Gather all enum values, set their type and sort them,
+ // allowing easier comparison with CaseVals.
+ for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
+ EDI != ED->enumerator_end(); EDI++) {
llvm::APSInt Val = (*EDI)->getInitVal();
if(Val.getBitWidth() < CondWidth)
Val.extend(CondWidth);
@@ -802,30 +842,36 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
EnumVals.push_back(std::make_pair(Val, (*EDI)));
}
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
- EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
+ EnumValsTy::iterator EIend =
+ std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
// See which case values aren't in enum
EnumValsTy::const_iterator EI = EnumVals.begin();
- for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) {
+ for (CaseValsTy::const_iterator CI = CaseVals.begin();
+ CI != CaseVals.end(); CI++) {
while (EI != EIend && EI->first < CI->first)
EI++;
if (EI == EIend || EI->first > CI->first)
- Diag(CI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
+ << ED->getDeclName();
}
// See which of case ranges aren't in enum
EI = EnumVals.begin();
- for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); RI != CaseRanges.end() && EI != EIend; RI++) {
+ for (CaseRangesTy::const_iterator RI = CaseRanges.begin();
+ RI != CaseRanges.end() && EI != EIend; RI++) {
while (EI != EIend && EI->first < RI->first)
EI++;
if (EI == EIend || EI->first != RI->first) {
- Diag(RI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
+ << ED->getDeclName();
}
llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
while (EI != EIend && EI->first < Hi)
EI++;
if (EI == EIend || EI->first != Hi)
- Diag(RI->second->getRHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum)
+ << ED->getDeclName();
}
//Check which enum vals aren't in switch
CaseValsTy::const_iterator CI = CaseVals.begin();
@@ -848,7 +894,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
if (RI == CaseRanges.end() || EI->first < RI->first)
- Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) << EI->second->getDeclName();
+ Diag(CondExpr->getExprLoc(), diag::warn_missing_cases)
+ << EI->second->getDeclName();
}
}
}
@@ -870,7 +917,7 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
VarDecl *ConditionVar = 0;
if (CondVar.get()) {
ConditionVar = CondVar.getAs<VarDecl>();
- CondResult = CheckConditionVariable(ConditionVar);
+ CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true);
if (CondResult.isInvalid())
return StmtError();
}
@@ -878,11 +925,6 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
if (!ConditionExpr)
return StmtError();
- if (CheckBooleanCondition(ConditionExpr, WhileLoc)) {
- CondResult = ConditionExpr;
- return StmtError();
- }
-
Stmt *bodyStmt = Body.takeAs<Stmt>();
DiagnoseUnusedExprResult(bodyStmt);
@@ -903,6 +945,10 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
return StmtError();
}
+ condExpr = MaybeCreateCXXExprWithTemporaries(condExpr);
+ if (!condExpr)
+ return StmtError();
+
Stmt *bodyStmt = Body.takeAs<Stmt>();
DiagnoseUnusedExprResult(bodyStmt);
@@ -939,17 +985,11 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
VarDecl *ConditionVar = 0;
if (secondVar.get()) {
ConditionVar = secondVar.getAs<VarDecl>();
- SecondResult = CheckConditionVariable(ConditionVar);
+ SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true);
if (SecondResult.isInvalid())
return StmtError();
}
- Expr *Second = SecondResult.takeAs<Expr>();
- if (Second && CheckBooleanCondition(Second, ForLoc)) {
- SecondResult = Second;
- return StmtError();
- }
-
Expr *Third = third.release().takeAs<Expr>();
Stmt *Body = static_cast<Stmt*>(body.get());
@@ -959,7 +999,8 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
first.release();
body.release();
- return Owned(new (Context) ForStmt(First, Second, ConditionVar, Third, Body,
+ return Owned(new (Context) ForStmt(First, SecondResult.takeAs<Expr>(),
+ ConditionVar, Third, Body,
ForLoc, LParenLoc, RParenLoc));
}
@@ -1068,6 +1109,45 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
return Owned(new (Context) BreakStmt(BreakLoc));
}
+/// \brief Determine whether a return statement is a candidate for the named
+/// return value optimization (C++0x 12.8p34, bullet 1).
+///
+/// \param Ctx The context in which the return expression and type occur.
+///
+/// \param RetType The return type of the function or block.
+///
+/// \param RetExpr The expression being returned from the function or block.
+///
+/// \returns The NRVO candidate variable, if the return statement may use the
+/// NRVO, or NULL if there is no such candidate.
+static const VarDecl *getNRVOCandidate(ASTContext &Ctx, QualType RetType,
+ Expr *RetExpr) {
+ QualType ExprType = RetExpr->getType();
+ // - in a return statement in a function with ...
+ // ... a class return type ...
+ if (!RetType->isRecordType())
+ return 0;
+ // ... the same cv-unqualified type as the function return type ...
+ if (!Ctx.hasSameUnqualifiedType(RetType, ExprType))
+ return 0;
+ // ... the expression is the name of a non-volatile automatic object ...
+ // We ignore parentheses here.
+ // FIXME: Is this compliant? (Everyone else does it)
+ const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens());
+ if (!DR)
+ return 0;
+ const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
+ if (!VD)
+ return 0;
+
+ if (VD->getKind() == Decl::Var && VD->hasLocalStorage() &&
+ !VD->getType()->isReferenceType() && !VD->hasAttr<BlocksAttr>() &&
+ !VD->getType().isVolatileQualified())
+ return VD;
+
+ return 0;
+}
+
/// ActOnBlockReturnStmt - Utility routine to figure out block's return type.
///
Action::OwningStmtResult
@@ -1102,68 +1182,58 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// Otherwise, verify that this result type matches the previous one. We are
// pickier with blocks than for normal functions because we don't have GCC
// compatibility to worry about here.
+ ReturnStmt *Result = 0;
if (CurBlock->ReturnType->isVoidType()) {
if (RetValExp) {
Diag(ReturnLoc, diag::err_return_block_has_expr);
RetValExp->Destroy(Context);
RetValExp = 0;
}
- return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
- }
-
- if (!RetValExp)
+ Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
+ } else if (!RetValExp) {
return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
+ } else {
+ const VarDecl *NRVOCandidate = 0;
+
+ if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
+ // we have a non-void block with an expression, continue checking
+
+ // 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.
+ // the C version of which boils down to CheckSingleAssignmentConstraints.
+ NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp);
+ OwningExprResult Res = PerformCopyInitialization(
+ InitializedEntity::InitializeResult(ReturnLoc,
+ FnRetType,
+ NRVOCandidate != 0),
+ SourceLocation(),
+ Owned(RetValExp));
+ if (Res.isInvalid()) {
+ // FIXME: Cleanup temporaries here, anyway?
+ return StmtError();
+ }
+
+ if (RetValExp)
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
- if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
- // we have a non-void block 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
- // function return.
-
- // In C++ the return statement is handled via a copy initialization.
- // the C version of which boils down to CheckSingleAssignmentConstraints.
- OwningExprResult Res = PerformCopyInitialization(
- InitializedEntity::InitializeResult(ReturnLoc,
- FnRetType),
- SourceLocation(),
- Owned(RetValExp));
- if (Res.isInvalid()) {
- // FIXME: Cleanup temporaries here, anyway?
- return StmtError();
+ RetValExp = Res.takeAs<Expr>();
+ if (RetValExp)
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
- RetValExp = Res.takeAs<Expr>();
- if (RetValExp)
- CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate);
}
- return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
-}
-
-/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that
-/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p15).
-static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
- Expr *RetExpr) {
- QualType ExprType = RetExpr->getType();
- // - in a return statement in a function with ...
- // ... a class return type ...
- if (!RetType->isRecordType())
- return false;
- // ... the same cv-unqualified type as the function return type ...
- if (!Ctx.hasSameUnqualifiedType(RetType, ExprType))
- return false;
- // ... the expression is the name of a non-volatile automatic object ...
- // We ignore parentheses here.
- // FIXME: Is this compliant?
- const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens());
- if (!DR)
- return false;
- const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
- if (!VD)
- return false;
- return VD->hasLocalStorage() && !VD->getType()->isReferenceType()
- && !VD->getType().isVolatileQualified();
+ // If we need to check for the named return value optimization, save the
+ // return statement in our scope for later processing.
+ if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
+ !CurContext->isDependentContext())
+ FunctionScopes.back()->Returns.push_back(Result);
+
+ return Owned(Result);
}
Action::OwningStmtResult
@@ -1184,6 +1254,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
else // If we don't have a function/method context, bail.
return StmtError();
+ ReturnStmt *Result = 0;
if (FnRetType->isVoidType()) {
if (RetValExp && !RetValExp->isTypeDependent()) {
// C99 6.8.6.4p1 (ext_ since GCC warns)
@@ -1202,10 +1273,9 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
}
- return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
- }
-
- if (!RetValExp && !FnRetType->isDependentType()) {
+
+ Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
+ } else if (!RetValExp && !FnRetType->isDependentType()) {
unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4
// C99 6.8.6.4p1 (ext_ since GCC warns)
if (getLangOptions().C99) DiagID = diag::ext_return_missing_expr;
@@ -1214,54 +1284,47 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
else
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
- return Owned(new (Context) ReturnStmt(ReturnLoc, (Expr*)0));
- }
+ Result = new (Context) ReturnStmt(ReturnLoc);
+ } else {
+ const VarDecl *NRVOCandidate = 0;
+ 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
+ // function return.
+
+ // In C++ the return statement is handled via a copy initialization.
+ // the C version of which boils down to CheckSingleAssignmentConstraints.
+ NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp);
+ OwningExprResult Res = PerformCopyInitialization(
+ InitializedEntity::InitializeResult(ReturnLoc,
+ FnRetType,
+ NRVOCandidate != 0),
+ SourceLocation(),
+ Owned(RetValExp));
+ if (Res.isInvalid()) {
+ // FIXME: Cleanup temporaries here, anyway?
+ return StmtError();
+ }
- 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
- // function return.
-
- // C++0x 12.8p15: When certain criteria are met, an implementation is
- // allowed to omit the copy construction of a class object, [...]
- // - in a return statement in a function with a class return type, when
- // the expression is the name of a non-volatile automatic object with
- // the same cv-unqualified type as the function return type, the copy
- // operation can be omitted [...]
- // C++0x 12.8p16: When the criteria for elision of a copy operation are met
- // and the object to be copied is designated by an lvalue, overload
- // resolution to select the constructor for the copy is first performed
- // as if the object were designated by an rvalue.
- // Note that we only compute Elidable if we're in C++0x, since we don't
- // care otherwise.
- bool Elidable = getLangOptions().CPlusPlus0x ?
- IsReturnCopyElidable(Context, FnRetType, RetValExp) :
- false;
- // FIXME: Elidable
- (void)Elidable;
-
- // In C++ the return statement is handled via a copy initialization.
- // the C version of which boils down to CheckSingleAssignmentConstraints.
- OwningExprResult Res = PerformCopyInitialization(
- InitializedEntity::InitializeResult(ReturnLoc,
- FnRetType),
- SourceLocation(),
- Owned(RetValExp));
- if (Res.isInvalid()) {
- // FIXME: Cleanup temporaries here, anyway?
- return StmtError();
+ RetValExp = Res.takeAs<Expr>();
+ if (RetValExp)
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
-
- RetValExp = Res.takeAs<Expr>();
- if (RetValExp)
- CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+
+ if (RetValExp)
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
+ Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate);
}
-
- if (RetValExp)
- RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
- return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
+
+ // If we need to check for the named return value optimization, save the
+ // return statement in our scope for later processing.
+ if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
+ !CurContext->isDependentContext())
+ FunctionScopes.back()->Returns.push_back(Result);
+
+ return Owned(Result);
}
/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 694b21c..307be9d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -100,10 +100,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
UnqualifiedId &Name,
TypeTy *ObjectTypePtr,
bool EnteringContext,
- TemplateTy &TemplateResult) {
+ TemplateTy &TemplateResult,
+ bool &MemberOfUnknownSpecialization) {
assert(getLangOptions().CPlusPlus && "No template names in C!");
DeclarationName TName;
+ MemberOfUnknownSpecialization = false;
switch (Name.getKind()) {
case UnqualifiedId::IK_Identifier:
@@ -128,7 +130,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
LookupResult R(*this, TName, Name.getSourceRange().getBegin(),
LookupOrdinaryName);
R.suppressDiagnostics();
- LookupTemplateName(R, S, SS, ObjectType, EnteringContext);
+ LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
+ MemberOfUnknownSpecialization);
if (R.empty() || R.isAmbiguous())
return TNK_Non_template;
@@ -172,6 +175,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
TemplateNameKind &SuggestedKind) {
// We can't recover unless there's a dependent scope specifier preceding the
// template name.
+ // FIXME: Typo correction?
if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) ||
computeDeclContext(*SS))
return false;
@@ -191,8 +195,10 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
void Sema::LookupTemplateName(LookupResult &Found,
Scope *S, CXXScopeSpec &SS,
QualType ObjectType,
- bool EnteringContext) {
+ bool EnteringContext,
+ bool &MemberOfUnknownSpecialization) {
// Determine where to perform name lookup
+ MemberOfUnknownSpecialization = false;
DeclContext *LookupCtx = 0;
bool isDependent = false;
if (!ObjectType.isNull()) {
@@ -241,6 +247,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
} else if (isDependent) {
// We cannot look into a dependent object type or nested nme
// specifier.
+ MemberOfUnknownSpecialization = true;
return;
} else {
// Perform unqualified name lookup in the current scope.
@@ -330,11 +337,13 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
const TemplateArgumentListInfo *TemplateArgs) {
NestedNameSpecifier *Qualifier
= static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+
+ DeclContext *DC = getFunctionLevelDeclContext();
if (!isAddressOfOperand &&
- isa<CXXMethodDecl>(CurContext) &&
- cast<CXXMethodDecl>(CurContext)->isInstance()) {
- QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context);
+ isa<CXXMethodDecl>(DC) &&
+ cast<CXXMethodDecl>(DC)->isInstance()) {
+ QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context);
// Since the 'this' expression is synthesized, we don't need to
// perform the double-lookup check.
@@ -525,6 +534,14 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
/// otherwise, produces a diagnostic and returns a NULL type.
QualType
Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
+ // We don't allow variably-modified types as the type of non-type template
+ // parameters.
+ if (T->isVariablyModifiedType()) {
+ Diag(Loc, diag::err_variably_modified_nontype_template_param)
+ << T;
+ return QualType();
+ }
+
// C++ [temp.param]p4:
//
// A non-type template-parameter shall have one of the following
@@ -555,7 +572,7 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
else if (T->isFunctionType())
// FIXME: Keep the type prior to promotion?
return Context.getPointerType(T);
-
+
Diag(Loc, diag::err_template_nontype_parm_bad_type)
<< T;
@@ -739,8 +756,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (CheckTemplateDeclScope(S, TemplateParams))
return true;
- TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
- assert(Kind != TagDecl::TK_enum && "can't build template of enumerated type");
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+ assert(Kind != TTK_Enum && "can't build template of enumerated type");
// There is no such thing as an unnamed class template.
if (!Name) {
@@ -1088,7 +1105,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
DiagnoseDefaultTemplateArgument(*this, TPC,
NewTypeParm->getLocation(),
NewTypeParm->getDefaultArgumentInfo()->getTypeLoc()
- .getFullSourceRange()))
+ .getSourceRange()))
NewTypeParm->removeDefaultArgument();
// Merge default arguments for template type parameters.
@@ -1506,10 +1523,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// specialization. Create the canonical declaration and add it to
// the set of specializations.
Decl = ClassTemplateSpecializationDecl::Create(Context,
- ClassTemplate->getDeclContext(),
- ClassTemplate->getLocation(),
- ClassTemplate,
- Converted, 0);
+ ClassTemplate->getTemplatedDecl()->getTagKind(),
+ ClassTemplate->getDeclContext(),
+ ClassTemplate->getLocation(),
+ ClassTemplate,
+ Converted, 0);
ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
Decl->setLexicalDeclContext(CurContext);
}
@@ -1567,7 +1585,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult,
QualType Type = GetTypeFromParser(TypeResult.get(), &DI);
// Verify the tag specifier.
- TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
+ TagTypeKind TagKind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
if (const RecordType *RT = Type->getAs<RecordType>()) {
RecordDecl *D = RT->getDecl();
@@ -1583,7 +1601,9 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult,
}
}
- QualType ElabType = Context.getElaboratedType(Type, TagKind);
+ ElaboratedTypeKeyword Keyword
+ = TypeWithKeyword::getKeywordForTagTypeKind(TagKind);
+ QualType ElabType = Context.getElaboratedType(Keyword, /*NNS=*/0, Type);
return ElabType.getAsOpaquePtr();
}
@@ -1618,8 +1638,8 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
= UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(),
Qualifier, QualifierRange,
R.getLookupName(), R.getNameLoc(),
- RequiresADL, TemplateArgs);
- ULE->addDecls(R.begin(), R.end());
+ RequiresADL, TemplateArgs,
+ R.begin(), R.end());
return Owned(ULE);
}
@@ -1636,8 +1656,10 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
RequireCompleteDeclContext(SS, DC))
return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs);
+ bool MemberOfUnknownSpecialization;
LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
- LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false);
+ LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false,
+ MemberOfUnknownSpecialization);
if (R.isAmbiguous())
return ExprError();
@@ -1694,8 +1716,10 @@ 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;
+ bool MemberOfUnknownSpecialization;
TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
- EnteringContext, Template);
+ EnteringContext, Template,
+ MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template && LookupCtx->isDependentContext() &&
isa<CXXRecordDecl>(LookupCtx) &&
cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) {
@@ -1704,7 +1728,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
Diag(Name.getSourceRange().getBegin(),
diag::err_template_kw_refers_to_non_template)
<< GetNameFromUnqualifiedId(Name)
- << Name.getSourceRange();
+ << Name.getSourceRange()
+ << TemplateKWLoc;
return TemplateTy();
} else {
// We found something; return it.
@@ -1734,7 +1759,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
Diag(Name.getSourceRange().getBegin(),
diag::err_template_kw_refers_to_non_template)
<< GetNameFromUnqualifiedId(Name)
- << Name.getSourceRange();
+ << Name.getSourceRange()
+ << TemplateKWLoc;
return TemplateTy();
}
@@ -2336,24 +2362,27 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
// compounded from any of these types shall not be used as a
// template-argument for a template type-parameter.
//
- // FIXME: Perform the recursive and no-linkage type checks.
+ // FIXME: Perform the unnamed type check.
+ SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
const TagType *Tag = 0;
if (const EnumType *EnumT = Arg->getAs<EnumType>())
Tag = EnumT;
else if (const RecordType *RecordT = Arg->getAs<RecordType>())
Tag = RecordT;
if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) {
- SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange();
+ SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
return Diag(SR.getBegin(), diag::err_template_arg_local_type)
<< QualType(Tag, 0) << SR;
} else if (Tag && !Tag->getDecl()->getDeclName() &&
!Tag->getDecl()->getTypedefForAnonDecl()) {
- SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange();
Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR;
Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
return true;
+ } else if (Arg->isVariablyModifiedType()) {
+ Diag(SR.getBegin(), diag::err_variably_modified_template_arg)
+ << Arg;
+ return true;
} else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) {
- SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange();
return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR;
}
@@ -3661,13 +3690,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Check that the specialization uses the same tag kind as the
// original template.
- 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;
- }
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+ assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!");
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
Kind, KWLoc,
*ClassTemplate->getIdentifier())) {
@@ -3796,7 +3820,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber()
: ClassTemplate->getPartialSpecializations().size();
ClassTemplatePartialSpecializationDecl *Partial
- = ClassTemplatePartialSpecializationDecl::Create(Context,
+ = ClassTemplatePartialSpecializationDecl::Create(Context, Kind,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
TemplateParams,
@@ -3857,7 +3881,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Create a new class template specialization declaration node for
// this explicit specialization or friend declaration.
Specialization
- = ClassTemplateSpecializationDecl::Create(Context,
+ = ClassTemplateSpecializationDecl::Create(Context, Kind,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
@@ -4217,10 +4241,10 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
return false;
}
-/// \brief Perform semantic analysis for the given function template
+/// \brief Perform semantic analysis for the given function template
/// specialization.
///
-/// This routine performs all of the semantic analysis required for an
+/// 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.
@@ -4228,24 +4252,14 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
/// \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 ExplicitTemplateArgs the explicitly-provided template arguments,
+/// if any. Note that this may be valid info even when 0 arguments are
+/// explicitly provided as in, e.g., \c void sort<>(char*, char*);
+/// as it anyway contains info on the angle brackets locations.
///
-/// \param RAngleLoc the location of the right angle bracket ('>'), if
-/// template arguments were explicitly provided.
-///
-/// \param PrevDecl the set of declarations that
-bool
+/// \param PrevDecl the set of declarations that may be specialized by
+/// this function specialization.
+bool
Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous) {
@@ -4347,12 +4361,16 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Turn the given function declaration into a function template
// specialization, with the template arguments from the previous
// specialization.
+ // Take copies of (semantic and syntactic) template argument lists.
+ const TemplateArgumentList* TemplArgs = new (Context)
+ TemplateArgumentList(Specialization->getTemplateSpecializationArgs());
+ const TemplateArgumentListInfo* TemplArgsAsWritten = ExplicitTemplateArgs
+ ? new (Context) TemplateArgumentListInfo(*ExplicitTemplateArgs) : 0;
FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(),
- new (Context) TemplateArgumentList(
- *Specialization->getTemplateSpecializationArgs()),
- /*InsertPos=*/0,
- SpecInfo->getTemplateSpecializationKind());
-
+ TemplArgs, /*InsertPos=*/0,
+ SpecInfo->getTemplateSpecializationKind(),
+ TemplArgsAsWritten);
+
// The "previous declaration" for this function template specialization is
// the prior function template specialization.
Previous.clear();
@@ -4541,10 +4559,16 @@ static void CheckExplicitInstantiationScope(Sema &S, NamedDecl *D,
if (S.getLangOptions().CPlusPlus0x &&
!CurContext->Encloses(ExpectedContext)) {
if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ExpectedContext))
- S.Diag(InstLoc, diag::err_explicit_instantiation_out_of_scope)
+ S.Diag(InstLoc,
+ S.getLangOptions().CPlusPlus0x?
+ diag::err_explicit_instantiation_out_of_scope
+ : diag::warn_explicit_instantiation_out_of_scope_0x)
<< D << NS;
else
- S.Diag(InstLoc, diag::err_explicit_instantiation_must_be_global)
+ S.Diag(InstLoc,
+ S.getLangOptions().CPlusPlus0x?
+ diag::err_explicit_instantiation_must_be_global
+ : diag::warn_explicit_instantiation_out_of_scope_0x)
<< D;
S.Diag(D->getLocation(), diag::note_explicit_instantiation_here);
return;
@@ -4561,7 +4585,10 @@ static void CheckExplicitInstantiationScope(Sema &S, NamedDecl *D,
if (CurContext->Equals(ExpectedContext))
return;
- S.Diag(InstLoc, diag::err_explicit_instantiation_unqualified_wrong_namespace)
+ S.Diag(InstLoc,
+ S.getLangOptions().CPlusPlus0x?
+ diag::err_explicit_instantiation_unqualified_wrong_namespace
+ : diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x)
<< D << ExpectedContext;
S.Diag(D->getLocation(), diag::note_explicit_instantiation_here);
}
@@ -4588,7 +4615,6 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) {
}
// Explicit instantiation of a class template specialization
-// FIXME: Implement extern template semantics
Sema::DeclResult
Sema::ActOnExplicitInstantiation(Scope *S,
SourceLocation ExternLoc,
@@ -4609,13 +4635,9 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Check that the specialization uses the same tag kind as the
// original template.
- 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;
- }
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+ assert(Kind != TTK_Enum &&
+ "Invalid enum tag in class template explicit instantiation!");
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
Kind, KWLoc,
*ClassTemplate->getIdentifier())) {
@@ -4703,7 +4725,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Create a new class template specialization declaration node for
// this explicit specialization.
Specialization
- = ClassTemplateSpecializationDecl::Create(Context,
+ = ClassTemplateSpecializationDecl::Create(Context, Kind,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
@@ -4755,7 +4777,9 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Specialization->getDefinition());
if (!Def)
InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
-
+ else if (TSK == TSK_ExplicitInstantiationDefinition)
+ MarkVTableUsed(TemplateNameLoc, Specialization, true);
+
// Instantiate the members of this class template specialization.
Def = cast_or_null<ClassTemplateSpecializationDecl>(
Specialization->getDefinition());
@@ -4890,6 +4914,9 @@ Sema::ActOnExplicitInstantiation(Scope *S,
InstantiateClassMembers(NameLoc, RecordDef,
getTemplateInstantiationArgs(Record), TSK);
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ MarkVTableUsed(NameLoc, RecordDef, true);
+
// FIXME: We don't have any representation for explicit instantiations of
// member classes. Such a representation is not needed for compilation, but it
// should be available for clients that want to see all of the declarations in
@@ -5161,37 +5188,33 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!NNS)
return true;
- ElaboratedTypeKeyword Keyword = ETK_None;
- switch (TagDecl::getTagKindForTypeSpec(TagSpec)) {
- case TagDecl::TK_struct: Keyword = ETK_Struct; break;
- case TagDecl::TK_class: Keyword = ETK_Class; break;
- case TagDecl::TK_union: Keyword = ETK_Union; break;
- case TagDecl::TK_enum: Keyword = ETK_Enum; break;
- }
- assert(Keyword != ETK_None && "Invalid tag kind!");
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
if (TUK == TUK_Declaration || TUK == TUK_Definition) {
Diag(NameLoc, diag::err_dependent_tag_decl)
- << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec)
- << SS.getRange();
+ << (TUK == TUK_Definition) << Kind << SS.getRange();
return true;
}
-
- return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
+
+ ElaboratedTypeKeyword Kwd = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
+ return Context.getDependentNameType(Kwd, NNS, Name).getAsOpaquePtr();
}
static void FillTypeLoc(DependentNameTypeLoc TL,
SourceLocation TypenameLoc,
- SourceRange QualifierRange) {
- // FIXME: typename, qualifier range
- TL.setNameLoc(TypenameLoc);
+ SourceRange QualifierRange,
+ SourceLocation NameLoc) {
+ TL.setKeywordLoc(TypenameLoc);
+ TL.setQualifierRange(QualifierRange);
+ TL.setNameLoc(NameLoc);
}
-static void FillTypeLoc(QualifiedNameTypeLoc TL,
+static void FillTypeLoc(ElaboratedTypeLoc TL,
SourceLocation TypenameLoc,
SourceRange QualifierRange) {
- // FIXME: typename, qualifier range
- TL.setNameLoc(TypenameLoc);
+ // FIXME: inner locations.
+ TL.setKeywordLoc(TypenameLoc);
+ TL.setQualifierRange(QualifierRange);
}
Sema::TypeResult
@@ -5203,7 +5226,7 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
return true;
QualType T = CheckTypenameType(ETK_Typename, NNS, II,
- SourceRange(TypenameLoc, IdLoc));
+ TypenameLoc, SS.getRange(), IdLoc);
if (T.isNull())
return true;
@@ -5211,9 +5234,9 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
if (isa<DependentNameType>(T)) {
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
// FIXME: fill inner type loc
- FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ FillTypeLoc(TL, TypenameLoc, SS.getRange(), IdLoc);
} else {
- QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+ ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
// FIXME: fill inner type loc
FillTypeLoc(TL, TypenameLoc, SS.getRange());
}
@@ -5233,14 +5256,11 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
if (computeDeclContext(SS, false)) {
// If we can compute a declaration context, then the "typename"
- // keyword was superfluous. Just build a QualifiedNameType to keep
+ // keyword was superfluous. Just build an ElaboratedType to keep
// track of the nested-name-specifier.
-
- // FIXME: Note that the QualifiedNameType had the "typename" keyword!
-
- T = Context.getQualifiedNameType(NNS, T);
+ T = Context.getElaboratedType(ETK_Typename, NNS, T);
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
- QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+ ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
// FIXME: fill inner type loc
FillTypeLoc(TL, TypenameLoc, SS.getRange());
return CreateLocInfoType(T, TSI).getAsOpaquePtr();
@@ -5250,7 +5270,7 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
// FIXME: fill inner type loc
- FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ FillTypeLoc(TL, TypenameLoc, SS.getRange(), TemplateLoc);
return CreateLocInfoType(T, TSI).getAsOpaquePtr();
}
@@ -5259,10 +5279,11 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
QualType
Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS, const IdentifierInfo &II,
- SourceRange Range) {
+ SourceLocation KeywordLoc, SourceRange NNSRange,
+ SourceLocation IILoc) {
CXXScopeSpec SS;
SS.setScopeRep(NNS);
- SS.setRange(Range);
+ SS.setRange(NNSRange);
DeclContext *Ctx = computeDeclContext(SS);
if (!Ctx) {
@@ -5282,7 +5303,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
return QualType();
DeclarationName Name(&II);
- LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName);
+ LookupResult Result(*this, Name, IILoc, LookupOrdinaryName);
LookupQualifiedName(Result, Ctx);
unsigned DiagID = 0;
Decl *Referenced = 0;
@@ -5297,10 +5318,10 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
case LookupResult::Found:
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.
- return Context.getQualifiedNameType(NNS, Context.getTypeDeclType(Type));
+ // We found a type. Build an ElaboratedType, since the
+ // typename-specifier was just sugar.
+ return Context.getElaboratedType(ETK_Typename, NNS,
+ Context.getTypeDeclType(Type));
}
DiagID = diag::err_typename_nested_not_type;
@@ -5322,7 +5343,9 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// If we get here, it's because name lookup did not find a
// type. Emit an appropriate diagnostic and return an error.
- Diag(Range.getEnd(), DiagID) << Range << Name << Ctx;
+ SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : NNSRange.getBegin(),
+ IILoc);
+ Diag(IILoc, DiagID) << FullRange << Name << Ctx;
if (Referenced)
Diag(Referenced->getLocation(), diag::note_typename_refers_here)
<< Name;
@@ -5379,9 +5402,10 @@ namespace {
/// \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 TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL,
- QualType ObjectType);
+ /// type-checking and building an ElaboratedType (when possible).
+ QualType TransformDependentNameType(TypeLocBuilder &TLB,
+ DependentNameTypeLoc TL,
+ QualType ObjectType);
};
}
@@ -5393,7 +5417,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
NestedNameSpecifier *NNS
= TransformNestedNameSpecifier(T->getQualifier(),
- /*FIXME:*/SourceRange(getBaseLocation()),
+ TL.getQualifierRange(),
ObjectType);
if (!NNS)
return QualType();
@@ -5402,7 +5426,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
// context corresponding to the nested-name-specifier, then this
// typename type will not change; exit early.
CXXScopeSpec SS;
- SS.setRange(SourceRange(getBaseLocation()));
+ SS.setRange(TL.getQualifierRange());
SS.setScopeRep(NNS);
QualType Result;
@@ -5410,7 +5434,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
Result = QualType(T, 0);
// Rebuild the typename type, which will probably turn into a
- // QualifiedNameType.
+ // ElaboratedType.
else if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
QualType NewTemplateId
= TransformType(QualType(TemplateId, 0));
@@ -5421,18 +5445,38 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
NewTemplateId == QualType(TemplateId, 0))
Result = QualType(T, 0);
else
- Result = getDerived().RebuildDependentNameType(T->getKeyword(),
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(),
NNS, NewTemplateId);
} else
- Result = getDerived().RebuildDependentNameType(T->getKeyword(),
- NNS, T->getIdentifier(),
- SourceRange(TL.getNameLoc()));
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ T->getIdentifier(),
+ TL.getKeywordLoc(),
+ TL.getQualifierRange(),
+ TL.getNameLoc());
if (Result.isNull())
return QualType();
- DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ if (const ElaboratedType* ElabT = Result->getAs<ElaboratedType>()) {
+ QualType NamedT = ElabT->getNamedType();
+ if (isa<TemplateSpecializationType>(NamedT)) {
+ TemplateSpecializationTypeLoc NamedTLoc
+ = TLB.push<TemplateSpecializationTypeLoc>(NamedT);
+ // FIXME: fill locations
+ NamedTLoc.initializeLocal(TL.getNameLoc());
+ } else {
+ TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc());
+ }
+ ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setQualifierRange(TL.getQualifierRange());
+ }
+ else {
+ DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setQualifierRange(TL.getQualifierRange());
+ NewTL.setNameLoc(TL.getNameLoc());
+ }
return Result;
}
@@ -5459,7 +5503,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
/// Here, the type "typename X<T>::pointer" will be created as a DependentNameType,
/// 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
+/// in X<T> and returning an ElaboratedType 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.
TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 2bb97eb..88ceeca 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -482,14 +482,20 @@ DeduceTemplateArguments(Sema &S,
// T *
case Type::Pointer: {
- const PointerType *PointerArg = Arg->getAs<PointerType>();
- if (!PointerArg)
+ QualType PointeeType;
+ if (const PointerType *PointerArg = Arg->getAs<PointerType>()) {
+ PointeeType = PointerArg->getPointeeType();
+ } else if (const ObjCObjectPointerType *PointerArg
+ = Arg->getAs<ObjCObjectPointerType>()) {
+ PointeeType = PointerArg->getPointeeType();
+ } else {
return Sema::TDK_NonDeducedMismatch;
+ }
unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
return DeduceTemplateArguments(S, TemplateParams,
cast<PointerType>(Param)->getPointeeType(),
- PointerArg->getPointeeType(),
+ PointeeType,
Info, Deduced, SubTDF);
}
@@ -1030,10 +1036,8 @@ FinishTemplateArgumentDeduction(Sema &S,
ClassTemplate->getTemplateParameters(), N);
if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
- InstArgs, false, ConvertedInstArgs)) {
- // FIXME: fail with more useful information?
+ InstArgs, false, ConvertedInstArgs))
return Sema::TDK_SubstitutionFailure;
- }
for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) {
TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I];
@@ -1190,8 +1194,13 @@ Sema::SubstituteExplicitTemplateArguments(
SourceLocation(),
ExplicitTemplateArgs,
true,
- Builder) || Trap.hasErrorOccurred())
+ Builder) || Trap.hasErrorOccurred()) {
+ unsigned Index = Builder.structuredSize();
+ if (Index >= TemplateParams->size())
+ Index = TemplateParams->size() - 1;
+ Info.Param = makeTemplateParameter(TemplateParams->getParam(Index));
return TDK_InvalidExplicitArguments;
+ }
// Form the template argument list from the explicitly-specified
// template arguments.
@@ -1374,6 +1383,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
NTTP->getDeclName());
if (NTTPType.isNull()) {
Info.Param = makeTemplateParameter(Param);
+ Info.reset(new (Context) TemplateArgumentList(Context, Builder,
+ /*TakeArgs=*/true));
return TDK_SubstitutionFailure;
}
}
@@ -1399,6 +1410,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
: CTAK_Deduced)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+ Info.reset(new (Context) TemplateArgumentList(Context, Builder,
+ /*TakeArgs=*/true));
return TDK_SubstitutionFailure;
}
@@ -1429,6 +1442,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
CTAK_Deduced)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+ Info.reset(new (Context) TemplateArgumentList(Context, Builder,
+ /*TakeArgs=*/true));
return TDK_SubstitutionFailure;
}
@@ -1456,7 +1471,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// If the template argument list is owned by the function template
// specialization, release it.
- if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList)
+ if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList &&
+ !Trap.hasErrorOccurred())
Info.take();
// There may have been an error that did not prevent us from constructing a
@@ -2636,6 +2652,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
case Type::Record:
case Type::Enum:
case Type::ObjCInterface:
+ case Type::ObjCObject:
case Type::ObjCObjectPointer:
case Type::UnresolvedUsing:
#define TYPE(Class, Base)
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 14bd243..1adf594 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -560,9 +560,7 @@ namespace {
///
/// 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();
- }
+ bool AlreadyTransformed(QualType T);
/// \brief Returns the location of the entity being instantiated, if known.
SourceLocation getBaseLocation() { return Loc; }
@@ -603,7 +601,8 @@ namespace {
/// \brief Check for tag mismatches when instantiating an
/// elaborated type.
- QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag);
+ QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, QualType T);
Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
@@ -624,6 +623,17 @@ namespace {
};
}
+bool TemplateInstantiator::AlreadyTransformed(QualType T) {
+ if (T.isNull())
+ return true;
+
+ if (T->isDependentType() || T->isVariablyModifiedType())
+ return false;
+
+ getSema().MarkDeclarationsReferencedInType(Loc, T);
+ return true;
+}
+
Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
if (!D)
return 0;
@@ -710,8 +720,9 @@ VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
}
QualType
-TemplateInstantiator::RebuildElaboratedType(QualType T,
- ElaboratedType::TagKind Tag) {
+TemplateInstantiator::RebuildElaboratedType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ QualType T) {
if (const TagType *TT = T->getAs<TagType>()) {
TagDecl* TD = TT->getDecl();
@@ -723,16 +734,20 @@ TemplateInstantiator::RebuildElaboratedType(QualType T,
// 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
- << FixItHint::CreateReplacement(SourceRange(TagLocation),
- TD->getKindName());
- SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
+ if (Keyword != ETK_None && Keyword != ETK_Typename) {
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
+ if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, TagLocation, *Id)) {
+ SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
+ << Id
+ << FixItHint::CreateReplacement(SourceRange(TagLocation),
+ TD->getKindName());
+ SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
+ }
}
}
- return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag);
+ return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(Keyword,
+ NNS, T);
}
Sema::OwningExprResult
@@ -927,7 +942,8 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
"Cannot perform an instantiation without some context on the "
"instantiation stack");
- if (!T->getType()->isDependentType())
+ if (!T->getType()->isDependentType() &&
+ !T->getType()->isVariablyModifiedType())
return T;
TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
@@ -942,8 +958,9 @@ QualType Sema::SubstType(QualType T,
"Cannot perform an instantiation without some context on the "
"instantiation stack");
- // If T is not a dependent type, there is nothing to do.
- if (!T->isDependentType())
+ // If T is not a dependent type or a variably-modified type, there
+ // is nothing to do.
+ if (!T->isDependentType() && !T->isVariablyModifiedType())
return T;
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
@@ -951,7 +968,7 @@ QualType Sema::SubstType(QualType T,
}
static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
- if (T->getType()->isDependentType())
+ if (T->getType()->isDependentType() || T->getType()->isVariablyModifiedType())
return true;
TypeLoc TL = T->getTypeLoc();
@@ -1160,6 +1177,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII SavedContext(*this, Instantiation);
+ EnterExpressionEvaluationContext EvalContext(*this,
+ Action::PotentiallyEvaluated);
// If this is an instantiation of a local class, merge this local
// instantiation scope with the enclosing scope. Otherwise, every
@@ -1169,6 +1188,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Start the definition of this instantiation.
Instantiation->startDefinition();
+
+ Instantiation->setTagKind(Pattern->getTagKind());
// Do substitution on the base class specifiers.
if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
@@ -1202,25 +1223,15 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Exit the scope of this instantiation.
SavedContext.pop();
- // If this is a polymorphic C++ class without a key function, we'll
- // have to mark all of the virtual members to allow emission of a vtable
- // in this translation unit.
- if (Instantiation->isDynamicClass() &&
- !Context.getKeyFunction(Instantiation)) {
- // Local classes need to have their methods instantiated immediately in
- // order to have the correct instantiation scope.
- if (Instantiation->isLocalClass()) {
- MarkVirtualMembersReferenced(PointOfInstantiation,
- Instantiation);
- } else {
- ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation,
- PointOfInstantiation));
- }
- }
-
- if (!Invalid)
+ if (!Invalid) {
Consumer.HandleTagDeclDefinition(Instantiation);
+ // Always emit the vtable for an explicit instantiation definition
+ // of a polymorphic class template specialization.
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ MarkVTableUsed(PointOfInstantiation, Instantiation, true);
+ }
+
return Invalid;
}
@@ -1244,6 +1255,12 @@ Sema::InstantiateClassTemplateSpecialization(
// declaration (C++0x [temp.explicit]p10); go ahead and perform the
// explicit instantiation.
ClassTemplateSpec->setSpecializationKind(TSK);
+
+ // If this is an explicit instantiation definition, mark the
+ // vtable as used.
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ MarkVTableUsed(PointOfInstantiation, ClassTemplateSpec, true);
+
return false;
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index da84806..834b86d 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -184,13 +184,16 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
- if (DI->getType()->isDependentType()) {
+ if (DI->getType()->isDependentType() ||
+ DI->getType()->isVariablyModifiedType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI) {
Invalid = true;
DI = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.Context.IntTy);
}
+ } else {
+ SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
}
// Create the new typedef
@@ -215,6 +218,7 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev));
}
+ InstantiateAttrs(D, Typedef);
Typedef->setAccess(D->getAccess());
Owner->addDecl(Typedef);
@@ -320,6 +324,13 @@ static bool InstantiateInitializer(Sema &S, Expr *Init,
}
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
+ // If this is the variable for an anonymous struct or union,
+ // instantiate the anonymous struct/union type first.
+ if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
+ if (RecordTy->getDecl()->isAnonymousStructOrUnion())
+ if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
+ return 0;
+
// Do substitution on the type of the declaration
TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
TemplateArgs,
@@ -349,7 +360,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Var->setLexicalDeclContext(D->getLexicalDeclContext());
Var->setAccess(D->getAccess());
-
+ Var->setUsed(D->isUsed());
+
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
bool Redeclaration = false;
@@ -417,13 +429,18 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
} else if (!Var->isStaticDataMember() || Var->isOutOfLine())
SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
+ // Diagnose unused local variables.
+ if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed())
+ SemaRef.DiagnoseUnusedDecl(Var);
+
return Var;
}
Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
- if (DI->getType()->isDependentType()) {
+ if (DI->getType()->isDependentType() ||
+ DI->getType()->isVariablyModifiedType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI) {
@@ -440,6 +457,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
<< DI->getType();
Invalid = true;
}
+ } else {
+ SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
}
Expr *BitWidth = D->getBitWidth();
@@ -480,6 +499,11 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
if (!Field->getDeclName()) {
// Keep track of where this decl came from.
SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D);
+ }
+ if (CXXRecordDecl *Parent= dyn_cast<CXXRecordDecl>(Field->getDeclContext())) {
+ if (Parent->isAnonymousStructOrUnion() &&
+ Parent->getLookupContext()->isFunctionOrMethod())
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Field);
}
Field->setImplicit(D->isImplicit());
@@ -903,7 +927,12 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (Decl::FriendObjectKind FOK = D->getFriendObjectKind())
Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared);
- Record->setAnonymousStructOrUnion(D->isAnonymousStructOrUnion());
+ // Make sure that anonymous structs and unions are recorded.
+ if (D->isAnonymousStructOrUnion()) {
+ Record->setAnonymousStructOrUnion(true);
+ if (Record->getDeclContext()->getLookupContext()->isFunctionOrMethod())
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record);
+ }
Owner->addDecl(Record);
return Record;
@@ -943,6 +972,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
bool MergeWithParentScope = (TemplateParams != 0) ||
+ Owner->isFunctionOrMethod() ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
@@ -1000,6 +1030,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Params[P]->setOwningFunction(Function);
Function->setParams(Params.data(), Params.size());
+ SourceLocation InstantiateAtPOI;
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
@@ -1118,6 +1149,38 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false);
+
+ if (!SemaRef.getLangOptions().CPlusPlus0x &&
+ D->isThisDeclarationADefinition()) {
+ // Check for a function body.
+ const FunctionDecl *Definition = 0;
+ if (Function->getBody(Definition) &&
+ Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
+ SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
+ << Function->getDeclName();
+ SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
+ Function->setInvalidDecl();
+ }
+ // Check for redefinitions due to other instantiations of this or
+ // a similar friend function.
+ else for (FunctionDecl::redecl_iterator R = Function->redecls_begin(),
+ REnd = Function->redecls_end();
+ R != REnd; ++R) {
+ if (*R != Function &&
+ ((*R)->getFriendObjectKind() != Decl::FOK_None)) {
+ if (const FunctionDecl *RPattern
+ = (*R)->getTemplateInstantiationPattern())
+ if (RPattern->getBody(RPattern)) {
+ SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
+ << Function->getDeclName();
+ SemaRef.Diag((*R)->getLocation(), diag::note_previous_definition);
+ Function->setInvalidDecl();
+ break;
+ }
+ }
+ }
+ }
+
}
if (Function->isOverloadedOperator() && !DC->isRecord() &&
@@ -1761,7 +1824,9 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// Create the class template partial specialization declaration.
ClassTemplatePartialSpecializationDecl *InstPartialSpec
- = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, Owner,
+ = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context,
+ PartialSpec->getTagKind(),
+ Owner,
PartialSpec->getLocation(),
InstParams,
ClassTemplate,
@@ -1946,15 +2011,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive,
bool DefinitionRequired) {
- if (Function->isInvalidDecl())
+ if (Function->isInvalidDecl() || Function->getBody())
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 = Function->getTemplateInstantiationPattern();
Stmt *Pattern = 0;
@@ -1975,6 +2038,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (PatternDecl)
Diag(PatternDecl->getLocation(),
diag::note_explicit_instantiation_here);
+ Function->setInvalidDecl();
}
return;
@@ -2000,6 +2064,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (Recursive)
PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+ EnterExpressionEvaluationContext EvalContext(*this,
+ Action::PotentiallyEvaluated);
ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function));
// Introduce a new scope where local variable instantiations will be
@@ -2644,8 +2710,7 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
Context.getSourceManager(),
"instantiating function definition");
- if (!Function->getBody())
- InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
+ InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
continue;
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index d1a74be..35efa61 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -25,6 +25,8 @@
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
+#include <iostream>
+
/// \brief Perform adjustment on the parameter type of a function.
///
/// This routine adjusts the given parameter type @p T to the actual
@@ -162,9 +164,10 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
case DeclSpec::TST_unspecified:
// "<proto1,proto2>" is an objc qualified ID with a missing id.
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy,
- (ObjCProtocolDecl**)PQ,
- DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
+ (ObjCProtocolDecl**)PQ,
+ DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectPointerType(Result);
break;
}
@@ -283,12 +286,11 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
// In C++, make an ElaboratedType.
if (TheSema.getLangOptions().CPlusPlus) {
- TagDecl::TagKind Tag
- = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType());
- Result = TheSema.getQualifiedNameType(DS.getTypeSpecScope(), Result);
- Result = Context.getElaboratedType(Result, Tag);
+ ElaboratedTypeKeyword Keyword
+ = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType());
+ Result = TheSema.getElaboratedType(Keyword, DS.getTypeSpecScope(),
+ Result);
}
-
if (D->isInvalidDecl())
TheDeclarator.setInvalidType(true);
break;
@@ -300,28 +302,28 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
Result = TheSema.GetTypeFromParser(DS.getTypeRep());
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- 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())
+ if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) {
+ // Silently drop any existing protocol qualifiers.
+ // TODO: determine whether that's the right thing to do.
+ if (ObjT->getNumProtocols())
+ Result = ObjT->getBaseType();
+
+ if (DS.getNumProtocolQualifiers())
+ Result = Context.getObjCObjectType(Result,
+ (ObjCProtocolDecl**) PQ,
+ DS.getNumProtocolQualifiers());
+ } else if (Result->isObjCIdType()) {
// id<protocol-list>
- Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy,
- (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers());
- else if (Result->isObjCClassType()) {
+ Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
+ (ObjCProtocolDecl**) PQ,
+ DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectPointerType(Result);
+ } else if (Result->isObjCClassType()) {
// Class<protocol-list>
- Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy,
- (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy,
+ (ObjCProtocolDecl**) PQ,
+ DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectPointerType(Result);
} else {
TheSema.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers)
<< DS.getSourceRange();
@@ -504,7 +506,7 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals,
Qs.removeRestrict();
}
- assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType");
+ assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
// Build the pointer type.
return Context.getQualifiedType(Context.getPointerType(T), Qs);
@@ -659,7 +661,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
// array, accept it as a GNU extension: C99 6.7.2.1p2.
if (EltTy->getDecl()->hasFlexibleArrayMember())
Diag(Loc, diag::ext_flexible_array_in_array) << T;
- } else if (T->isObjCInterfaceType()) {
+ } else if (T->isObjCObjectType()) {
Diag(Loc, diag::err_objc_array_of_interfaces) << T;
return QualType();
}
@@ -678,7 +680,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
T = Context.getVariableArrayType(T, 0, ASM, Quals, Brackets);
else
T = Context.getIncompleteArrayType(T, ASM, Quals);
- } else if (ArraySize->isValueDependent()) {
+ } else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) {
T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets);
} else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
(!T->isDependentType() && !T->isIncompleteType() &&
@@ -707,11 +709,23 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
}
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
if (!getLangOptions().C99) {
- if (ArraySize && !ArraySize->isTypeDependent() &&
- !ArraySize->isValueDependent() &&
- !ArraySize->isIntegerConstantExpr(Context))
- Diag(Loc, getLangOptions().CPlusPlus? diag::err_vla_cxx : diag::ext_vla);
- else if (ASM != ArrayType::Normal || Quals != 0)
+ if (T->isVariableArrayType()) {
+ // Prohibit the use of non-POD types in VLAs.
+ if (!T->isDependentType() &&
+ !Context.getBaseElementType(T)->isPODType()) {
+ Diag(Loc, diag::err_vla_non_pod)
+ << Context.getBaseElementType(T);
+ return QualType();
+ }
+ // Prohibit the use of VLAs during template argument deduction.
+ else if (isSFINAEContext()) {
+ Diag(Loc, diag::err_vla_in_sfinae);
+ return QualType();
+ }
+ // Just extwarn about VLAs.
+ else
+ Diag(Loc, diag::ext_vla);
+ } else if (ASM != ArrayType::Normal || Quals != 0)
Diag(Loc,
getLangOptions().CPlusPlus? diag::err_c99_array_usage_cxx
: diag::ext_c99_array_usage);
@@ -995,10 +1009,10 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
case Declarator::MemberContext:
switch (cast<TagDecl>(CurContext)->getTagKind()) {
- case TagDecl::TK_enum: assert(0 && "unhandled tag kind"); break;
- 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;
+ case TTK_Enum: assert(0 && "unhandled tag kind"); break;
+ case TTK_Struct: Error = 1; /* Struct member */ break;
+ case TTK_Union: Error = 2; /* Union member */ break;
+ case TTK_Class: Error = 3; /* Class member */ break;
}
break;
case Declarator::CXXCatchContext:
@@ -1056,13 +1070,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
D.setInvalidType(true);
// Build the type anyway.
}
- if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) {
- const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>();
- T = Context.getObjCObjectPointerType(T,
- const_cast<ObjCProtocolDecl **>(
- OIT->qual_begin()),
- OIT->getNumProtocols(),
- DeclType.Ptr.TypeQuals);
+ if (getLangOptions().ObjC1 && T->getAs<ObjCObjectType>()) {
+ T = Context.getObjCObjectPointerType(T);
+ T = Context.getCVRQualifiedType(T, DeclType.Ptr.TypeQuals);
break;
}
T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
@@ -1301,7 +1311,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case NestedNameSpecifier::TypeSpecWithTemplate:
ClsType = QualType(NNS->getAsType(), 0);
if (NNSPrefix)
- ClsType = Context.getQualifiedNameType(NNSPrefix, ClsType);
+ ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType);
break;
}
} else {
@@ -1401,7 +1411,18 @@ namespace {
}
void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ }
+ void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ // Handle the base type, which might not have been written explicitly.
+ if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
+ TL.setHasBaseTypeAsWritten(false);
+ TL.getBaseLoc().initialize(SourceLocation());
+ } else {
+ TL.setHasBaseTypeAsWritten(true);
+ Visit(TL.getBaseLoc());
+ }
+ // Protocol qualifiers.
if (DS.getProtocolQualifiers()) {
assert(TL.getNumProtocols() > 0);
assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
@@ -1416,34 +1437,8 @@ namespace {
}
}
void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
- assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
-
TL.setStarLoc(SourceLocation());
-
- if (DS.getProtocolQualifiers()) {
- assert(TL.getNumProtocols() > 0);
- assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
- TL.setHasProtocolsAsWritten(true);
- TL.setLAngleLoc(DS.getProtocolLAngleLoc());
- TL.setRAngleLoc(DS.getSourceRange().getEnd());
- for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i)
- TL.setProtocolLoc(i, DS.getProtocolLocs()[i]);
-
- } else {
- assert(TL.getNumProtocols() == 0);
- TL.setHasProtocolsAsWritten(false);
- TL.setLAngleLoc(SourceLocation());
- TL.setRAngleLoc(SourceLocation());
- }
-
- // This might not have been written with an inner type.
- if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
- TL.setHasBaseTypeAsWritten(false);
- TL.getBaseTypeLoc().initialize(SourceLocation());
- } else {
- TL.setHasBaseTypeAsWritten(true);
- Visit(TL.getBaseTypeLoc());
- }
+ Visit(TL.getPointeeLoc());
}
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
TypeSourceInfo *TInfo = 0;
@@ -1456,9 +1451,15 @@ namespace {
return;
}
- TemplateSpecializationTypeLoc OldTL =
- cast<TemplateSpecializationTypeLoc>(TInfo->getTypeLoc());
- TL.copy(OldTL);
+ TypeLoc OldTL = TInfo->getTypeLoc();
+ if (TInfo->getType()->getAs<ElaboratedType>()) {
+ ElaboratedTypeLoc ElabTL = cast<ElaboratedTypeLoc>(OldTL);
+ TemplateSpecializationTypeLoc NamedTL =
+ cast<TemplateSpecializationTypeLoc>(ElabTL.getNamedTypeLoc());
+ TL.copy(NamedTL);
+ }
+ else
+ TL.copy(cast<TemplateSpecializationTypeLoc>(OldTL));
}
void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr);
@@ -1489,6 +1490,44 @@ namespace {
TL.setBuiltinLoc(DS.getTypeSpecWidthLoc());
}
}
+ void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ ElaboratedTypeKeyword Keyword
+ = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType());
+ if (Keyword == ETK_Typename) {
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo);
+ if (TInfo) {
+ TL.copy(cast<ElaboratedTypeLoc>(TInfo->getTypeLoc()));
+ return;
+ }
+ }
+ TL.setKeywordLoc(Keyword != ETK_None
+ ? DS.getTypeSpecTypeLoc()
+ : SourceLocation());
+ const CXXScopeSpec& SS = DS.getTypeSpecScope();
+ TL.setQualifierRange(SS.isEmpty() ? SourceRange(): SS.getRange());
+ Visit(TL.getNextTypeLoc().getUnqualifiedLoc());
+ }
+ void VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ ElaboratedTypeKeyword Keyword
+ = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType());
+ if (Keyword == ETK_Typename) {
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo);
+ if (TInfo) {
+ TL.copy(cast<DependentNameTypeLoc>(TInfo->getTypeLoc()));
+ return;
+ }
+ }
+ TL.setKeywordLoc(Keyword != ETK_None
+ ? DS.getTypeSpecTypeLoc()
+ : SourceLocation());
+ const CXXScopeSpec& SS = DS.getTypeSpecScope();
+ TL.setQualifierRange(SS.isEmpty() ? SourceRange() : SS.getRange());
+ // FIXME: load appropriate source location.
+ TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ }
+
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
TL.initialize(DS.getTypeSpecTypeLoc());
@@ -1516,10 +1555,6 @@ namespace {
void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::Pointer);
TL.setStarLoc(Chunk.Loc);
- TL.setHasBaseTypeAsWritten(true);
- TL.setHasProtocolsAsWritten(false);
- TL.setLAngleLoc(SourceLocation());
- TL.setRAngleLoc(SourceLocation());
}
void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::MemberPointer);
@@ -1642,6 +1677,16 @@ bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) {
T2 = T2MPType->getPointeeType();
return true;
}
+
+ if (getLangOptions().ObjC1) {
+ const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(),
+ *T2OPType = T2->getAs<ObjCObjectPointerType>();
+ if (T1OPType && T2OPType) {
+ T1 = T1OPType->getPointeeType();
+ T2 = T2OPType->getPointeeType();
+ return true;
+ }
+ }
return false;
}
@@ -1704,7 +1749,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
}
Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt addrSpace(32);
- if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
+ if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() ||
+ !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int)
<< ASArgExpr->getSourceRange();
Attr.setInvalid();
@@ -1810,7 +1856,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
llvm::APSInt NumParams(32);
// The warning is emitted elsewhere
- if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context))
+ if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
+ !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context))
return false;
Type = S.Context.getRegParmType(Type, NumParams.getZExtValue());
@@ -1838,6 +1885,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
case AttributeList::AT_cdecl: CC = CC_C; break;
case AttributeList::AT_fastcall: CC = CC_X86FastCall; break;
case AttributeList::AT_stdcall: CC = CC_X86StdCall; break;
+ case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break;
default: llvm_unreachable("unexpected attribute kind"); return false;
}
@@ -1895,7 +1943,8 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
}
Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt vecSize(32);
- if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
+ if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() ||
+ !sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "vector_size" << sizeExpr->getSourceRange();
Attr.setInvalid();
@@ -1962,6 +2011,7 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result,
case AttributeList::AT_cdecl:
case AttributeList::AT_fastcall:
case AttributeList::AT_stdcall:
+ case AttributeList::AT_thiscall:
case AttributeList::AT_regparm:
// Don't process these on the DeclSpec.
if (IsDeclSpec ||
@@ -2082,15 +2132,21 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
std::make_pair(SourceLocation(), PDiag(0)));
}
-/// \brief Retrieve a version of the type 'T' that is qualified by the
-/// nested-name-specifier contained in SS.
-QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
- if (!SS.isSet() || SS.isInvalid() || T.isNull())
+/// \brief Retrieve a version of the type 'T' that is elaborated by Keyword
+/// and qualified by the nested-name-specifier contained in SS.
+QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
+ const CXXScopeSpec &SS, QualType T) {
+ if (T.isNull())
return T;
-
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- return Context.getQualifiedNameType(NNS, T);
+ NestedNameSpecifier *NNS;
+ if (SS.isValid())
+ NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ else {
+ if (Keyword == ETK_None)
+ return T;
+ NNS = 0;
+ }
+ return Context.getElaboratedType(Keyword, NNS, T);
}
QualType Sema::BuildTypeofExprType(Expr *E) {
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 5ce268b..a18701e 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -344,8 +344,8 @@ public:
OwningStmtResult Transform##Node(Node *S);
#define EXPR(Node, Parent) \
OwningExprResult Transform##Node(Node *E);
-#define ABSTRACT_EXPR(Node, Parent)
-#include "clang/AST/StmtNodes.def"
+#define ABSTRACT_STMT(Stmt)
+#include "clang/AST/StmtNodes.inc"
/// \brief Build a new pointer type given its pointee type.
///
@@ -492,11 +492,6 @@ public:
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.
@@ -525,19 +520,19 @@ public:
/// \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);
+ /// By default, builds a new ElaboratedType type from the keyword,
+ /// the nested-name-specifier and the named type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, QualType Named) {
+ return SemaRef.Context.getElaboratedType(Keyword, NNS, Named);
}
/// \brief Build a new typename type that refers to a template-id.
///
- /// By default, builds a new DependentNameType type from the
- /// nested-name-specifier
- /// and the given type. Subclasses may override this routine to provide
- /// different behavior.
+ /// By default, builds a new DependentNameType type from the
+ /// nested-name-specifier and the given type. Subclasses may override
+ /// this routine to provide different behavior.
QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS, QualType T) {
if (NNS->isDependent()) {
@@ -548,50 +543,48 @@ public:
return SemaRef.Context.getDependentNameType(Keyword, NNS,
cast<TemplateSpecializationType>(T));
}
-
- // FIXME: Handle elaborated-type-specifiers separately.
- return SemaRef.Context.getQualifiedNameType(NNS, T);
+
+ return SemaRef.Context.getElaboratedType(Keyword, 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
+ /// (or elaborated type). Subclasses may override this routine to provide
/// different behavior.
- QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
+ QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Id,
- SourceRange SR) {
+ SourceLocation KeywordLoc,
+ SourceRange NNSRange,
+ SourceLocation IdLoc) {
CXXScopeSpec SS;
SS.setScopeRep(NNS);
-
+ SS.setRange(NNSRange);
+
if (NNS->isDependent()) {
// If the name is still dependent, just build a new dependent name type.
if (!SemaRef.computeDeclContext(SS))
return SemaRef.Context.getDependentNameType(Keyword, NNS, Id);
}
- TagDecl::TagKind Kind = TagDecl::TK_enum;
- switch (Keyword) {
- case ETK_None:
- // Fall through.
- case ETK_Typename:
- return SemaRef.CheckTypenameType(Keyword, NNS, *Id, SR);
-
- case ETK_Class: Kind = TagDecl::TK_class; break;
- case ETK_Struct: Kind = TagDecl::TK_struct; break;
- case ETK_Union: Kind = TagDecl::TK_union; break;
- case ETK_Enum: Kind = TagDecl::TK_enum; break;
- }
-
- // We had a dependent elaborated-type-specifier that as been transformed
+ if (Keyword == ETK_None || Keyword == ETK_Typename)
+ return SemaRef.CheckTypenameType(Keyword, NNS, *Id,
+ KeywordLoc, NNSRange, IdLoc);
+
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
+
+ // We had a dependent elaborated-type-specifier that has been transformed
// into a non-dependent elaborated-type-specifier. Find the tag we're
// referring to.
- LookupResult Result(SemaRef, Id, SR.getEnd(), Sema::LookupTagName);
+ LookupResult Result(SemaRef, Id, IdLoc, Sema::LookupTagName);
DeclContext *DC = SemaRef.computeDeclContext(SS, false);
if (!DC)
return QualType();
+ if (SemaRef.RequireCompleteDeclContext(SS, DC))
+ return QualType();
+
TagDecl *Tag = 0;
SemaRef.LookupQualifiedName(Result, DC);
switch (Result.getResultKind()) {
@@ -615,22 +608,20 @@ public:
if (!Tag) {
// FIXME: Would be nice to highlight just the source range.
- SemaRef.Diag(SR.getEnd(), diag::err_not_tag_in_scope)
+ SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope)
<< Kind << Id << DC;
return QualType();
}
-
- // FIXME: Terrible location information
- if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, SR.getEnd(), *Id)) {
- SemaRef.Diag(SR.getBegin(), diag::err_use_with_wrong_tag) << Id;
+
+ if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, IdLoc, *Id)) {
+ SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id;
SemaRef.Diag(Tag->getLocation(), diag::note_previous_use);
return QualType();
}
// Build the elaborated-type-specifier type.
QualType T = SemaRef.Context.getTypeDeclType(Tag);
- T = SemaRef.Context.getQualifiedNameType(NNS, T);
- return SemaRef.Context.getElaboratedType(T, Kind);
+ return SemaRef.Context.getElaboratedType(Keyword, NNS, T);
}
/// \brief Build a new nested-name-specifier given the prefix and an
@@ -769,9 +760,11 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- OwningStmtResult RebuildSwitchStmtStart(Sema::FullExprArg Cond,
+ OwningStmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc,
+ Sema::ExprArg Cond,
VarDecl *CondVar) {
- return getSema().ActOnStartOfSwitchStmt(Cond, DeclPtrTy::make(CondVar));
+ return getSema().ActOnStartOfSwitchStmt(SwitchLoc, move(Cond),
+ DeclPtrTy::make(CondVar));
}
/// \brief Attach the body to the switch statement.
@@ -792,8 +785,8 @@ public:
Sema::FullExprArg Cond,
VarDecl *CondVar,
StmtArg Body) {
- return getSema().ActOnWhileStmt(WhileLoc, Cond, DeclPtrTy::make(CondVar),
- move(Body));
+ return getSema().ActOnWhileStmt(WhileLoc, Cond,
+ DeclPtrTy::make(CondVar), move(Body));
}
/// \brief Build a new do-while statement.
@@ -1966,13 +1959,13 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
#define STMT(Node, Parent) \
case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S));
#define EXPR(Node, Parent)
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
// Transform expressions by calling TransformExpr.
#define STMT(Node, Parent)
-#define ABSTRACT_EXPR(Node, Parent)
+#define ABSTRACT_STMT(Stmt)
#define EXPR(Node, Parent) case Stmt::Node##Class:
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
{
Sema::OwningExprResult E = getDerived().TransformExpr(cast<Expr>(S));
if (E.isInvalid())
@@ -1994,10 +1987,10 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
switch (E->getStmtClass()) {
case Stmt::NoStmtClass: break;
#define STMT(Node, Parent) case Stmt::Node##Class: break;
-#define ABSTRACT_EXPR(Node, Parent)
+#define ABSTRACT_STMT(Stmt)
#define EXPR(Node, Parent) \
case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E));
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
}
return SemaRef.Owned(E->Retain());
@@ -2457,23 +2450,15 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
return QualType();
QualType Result = TL.getType();
- if (PointeeType->isObjCInterfaceType()) {
+ if (PointeeType->getAs<ObjCObjectType>()) {
// A dependent pointer type 'T *' has is being transformed such
// that an Objective-C class type is being replaced for 'T'. The
// resulting pointer type is an ObjCObjectPointerType, not a
// PointerType.
- const ObjCInterfaceType *IFace = PointeeType->getAs<ObjCInterfaceType>();
- Result = SemaRef.Context.getObjCObjectPointerType(PointeeType,
- const_cast<ObjCProtocolDecl **>(
- IFace->qual_begin()),
- IFace->getNumProtocols());
+ Result = SemaRef.Context.getObjCObjectPointerType(PointeeType);
- ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
- NewT.setStarLoc(TL.getSigilLoc());
- NewT.setHasProtocolsAsWritten(false);
- NewT.setLAngleLoc(SourceLocation());
- NewT.setRAngleLoc(SourceLocation());
- NewT.setHasBaseTypeAsWritten(true);
+ ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
+ NewT.setStarLoc(TL.getStarLoc());
return Result;
}
@@ -3144,31 +3129,6 @@ QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB,
return Result;
}
-template <typename Derived>
-QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
- ElaboratedTypeLoc TL,
- QualType ObjectType) {
- ElaboratedType *T = TL.getTypePtr();
-
- // FIXME: this should be a nested type.
- QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
- if (Underlying.isNull())
- return QualType();
-
- QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() ||
- Underlying != T->getUnderlyingType()) {
- Result = getDerived().RebuildElaboratedType(Underlying, T->getTagKind());
- if (Result.isNull())
- return QualType();
- }
-
- ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
-
- return Result;
-}
-
template<typename Derived>
QualType TreeTransform<Derived>::TransformInjectedClassNameType(
TypeLocBuilder &TLB,
@@ -3273,32 +3233,54 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
template<typename Derived>
QualType
-TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB,
- QualifiedNameTypeLoc TL,
- QualType ObjectType) {
- QualifiedNameType *T = TL.getTypePtr();
- NestedNameSpecifier *NNS
- = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
- SourceRange(),
- ObjectType);
- if (!NNS)
- return QualType();
+TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
+ ElaboratedTypeLoc TL,
+ QualType ObjectType) {
+ ElaboratedType *T = TL.getTypePtr();
- QualType Named = getDerived().TransformType(T->getNamedType());
- if (Named.isNull())
- return QualType();
+ NestedNameSpecifier *NNS = 0;
+ // NOTE: the qualifier in an ElaboratedType is optional.
+ if (T->getQualifier() != 0) {
+ NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
+ TL.getQualifierRange(),
+ ObjectType);
+ if (!NNS)
+ return QualType();
+ }
+
+ QualType NamedT;
+ // FIXME: this test is meant to workaround a problem (failing assertion)
+ // occurring if directly executing the code in the else branch.
+ if (isa<TemplateSpecializationTypeLoc>(TL.getNamedTypeLoc())) {
+ TemplateSpecializationTypeLoc OldNamedTL
+ = cast<TemplateSpecializationTypeLoc>(TL.getNamedTypeLoc());
+ const TemplateSpecializationType* OldTST
+ = OldNamedTL.getType()->template getAs<TemplateSpecializationType>();
+ NamedT = TransformTemplateSpecializationType(OldTST, ObjectType);
+ if (NamedT.isNull())
+ return QualType();
+ TemplateSpecializationTypeLoc NewNamedTL
+ = TLB.push<TemplateSpecializationTypeLoc>(NamedT);
+ NewNamedTL.copy(OldNamedTL);
+ }
+ else {
+ NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc());
+ if (NamedT.isNull())
+ return QualType();
+ }
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
NNS != T->getQualifier() ||
- Named != T->getNamedType()) {
- Result = getDerived().RebuildQualifiedNameType(NNS, Named);
+ NamedT != T->getNamedType()) {
+ Result = getDerived().RebuildElaboratedType(T->getKeyword(), NNS, NamedT);
if (Result.isNull())
return QualType();
}
- QualifiedNameTypeLoc NewTL = TLB.push<QualifiedNameTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setQualifierRange(TL.getQualifierRange());
return Result;
}
@@ -3309,11 +3291,9 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
QualType ObjectType) {
DependentNameType *T = TL.getTypePtr();
- /* FIXME: preserve source information better than this */
- SourceRange SR(TL.getNameLoc());
-
NestedNameSpecifier *NNS
- = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR,
+ = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
+ TL.getQualifierRange(),
ObjectType);
if (!NNS)
return QualType();
@@ -3331,18 +3311,38 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
NewTemplateId == QualType(TemplateId, 0))
return QualType(T, 0);
- Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
NewTemplateId);
} else {
- Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
- T->getIdentifier(), SR);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ T->getIdentifier(),
+ TL.getKeywordLoc(),
+ TL.getQualifierRange(),
+ TL.getNameLoc());
}
if (Result.isNull())
return QualType();
- DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
-
+ if (const ElaboratedType* ElabT = Result->getAs<ElaboratedType>()) {
+ QualType NamedT = ElabT->getNamedType();
+ if (isa<TemplateSpecializationType>(NamedT)) {
+ TemplateSpecializationTypeLoc NamedTLoc
+ = TLB.push<TemplateSpecializationTypeLoc>(NamedT);
+ // FIXME: fill locations
+ NamedTLoc.initializeLocal(TL.getNameLoc());
+ } else {
+ TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc());
+ }
+ ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setQualifierRange(TL.getQualifierRange());
+ }
+ else {
+ DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setQualifierRange(TL.getQualifierRange());
+ NewTL.setNameLoc(TL.getNameLoc());
+ }
return Result;
}
@@ -3352,6 +3352,17 @@ TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB,
ObjCInterfaceTypeLoc TL,
QualType ObjectType) {
// ObjCInterfaceType is never dependent.
+ TLB.pushFullCopy(TL);
+ return TL.getType();
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
+ ObjCObjectTypeLoc TL,
+ QualType ObjectType) {
+ // ObjCObjectType is never dependent.
+ TLB.pushFullCopy(TL);
return TL.getType();
}
@@ -3361,6 +3372,7 @@ TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
ObjCObjectPointerTypeLoc TL,
QualType ObjectType) {
// ObjCObjectPointerType is never dependent.
+ TLB.pushFullCopy(TL);
return TL.getType();
}
@@ -3489,10 +3501,23 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
if (Cond.isInvalid())
return SemaRef.StmtError();
+
+ // Convert the condition to a boolean value.
+ if (S->getCond()) {
+ OwningExprResult CondE = getSema().ActOnBooleanCondition(0,
+ S->getIfLoc(),
+ move(Cond));
+ if (CondE.isInvalid())
+ return getSema().StmtError();
+
+ Cond = move(CondE);
+ }
}
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
-
+ if (!S->getConditionVariable() && S->getCond() && !FullCond->get())
+ return SemaRef.StmtError();
+
// Transform the "then" branch.
OwningStmtResult Then = getDerived().TransformStmt(S->getThen());
if (Then.isInvalid())
@@ -3536,11 +3561,10 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
return SemaRef.StmtError();
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
-
// Rebuild the switch statement.
- OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(FullCond,
- ConditionVar);
+ OwningStmtResult Switch
+ = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), move(Cond),
+ ConditionVar);
if (Switch.isInvalid())
return SemaRef.StmtError();
@@ -3573,9 +3597,21 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
if (Cond.isInvalid())
return SemaRef.StmtError();
+
+ if (S->getCond()) {
+ // Convert the condition to a boolean value.
+ OwningExprResult CondE = getSema().ActOnBooleanCondition(0,
+ S->getWhileLoc(),
+ move(Cond));
+ if (CondE.isInvalid())
+ return getSema().StmtError();
+ Cond = move(CondE);
+ }
}
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
+ if (!S->getConditionVariable() && S->getCond() && !FullCond->get())
+ return SemaRef.StmtError();
// Transform the body
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
@@ -3588,23 +3624,23 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
Body.get() == S->getBody())
return SemaRef.Owned(S->Retain());
- return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, ConditionVar,
- move(Body));
+ return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond,
+ ConditionVar, 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();
+ // Transform the condition
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
if (!getDerived().AlwaysRebuild() &&
Cond.get() == S->getCond() &&
Body.get() == S->getBody())
@@ -3639,13 +3675,32 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
if (Cond.isInvalid())
return SemaRef.StmtError();
+
+ if (S->getCond()) {
+ // Convert the condition to a boolean value.
+ OwningExprResult CondE = getSema().ActOnBooleanCondition(0,
+ S->getForLoc(),
+ move(Cond));
+ if (CondE.isInvalid())
+ return getSema().StmtError();
+
+ Cond = move(CondE);
+ }
}
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
+ if (!S->getConditionVariable() && S->getCond() && !FullCond->get())
+ return SemaRef.StmtError();
+
// Transform the increment
OwningExprResult Inc = getDerived().TransformExpr(S->getInc());
if (Inc.isInvalid())
return SemaRef.StmtError();
+ Sema::FullExprArg FullInc(getSema().MakeFullExpr(Inc));
+ if (S->getInc() && !FullInc->get())
+ return SemaRef.StmtError();
+
// Transform the body
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
if (Body.isInvalid())
@@ -3653,16 +3708,14 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
if (!getDerived().AlwaysRebuild() &&
Init.get() == S->getInit() &&
- Cond.get() == S->getCond() &&
+ FullCond->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), getSema().MakeFullExpr(Cond),
- ConditionVar,
- getSema().MakeFullExpr(Inc),
- S->getRParenLoc(), move(Body));
+ move(Init), FullCond, ConditionVar,
+ FullInc, S->getRParenLoc(), move(Body));
}
template<typename Derived>
@@ -5160,6 +5213,9 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// transform the constructor arguments (if any).
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef);
for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) {
+ if (getDerived().DropCallArgument(E->getConstructorArg(I)))
+ break;
+
OwningExprResult Arg = getDerived().TransformExpr(E->getConstructorArg(I));
if (Arg.isInvalid())
return SemaRef.ExprError();
@@ -5855,7 +5911,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
R.resolveKind();
// Determine the naming class.
- if (!Old->getNamingClass()) {
+ if (Old->getNamingClass()) {
CXXRecordDecl *NamingClass
= cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
Old->getMemberLoc(),
OpenPOWER on IntegriCloud