summaryrefslogtreecommitdiffstats
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp502
-rw-r--r--lib/Sema/AttributeList.cpp39
-rw-r--r--lib/Sema/CMakeLists.txt39
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp27
-rw-r--r--lib/Sema/DeclSpec.cpp39
-rw-r--r--lib/Sema/Sema.cpp177
-rw-r--r--lib/Sema/SemaAccess.cpp83
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp12
-rw-r--r--lib/Sema/SemaCast.cpp30
-rw-r--r--lib/Sema/SemaChecking.cpp931
-rw-r--r--lib/Sema/SemaCodeComplete.cpp210
-rw-r--r--lib/Sema/SemaDecl.cpp911
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1637
-rw-r--r--lib/Sema/SemaDeclCXX.cpp1738
-rw-r--r--lib/Sema/SemaDeclObjC.cpp311
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp41
-rw-r--r--lib/Sema/SemaExpr.cpp1155
-rw-r--r--lib/Sema/SemaExprCXX.cpp410
-rw-r--r--lib/Sema/SemaExprMember.cpp95
-rw-r--r--lib/Sema/SemaExprObjC.cpp925
-rw-r--r--lib/Sema/SemaFixItUtils.cpp71
-rw-r--r--lib/Sema/SemaInit.cpp372
-rw-r--r--lib/Sema/SemaLambda.cpp316
-rw-r--r--lib/Sema/SemaLookup.cpp198
-rw-r--r--lib/Sema/SemaObjCProperty.cpp375
-rw-r--r--lib/Sema/SemaOverload.cpp456
-rw-r--r--lib/Sema/SemaPseudoObject.cpp60
-rw-r--r--lib/Sema/SemaStmt.cpp735
-rw-r--r--lib/Sema/SemaStmtAttr.cpp36
-rw-r--r--lib/Sema/SemaTemplate.cpp238
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp124
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp266
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp162
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp113
-rw-r--r--lib/Sema/SemaType.cpp568
-rw-r--r--lib/Sema/TargetAttributesSema.cpp63
-rw-r--r--lib/Sema/TreeTransform.h1264
37 files changed, 9594 insertions, 5135 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index a8e6791..19a7d6f 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -19,6 +19,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/Lexer.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -27,6 +28,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
@@ -42,7 +44,9 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include <algorithm>
+#include <iterator>
#include <vector>
+#include <deque>
using namespace clang;
@@ -185,6 +189,12 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
continue;
}
}
+ if (isa<MSAsmStmt>(S)) {
+ // TODO: Verify this is correct.
+ HasFakeEdge = true;
+ HasLiveReturn = true;
+ continue;
+ }
if (isa<CXXTryStmt>(S)) {
HasAbnormalEdge = true;
continue;
@@ -438,9 +448,14 @@ static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
return false;
// Suggest possible initialization (if any).
- const char *Init = S.getFixItZeroInitializerForType(VariableTy);
- if (!Init)
+ std::string Init = S.getFixItZeroInitializerForType(VariableTy);
+ if (Init.empty())
return false;
+
+ // Don't suggest a fixit inside macros.
+ if (VD->getLocEnd().isMacroID())
+ return false;
+
SourceLocation Loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
@@ -448,82 +463,428 @@ static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
return true;
}
+/// Create a fixit to remove an if-like statement, on the assumption that its
+/// condition is CondVal.
+static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then,
+ const Stmt *Else, bool CondVal,
+ FixItHint &Fixit1, FixItHint &Fixit2) {
+ if (CondVal) {
+ // If condition is always true, remove all but the 'then'.
+ Fixit1 = FixItHint::CreateRemoval(
+ CharSourceRange::getCharRange(If->getLocStart(),
+ Then->getLocStart()));
+ if (Else) {
+ SourceLocation ElseKwLoc = Lexer::getLocForEndOfToken(
+ Then->getLocEnd(), 0, S.getSourceManager(), S.getLangOpts());
+ Fixit2 = FixItHint::CreateRemoval(
+ SourceRange(ElseKwLoc, Else->getLocEnd()));
+ }
+ } else {
+ // If condition is always false, remove all but the 'else'.
+ if (Else)
+ Fixit1 = FixItHint::CreateRemoval(
+ CharSourceRange::getCharRange(If->getLocStart(),
+ Else->getLocStart()));
+ else
+ Fixit1 = FixItHint::CreateRemoval(If->getSourceRange());
+ }
+}
+
+/// DiagUninitUse -- Helper function to produce a diagnostic for an
+/// uninitialized use of a variable.
+static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
+ bool IsCapturedByBlock) {
+ bool Diagnosed = false;
+
+ // Diagnose each branch which leads to a sometimes-uninitialized use.
+ for (UninitUse::branch_iterator I = Use.branch_begin(), E = Use.branch_end();
+ I != E; ++I) {
+ assert(Use.getKind() == UninitUse::Sometimes);
+
+ const Expr *User = Use.getUser();
+ const Stmt *Term = I->Terminator;
+
+ // Information used when building the diagnostic.
+ unsigned DiagKind;
+ const char *Str;
+ SourceRange Range;
+
+ // FixIts to suppress the diagnosic by removing the dead condition.
+ // For all binary terminators, branch 0 is taken if the condition is true,
+ // and branch 1 is taken if the condition is false.
+ int RemoveDiagKind = -1;
+ const char *FixitStr =
+ S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false")
+ : (I->Output ? "1" : "0");
+ FixItHint Fixit1, Fixit2;
+
+ switch (Term->getStmtClass()) {
+ default:
+ // Don't know how to report this. Just fall back to 'may be used
+ // uninitialized'. This happens for range-based for, which the user
+ // can't explicitly fix.
+ // FIXME: This also happens if the first use of a variable is always
+ // uninitialized, eg "for (int n; n < 10; ++n)". We should report that
+ // with the 'is uninitialized' diagnostic.
+ continue;
+
+ // "condition is true / condition is false".
+ case Stmt::IfStmtClass: {
+ const IfStmt *IS = cast<IfStmt>(Term);
+ DiagKind = 0;
+ Str = "if";
+ Range = IS->getCond()->getSourceRange();
+ RemoveDiagKind = 0;
+ CreateIfFixit(S, IS, IS->getThen(), IS->getElse(),
+ I->Output, Fixit1, Fixit2);
+ break;
+ }
+ case Stmt::ConditionalOperatorClass: {
+ const ConditionalOperator *CO = cast<ConditionalOperator>(Term);
+ DiagKind = 0;
+ Str = "?:";
+ Range = CO->getCond()->getSourceRange();
+ RemoveDiagKind = 0;
+ CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(),
+ I->Output, Fixit1, Fixit2);
+ break;
+ }
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *BO = cast<BinaryOperator>(Term);
+ if (!BO->isLogicalOp())
+ continue;
+ DiagKind = 0;
+ Str = BO->getOpcodeStr();
+ Range = BO->getLHS()->getSourceRange();
+ RemoveDiagKind = 0;
+ if ((BO->getOpcode() == BO_LAnd && I->Output) ||
+ (BO->getOpcode() == BO_LOr && !I->Output))
+ // true && y -> y, false || y -> y.
+ Fixit1 = FixItHint::CreateRemoval(SourceRange(BO->getLocStart(),
+ BO->getOperatorLoc()));
+ else
+ // false && y -> false, true || y -> true.
+ Fixit1 = FixItHint::CreateReplacement(BO->getSourceRange(), FixitStr);
+ break;
+ }
+
+ // "loop is entered / loop is exited".
+ case Stmt::WhileStmtClass:
+ DiagKind = 1;
+ Str = "while";
+ Range = cast<WhileStmt>(Term)->getCond()->getSourceRange();
+ RemoveDiagKind = 1;
+ Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
+ break;
+ case Stmt::ForStmtClass:
+ DiagKind = 1;
+ Str = "for";
+ Range = cast<ForStmt>(Term)->getCond()->getSourceRange();
+ RemoveDiagKind = 1;
+ if (I->Output)
+ Fixit1 = FixItHint::CreateRemoval(Range);
+ else
+ Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
+ break;
+
+ // "condition is true / loop is exited".
+ case Stmt::DoStmtClass:
+ DiagKind = 2;
+ Str = "do";
+ Range = cast<DoStmt>(Term)->getCond()->getSourceRange();
+ RemoveDiagKind = 1;
+ Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
+ break;
+
+ // "switch case is taken".
+ case Stmt::CaseStmtClass:
+ DiagKind = 3;
+ Str = "case";
+ Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange();
+ break;
+ case Stmt::DefaultStmtClass:
+ DiagKind = 3;
+ Str = "default";
+ Range = cast<DefaultStmt>(Term)->getDefaultLoc();
+ break;
+ }
+
+ S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
+ << VD->getDeclName() << IsCapturedByBlock << DiagKind
+ << Str << I->Output << Range;
+ S.Diag(User->getLocStart(), diag::note_uninit_var_use)
+ << IsCapturedByBlock << User->getSourceRange();
+ if (RemoveDiagKind != -1)
+ S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond)
+ << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
+
+ Diagnosed = true;
+ }
+
+ if (!Diagnosed)
+ S.Diag(Use.getUser()->getLocStart(),
+ Use.getKind() == UninitUse::Always ? diag::warn_uninit_var
+ : diag::warn_maybe_uninit_var)
+ << VD->getDeclName() << IsCapturedByBlock
+ << Use.getUser()->getSourceRange();
+}
+
/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
/// uninitialized variable. This manages the different forms of diagnostic
/// emitted for particular types of uses. Returns true if the use was diagnosed
-/// as a warning. If a pariticular use is one we omit warnings for, returns
+/// as a warning. If a particular use is one we omit warnings for, returns
/// false.
static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
- const Expr *E, bool isAlwaysUninit,
+ const UninitUse &Use,
bool alwaysReportSelfInit = false) {
- bool isSelfInit = false;
-
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
- if (isAlwaysUninit) {
- // Inspect the initializer of the variable declaration which is
- // being referenced prior to its initialization. We emit
- // specialized diagnostics for self-initialization, and we
- // specifically avoid warning about self references which take the
- // form of:
- //
- // int x = x;
- //
- // This is used to indicate to GCC that 'x' is intentionally left
- // uninitialized. Proven code paths which access 'x' in
- // an uninitialized state after this will still warn.
- //
- // TODO: Should we suppress maybe-uninitialized warnings for
- // variables initialized in this way?
- if (const Expr *Initializer = VD->getInit()) {
- if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts())
- return false;
-
- ContainsReference CR(S.Context, DRE);
- CR.Visit(const_cast<Expr*>(Initializer));
- isSelfInit = CR.doesContainReference();
- }
- if (isSelfInit) {
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Use.getUser())) {
+ // Inspect the initializer of the variable declaration which is
+ // being referenced prior to its initialization. We emit
+ // specialized diagnostics for self-initialization, and we
+ // specifically avoid warning about self references which take the
+ // form of:
+ //
+ // int x = x;
+ //
+ // This is used to indicate to GCC that 'x' is intentionally left
+ // uninitialized. Proven code paths which access 'x' in
+ // an uninitialized state after this will still warn.
+ if (const Expr *Initializer = VD->getInit()) {
+ if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts())
+ return false;
+
+ ContainsReference CR(S.Context, DRE);
+ CR.Visit(const_cast<Expr*>(Initializer));
+ if (CR.doesContainReference()) {
S.Diag(DRE->getLocStart(),
diag::warn_uninit_self_reference_in_init)
- << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange();
- } else {
- S.Diag(DRE->getLocStart(), diag::warn_uninit_var)
- << VD->getDeclName() << DRE->getSourceRange();
+ << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange();
+ return true;
}
- } else {
- S.Diag(DRE->getLocStart(), diag::warn_maybe_uninit_var)
- << VD->getDeclName() << DRE->getSourceRange();
}
+
+ DiagUninitUse(S, VD, Use, false);
} else {
- const BlockExpr *BE = cast<BlockExpr>(E);
- if (VD->getType()->isBlockPointerType() &&
- !VD->hasAttr<BlocksAttr>())
- S.Diag(BE->getLocStart(), diag::warn_uninit_byref_blockvar_captured_by_block)
- << VD->getDeclName();
- else
+ const BlockExpr *BE = cast<BlockExpr>(Use.getUser());
+ if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>())
S.Diag(BE->getLocStart(),
- isAlwaysUninit ? diag::warn_uninit_var_captured_by_block
- : diag::warn_maybe_uninit_var_captured_by_block)
+ diag::warn_uninit_byref_blockvar_captured_by_block)
<< VD->getDeclName();
+ else
+ DiagUninitUse(S, VD, Use, true);
}
// Report where the variable was declared when the use wasn't within
// the initializer of that declaration & we didn't already suggest
// an initialization fixit.
- if (!isSelfInit && !SuggestInitializationFixit(S, VD))
+ if (!SuggestInitializationFixit(S, VD))
S.Diag(VD->getLocStart(), diag::note_uninit_var_def)
<< VD->getDeclName();
return true;
}
-typedef std::pair<const Expr*, bool> UninitUse;
+namespace {
+ class FallthroughMapper : public RecursiveASTVisitor<FallthroughMapper> {
+ public:
+ FallthroughMapper(Sema &S)
+ : FoundSwitchStatements(false),
+ S(S) {
+ }
+
+ bool foundSwitchStatements() const { return FoundSwitchStatements; }
+
+ void markFallthroughVisited(const AttributedStmt *Stmt) {
+ bool Found = FallthroughStmts.erase(Stmt);
+ assert(Found);
+ (void)Found;
+ }
+
+ typedef llvm::SmallPtrSet<const AttributedStmt*, 8> AttrStmts;
+
+ const AttrStmts &getFallthroughStmts() const {
+ return FallthroughStmts;
+ }
+
+ bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt) {
+ int UnannotatedCnt = 0;
+ AnnotatedCnt = 0;
+
+ std::deque<const CFGBlock*> BlockQueue;
+
+ std::copy(B.pred_begin(), B.pred_end(), std::back_inserter(BlockQueue));
+
+ while (!BlockQueue.empty()) {
+ const CFGBlock *P = BlockQueue.front();
+ BlockQueue.pop_front();
+
+ const Stmt *Term = P->getTerminator();
+ if (Term && isa<SwitchStmt>(Term))
+ continue; // Switch statement, good.
+
+ const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->getLabel());
+ if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end())
+ continue; // Previous case label has no statements, good.
+
+ if (P->pred_begin() == P->pred_end()) { // The block is unreachable.
+ // This only catches trivially unreachable blocks.
+ for (CFGBlock::const_iterator ElIt = P->begin(), ElEnd = P->end();
+ ElIt != ElEnd; ++ElIt) {
+ if (const CFGStmt *CS = ElIt->getAs<CFGStmt>()){
+ if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
+ S.Diag(AS->getLocStart(),
+ diag::warn_fallthrough_attr_unreachable);
+ markFallthroughVisited(AS);
+ ++AnnotatedCnt;
+ }
+ // Don't care about other unreachable statements.
+ }
+ }
+ // If there are no unreachable statements, this may be a special
+ // case in CFG:
+ // case X: {
+ // A a; // A has a destructor.
+ // break;
+ // }
+ // // <<<< This place is represented by a 'hanging' CFG block.
+ // case Y:
+ continue;
+ }
+
+ const Stmt *LastStmt = getLastStmt(*P);
+ if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
+ markFallthroughVisited(AS);
+ ++AnnotatedCnt;
+ continue; // Fallthrough annotation, good.
+ }
+
+ if (!LastStmt) { // This block contains no executable statements.
+ // Traverse its predecessors.
+ std::copy(P->pred_begin(), P->pred_end(),
+ std::back_inserter(BlockQueue));
+ continue;
+ }
+
+ ++UnannotatedCnt;
+ }
+ return !!UnannotatedCnt;
+ }
+
+ // RecursiveASTVisitor setup.
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool VisitAttributedStmt(AttributedStmt *S) {
+ if (asFallThroughAttr(S))
+ FallthroughStmts.insert(S);
+ return true;
+ }
+
+ bool VisitSwitchStmt(SwitchStmt *S) {
+ FoundSwitchStatements = true;
+ return true;
+ }
+
+ private:
+
+ static const AttributedStmt *asFallThroughAttr(const Stmt *S) {
+ if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
+ if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
+ return AS;
+ }
+ return 0;
+ }
+
+ static const Stmt *getLastStmt(const CFGBlock &B) {
+ if (const Stmt *Term = B.getTerminator())
+ return Term;
+ for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(),
+ ElemEnd = B.rend();
+ ElemIt != ElemEnd; ++ElemIt) {
+ if (const CFGStmt *CS = ElemIt->getAs<CFGStmt>())
+ return CS->getStmt();
+ }
+ // Workaround to detect a statement thrown out by CFGBuilder:
+ // case X: {} case Y:
+ // case X: ; case Y:
+ if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel()))
+ if (!isa<SwitchCase>(SW->getSubStmt()))
+ return SW->getSubStmt();
+
+ return 0;
+ }
+
+ bool FoundSwitchStatements;
+ AttrStmts FallthroughStmts;
+ Sema &S;
+ };
+}
+
+static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
+ bool PerFunction) {
+ FallthroughMapper FM(S);
+ FM.TraverseStmt(AC.getBody());
+
+ if (!FM.foundSwitchStatements())
+ return;
+
+ if (PerFunction && FM.getFallthroughStmts().empty())
+ return;
+
+ CFG *Cfg = AC.getCFG();
+
+ if (!Cfg)
+ return;
+
+ int AnnotatedCnt;
+
+ for (CFG::reverse_iterator I = Cfg->rbegin(), E = Cfg->rend(); I != E; ++I) {
+ const CFGBlock &B = **I;
+ const Stmt *Label = B.getLabel();
+
+ if (!Label || !isa<SwitchCase>(Label))
+ continue;
+
+ if (!FM.checkFallThroughIntoBlock(B, AnnotatedCnt))
+ continue;
+
+ S.Diag(Label->getLocStart(),
+ PerFunction ? diag::warn_unannotated_fallthrough_per_function
+ : diag::warn_unannotated_fallthrough);
+
+ if (!AnnotatedCnt) {
+ SourceLocation L = Label->getLocStart();
+ if (L.isMacroID())
+ continue;
+ if (S.getLangOpts().CPlusPlus0x) {
+ const Stmt *Term = B.getTerminator();
+ if (!(B.empty() && Term && isa<BreakStmt>(Term))) {
+ S.Diag(L, diag::note_insert_fallthrough_fixit) <<
+ FixItHint::CreateInsertion(L, "[[clang::fallthrough]]; ");
+ }
+ }
+ S.Diag(L, diag::note_insert_break_fixit) <<
+ FixItHint::CreateInsertion(L, "break; ");
+ }
+ }
+
+ const FallthroughMapper::AttrStmts &Fallthroughs = FM.getFallthroughStmts();
+ for (FallthroughMapper::AttrStmts::const_iterator I = Fallthroughs.begin(),
+ E = Fallthroughs.end();
+ I != E; ++I) {
+ S.Diag((*I)->getLocStart(), diag::warn_fallthrough_attr_invalid_placement);
+ }
+
+}
namespace {
struct SLocSort {
bool operator()(const UninitUse &a, const UninitUse &b) {
- SourceLocation aLoc = a.first->getLocStart();
- SourceLocation bLoc = b.first->getLocStart();
+ // Prefer a more confident report over a less confident one.
+ if (a.getKind() != b.getKind())
+ return a.getKind() > b.getKind();
+ SourceLocation aLoc = a.getUser()->getLocStart();
+ SourceLocation bLoc = b.getUser()->getLocStart();
return aLoc.getRawEncoding() < bLoc.getRawEncoding();
}
};
@@ -552,9 +913,8 @@ public:
return V;
}
- void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd,
- bool isAlwaysUninit) {
- getUses(vd).first->push_back(std::make_pair(ex, isAlwaysUninit));
+ void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use) {
+ getUses(vd).first->push_back(use);
}
void handleSelfInit(const VarDecl *vd) {
@@ -565,6 +925,8 @@ public:
if (!uses)
return;
+ // FIXME: This iteration order, and thus the resulting diagnostic order,
+ // is nondeterministic.
for (UsesMap::iterator i = uses->begin(), e = uses->end(); i != e; ++i) {
const VarDecl *vd = i->first;
const UsesMap::mapped_type &V = i->second;
@@ -576,8 +938,9 @@ public:
// variable, but the root cause is an idiomatic self-init. We want
// to report the diagnostic at the self-init since that is the root cause.
if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
- DiagnoseUninitializedUse(S, vd, vd->getInit()->IgnoreParenCasts(),
- /* isAlwaysUninit */ true,
+ DiagnoseUninitializedUse(S, vd,
+ UninitUse(vd->getInit()->IgnoreParenCasts(),
+ /* isAlwaysUninit */ true),
/* alwaysReportSelfInit */ true);
else {
// Sort the uses by their SourceLocations. While not strictly
@@ -587,8 +950,10 @@ public:
for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve;
++vi) {
- if (DiagnoseUninitializedUse(S, vd, vi->first,
- /*isAlwaysUninit=*/vi->second))
+ // If we have self-init, downgrade all uses to 'may be uninitialized'.
+ UninitUse Use = hasSelfInit ? UninitUse(vi->getUser(), false) : *vi;
+
+ if (DiagnoseUninitializedUse(S, vd, Use))
// Skip further diagnostics for this variable. We try to warn only
// on the first point at which a variable is used uninitialized.
break;
@@ -604,7 +969,7 @@ public:
private:
static bool hasAlwaysUninitializedUse(const UsesVec* vec) {
for (UsesVec::const_iterator i = vec->begin(), e = vec->end(); i != e; ++i) {
- if (i->second) {
+ if (i->getKind() == UninitUse::Always) {
return true;
}
}
@@ -696,6 +1061,9 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
case LEK_LockedAtEndOfFunction:
DiagID = diag::warn_no_unlock;
break;
+ case LEK_NotLockedAtEndOfFunction:
+ DiagID = diag::warn_expecting_locked;
+ break;
}
if (LocEndOfScope.isInvalid())
LocEndOfScope = FunEndLocation;
@@ -830,7 +1198,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
const Stmt *Body = D->getBody();
assert(Body);
- AnalysisDeclContext AC(/* AnalysisDeclContextManager */ 0, D, 0);
+ AnalysisDeclContext AC(/* AnalysisDeclContextManager */ 0, D);
// Don't generate EH edges for CallExprs as we'd like to avoid the n^2
// explosion for destrutors that can result and the compile time hit.
@@ -852,11 +1220,13 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
else {
AC.getCFGBuildOptions()
.setAlwaysAdd(Stmt::BinaryOperatorClass)
+ .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
.setAlwaysAdd(Stmt::BlockExprClass)
.setAlwaysAdd(Stmt::CStyleCastExprClass)
.setAlwaysAdd(Stmt::DeclRefExprClass)
.setAlwaysAdd(Stmt::ImplicitCastExprClass)
- .setAlwaysAdd(Stmt::UnaryOperatorClass);
+ .setAlwaysAdd(Stmt::UnaryOperatorClass)
+ .setAlwaysAdd(Stmt::AttributedStmtClass);
}
// Construct the analysis context with the specified CFG build options.
@@ -945,6 +1315,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart())
!= DiagnosticsEngine::Ignored ||
+ Diags.getDiagnosticLevel(diag::warn_sometimes_uninit_var,D->getLocStart())
+ != DiagnosticsEngine::Ignored ||
Diags.getDiagnosticLevel(diag::warn_maybe_uninit_var, D->getLocStart())
!= DiagnosticsEngine::Ignored) {
if (CFG *cfg = AC.getCFG()) {
@@ -968,6 +1340,16 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
}
}
+ bool FallThroughDiagFull =
+ Diags.getDiagnosticLevel(diag::warn_unannotated_fallthrough,
+ D->getLocStart()) != DiagnosticsEngine::Ignored;
+ bool FallThroughDiagPerFunction =
+ Diags.getDiagnosticLevel(diag::warn_unannotated_fallthrough_per_function,
+ D->getLocStart()) != DiagnosticsEngine::Ignored;
+ if (FallThroughDiagFull || FallThroughDiagPerFunction) {
+ DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);
+ }
+
// Collect statistics about the CFG if it was built.
if (S.CollectStats && AC.isCFGBuilt()) {
++NumFunctionsAnalyzed;
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index f142ab4..0f209fd 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -12,9 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/AttributeList.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
size_t AttributeList::allocated_size() const {
@@ -94,10 +96,15 @@ AttributePool::createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
SourceLocation TokLoc, int Arg) {
Expr *IArg = IntegerLiteral::Create(C, llvm::APInt(32, (uint64_t) Arg),
C.IntTy, TokLoc);
- return create(Name, TokLoc, 0, TokLoc, 0, TokLoc, &IArg, 1, 0);
+ return create(Name, TokLoc, 0, TokLoc, 0, TokLoc, &IArg, 1,
+ AttributeList::AS_GNU);
}
-AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
+#include "clang/Sema/AttrParsedAttrKinds.inc"
+
+AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name,
+ const IdentifierInfo *ScopeName,
+ Syntax SyntaxUsed) {
StringRef AttrName = Name->getName();
// Normalize the attribute name, __foo__ becomes foo.
@@ -105,22 +112,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
AttrName.size() >= 4)
AttrName = AttrName.substr(2, AttrName.size() - 4);
- return llvm::StringSwitch<AttributeList::Kind>(AttrName)
- #include "clang/Sema/AttrParsedAttrKinds.inc"
- .Case("address_space", AT_address_space)
- .Case("align", AT_aligned) // FIXME - should it be "aligned"?
- .Case("base_check", AT_base_check)
- .Case("bounded", IgnoredAttribute) // OpenBSD
- .Case("__const", AT_const) // some GCC headers do contain this spelling
- .Case("cf_returns_autoreleased", AT_cf_returns_autoreleased)
- .Case("mode", AT_mode)
- .Case("vec_type_hint", IgnoredAttribute)
- .Case("ext_vector_type", AT_ext_vector_type)
- .Case("neon_vector_type", AT_neon_vector_type)
- .Case("neon_polyvector_type", AT_neon_polyvector_type)
- .Case("opencl_image_access", AT_opencl_image_access)
- .Case("objc_gc", AT_objc_gc)
- .Case("objc_ownership", AT_objc_ownership)
- .Case("vector_size", AT_vector_size)
- .Default(UnknownAttribute);
+ SmallString<64> Buf;
+ if (ScopeName)
+ Buf += ScopeName->getName();
+ // Ensure that in the case of C++11 attributes, we look for '::foo' if it is
+ // unscoped.
+ if (ScopeName || SyntaxUsed == AS_CXX11)
+ Buf += "::";
+ Buf += AttrName;
+
+ return ::getAttrKind(Buf);
}
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 07734c7..46dfa05 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -1,9 +1,8 @@
-set(LLVM_USED_LIBS
- clangAST
- clangAnalysis
- clangBasic
- clangEdit
- clangLex
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ asmparser
+ support
+ mc
)
add_clang_library(clangSema
@@ -50,9 +49,27 @@ add_clang_library(clangSema
TargetAttributesSema.cpp
)
-add_dependencies(clangSema ClangARMNeon ClangAttrClasses ClangAttrList
- ClangDiagnosticSema ClangDeclNodes ClangStmtNodes
- ClangAttrTemplateInstantiate ClangAttrParsedAttrList
- ClangAttrParsedAttrKinds)
-
+add_dependencies(clangSema
+ ClangARMNeon
+ ClangAttrClasses
+ ClangAttrList
+ ClangAttrParsedAttrList
+ ClangAttrParsedAttrKinds
+ ClangAttrTemplateInstantiate
+ ClangCommentNodes
+ ClangDeclNodes
+ ClangDiagnosticAST
+ ClangDiagnosticComment
+ ClangDiagnosticCommon
+ ClangDiagnosticParse
+ ClangDiagnosticSema
+ ClangStmtNodes
+ )
+target_link_libraries(clangSema
+ clangAST
+ clangAnalysis
+ clangBasic
+ clangEdit
+ clangLex
+ )
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index ce9bbb9..a835725 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -194,10 +194,11 @@ CodeCompletionString::CodeCompletionString(const Chunk *Chunks,
const char **Annotations,
unsigned NumAnnotations,
CXCursorKind ParentKind,
- StringRef ParentName)
+ StringRef ParentName,
+ const char *BriefComment)
: NumChunks(NumChunks), NumAnnotations(NumAnnotations),
Priority(Priority), Availability(Availability), ParentKind(ParentKind),
- ParentName(ParentName)
+ ParentName(ParentName), BriefComment(BriefComment)
{
assert(NumChunks <= 0xffff);
assert(NumAnnotations <= 0xffff);
@@ -338,7 +339,7 @@ CodeCompletionString *CodeCompletionBuilder::TakeString() {
= new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(),
Priority, Availability,
Annotations.data(), Annotations.size(),
- ParentKind, ParentName);
+ ParentKind, ParentName, BriefComment);
Chunks.clear();
return Result;
}
@@ -394,6 +395,10 @@ void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
ParentName = getCodeCompletionTUInfo().getParentName(DC);
}
+void CodeCompletionBuilder::addBriefComment(StringRef Comment) {
+ BriefComment = Allocator.CopyString(Comment);
+}
+
unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) {
if (!ND)
return CCP_Unlikely;
@@ -474,8 +479,11 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
OS << " (Hidden)";
if (CodeCompletionString *CCS
= Results[I].CreateCodeCompletionString(SemaRef, getAllocator(),
- CCTUInfo)) {
+ CCTUInfo,
+ includeBriefComments())) {
OS << " : " << CCS->getAsString();
+ if (const char *BriefComment = CCS->getBriefComment())
+ OS << " : " << BriefComment;
}
OS << '\n';
@@ -489,7 +497,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
OS << Results[I].Macro->getName();
if (CodeCompletionString *CCS
= Results[I].CreateCodeCompletionString(SemaRef, getAllocator(),
- CCTUInfo)) {
+ CCTUInfo,
+ includeBriefComments())) {
OS << " : " << CCS->getAsString();
}
OS << '\n';
@@ -573,14 +582,8 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
}
case RK_Macro:
- Availability = CXAvailability_Available;
- CursorKind = CXCursor_MacroDefinition;
- break;
-
case RK_Keyword:
- Availability = CXAvailability_Available;
- CursorKind = CXCursor_NotImplemented;
- break;
+ llvm_unreachable("Macro and keyword kinds are handled by the constructors");
}
if (!Accessible)
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index b531acc..d12ca78 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -145,6 +145,7 @@ CXXScopeSpec::getWithLocInContext(ASTContext &Context) const {
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
+ bool isAmbiguous,
SourceLocation EllipsisLoc,
ParamInfo *ArgInfo,
unsigned NumArgs,
@@ -165,7 +166,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
SourceLocation LocalRangeBegin,
SourceLocation LocalRangeEnd,
Declarator &TheDeclarator,
- ParsedType TrailingReturnType) {
+ TypeResult TrailingReturnType) {
DeclaratorChunk I;
I.Kind = Function;
I.Loc = LocalRangeBegin;
@@ -173,6 +174,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
I.Fun.AttrList = 0;
I.Fun.hasPrototype = hasProto;
I.Fun.isVariadic = isVariadic;
+ I.Fun.isAmbiguous = isAmbiguous;
I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
I.Fun.DeleteArgInfo = false;
I.Fun.TypeQuals = TypeQuals;
@@ -188,7 +190,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
I.Fun.NumExceptions = 0;
I.Fun.Exceptions = 0;
I.Fun.NoexceptExpr = 0;
- I.Fun.TrailingReturnType = TrailingReturnType.getAsOpaquePtr();
+ I.Fun.HasTrailingReturnType = TrailingReturnType.isUsable() ||
+ TrailingReturnType.isInvalid();
+ I.Fun.TrailingReturnType = TrailingReturnType.get();
// new[] an argument array if needed.
if (NumArgs) {
@@ -418,19 +422,27 @@ const char *DeclSpec::getSpecifierName(TQ T) {
bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID) {
- // OpenCL 1.1 6.8g: "The extern, static, auto and register storage-class
- // specifiers are not supported."
+ // OpenCL v1.1 s6.8g: "The extern, static, auto and register storage-class
+ // specifiers are not supported.
// It seems sensible to prohibit private_extern too
// The cl_clang_storage_class_specifiers extension enables support for
// these storage-class specifiers.
+ // OpenCL v1.2 s6.8 changes this to "The auto and register storage-class
+ // specifiers are not supported."
if (S.getLangOpts().OpenCL &&
!S.getOpenCLOptions().cl_clang_storage_class_specifiers) {
switch (SC) {
case SCS_extern:
case SCS_private_extern:
+ case SCS_static:
+ if (S.getLangOpts().OpenCLVersion < 120) {
+ DiagID = diag::err_not_opencl_storage_class_specifier;
+ PrevSpec = getSpecifierName(SC);
+ return true;
+ }
+ break;
case SCS_auto:
case SCS_register:
- case SCS_static:
DiagID = diag::err_not_opencl_storage_class_specifier;
PrevSpec = getSpecifierName(SC);
return true;
@@ -658,9 +670,11 @@ bool DeclSpec::SetTypeSpecError() {
}
bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID, const LangOptions &Lang) {
- // Duplicates turn into warnings pre-C99.
- if ((TypeQualifiers & T) && !Lang.C99)
+ unsigned &DiagID, const LangOptions &Lang,
+ bool IsTypeSpec) {
+ // Duplicates are permitted in C99, and are permitted in C++11 unless the
+ // cv-qualifier appears as a type-specifier.
+ if ((TypeQualifiers & T) && !Lang.C99 && (!Lang.CPlusPlus0x || IsTypeSpec))
return BadSpecifier(T, T, PrevSpec, DiagID);
TypeQualifiers |= T;
@@ -751,7 +765,7 @@ void DeclSpec::SaveWrittenBuiltinSpecs() {
writtenBS.ModeAttr = false;
AttributeList* attrs = getAttributes().getList();
while (attrs) {
- if (attrs->getKind() == AttributeList::AT_mode) {
+ if (attrs->getKind() == AttributeList::AT_Mode) {
writtenBS.ModeAttr = true;
break;
}
@@ -935,13 +949,6 @@ bool DeclSpec::isMissingDeclaratorOk() {
StorageClassSpec != DeclSpec::SCS_typedef;
}
-void UnqualifiedId::clear() {
- Kind = IK_Identifier;
- Identifier = 0;
- StartLocation = SourceLocation();
- EndLocation = SourceLocation();
-}
-
void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc,
OverloadedOperatorKind Op,
SourceLocation SymbolLocations[3]) {
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 30a9cd7..7f79f0c 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "clang/Sema/CXXFieldCollector.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/ExternalSemaSource.h"
@@ -29,6 +30,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@@ -90,13 +92,13 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
PackContext(0), MSStructPragmaOn(false), VisContext(0),
ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
- NSNumberDecl(0), NSArrayDecl(0), ArrayWithObjectsMethod(0),
+ NSNumberDecl(0),
+ NSStringDecl(0), StringWithUTF8StringMethod(0),
+ NSArrayDecl(0), ArrayWithObjectsMethod(0),
NSDictionaryDecl(0), DictionaryWithObjectsMethod(0),
GlobalNewDeleteDeclared(false),
- ObjCShouldCallSuperDealloc(false),
- ObjCShouldCallSuperFinalize(false),
TUKind(TUKind),
- NumSFINAEErrors(0), InFunctionDeclarator(0), SuppressAccessChecking(false),
+ NumSFINAEErrors(0), InFunctionDeclarator(0),
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
CurrentInstantiationScope(0), TyposCorrected(0),
@@ -176,6 +178,10 @@ void Sema::Initialize() {
if (IdResolver.begin(Protocol) == IdResolver.end())
PushOnScopeChains(Context.getObjCProtocolDecl(), TUScope);
}
+
+ DeclarationName BuiltinVaList = &Context.Idents.get("__builtin_va_list");
+ if (IdResolver.begin(BuiltinVaList) == IdResolver.end())
+ PushOnScopeChains(Context.getBuiltinVaListDecl(), TUScope);
}
Sema::~Sema() {
@@ -199,7 +205,6 @@ Sema::~Sema() {
ExternalSema->ForgetSema();
}
-
/// makeUnavailableInSystemHeader - There is an error in the current
/// context. If we're still in a system header, and we can plausibly
/// make the relevant declaration unavailable instead of erroring, do
@@ -420,10 +425,88 @@ void Sema::LoadExternalWeakUndeclaredIdentifiers() {
}
}
+
+typedef llvm::DenseMap<const CXXRecordDecl*, bool> RecordCompleteMap;
+
+/// \brief Returns true, if all methods and nested classes of the given
+/// CXXRecordDecl are defined in this translation unit.
+///
+/// Should only be called from ActOnEndOfTranslationUnit so that all
+/// definitions are actually read.
+static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD,
+ RecordCompleteMap &MNCComplete) {
+ RecordCompleteMap::iterator Cache = MNCComplete.find(RD);
+ if (Cache != MNCComplete.end())
+ return Cache->second;
+ if (!RD->isCompleteDefinition())
+ return false;
+ bool Complete = true;
+ for (DeclContext::decl_iterator I = RD->decls_begin(),
+ E = RD->decls_end();
+ I != E && Complete; ++I) {
+ if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I))
+ Complete = M->isDefined() || (M->isPure() && !isa<CXXDestructorDecl>(M));
+ else if (const FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(*I))
+ Complete = F->getTemplatedDecl()->isDefined();
+ else if (const CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(*I)) {
+ if (R->isInjectedClassName())
+ continue;
+ if (R->hasDefinition())
+ Complete = MethodsAndNestedClassesComplete(R->getDefinition(),
+ MNCComplete);
+ else
+ Complete = false;
+ }
+ }
+ MNCComplete[RD] = Complete;
+ return Complete;
+}
+
+/// \brief Returns true, if the given CXXRecordDecl is fully defined in this
+/// translation unit, i.e. all methods are defined or pure virtual and all
+/// friends, friend functions and nested classes are fully defined in this
+/// translation unit.
+///
+/// Should only be called from ActOnEndOfTranslationUnit so that all
+/// definitions are actually read.
+static bool IsRecordFullyDefined(const CXXRecordDecl *RD,
+ RecordCompleteMap &RecordsComplete,
+ RecordCompleteMap &MNCComplete) {
+ RecordCompleteMap::iterator Cache = RecordsComplete.find(RD);
+ if (Cache != RecordsComplete.end())
+ return Cache->second;
+ bool Complete = MethodsAndNestedClassesComplete(RD, MNCComplete);
+ for (CXXRecordDecl::friend_iterator I = RD->friend_begin(),
+ E = RD->friend_end();
+ I != E && Complete; ++I) {
+ // Check if friend classes and methods are complete.
+ if (TypeSourceInfo *TSI = (*I)->getFriendType()) {
+ // Friend classes are available as the TypeSourceInfo of the FriendDecl.
+ if (CXXRecordDecl *FriendD = TSI->getType()->getAsCXXRecordDecl())
+ Complete = MethodsAndNestedClassesComplete(FriendD, MNCComplete);
+ else
+ Complete = false;
+ } else {
+ // Friend functions are available through the NamedDecl of FriendDecl.
+ if (const FunctionDecl *FD =
+ dyn_cast<FunctionDecl>((*I)->getFriendDecl()))
+ Complete = FD->isDefined();
+ else
+ // This is a template friend, give up.
+ Complete = false;
+ }
+ }
+ RecordsComplete[RD] = Complete;
+ return Complete;
+}
+
/// ActOnEndOfTranslationUnit - This is called at the very end of the
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
void Sema::ActOnEndOfTranslationUnit() {
+ assert(DelayedDiagnostics.getCurrentPool() == NULL
+ && "reached end of translation unit with a pool attached?");
+
// Only complete translation units define vtables and perform implicit
// instantiations.
if (TUKind == TU_Complete) {
@@ -597,9 +680,17 @@ void Sema::ActOnEndOfTranslationUnit() {
if (isa<CXXMethodDecl>(DiagD))
Diag(DiagD->getLocation(), diag::warn_unneeded_member_function)
<< DiagD->getDeclName();
- else
- Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl)
- << /*function*/0 << DiagD->getDeclName();
+ else {
+ if (FD->getStorageClassAsWritten() == SC_Static &&
+ !FD->isInlineSpecified() &&
+ !SourceMgr.isFromMainFile(
+ SourceMgr.getExpansionLoc(FD->getLocation())))
+ Diag(DiagD->getLocation(), diag::warn_unneeded_static_internal_decl)
+ << DiagD->getDeclName();
+ else
+ Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl)
+ << /*function*/0 << DiagD->getDeclName();
+ }
} else {
Diag(DiagD->getLocation(),
isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function
@@ -623,6 +714,23 @@ void Sema::ActOnEndOfTranslationUnit() {
checkUndefinedInternals(*this);
}
+ if (Diags.getDiagnosticLevel(diag::warn_unused_private_field,
+ SourceLocation())
+ != DiagnosticsEngine::Ignored) {
+ RecordCompleteMap RecordsComplete;
+ RecordCompleteMap MNCComplete;
+ for (NamedDeclSetType::iterator I = UnusedPrivateFields.begin(),
+ E = UnusedPrivateFields.end(); I != E; ++I) {
+ const NamedDecl *D = *I;
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext());
+ if (RD && !RD->isUnion() &&
+ IsRecordFullyDefined(RD, RecordsComplete, MNCComplete)) {
+ Diag(D->getLocation(), diag::warn_unused_private_field)
+ << D->getDeclName();
+ }
+ }
+ }
+
// Check we've noticed that we're no longer parsing the initializer for every
// variable. If we miss cases, then at best we have a performance issue and
// at worst a rejects-valid bug.
@@ -693,6 +801,15 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// Count this failure so that we know that template argument deduction
// has failed.
++NumSFINAEErrors;
+
+ // Make a copy of this suppressed diagnostic and store it with the
+ // template-deduction information.
+ if (*Info && !(*Info)->hasSFINAEDiagnostic()) {
+ Diagnostic DiagInfo(&Diags);
+ (*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(),
+ PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
+ }
+
Diags.setLastDiagnosticIgnored();
Diags.Clear();
return;
@@ -709,6 +826,15 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// Suppress this diagnostic.
++NumSFINAEErrors;
+
+ // Make a copy of this suppressed diagnostic and store it with the
+ // template-deduction information.
+ if (*Info && !(*Info)->hasSFINAEDiagnostic()) {
+ Diagnostic DiagInfo(&Diags);
+ (*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(),
+ PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
+ }
+
Diags.setLastDiagnosticIgnored();
Diags.Clear();
@@ -725,13 +851,13 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
case DiagnosticIDs::SFINAE_Suppress:
// Make a copy of this suppressed diagnostic and store it with the
// template-deduction information;
- Diagnostic DiagInfo(&Diags);
-
- if (*Info)
+ if (*Info) {
+ Diagnostic DiagInfo(&Diags);
(*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(),
- PartialDiagnostic(DiagInfo,Context.getDiagAllocator()));
-
- // Suppress this diagnostic.
+ PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
+ }
+
+ // Suppress this diagnostic.
Diags.setLastDiagnosticIgnored();
Diags.Clear();
return;
@@ -894,6 +1020,29 @@ LambdaScopeInfo *Sema::getCurLambda() {
return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
}
+void Sema::ActOnComment(SourceRange Comment) {
+ RawComment RC(SourceMgr, Comment);
+ if (RC.isAlmostTrailingComment()) {
+ SourceRange MagicMarkerRange(Comment.getBegin(),
+ Comment.getBegin().getLocWithOffset(3));
+ StringRef MagicMarkerText;
+ switch (RC.getKind()) {
+ case RawComment::RCK_OrdinaryBCPL:
+ MagicMarkerText = "///<";
+ break;
+ case RawComment::RCK_OrdinaryC:
+ MagicMarkerText = "/**<";
+ break;
+ default:
+ llvm_unreachable("if this is an almost Doxygen comment, "
+ "it should be ordinary");
+ }
+ Diag(Comment.getBegin(), diag::warn_not_a_doxygen_trailing_member_comment) <<
+ FixItHint::CreateReplacement(MagicMarkerRange, MagicMarkerText);
+ }
+ Context.addComment(RC);
+}
+
// Pin this vtable to this file.
ExternalSemaSource::~ExternalSemaSource() {}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 01c141e..3481171 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -152,7 +152,8 @@ struct AccessTarget : public AccessedEntity {
CXXRecordDecl *NamingClass,
DeclAccessPair FoundDecl,
QualType BaseObjectType)
- : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) {
+ : AccessedEntity(Context.getDiagAllocator(), Member, NamingClass,
+ FoundDecl, BaseObjectType) {
initialize();
}
@@ -161,7 +162,8 @@ struct AccessTarget : public AccessedEntity {
CXXRecordDecl *BaseClass,
CXXRecordDecl *DerivedClass,
AccessSpecifier Access)
- : AccessedEntity(Context, Base, BaseClass, DerivedClass, Access) {
+ : AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass,
+ Access) {
initialize();
}
@@ -781,7 +783,7 @@ static AccessResult HasAccess(Sema &S,
// Emulate a MSVC bug where the creation of pointer-to-member
// to protected member of base class is allowed but only from
- // a static function member functions.
+ // static member functions.
if (S.getLangOpts().MicrosoftMode && !EC.Functions.empty())
if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front()))
if (MD->isStatic()) return AR_accessible;
@@ -1391,9 +1393,6 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
if (Entity.getAccess() == AS_public)
return Sema::AR_accessible;
- if (S.SuppressAccessChecking)
- return Sema::AR_accessible;
-
// If we're currently parsing a declaration, we may need to delay
// access control checking, because our effective context might be
// different based on what the declaration comes out as.
@@ -1633,25 +1632,6 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
return CheckAccess(*this, UseLoc, AccessEntity);
}
-/// Checks direct (i.e. non-inherited) access to an arbitrary class
-/// member.
-Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
- NamedDecl *Target,
- const PartialDiagnostic &Diag) {
- AccessSpecifier Access = Target->getAccess();
- if (!getLangOpts().AccessControl ||
- Access == AS_public)
- return AR_accessible;
-
- CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
- AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
- DeclAccessPair::make(Target, Access),
- QualType());
- Entity.setDiag(Diag);
- return CheckAccess(*this, UseLoc, Entity);
-}
-
-
/// Checks access to an overloaded operator new or delete.
Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
SourceRange PlacementRange,
@@ -1694,6 +1674,44 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
return CheckAccess(*this, OpLoc, Entity);
}
+/// Checks access to the target of a friend declaration.
+Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
+ assert(isa<CXXMethodDecl>(target) ||
+ (isa<FunctionTemplateDecl>(target) &&
+ isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(target)
+ ->getTemplatedDecl())));
+
+ // Friendship lookup is a redeclaration lookup, so there's never an
+ // inheritance path modifying access.
+ AccessSpecifier access = target->getAccess();
+
+ if (!getLangOpts().AccessControl || access == AS_public)
+ return AR_accessible;
+
+ CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(target);
+ if (!method)
+ method = cast<CXXMethodDecl>(
+ cast<FunctionTemplateDecl>(target)->getTemplatedDecl());
+ assert(method->getQualifier());
+
+ AccessTarget entity(Context, AccessTarget::Member,
+ cast<CXXRecordDecl>(target->getDeclContext()),
+ DeclAccessPair::make(target, access),
+ /*no instance context*/ QualType());
+ entity.setDiag(diag::err_access_friend_function)
+ << method->getQualifierLoc().getSourceRange();
+
+ // We need to bypass delayed-diagnostics because we might be called
+ // while the ParsingDeclarator is active.
+ EffectiveContext EC(CurContext);
+ switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) {
+ case AR_accessible: return Sema::AR_accessible;
+ case AR_inaccessible: return Sema::AR_inaccessible;
+ case AR_dependent: return Sema::AR_dependent;
+ }
+ llvm_unreachable("falling off end");
+}
+
Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
DeclAccessPair Found) {
if (!getLangOpts().AccessControl ||
@@ -1714,13 +1732,10 @@ Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
/// Checks access for a hierarchy conversion.
///
-/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
-/// or a derived-to-base conversion (false)
/// \param ForceCheck true if this check should be performed even if access
/// control is disabled; some things rely on this for semantics
/// \param ForceUnprivileged true if this check should proceed as if the
/// context had no special privileges
-/// \param ADK controls the kind of diagnostics that are used
Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
QualType Base,
QualType Derived,
@@ -1836,15 +1851,3 @@ bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) {
return true;
}
-
-void Sema::ActOnStartSuppressingAccessChecks() {
- assert(!SuppressAccessChecking &&
- "Tried to start access check suppression when already started.");
- SuppressAccessChecking = true;
-}
-
-void Sema::ActOnStopSuppressingAccessChecks() {
- assert(SuppressAccessChecking &&
- "Tried to stop access check suprression when already stopped.");
- SuppressAccessChecking = false;
-}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 5a0fcec..0de9dd5 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -227,9 +227,8 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
if (loc.isInvalid()) loc = SS.getRange().getBegin();
// The type must be complete.
- if (RequireCompleteType(loc, type,
- PDiag(diag::err_incomplete_nested_name_spec)
- << SS.getRange())) {
+ if (RequireCompleteType(loc, type, diag::err_incomplete_nested_name_spec,
+ SS.getRange())) {
SS.SetInvalid(SS.getRange());
return true;
}
@@ -539,8 +538,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
NamedDecl *SD = Found.getAsSingle<NamedDecl>();
if (isAcceptableNestedNameSpecifier(SD)) {
- if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) {
- // C++ [basic.lookup.classref]p4:
+ if (!ObjectType.isNull() && !ObjectTypeSearchedInScope &&
+ !getLangOpts().CPlusPlus0x) {
+ // C++03 [basic.lookup.classref]p4:
// [...] If the name is found in both contexts, the
// class-name-or-namespace-name shall refer to the same entity.
//
@@ -548,6 +548,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// into the current scope (the scope of the postfix-expression) to
// see if we can find the same name there. As above, if there is no
// scope, reconstruct the result from the template instantiation itself.
+ //
+ // Note that C++11 does *not* perform this redundant lookup.
NamedDecl *OuterDecl;
if (S) {
LookupResult FoundOuter(*this, &Identifier, IdentifierLoc,
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index 54683e1..8199751 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -561,8 +561,8 @@ void CastOperation::CheckDynamicCast() {
assert(DestPointer && "Reference to void is not possible");
} else if (DestRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
- Self.PDiag(diag::err_bad_dynamic_cast_incomplete)
- << DestRange))
+ diag::err_bad_dynamic_cast_incomplete,
+ DestRange))
return;
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
@@ -597,8 +597,8 @@ void CastOperation::CheckDynamicCast() {
const RecordType *SrcRecord = SrcPointee->getAs<RecordType>();
if (SrcRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
- Self.PDiag(diag::err_bad_dynamic_cast_incomplete)
- << SrcExpr.get()->getSourceRange()))
+ diag::err_bad_dynamic_cast_incomplete,
+ SrcExpr.get()))
return;
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
@@ -1075,8 +1075,8 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
QualType OrigDestType, unsigned &msg,
CastKind &Kind, CXXCastPath &BasePath) {
// We can only work with complete types. But don't complain if it doesn't work
- if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, Self.PDiag(0)) ||
- Self.RequireCompleteType(OpRange.getBegin(), DestType, Self.PDiag(0)))
+ if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, 0) ||
+ Self.RequireCompleteType(OpRange.getBegin(), DestType, 0))
return TC_NotApplicable;
// Downcast can only happen in class hierarchies, so we need classes.
@@ -1302,7 +1302,9 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
CastKind &Kind, bool ListInitialization) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
- diag::err_bad_dynamic_cast_incomplete)) {
+ diag::err_bad_dynamic_cast_incomplete) ||
+ Self.RequireNonAbstractType(OpRange.getBegin(), DestType,
+ diag::err_allocation_of_abstract_type)) {
msg = 0;
return TC_Failed;
}
@@ -1504,10 +1506,9 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
}
if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
- bool LValue = DestTypeTmp->isLValueReferenceType();
- if (LValue && !SrcExpr.get()->isLValue()) {
- // Cannot cast non-lvalue to lvalue reference type. See the similar
- // comment in const_cast.
+ if (!SrcExpr.get()->isGLValue()) {
+ // Cannot cast non-glvalue to (lvalue or rvalue) reference type. See the
+ // similar comment in const_cast.
msg = diag::err_bad_cxx_cast_rvalue;
return TC_NotApplicable;
}
@@ -1915,10 +1916,6 @@ void CastOperation::CheckCStyleCast() {
return;
QualType SrcType = SrcExpr.get()->getType();
- // You can cast an _Atomic(T) to anything you can cast a T to.
- if (const AtomicType *AtomicSrcType = SrcType->getAs<AtomicType>())
- SrcType = AtomicSrcType->getValueType();
-
assert(!SrcType->isPlaceholderType());
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
@@ -2105,6 +2102,9 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
Op.CheckCXXCStyleCast(/*FunctionalStyle=*/true, /*ListInit=*/false);
if (Op.SrcExpr.isInvalid())
return ExprError();
+
+ if (CXXConstructExpr *ConstructExpr = dyn_cast<CXXConstructExpr>(Op.SrcExpr.get()))
+ ConstructExpr->setParenRange(SourceRange(LPLoc, RPLoc));
return Op.complete(CXXFunctionalCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, CastTypeInfo, Op.DestRange.getBegin(),
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 0d15ce2..2594648 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -16,12 +16,14 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
@@ -66,16 +68,31 @@ static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) {
<< call->getArg(1)->getSourceRange();
}
-/// CheckBuiltinAnnotationString - Checks that string argument to the builtin
-/// annotation is a non wide string literal.
-static bool CheckBuiltinAnnotationString(Sema &S, Expr *Arg) {
- Arg = Arg->IgnoreParenCasts();
- StringLiteral *Literal = dyn_cast<StringLiteral>(Arg);
+/// Check that the first argument to __builtin_annotation is an integer
+/// and the second argument is a non-wide string literal.
+static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) {
+ if (checkArgCount(S, TheCall, 2))
+ return true;
+
+ // First argument should be an integer.
+ Expr *ValArg = TheCall->getArg(0);
+ QualType Ty = ValArg->getType();
+ if (!Ty->isIntegerType()) {
+ S.Diag(ValArg->getLocStart(), diag::err_builtin_annotation_first_arg)
+ << ValArg->getSourceRange();
+ return true;
+ }
+
+ // Second argument should be a constant string.
+ Expr *StrArg = TheCall->getArg(1)->IgnoreParenCasts();
+ StringLiteral *Literal = dyn_cast<StringLiteral>(StrArg);
if (!Literal || !Literal->isAscii()) {
- S.Diag(Arg->getLocStart(), diag::err_builtin_annotation_not_string_constant)
- << Arg->getSourceRange();
+ S.Diag(StrArg->getLocStart(), diag::err_builtin_annotation_second_arg)
+ << StrArg->getSourceRange();
return true;
}
+
+ TheCall->setType(Ty);
return false;
}
@@ -256,7 +273,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::AO##ID);
#include "clang/Basic/Builtins.def"
case Builtin::BI__builtin_annotation:
- if (CheckBuiltinAnnotationString(*this, TheCall->getArg(1)))
+ if (SemaBuiltinAnnotation(*this, TheCall))
return ExprError();
break;
}
@@ -270,6 +287,13 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ if (CheckMipsBuiltinFunctionCall(BuiltinID, TheCall))
+ return ExprError();
+ break;
default:
break;
}
@@ -331,7 +355,7 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context) {
bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
llvm::APSInt Result;
- unsigned mask = 0;
+ uint64_t mask = 0;
unsigned TV = 0;
int PtrArgNum = -1;
bool HasConstPtr = false;
@@ -349,7 +373,7 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
TV = Result.getLimitedValue(64);
- if ((TV > 63) || (mask & (1 << TV)) == 0)
+ if ((TV > 63) || (mask & (1ULL << TV)) == 0)
return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code)
<< TheCall->getArg(ImmArg)->getSourceRange();
}
@@ -388,6 +412,11 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
#undef GET_NEON_IMMEDIATE_CHECK
};
+ // We can't check the value of a dependent argument.
+ if (TheCall->getArg(i)->isTypeDependent() ||
+ TheCall->getArg(i)->isValueDependent())
+ return false;
+
// Check that the immediate argument is actually a constant.
if (SemaBuiltinConstantArg(TheCall, i, Result))
return true;
@@ -402,34 +431,119 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return false;
}
-/// CheckFunctionCall - Check a direct function call for various correctness
-/// and safety properties not strictly enforced by the C type system.
-bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
- // Get the IdentifierInfo* for the called function.
- IdentifierInfo *FnInfo = FDecl->getIdentifier();
+bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+ unsigned i = 0, l = 0, u = 0;
+ switch (BuiltinID) {
+ default: return false;
+ case Mips::BI__builtin_mips_wrdsp: i = 1; l = 0; u = 63; break;
+ case Mips::BI__builtin_mips_rddsp: i = 0; l = 0; u = 63; break;
+ };
- // None of the checks below are needed for functions that don't have
- // simple names (e.g., C++ conversion functions).
- if (!FnInfo)
+ // We can't check the value of a dependent argument.
+ if (TheCall->getArg(i)->isTypeDependent() ||
+ TheCall->getArg(i)->isValueDependent())
return false;
+ // Check that the immediate argument is actually a constant.
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, i, Result))
+ return true;
+
+ // Range check against the upper/lower values for this instruction.
+ unsigned Val = Result.getZExtValue();
+ if (Val < l || Val > u)
+ return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
+ << l << u << TheCall->getArg(i)->getSourceRange();
+
+ return false;
+}
+
+/// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo
+/// parameter with the FormatAttr's correct format_idx and firstDataArg.
+/// Returns true when the format fits the function and the FormatStringInfo has
+/// been populated.
+bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
+ FormatStringInfo *FSI) {
+ FSI->HasVAListArg = Format->getFirstArg() == 0;
+ FSI->FormatIdx = Format->getFormatIdx() - 1;
+ FSI->FirstDataArg = FSI->HasVAListArg ? 0 : Format->getFirstArg() - 1;
+
+ // The way the format attribute works in GCC, the implicit this argument
+ // of member functions is counted. However, it doesn't appear in our own
+ // lists, so decrement format_idx in that case.
+ if (IsCXXMember) {
+ if(FSI->FormatIdx == 0)
+ return false;
+ --FSI->FormatIdx;
+ if (FSI->FirstDataArg != 0)
+ --FSI->FirstDataArg;
+ }
+ return true;
+}
+
+/// Handles the checks for format strings, non-POD arguments to vararg
+/// functions, and NULL arguments passed to non-NULL parameters.
+void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
+ unsigned NumArgs,
+ unsigned NumProtoArgs,
+ bool IsMemberFunction,
+ SourceLocation Loc,
+ SourceRange Range,
+ VariadicCallType CallType) {
// FIXME: This mechanism should be abstracted to be less fragile and
// more efficient. For example, just map function ids to custom
// handlers.
// Printf and scanf checking.
+ bool HandledFormatString = false;
for (specific_attr_iterator<FormatAttr>
- i = FDecl->specific_attr_begin<FormatAttr>(),
- e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
- CheckFormatArguments(*i, TheCall);
- }
+ I = FDecl->specific_attr_begin<FormatAttr>(),
+ E = FDecl->specific_attr_end<FormatAttr>(); I != E ; ++I)
+ if (CheckFormatArguments(*I, Args, NumArgs, IsMemberFunction, CallType,
+ Loc, Range))
+ HandledFormatString = true;
+
+ // Refuse POD arguments that weren't caught by the format string
+ // checks above.
+ if (!HandledFormatString && CallType != VariadicDoesNotApply)
+ for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx)
+ variadicArgumentPODCheck(Args[ArgIdx], CallType);
for (specific_attr_iterator<NonNullAttr>
- i = FDecl->specific_attr_begin<NonNullAttr>(),
- e = FDecl->specific_attr_end<NonNullAttr>(); i != e; ++i) {
- CheckNonNullArguments(*i, TheCall->getArgs(),
- TheCall->getCallee()->getLocStart());
- }
+ I = FDecl->specific_attr_begin<NonNullAttr>(),
+ E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
+ CheckNonNullArguments(*I, Args, Loc);
+}
+
+/// CheckConstructorCall - Check a constructor call for correctness and safety
+/// properties not enforced by the C type system.
+void Sema::CheckConstructorCall(FunctionDecl *FDecl, Expr **Args,
+ unsigned NumArgs,
+ const FunctionProtoType *Proto,
+ SourceLocation Loc) {
+ VariadicCallType CallType =
+ Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
+ checkCall(FDecl, Args, NumArgs, Proto->getNumArgs(),
+ /*IsMemberFunction=*/true, Loc, SourceRange(), CallType);
+}
+
+/// CheckFunctionCall - Check a direct function call for various correctness
+/// and safety properties not strictly enforced by the C type system.
+bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
+ const FunctionProtoType *Proto) {
+ bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall);
+ VariadicCallType CallType = getVariadicCallType(FDecl, Proto,
+ TheCall->getCallee());
+ unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
+ checkCall(FDecl, TheCall->getArgs(), TheCall->getNumArgs(), NumProtoArgs,
+ IsMemberFunction, TheCall->getRParenLoc(),
+ TheCall->getCallee()->getSourceRange(), CallType);
+
+ IdentifierInfo *FnInfo = FDecl->getIdentifier();
+ // None of the checks below are needed for functions that don't have
+ // simple names (e.g., C++ conversion functions).
+ if (!FnInfo)
+ return false;
unsigned CMId = FDecl->getMemoryFunctionKind();
if (CMId == 0)
@@ -448,25 +562,18 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
Expr **Args, unsigned NumArgs) {
- for (specific_attr_iterator<FormatAttr>
- i = Method->specific_attr_begin<FormatAttr>(),
- e = Method->specific_attr_end<FormatAttr>(); i != e ; ++i) {
-
- CheckFormatArguments(*i, Args, NumArgs, false, lbrac,
- Method->getSourceRange());
- }
+ VariadicCallType CallType =
+ Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
- // diagnose nonnull arguments.
- for (specific_attr_iterator<NonNullAttr>
- i = Method->specific_attr_begin<NonNullAttr>(),
- e = Method->specific_attr_end<NonNullAttr>(); i != e; ++i) {
- CheckNonNullArguments(*i, Args, lbrac);
- }
+ checkCall(Method, Args, NumArgs, Method->param_size(),
+ /*IsMemberFunction=*/false,
+ lbrac, Method->getSourceRange(), CallType);
return false;
}
-bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
+bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
+ const FunctionProtoType *Proto) {
const VarDecl *V = dyn_cast<VarDecl>(NDecl);
if (!V)
return false;
@@ -475,13 +582,15 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
if (!Ty->isBlockPointerType())
return false;
- // format string checking.
- for (specific_attr_iterator<FormatAttr>
- i = NDecl->specific_attr_begin<FormatAttr>(),
- e = NDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
- CheckFormatArguments(*i, TheCall);
- }
+ VariadicCallType CallType =
+ Proto && Proto->isVariadic() ? VariadicBlock : VariadicDoesNotApply ;
+ unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
+ checkCall(NDecl, TheCall->getArgs(), TheCall->getNumArgs(),
+ NumProtoArgs, /*IsMemberFunction=*/false,
+ TheCall->getRParenLoc(),
+ TheCall->getCallee()->getSourceRange(), CallType);
+
return false;
}
@@ -1260,7 +1369,7 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
// If the common type isn't a real floating type, then the arguments were
// invalid for this operation.
- if (!Res->isRealFloatingType())
+ if (Res.isNull() || !Res->isRealFloatingType())
return Diag(OrigArg0.get()->getLocStart(),
diag::err_typecheck_call_invalid_ordered_compare)
<< OrigArg0.get()->getType() << OrigArg1.get()->getType()
@@ -1409,7 +1518,11 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
// constant integers.
for (unsigned i = 1; i != NumArgs; ++i) {
Expr *Arg = TheCall->getArg(i);
-
+
+ // We can't check the value of a dependent argument.
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ continue;
+
llvm::APSInt Result;
if (SemaBuiltinConstantArg(TheCall, i, Result))
return true;
@@ -1454,7 +1567,12 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
// For compatibility check 0-3, llvm only handles 0 and 2.
bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
llvm::APSInt Result;
-
+
+ // We can't check the value of a dependent argument.
+ if (TheCall->getArg(1)->isTypeDependent() ||
+ TheCall->getArg(1)->isValueDependent())
+ return false;
+
// Check constant-ness first.
if (SemaBuiltinConstantArg(TheCall, 1, Result))
return true;
@@ -1485,14 +1603,19 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
return false;
}
-// Handle i > 1 ? "x" : "y", recursively.
-bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
- unsigned NumArgs, bool HasVAListArg,
- unsigned format_idx, unsigned firstDataArg,
- FormatStringType Type, bool inFunctionCall) {
+// Determine if an expression is a string literal or constant string.
+// If this function returns false on the arguments to a function expecting a
+// format string, we will usually need to emit a warning.
+// True string literals are then checked by CheckFormatString.
+Sema::StringLiteralCheckType
+Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
+ unsigned NumArgs, bool HasVAListArg,
+ unsigned format_idx, unsigned firstDataArg,
+ FormatStringType Type, VariadicCallType CallType,
+ bool inFunctionCall) {
tryAgain:
if (E->isTypeDependent() || E->isValueDependent())
- return false;
+ return SLCT_NotALiteral;
E = E->IgnoreParenCasts();
@@ -1501,18 +1624,26 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
// The behavior of printf and friends in this case is implementation
// dependent. Ideally if the format string cannot be null then
// it should have a 'nonnull' attribute in the function prototype.
- return true;
+ return SLCT_CheckedLiteral;
switch (E->getStmtClass()) {
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
- const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
- return SemaCheckStringLiteral(C->getTrueExpr(), Args, NumArgs, HasVAListArg,
- format_idx, firstDataArg, Type,
- inFunctionCall)
- && SemaCheckStringLiteral(C->getFalseExpr(), Args, NumArgs, HasVAListArg,
- format_idx, firstDataArg, Type,
- inFunctionCall);
+ // The expression is a literal if both sub-expressions were, and it was
+ // completely checked only if both sub-expressions were checked.
+ const AbstractConditionalOperator *C =
+ cast<AbstractConditionalOperator>(E);
+ StringLiteralCheckType Left =
+ checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs,
+ HasVAListArg, format_idx, firstDataArg,
+ Type, CallType, inFunctionCall);
+ if (Left == SLCT_NotALiteral)
+ return SLCT_NotALiteral;
+ StringLiteralCheckType Right =
+ checkFormatStringExpr(C->getFalseExpr(), Args, NumArgs,
+ HasVAListArg, format_idx, firstDataArg,
+ Type, CallType, inFunctionCall);
+ return Left < Right ? Left : Right;
}
case Stmt::ImplicitCastExprClass: {
@@ -1525,13 +1656,13 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
E = src;
goto tryAgain;
}
- return false;
+ return SLCT_NotALiteral;
case Stmt::PredefinedExprClass:
// While __func__, etc., are technically not string literals, they
// cannot contain format specifiers and thus are not a security
// liability.
- return true;
+ return SLCT_UncheckedLiteral;
case Stmt::DeclRefExprClass: {
const DeclRefExpr *DR = cast<DeclRefExpr>(E);
@@ -1554,10 +1685,17 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
}
if (isConstant) {
- if (const Expr *Init = VD->getAnyInitializer())
- return SemaCheckStringLiteral(Init, Args, NumArgs,
- HasVAListArg, format_idx, firstDataArg,
- Type, /*inFunctionCall*/false);
+ if (const Expr *Init = VD->getAnyInitializer()) {
+ // Look through initializers like const char c[] = { "foo" }
+ if (const InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) {
+ if (InitList->isStringLiteralInit())
+ Init = InitList->getInit(0)->IgnoreParenImpCasts();
+ }
+ return checkFormatStringExpr(Init, Args, NumArgs,
+ HasVAListArg, format_idx,
+ firstDataArg, Type, CallType,
+ /*inFunctionCall*/false);
+ }
}
// For vprintf* functions (i.e., HasVAListArg==true), we add a
@@ -1590,14 +1728,14 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
// We can't pass a 'scanf' string to a 'printf' function.
if (PVIndex == PVFormat->getFormatIdx() &&
Type == GetFormatStringType(PVFormat))
- return true;
+ return SLCT_UncheckedLiteral;
}
}
}
}
}
- return false;
+ return SLCT_NotALiteral;
}
case Stmt::CallExprClass:
@@ -1611,13 +1749,23 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
--ArgIndex;
const Expr *Arg = CE->getArg(ArgIndex - 1);
- return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
- format_idx, firstDataArg, Type,
- inFunctionCall);
+ return checkFormatStringExpr(Arg, Args, NumArgs,
+ HasVAListArg, format_idx, firstDataArg,
+ Type, CallType, inFunctionCall);
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ unsigned BuiltinID = FD->getBuiltinID();
+ if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
+ BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
+ const Expr *Arg = CE->getArg(0);
+ return checkFormatStringExpr(Arg, Args, NumArgs,
+ HasVAListArg, format_idx,
+ firstDataArg, Type, CallType,
+ inFunctionCall);
+ }
}
}
- return false;
+ return SLCT_NotALiteral;
}
case Stmt::ObjCStringLiteralClass:
case Stmt::StringLiteralClass: {
@@ -1630,15 +1778,15 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
if (StrE) {
CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
- firstDataArg, Type, inFunctionCall);
- return true;
+ firstDataArg, Type, inFunctionCall, CallType);
+ return SLCT_CheckedLiteral;
}
- return false;
+ return SLCT_NotALiteral;
}
default:
- return false;
+ return SLCT_NotALiteral;
}
}
@@ -1667,44 +1815,30 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
.Default(FST_Unknown);
}
-/// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar
+/// CheckFormatArguments - Check calls to printf and scanf (and similar
/// functions) for correct use of format strings.
-void Sema::CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall) {
- bool IsCXXMember = false;
- // The way the format attribute works in GCC, the implicit this argument
- // of member functions is counted. However, it doesn't appear in our own
- // lists, so decrement format_idx in that case.
- IsCXXMember = isa<CXXMemberCallExpr>(TheCall);
- CheckFormatArguments(Format, TheCall->getArgs(), TheCall->getNumArgs(),
- IsCXXMember, TheCall->getRParenLoc(),
- TheCall->getCallee()->getSourceRange());
-}
-
-void Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
+/// Returns true if a format string has been fully checked.
+bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
unsigned NumArgs, bool IsCXXMember,
+ VariadicCallType CallType,
SourceLocation Loc, SourceRange Range) {
- bool HasVAListArg = Format->getFirstArg() == 0;
- unsigned format_idx = Format->getFormatIdx() - 1;
- unsigned firstDataArg = HasVAListArg ? 0 : Format->getFirstArg() - 1;
- if (IsCXXMember) {
- if (format_idx == 0)
- return;
- --format_idx;
- if(firstDataArg != 0)
- --firstDataArg;
- }
- CheckFormatArguments(Args, NumArgs, HasVAListArg, format_idx,
- firstDataArg, GetFormatStringType(Format), Loc, Range);
+ FormatStringInfo FSI;
+ if (getFormatStringInfo(Format, IsCXXMember, &FSI))
+ return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx,
+ FSI.FirstDataArg, GetFormatStringType(Format),
+ CallType, Loc, Range);
+ return false;
}
-void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
+bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
+ VariadicCallType CallType,
SourceLocation Loc, SourceRange Range) {
// CHECK: printf/scanf-like function is called with no format string.
if (format_idx >= NumArgs) {
Diag(Loc, diag::warn_missing_format_string) << Range;
- return;
+ return false;
}
const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
@@ -1721,21 +1855,25 @@ void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
// C string (e.g. "%d")
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
- if (SemaCheckStringLiteral(OrigFormatExpr, Args, NumArgs, HasVAListArg,
- format_idx, firstDataArg, Type))
- return; // Literal format string found, check done!
+ StringLiteralCheckType CT =
+ checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg,
+ format_idx, firstDataArg, Type, CallType);
+ if (CT != SLCT_NotALiteral)
+ // Literal format string found, check done!
+ return CT == SLCT_CheckedLiteral;
// Strftime is particular as it always uses a single 'time' argument,
// so it is safe to pass a non-literal string.
if (Type == FST_Strftime)
- return;
+ return false;
// Do not emit diag when the string param is a macro expansion and the
// format is either NSString or CFString. This is a hack to prevent
// diag when using the NSLocalizedString and CFCopyLocalizedString macros
// which are usually used in place of NS and CF string literals.
- if (Type == FST_NSString && Args[format_idx]->getLocStart().isMacroID())
- return;
+ if (Type == FST_NSString &&
+ SourceMgr.isInSystemMacro(Args[format_idx]->getLocStart()))
+ return false;
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
@@ -1747,6 +1885,7 @@ void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral)
<< OrigFormatExpr->getSourceRange();
+ return false;
}
namespace {
@@ -1757,7 +1896,6 @@ protected:
const Expr *OrigFormatExpr;
const unsigned FirstDataArg;
const unsigned NumDataArgs;
- const bool IsObjCLiteral;
const char *Beg; // Start of format string.
const bool HasVAListArg;
const Expr * const *Args;
@@ -1767,21 +1905,20 @@ protected:
bool usesPositionalArgs;
bool atFirstArg;
bool inFunctionCall;
+ Sema::VariadicCallType CallType;
public:
CheckFormatHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
- unsigned numDataArgs, bool isObjCLiteral,
- const char *beg, bool hasVAListArg,
+ unsigned numDataArgs, const char *beg, bool hasVAListArg,
Expr **args, unsigned numArgs,
- unsigned formatIdx, bool inFunctionCall)
+ unsigned formatIdx, bool inFunctionCall,
+ Sema::VariadicCallType callType)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
- FirstDataArg(firstDataArg),
- NumDataArgs(numDataArgs),
- IsObjCLiteral(isObjCLiteral), Beg(beg),
- HasVAListArg(hasVAListArg),
+ FirstDataArg(firstDataArg), NumDataArgs(numDataArgs),
+ Beg(beg), HasVAListArg(hasVAListArg),
Args(args), NumArgs(numArgs), FormatIdx(formatIdx),
usesPositionalArgs(false), atFirstArg(true),
- inFunctionCall(inFunctionCall) {
+ inFunctionCall(inFunctionCall), CallType(callType) {
CoveredArgs.resize(numDataArgs);
CoveredArgs.reset();
}
@@ -1938,7 +2075,7 @@ void CheckFormatHandler::HandleZeroPosition(const char *startPos,
}
void CheckFormatHandler::HandleNullChar(const char *nullCharacter) {
- if (!IsObjCLiteral) {
+ if (!isa<ObjCStringLiteral>(OrigFormatExpr)) {
// The presence of a null character is likely an error.
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_format_string_contains_null_char),
@@ -1947,6 +2084,8 @@ void CheckFormatHandler::HandleNullChar(const char *nullCharacter) {
}
}
+// Note that this may return NULL if there was an error parsing or building
+// one of the argument expressions.
const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
return Args[FirstDataArg + i];
}
@@ -1960,9 +2099,14 @@ void CheckFormatHandler::DoneProcessing() {
signed notCoveredArg = CoveredArgs.find_first();
if (notCoveredArg >= 0) {
assert((unsigned)notCoveredArg < NumDataArgs);
- EmitFormatDiagnostic(S.PDiag(diag::warn_printf_data_arg_not_used),
- getDataArg((unsigned) notCoveredArg)->getLocStart(),
- /*IsStringLocation*/false, getFormatStringRange());
+ if (const Expr *E = getDataArg((unsigned) notCoveredArg)) {
+ SourceLocation Loc = E->getLocStart();
+ if (!S.getSourceManager().isInSystemMacro(Loc)) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_data_arg_not_used),
+ Loc, /*IsStringLocation*/false,
+ getFormatStringRange());
+ }
+ }
}
}
}
@@ -2086,17 +2230,20 @@ void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall,
namespace {
class CheckPrintfHandler : public CheckFormatHandler {
+ bool ObjCContext;
public:
CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
- unsigned numDataArgs, bool isObjCLiteral,
+ unsigned numDataArgs, bool isObjC,
const char *beg, bool hasVAListArg,
Expr **Args, unsigned NumArgs,
- unsigned formatIdx, bool inFunctionCall)
+ unsigned formatIdx, bool inFunctionCall,
+ Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
- numDataArgs, isObjCLiteral, beg, hasVAListArg,
- Args, NumArgs, formatIdx, inFunctionCall) {}
-
+ numDataArgs, beg, hasVAListArg, Args, NumArgs,
+ formatIdx, inFunctionCall, CallType), ObjCContext(isObjC)
+ {}
+
bool HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS,
@@ -2106,7 +2253,11 @@ public:
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen);
-
+ bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
+ const char *StartSpecifier,
+ unsigned SpecifierLen,
+ const Expr *E);
+
bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k,
const char *startSpecifier, unsigned specifierLen);
void HandleInvalidAmount(const analyze_printf::PrintfSpecifier &FS,
@@ -2120,6 +2271,9 @@ public:
const analyze_printf::OptionalFlag &ignoredFlag,
const analyze_printf::OptionalFlag &flag,
const char *startSpecifier, unsigned specifierLen);
+ bool checkForCStrMembers(const analyze_printf::ArgType &AT,
+ const Expr *E, const CharSourceRange &CSR);
+
};
}
@@ -2161,14 +2315,17 @@ bool CheckPrintfHandler::HandleAmount(
// doesn't emit a warning for that case.
CoveredArgs.set(argIndex);
const Expr *Arg = getDataArg(argIndex);
+ if (!Arg)
+ return false;
+
QualType T = Arg->getType();
- const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context);
- assert(ATR.isValid());
+ const analyze_printf::ArgType &AT = Amt.getArgType(S.Context);
+ assert(AT.isValid());
- if (!ATR.matchesType(S.Context, T)) {
+ if (!AT.matchesType(S.Context, T)) {
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_wrong_type)
- << k << ATR.getRepresentativeTypeName(S.Context)
+ << k << AT.getRepresentativeTypeName(S.Context)
<< T << Arg->getSourceRange(),
getLocationOfByte(Amt.getStart()),
/*IsStringLocation*/true,
@@ -2237,6 +2394,64 @@ void CheckPrintfHandler::HandleIgnoredFlag(
getSpecifierRange(ignoredFlag.getPosition(), 1)));
}
+// Determines if the specified is a C++ class or struct containing
+// a member with the specified name and kind (e.g. a CXXMethodDecl named
+// "c_str()").
+template<typename MemberKind>
+static llvm::SmallPtrSet<MemberKind*, 1>
+CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
+ const RecordType *RT = Ty->getAs<RecordType>();
+ llvm::SmallPtrSet<MemberKind*, 1> Results;
+
+ if (!RT)
+ return Results;
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return Results;
+
+ LookupResult R(S, &S.PP.getIdentifierTable().get(Name), SourceLocation(),
+ Sema::LookupMemberName);
+
+ // We just need to include all members of the right kind turned up by the
+ // filter, at this point.
+ if (S.LookupQualifiedName(R, RT->getDecl()))
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ NamedDecl *decl = (*I)->getUnderlyingDecl();
+ if (MemberKind *FK = dyn_cast<MemberKind>(decl))
+ Results.insert(FK);
+ }
+ return Results;
+}
+
+// Check if a (w)string was passed when a (w)char* was needed, and offer a
+// better diagnostic if so. AT is assumed to be valid.
+// Returns true when a c_str() conversion method is found.
+bool CheckPrintfHandler::checkForCStrMembers(
+ const analyze_printf::ArgType &AT, const Expr *E,
+ const CharSourceRange &CSR) {
+ typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet;
+
+ MethodSet Results =
+ CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, E->getType());
+
+ for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
+ MI != ME; ++MI) {
+ const CXXMethodDecl *Method = *MI;
+ if (Method->getNumParams() == 0 &&
+ AT.matchesType(S.Context, Method->getResultType())) {
+ // FIXME: Suggest parens if the expression needs them.
+ SourceLocation EndLoc =
+ S.getPreprocessor().getLocForEndOfToken(E->getLocEnd());
+ S.Diag(E->getLocStart(), diag::note_printf_c_str)
+ << "c_str()"
+ << FixItHint::CreateInsertion(EndLoc, ".c_str()");
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool
CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
&FS,
@@ -2288,7 +2503,7 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
// Check for using an Objective-C specific conversion specifier
// in a non-ObjC literal.
- if (!IsObjCLiteral && CS.isObjCArg()) {
+ if (!ObjCContext && CS.isObjCArg()) {
return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
specifierLen);
}
@@ -2346,17 +2561,6 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
HandleNonStandardConversionSpecification(LM, CS, startSpecifier,
specifierLen);
- // Are we using '%n'?
- if (CS.getKind() == ConversionSpecifier::nArg) {
- // Issue a warning about this being a possible security issue.
- EmitFormatDiagnostic(S.PDiag(diag::warn_printf_write_back),
- getLocationOfByte(CS.getStart()),
- /*IsStringLocation*/true,
- getSpecifierRange(startSpecifier, specifierLen));
- // Continue checking the other format specifiers.
- return true;
- }
-
// The remaining checks depend on the data arguments.
if (HasVAListArg)
return true;
@@ -2364,54 +2568,98 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
return false;
+ const Expr *Arg = getDataArg(argIndex);
+ if (!Arg)
+ return true;
+
+ return checkFormatExpr(FS, startSpecifier, specifierLen, Arg);
+}
+
+bool
+CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
+ const char *StartSpecifier,
+ unsigned SpecifierLen,
+ const Expr *E) {
+ using namespace analyze_format_string;
+ using namespace analyze_printf;
// Now type check the data expression that matches the
// format specifier.
- const Expr *Ex = getDataArg(argIndex);
- const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context,
- IsObjCLiteral);
- if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
- // Check if we didn't match because of an implicit cast from a 'char'
- // or 'short' to an 'int'. This is done because printf is a varargs
- // function.
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex))
- if (ICE->getType() == S.Context.IntTy) {
- // All further checking is done on the subexpression.
- Ex = ICE->getSubExpr();
- if (ATR.matchesType(S.Context, Ex->getType()))
- return true;
+ const analyze_printf::ArgType &AT = FS.getArgType(S.Context,
+ ObjCContext);
+ if (AT.isValid() && !AT.matchesType(S.Context, E->getType())) {
+ // Look through argument promotions for our error message's reported type.
+ // This includes the integral and floating promotions, but excludes array
+ // and function pointer decay; seeing that an argument intended to be a
+ // string has type 'char [6]' is probably more confusing than 'char *'.
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->getCastKind() == CK_IntegralCast ||
+ ICE->getCastKind() == CK_FloatingCast) {
+ E = ICE->getSubExpr();
+
+ // Check if we didn't match because of an implicit cast from a 'char'
+ // or 'short' to an 'int'. This is done because printf is a varargs
+ // function.
+ if (ICE->getType() == S.Context.IntTy ||
+ ICE->getType() == S.Context.UnsignedIntTy) {
+ // All further checking is done on the subexpression.
+ if (AT.matchesType(S.Context, E->getType()))
+ return true;
+ }
}
+ }
// We may be able to offer a FixItHint if it is a supported type.
PrintfSpecifier fixedFS = FS;
- bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(),
- S.Context, IsObjCLiteral);
+ bool success = fixedFS.fixType(E->getType(), S.getLangOpts(),
+ S.Context, ObjCContext);
if (success) {
// Get the fix string from the fixed format specifier
- SmallString<128> buf;
+ SmallString<16> buf;
llvm::raw_svector_ostream os(buf);
fixedFS.toString(os);
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
- << Ex->getSourceRange(),
- getLocationOfByte(CS.getStart()),
- /*IsStringLocation*/true,
- getSpecifierRange(startSpecifier, specifierLen),
+ << AT.getRepresentativeTypeName(S.Context) << E->getType()
+ << E->getSourceRange(),
+ E->getLocStart(),
+ /*IsStringLocation*/false,
+ getSpecifierRange(StartSpecifier, SpecifierLen),
FixItHint::CreateReplacement(
- getSpecifierRange(startSpecifier, specifierLen),
+ getSpecifierRange(StartSpecifier, SpecifierLen),
os.str()));
- }
- else {
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
- << getSpecifierRange(startSpecifier, specifierLen)
- << Ex->getSourceRange(),
- getLocationOfByte(CS.getStart()),
- true,
- getSpecifierRange(startSpecifier, specifierLen));
+ } else {
+ const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
+ SpecifierLen);
+ // Since the warning for passing non-POD types to variadic functions
+ // was deferred until now, we emit a warning for non-POD
+ // arguments here.
+ if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) {
+ unsigned DiagKind;
+ if (E->getType()->isObjCObjectType())
+ DiagKind = diag::err_cannot_pass_objc_interface_to_vararg_format;
+ else
+ DiagKind = diag::warn_non_pod_vararg_with_format_string;
+
+ EmitFormatDiagnostic(
+ S.PDiag(DiagKind)
+ << S.getLangOpts().CPlusPlus0x
+ << E->getType()
+ << CallType
+ << AT.getRepresentativeTypeName(S.Context)
+ << CSR
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false, CSR);
+
+ checkForCStrMembers(AT, E, CSR);
+ } else
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << E->getType()
+ << CSR
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false, CSR);
}
}
@@ -2425,13 +2673,14 @@ class CheckScanfHandler : public CheckFormatHandler {
public:
CheckScanfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
- unsigned numDataArgs, bool isObjCLiteral,
- const char *beg, bool hasVAListArg,
+ unsigned numDataArgs, const char *beg, bool hasVAListArg,
Expr **Args, unsigned NumArgs,
- unsigned formatIdx, bool inFunctionCall)
+ unsigned formatIdx, bool inFunctionCall,
+ Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
- numDataArgs, isObjCLiteral, beg, hasVAListArg,
- Args, NumArgs, formatIdx, inFunctionCall) {}
+ numDataArgs, beg, hasVAListArg,
+ Args, NumArgs, formatIdx, inFunctionCall, CallType)
+ {}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
@@ -2548,8 +2797,11 @@ bool CheckScanfHandler::HandleScanfSpecifier(
// Check that the argument type matches the format specifier.
const Expr *Ex = getDataArg(argIndex);
- const analyze_scanf::ScanfArgTypeResult &ATR = FS.getArgType(S.Context);
- if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
+ if (!Ex)
+ return true;
+
+ const analyze_format_string::ArgType &AT = FS.getArgType(S.Context);
+ if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) {
ScanfSpecifier fixedFS = FS;
bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(),
S.Context);
@@ -2562,10 +2814,10 @@ bool CheckScanfHandler::HandleScanfSpecifier(
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+ << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
<< Ex->getSourceRange(),
- getLocationOfByte(CS.getStart()),
- /*IsStringLocation*/true,
+ Ex->getLocStart(),
+ /*IsStringLocation*/false,
getSpecifierRange(startSpecifier, specifierLen),
FixItHint::CreateReplacement(
getSpecifierRange(startSpecifier, specifierLen),
@@ -2573,10 +2825,10 @@ bool CheckScanfHandler::HandleScanfSpecifier(
} else {
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+ << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
<< Ex->getSourceRange(),
- getLocationOfByte(CS.getStart()),
- /*IsStringLocation*/true,
+ Ex->getLocStart(),
+ /*IsStringLocation*/false,
getSpecifierRange(startSpecifier, specifierLen));
}
}
@@ -2589,10 +2841,10 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
Expr **Args, unsigned NumArgs,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
- bool inFunctionCall) {
+ bool inFunctionCall, VariadicCallType CallType) {
// CHECK: is the format string a wide literal?
- if (!FExpr->isAscii()) {
+ if (!FExpr->isAscii() && !FExpr->isUTF8()) {
CheckFormatHandler::EmitFormatDiagnostic(
*this, inFunctionCall, Args[format_idx],
PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(),
@@ -2617,18 +2869,17 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
if (Type == FST_Printf || Type == FST_NSString) {
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
- numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
+ numDataArgs, (Type == FST_NSString),
Str, HasVAListArg, Args, NumArgs, format_idx,
- inFunctionCall);
+ inFunctionCall, CallType);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
getLangOpts()))
H.DoneProcessing();
} else if (Type == FST_Scanf) {
- CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
- numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
+ CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
Str, HasVAListArg, Args, NumArgs, format_idx,
- inFunctionCall);
+ inFunctionCall, CallType);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
getLangOpts()))
@@ -2728,19 +2979,43 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
// TODO: For strncpy() and friends, this could suggest sizeof(dst)
// over sizeof(src) as well.
unsigned ActionIdx = 0; // Default is to suggest dereferencing.
+ StringRef ReadableName = FnName->getName();
+
if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
if (UnaryOp->getOpcode() == UO_AddrOf)
ActionIdx = 1; // If its an address-of operator, just remove it.
if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
ActionIdx = 2; // If the pointee's size is sizeof(char),
// suggest an explicit length.
- unsigned DestSrcSelect =
- (BId == Builtin::BIstrndup ? 1 : ArgIdx);
- DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest,
+
+ // If the function is defined as a builtin macro, do not show macro
+ // expansion.
+ SourceLocation SL = SizeOfArg->getExprLoc();
+ SourceRange DSR = Dest->getSourceRange();
+ SourceRange SSR = SizeOfArg->getSourceRange();
+ SourceManager &SM = PP.getSourceManager();
+
+ if (SM.isMacroArgExpansion(SL)) {
+ ReadableName = Lexer::getImmediateMacroName(SL, SM, LangOpts);
+ SL = SM.getSpellingLoc(SL);
+ DSR = SourceRange(SM.getSpellingLoc(DSR.getBegin()),
+ SM.getSpellingLoc(DSR.getEnd()));
+ SSR = SourceRange(SM.getSpellingLoc(SSR.getBegin()),
+ SM.getSpellingLoc(SSR.getEnd()));
+ }
+
+ DiagRuntimeBehavior(SL, SizeOfArg,
PDiag(diag::warn_sizeof_pointer_expr_memaccess)
- << FnName << DestSrcSelect << ActionIdx
- << Dest->getSourceRange()
- << SizeOfArg->getSourceRange());
+ << ReadableName
+ << PointeeTy
+ << DestTy
+ << DSR
+ << SSR);
+ DiagRuntimeBehavior(SL, SizeOfArg,
+ PDiag(diag::warn_sizeof_pointer_expr_memaccess_note)
+ << ActionIdx
+ << SSR);
+
break;
}
}
@@ -2826,6 +3101,19 @@ static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) {
return Ex;
}
+static bool isConstantSizeArrayWithMoreThanOneElement(QualType Ty,
+ ASTContext &Context) {
+ // Only handle constant-sized or VLAs, but not flexible members.
+ if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(Ty)) {
+ // Only issue the FIXIT for arrays of size > 1.
+ if (CAT->getSize().getSExtValue() <= 1)
+ return false;
+ } else if (!Ty->isVariableArrayType()) {
+ return false;
+ }
+ return true;
+}
+
// Warn if the user has made the 'size' argument to strlcpy or strlcat
// be the size of the source, instead of the destination.
void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
@@ -2876,16 +3164,8 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
// pointers if we know the actual size, like if DstArg is 'array+2'
// we could say 'sizeof(array)-2'.
const Expr *DstArg = Call->getArg(0)->IgnoreParenImpCasts();
- QualType DstArgTy = DstArg->getType();
-
- // Only handle constant-sized or VLAs, but not flexible members.
- if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(DstArgTy)) {
- // Only issue the FIXIT for arrays of size > 1.
- if (CAT->getSize().getSExtValue() <= 1)
- return;
- } else if (!DstArgTy->isVariableArrayType()) {
+ if (!isConstantSizeArrayWithMoreThanOneElement(DstArg->getType(), Context))
return;
- }
SmallString<128> sizeString;
llvm::raw_svector_ostream OS(sizeString);
@@ -2967,26 +3247,23 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
SM.getSpellingLoc(SR.getEnd()));
}
+ // Check if the destination is an array (rather than a pointer to an array).
+ QualType DstTy = DstArg->getType();
+ bool isKnownSizeArray = isConstantSizeArrayWithMoreThanOneElement(DstTy,
+ Context);
+ if (!isKnownSizeArray) {
+ if (PatternType == 1)
+ Diag(SL, diag::warn_strncat_wrong_size) << SR;
+ else
+ Diag(SL, diag::warn_strncat_src_size) << SR;
+ return;
+ }
+
if (PatternType == 1)
Diag(SL, diag::warn_strncat_large_size) << SR;
else
Diag(SL, diag::warn_strncat_src_size) << SR;
- // Output a FIXIT hint if the destination is an array (rather than a
- // pointer to an array). This could be enhanced to handle some
- // pointers if we know the actual size, like if DstArg is 'array+2'
- // we could say 'sizeof(array)-2'.
- QualType DstArgTy = DstArg->getType();
-
- // Only handle constant-sized or VLAs, but not flexible members.
- if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(DstArgTy)) {
- // Only issue the FIXIT for arrays of size > 1.
- if (CAT->getSize().getSExtValue() <= 1)
- return;
- } else if (!DstArgTy->isVariableArrayType()) {
- return;
- }
-
SmallString<128> sizeString;
llvm::raw_svector_ostream OS(sizeString);
OS << "sizeof(";
@@ -3002,8 +3279,10 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
//===--- CHECK: Return Address of Stack Variable --------------------------===//
-static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars);
-static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars);
+static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
+ Decl *ParentDecl);
+static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars,
+ Decl *ParentDecl);
/// CheckReturnStackAddr - Check if a return statement returns the address
/// of a stack variable.
@@ -3018,9 +3297,9 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
// label addresses or references to temporaries.
if (lhsType->isPointerType() ||
(!getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
- stackE = EvalAddr(RetValExp, refVars);
+ stackE = EvalAddr(RetValExp, refVars, /*ParentDecl=*/0);
} else if (lhsType->isReferenceType()) {
- stackE = EvalVal(RetValExp, refVars);
+ stackE = EvalVal(RetValExp, refVars, /*ParentDecl=*/0);
}
if (stackE == 0)
@@ -3094,7 +3373,8 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
/// * arbitrary interplay between "&" and "*" operators
/// * pointer arithmetic from an address of a stack variable
/// * taking the address of an array element where the array is on the stack
-static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
+static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
+ Decl *ParentDecl) {
if (E->isTypeDependent())
return NULL;
@@ -3120,7 +3400,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
V->getType()->isReferenceType() && V->hasInit()) {
// Add the reference variable to the "trail".
refVars.push_back(DR);
- return EvalAddr(V->getInit(), refVars);
+ return EvalAddr(V->getInit(), refVars, ParentDecl);
}
return NULL;
@@ -3132,7 +3412,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
UnaryOperator *U = cast<UnaryOperator>(E);
if (U->getOpcode() == UO_AddrOf)
- return EvalVal(U->getSubExpr(), refVars);
+ return EvalVal(U->getSubExpr(), refVars, ParentDecl);
else
return NULL;
}
@@ -3153,7 +3433,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
if (!Base->getType()->isPointerType()) Base = B->getRHS();
assert (Base->getType()->isPointerType());
- return EvalAddr(Base, refVars);
+ return EvalAddr(Base, refVars, ParentDecl);
}
// For conditional operators we need to see if either the LHS or RHS are
@@ -3165,7 +3445,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
if (Expr *lhsExpr = C->getLHS()) {
// In C++, we can have a throw-expression, which has 'void' type.
if (!lhsExpr->getType()->isVoidType())
- if (Expr* LHS = EvalAddr(lhsExpr, refVars))
+ if (Expr* LHS = EvalAddr(lhsExpr, refVars, ParentDecl))
return LHS;
}
@@ -3173,7 +3453,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
if (C->getRHS()->getType()->isVoidType())
return NULL;
- return EvalAddr(C->getRHS(), refVars);
+ return EvalAddr(C->getRHS(), refVars, ParentDecl);
}
case Stmt::BlockExprClass:
@@ -3185,7 +3465,8 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
return E; // address of label.
case Stmt::ExprWithCleanupsClass:
- return EvalAddr(cast<ExprWithCleanups>(E)->getSubExpr(), refVars);
+ return EvalAddr(cast<ExprWithCleanups>(E)->getSubExpr(), refVars,
+ ParentDecl);
// For casts, we need to handle conversions from arrays to
// pointer values, and pointer-to-pointer conversions.
@@ -3209,10 +3490,10 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
- return EvalAddr(SubExpr, refVars);
+ return EvalAddr(SubExpr, refVars, ParentDecl);
case CK_ArrayToPointerDecay:
- return EvalVal(SubExpr, refVars);
+ return EvalVal(SubExpr, refVars, ParentDecl);
default:
return 0;
@@ -3222,7 +3503,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
case Stmt::MaterializeTemporaryExprClass:
if (Expr *Result = EvalAddr(
cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
- refVars))
+ refVars, ParentDecl))
return Result;
return E;
@@ -3236,7 +3517,8 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
/// EvalVal - This function is complements EvalAddr in the mutual recursion.
/// See the comments for EvalAddr for more details.
-static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
+static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
+ Decl *ParentDecl) {
do {
// We should only be called for evaluating non-pointer expressions, or
// expressions with a pointer type that are not used as references but instead
@@ -3258,7 +3540,7 @@ do {
}
case Stmt::ExprWithCleanupsClass:
- return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars);
+ return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars,ParentDecl);
case Stmt::DeclRefExprClass: {
// When we hit a DeclRefExpr we are looking at code that refers to a
@@ -3266,7 +3548,11 @@ do {
// local storage within the function, and if so, return the expression.
DeclRefExpr *DR = cast<DeclRefExpr>(E);
- if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
+ if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) {
+ // Check if it refers to itself, e.g. "int& i = i;".
+ if (V == ParentDecl)
+ return DR;
+
if (V->hasLocalStorage()) {
if (!V->getType()->isReferenceType())
return DR;
@@ -3276,9 +3562,10 @@ do {
if (V->hasInit()) {
// Add the reference variable to the "trail".
refVars.push_back(DR);
- return EvalVal(V->getInit(), refVars);
+ return EvalVal(V->getInit(), refVars, V);
}
}
+ }
return NULL;
}
@@ -3290,7 +3577,7 @@ do {
UnaryOperator *U = cast<UnaryOperator>(E);
if (U->getOpcode() == UO_Deref)
- return EvalAddr(U->getSubExpr(), refVars);
+ return EvalAddr(U->getSubExpr(), refVars, ParentDecl);
return NULL;
}
@@ -3299,7 +3586,7 @@ do {
// Array subscripts are potential references to data on the stack. We
// retrieve the DeclRefExpr* for the array variable if it indeed
// has local storage.
- return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars);
+ return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars,ParentDecl);
}
case Stmt::ConditionalOperatorClass: {
@@ -3309,10 +3596,10 @@ do {
// Handle the GNU extension for missing LHS.
if (Expr *lhsExpr = C->getLHS())
- if (Expr *LHS = EvalVal(lhsExpr, refVars))
+ if (Expr *LHS = EvalVal(lhsExpr, refVars, ParentDecl))
return LHS;
- return EvalVal(C->getRHS(), refVars);
+ return EvalVal(C->getRHS(), refVars, ParentDecl);
}
// Accesses to members are potential references to data on the stack.
@@ -3328,13 +3615,13 @@ do {
if (M->getMemberDecl()->getType()->isReferenceType())
return NULL;
- return EvalVal(M->getBase(), refVars);
+ return EvalVal(M->getBase(), refVars, ParentDecl);
}
case Stmt::MaterializeTemporaryExprClass:
if (Expr *Result = EvalVal(
cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
- refVars))
+ refVars, ParentDecl))
return Result;
return E;
@@ -3357,8 +3644,6 @@ do {
/// Issue a warning if these are no self-comparisons, as they are not likely
/// to do what the programmer intended.
void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
- bool EmitWarning = true;
-
Expr* LeftExprSansParen = LHS->IgnoreParenImpCasts();
Expr* RightExprSansParen = RHS->IgnoreParenImpCasts();
@@ -3367,7 +3652,7 @@ void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LeftExprSansParen))
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RightExprSansParen))
if (DRL->getDecl() == DRR->getDecl())
- EmitWarning = false;
+ return;
// Special case: check for comparisons against literals that can be exactly
@@ -3375,32 +3660,26 @@ void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
// is a heuristic: often comparison against such literals are used to
// detect if a value in a variable has not changed. This clearly can
// lead to false negatives.
- if (EmitWarning) {
- if (FloatingLiteral* FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) {
- if (FLL->isExact())
- EmitWarning = false;
- } else
- if (FloatingLiteral* FLR = dyn_cast<FloatingLiteral>(RightExprSansParen)){
- if (FLR->isExact())
- EmitWarning = false;
- }
- }
+ if (FloatingLiteral* FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) {
+ if (FLL->isExact())
+ return;
+ } else
+ if (FloatingLiteral* FLR = dyn_cast<FloatingLiteral>(RightExprSansParen))
+ if (FLR->isExact())
+ return;
// Check for comparisons with builtin types.
- if (EmitWarning)
- if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen))
- if (CL->isBuiltinCall())
- EmitWarning = false;
+ if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen))
+ if (CL->isBuiltinCall())
+ return;
- if (EmitWarning)
- if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
- if (CR->isBuiltinCall())
- EmitWarning = false;
+ if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
+ if (CR->isBuiltinCall())
+ return;
// Emit the diagnostic.
- if (EmitWarning)
- Diag(Loc, diag::warn_floatingpoint_eq)
- << LHS->getSourceRange() << RHS->getSourceRange();
+ Diag(Loc, diag::warn_floatingpoint_eq)
+ << LHS->getSourceRange() << RHS->getSourceRange();
}
//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===//
@@ -3927,9 +4206,10 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
return;
}
- S.Diag(E->getOperatorLoc(), diag::warn_mixed_sign_comparison)
- << LHS->getType() << RHS->getType()
- << LHS->getSourceRange() << RHS->getSourceRange();
+ S.DiagRuntimeBehavior(E->getOperatorLoc(), E,
+ S.PDiag(diag::warn_mixed_sign_comparison)
+ << LHS->getType() << RHS->getType()
+ << LHS->getSourceRange() << RHS->getSourceRange());
}
/// Analyzes an attempt to assign the given value to a bitfield.
@@ -3970,7 +4250,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
// Check whether the stored value is equal to the original value.
TruncatedValue = TruncatedValue.extend(OriginalWidth);
- if (Value == TruncatedValue)
+ if (llvm::APSInt::isSameValue(Value, TruncatedValue))
return false;
// Special-case bitfields of width 1: booleans are naturally 0/1, and
@@ -4044,8 +4324,17 @@ void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T,
== llvm::APFloat::opOK && isExact)
return;
+ SmallString<16> PrettySourceValue;
+ Value.toString(PrettySourceValue);
+ SmallString<16> PrettyTargetValue;
+ if (T->isSpecificBuiltinType(BuiltinType::Bool))
+ PrettyTargetValue = IntegerValue == 0 ? "false" : "true";
+ else
+ IntegerValue.toString(PrettyTargetValue);
+
S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer)
- << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext);
+ << FL->getType() << T.getUnqualifiedType() << PrettySourceValue
+ << PrettyTargetValue << FL->getSourceRange() << SourceRange(CContext);
}
std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
@@ -4112,7 +4401,6 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
}
}
- return; // Other casts to bool are not checked.
}
// Strip vector types.
@@ -4176,7 +4464,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
// If the target is integral, always warn.
- if ((TargetBT && TargetBT->isInteger())) {
+ if (TargetBT && TargetBT->isInteger()) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
@@ -4196,19 +4484,26 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
}
- if (!Source->isIntegerType() || !Target->isIntegerType())
- return;
-
if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
- == Expr::NPCK_GNUNull) && Target->isIntegerType()) {
+ == Expr::NPCK_GNUNull) && !Target->isAnyPointerType()
+ && !Target->isBlockPointerType() && !Target->isMemberPointerType()) {
SourceLocation Loc = E->getSourceRange().getBegin();
if (Loc.isMacroID())
Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
- S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
- << T << Loc << clang::SourceRange(CC);
- return;
+ if (!Loc.isMacroID() || CC.isMacroID())
+ S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
+ << T << clang::SourceRange(CC)
+ << FixItHint::CreateReplacement(Loc, S.getFixItZeroLiteralForType(T));
}
+ if (!Source->isIntegerType() || !Target->isIntegerType())
+ return;
+
+ // TODO: remove this early return once the false positives for constant->bool
+ // in templates, macros, etc, are reduced or removed.
+ if (Target->isSpecificBuiltinType(BuiltinType::Bool))
+ return;
+
IntRange SourceRange = GetExprRange(S.Context, E);
IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target);
@@ -4293,14 +4588,15 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
}
-void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T);
+void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
+ SourceLocation CC, QualType T);
void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool &ICContext) {
E = E->IgnoreParenImpCasts();
if (isa<ConditionalOperator>(E))
- return CheckConditionalOperator(S, cast<ConditionalOperator>(E), T);
+ return CheckConditionalOperator(S, cast<ConditionalOperator>(E), CC, T);
AnalyzeImplicitConversions(S, E, CC);
if (E->getType() != T)
@@ -4308,9 +4604,8 @@ void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
return;
}
-void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) {
- SourceLocation CC = E->getQuestionLoc();
-
+void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
+ SourceLocation CC, QualType T) {
AnalyzeImplicitConversions(S, E->getCond(), CC);
bool Suspicious = false;
@@ -4352,7 +4647,7 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
// were being fed directly into the output.
if (isa<ConditionalOperator>(E)) {
ConditionalOperator *CO = cast<ConditionalOperator>(E);
- CheckConditionalOperator(S, CO, T);
+ CheckConditionalOperator(S, CO, CC, T);
return;
}
@@ -4417,7 +4712,7 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
/// conversion
void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
// Don't diagnose in unevaluated contexts.
- if (ExprEvalContexts.back().Context == Sema::Unevaluated)
+ if (isUnevaluatedContext())
return;
// Don't diagnose for value- or type-dependent expressions.
@@ -4457,7 +4752,7 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd,
// This is also C++ [dcl.fct]p6.
if (!Param->isInvalidDecl() &&
RequireCompleteType(Param->getLocation(), Param->getType(),
- diag::err_typecheck_decl_incomplete_type)) {
+ diag::err_typecheck_decl_incomplete_type)) {
Param->setInvalidDecl();
HasInvalidParm = true;
}
@@ -4478,7 +4773,7 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd,
QualType PType = Param->getOriginalType();
if (const ArrayType *AT = Context.getAsArrayType(PType)) {
if (AT->getSizeModifier() == ArrayType::Star) {
- // FIXME: This diagnosic should point the the '[*]' if source-location
+ // FIXME: This diagnosic should point the '[*]' if source-location
// information is added for it.
Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
}
@@ -4556,11 +4851,23 @@ static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size,
// Don't consider sizes resulting from macro expansions or template argument
// substitution to form C89 tail-padded arrays.
- ConstantArrayTypeLoc TL =
- cast<ConstantArrayTypeLoc>(FD->getTypeSourceInfo()->getTypeLoc());
- const Expr *SizeExpr = dyn_cast<IntegerLiteral>(TL.getSizeExpr());
- if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
- return false;
+
+ TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
+ while (TInfo) {
+ TypeLoc TL = TInfo->getTypeLoc();
+ // Look through typedefs.
+ const TypedefTypeLoc *TTL = dyn_cast<TypedefTypeLoc>(&TL);
+ if (TTL) {
+ const TypedefNameDecl *TDL = TTL->getTypedefNameDecl();
+ TInfo = TDL->getTypeSourceInfo();
+ continue;
+ }
+ ConstantArrayTypeLoc CTL = cast<ConstantArrayTypeLoc>(TL);
+ const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
+ if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
+ return false;
+ break;
+ }
const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext());
if (!RD) return false;
@@ -4966,7 +5273,7 @@ bool Sema::checkUnsafeAssigns(SourceLocation Loc,
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
if (cast->getCastKind() == CK_ARCConsumeObject) {
Diag(Loc, diag::warn_arc_retained_assign)
- << (LT == Qualifiers::OCL_ExplicitNone)
+ << (LT == Qualifiers::OCL_ExplicitNone) << 1
<< RHS->getSourceRange();
return true;
}
@@ -5023,6 +5330,16 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
RHS = cast->getSubExpr();
}
}
+ else if (Attributes & ObjCPropertyDecl::OBJC_PR_weak) {
+ while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+ if (cast->getCastKind() == CK_ARCConsumeObject) {
+ Diag(Loc, diag::warn_arc_retained_assign)
+ << 0 << 0<< RHS->getSourceRange();
+ return;
+ }
+ RHS = cast->getSubExpr();
+ }
+ }
}
}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 1ee7532..9fa757d 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -158,7 +158,7 @@ namespace {
/// \brief The completion context in which we are gathering results.
CodeCompletionContext CompletionContext;
- /// \brief If we are in an instance method definition, the @implementation
+ /// \brief If we are in an instance method definition, the \@implementation
/// object.
ObjCImplementationDecl *ObjCImplementation;
@@ -1181,7 +1181,7 @@ bool ResultBuilder::IsImpossibleToSatisfy(NamedDecl *ND) const {
return false;
}
-/// \rief Determines whether the given declaration is an Objective-C
+/// \brief Determines whether the given declaration is an Objective-C
/// instance variable.
bool ResultBuilder::IsObjCIvar(NamedDecl *ND) const {
return isa<ObjCIvarDecl>(ND);
@@ -1414,7 +1414,7 @@ static const char *GetCompletionTypeString(QualType T,
if (!T.getLocalQualifiers()) {
// Built-in type names are constant strings.
if (const BuiltinType *BT = dyn_cast<BuiltinType>(T))
- return BT->getName(Policy);
+ return BT->getNameAsCString(Policy);
// Anonymous tag types are constant strings.
if (const TagType *TagT = dyn_cast<TagType>(T))
@@ -1955,6 +1955,19 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
AddObjCExpressionResults(Results, true);
}
+ if (SemaRef.getLangOpts().C11) {
+ // _Alignof
+ Builder.AddResultTypeChunk("size_t");
+ if (SemaRef.getASTContext().Idents.get("alignof").hasMacroDefinition())
+ Builder.AddTypedTextChunk("alignof");
+ else
+ Builder.AddTypedTextChunk("_Alignof");
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddPlaceholderChunk("type");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Builder.TakeString()));
+ }
+
// sizeof expression
Builder.AddResultTypeChunk("size_t");
Builder.AddTypedTextChunk("sizeof");
@@ -2356,11 +2369,11 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
// Handle multiple qualifiers.
std::string QualsStr;
- if (Proto->getTypeQuals() & Qualifiers::Const)
+ if (Proto->isConst())
QualsStr += " const";
- if (Proto->getTypeQuals() & Qualifiers::Volatile)
+ if (Proto->isVolatile())
QualsStr += " volatile";
- if (Proto->getTypeQuals() & Qualifiers::Restrict)
+ if (Proto->isRestrict())
QualsStr += " restrict";
Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr));
}
@@ -2440,8 +2453,10 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(Sema &S,
CodeCompletionAllocator &Allocator,
- CodeCompletionTUInfo &CCTUInfo) {
- return CreateCodeCompletionString(S.Context, S.PP, Allocator, CCTUInfo);
+ CodeCompletionTUInfo &CCTUInfo,
+ bool IncludeBriefComments) {
+ return CreateCodeCompletionString(S.Context, S.PP, Allocator, CCTUInfo,
+ IncludeBriefComments);
}
/// \brief If possible, create a new code completion string for the given
@@ -2454,7 +2469,8 @@ CodeCompletionString *
CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
Preprocessor &PP,
CodeCompletionAllocator &Allocator,
- CodeCompletionTUInfo &CCTUInfo) {
+ CodeCompletionTUInfo &CCTUInfo,
+ bool IncludeBriefComments) {
CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability);
PrintingPolicy Policy = getCompletionPrintingPolicy(Ctx, PP);
@@ -2524,7 +2540,14 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
assert(Kind == RK_Declaration && "Missed a result kind?");
NamedDecl *ND = Declaration;
Result.addParentContext(ND->getDeclContext());
-
+
+ if (IncludeBriefComments) {
+ // Add documentation comment, if it exists.
+ if (const RawComment *RC = Ctx.getRawCommentForAnyRedecl(ND)) {
+ Result.addBriefComment(RC->getBriefText(Ctx));
+ }
+ }
+
if (StartsNestedNameSpecifier) {
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(ND->getNameAsString()));
@@ -2842,6 +2865,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
case Decl::ClassTemplatePartialSpecialization:
return CXCursor_ClassTemplatePartialSpecialization;
case Decl::UsingDirective: return CXCursor_UsingDirective;
+ case Decl::TranslationUnit: return CXCursor_TranslationUnit;
case Decl::Using:
case Decl::UnresolvedUsingValue:
@@ -3270,9 +3294,6 @@ struct Sema::CodeCompleteExpressionData {
/// \brief Perform code-completion in an expression context when we know what
/// type we're looking for.
-///
-/// \param IntegralConstantExpression Only permit integral constant
-/// expressions.
void Sema::CodeCompleteExpression(Scope *S,
const CodeCompleteExpressionData &Data) {
typedef CodeCompletionResult Result;
@@ -3333,7 +3354,25 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) {
/// property name.
typedef llvm::SmallPtrSet<IdentifierInfo*, 16> AddedPropertiesSet;
-static void AddObjCProperties(ObjCContainerDecl *Container,
+/// \brief Retrieve the container definition, if any?
+static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) {
+ if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
+ if (Interface->hasDefinition())
+ return Interface->getDefinition();
+
+ return Interface;
+ }
+
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
+ if (Protocol->hasDefinition())
+ return Protocol->getDefinition();
+
+ return Protocol;
+ }
+ return Container;
+}
+
+static void AddObjCProperties(ObjCContainerDecl *Container,
bool AllowCategories,
bool AllowNullaryMethods,
DeclContext *CurContext,
@@ -3341,6 +3380,9 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
ResultBuilder &Results) {
typedef CodeCompletionResult Result;
+ // Retrieve the definition.
+ Container = getContainerDef(Container);
+
// Add properties in this container.
for (ObjCContainerDecl::prop_iterator P = Container->prop_begin(),
PEnd = Container->prop_end();
@@ -3616,6 +3658,8 @@ void Sema::CodeCompleteCase(Scope *S) {
// Code-complete the cases of a switch statement over an enumeration type
// by providing the list of
EnumDecl *Enum = type->castAs<EnumType>()->getDecl();
+ if (EnumDecl *Def = Enum->getDefinition())
+ Enum = Def;
// Determine which enumerators we have already seen in the switch statement.
// FIXME: Ideally, we would also be able to look *past* the code-completion
@@ -4273,27 +4317,28 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
Results.data(), Results.size());
}
-// Macro that expands to @Keyword or Keyword, depending on whether NeedAt is
-// true or false.
-#define OBJC_AT_KEYWORD_NAME(NeedAt,Keyword) NeedAt? "@" #Keyword : #Keyword
+/// Macro that optionally prepends an "@" to the string literal passed in via
+/// Keyword, depending on whether NeedAt is true or false.
+#define OBJC_AT_KEYWORD_NAME(NeedAt,Keyword) ((NeedAt)? "@" Keyword : Keyword)
+
static void AddObjCImplementationResults(const LangOptions &LangOpts,
ResultBuilder &Results,
bool NeedAt) {
typedef CodeCompletionResult Result;
// Since we have an implementation, we can end it.
- Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"end")));
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
if (LangOpts.ObjC2) {
// @dynamic
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,dynamic));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"dynamic"));
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("property");
Results.AddResult(Result(Builder.TakeString()));
// @synthesize
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synthesize));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"synthesize"));
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("property");
Results.AddResult(Result(Builder.TakeString()));
@@ -4306,17 +4351,17 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts,
typedef CodeCompletionResult Result;
// Since we have an interface or protocol, we can end it.
- Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"end")));
if (LangOpts.ObjC2) {
// @property
- Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,property)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"property")));
// @required
- Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,required)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"required")));
// @optional
- Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,optional)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"optional")));
}
}
@@ -4326,7 +4371,7 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
Results.getCodeCompletionTUInfo());
// @class name ;
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"class"));
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("name");
Results.AddResult(Result(Builder.TakeString()));
@@ -4335,26 +4380,26 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
// @interface name
// FIXME: Could introduce the whole pattern, including superclasses and
// such.
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,interface));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"interface"));
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("class");
Results.AddResult(Result(Builder.TakeString()));
// @protocol name
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"protocol"));
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("protocol");
Results.AddResult(Result(Builder.TakeString()));
// @implementation name
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,implementation));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"implementation"));
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("class");
Results.AddResult(Result(Builder.TakeString()));
}
// @compatibility_alias name
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,compatibility_alias));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"compatibility_alias"));
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("alias");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
@@ -4389,9 +4434,9 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
const char *EncodeType = "char[]";
if (Results.getSema().getLangOpts().CPlusPlus ||
Results.getSema().getLangOpts().ConstStrings)
- EncodeType = " const char[]";
+ EncodeType = "const char[]";
Builder.AddResultTypeChunk(EncodeType);
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,encode));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"encode"));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("type-name");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -4399,7 +4444,7 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
// @protocol ( protocol-name )
Builder.AddResultTypeChunk("Protocol *");
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"protocol"));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("protocol-name");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -4407,31 +4452,43 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
// @selector ( selector )
Builder.AddResultTypeChunk("SEL");
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,selector));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"selector"));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("selector");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
Results.AddResult(Result(Builder.TakeString()));
-
- // @[ objects, ... ]
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,[));
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+
+ // @"string"
+ Builder.AddResultTypeChunk("NSString *");
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"\""));
+ Builder.AddPlaceholderChunk("string");
+ Builder.AddTextChunk("\"");
+ Results.AddResult(Result(Builder.TakeString()));
+
+ // @[objects, ...]
+ Builder.AddResultTypeChunk("NSArray *");
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"["));
Builder.AddPlaceholderChunk("objects, ...");
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_RightBracket);
Results.AddResult(Result(Builder.TakeString()));
- // @{ key : object, ... }
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,{));
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ // @{key : object, ...}
+ Builder.AddResultTypeChunk("NSDictionary *");
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"{"));
Builder.AddPlaceholderChunk("key");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_Colon);
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("object, ...");
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
Results.AddResult(Result(Builder.TakeString()));
+
+ // @(expression)
+ Builder.AddResultTypeChunk("id");
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "("));
+ Builder.AddPlaceholderChunk("expression");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Builder.TakeString()));
}
static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
@@ -4442,7 +4499,7 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
if (Results.includeCodePatterns()) {
// @try { statements } @catch ( declaration ) { statements } @finally
// { statements }
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,try));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"try"));
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
Builder.AddPlaceholderChunk("statements");
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
@@ -4461,14 +4518,14 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
}
// @throw
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"throw"));
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("expression");
Results.AddResult(Result(Builder.TakeString()));
if (Results.includeCodePatterns()) {
// @synchronized ( expression ) { statements }
- Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synchronized));
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"synchronized"));
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("expression");
@@ -4484,11 +4541,11 @@ static void AddObjCVisibilityResults(const LangOptions &LangOpts,
ResultBuilder &Results,
bool NeedAt) {
typedef CodeCompletionResult Result;
- Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,private)));
- Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,protected)));
- Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,public)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"private")));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"protected")));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"public")));
if (LangOpts.ObjC2)
- Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,package)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"package")));
}
void Sema::CodeCompleteObjCAtVisibility(Scope *S) {
@@ -4616,12 +4673,12 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
Results.data(),Results.size());
}
-/// \brief Descripts the kind of Objective-C method that we want to find
+/// \brief Describes the kind of Objective-C method that we want to find
/// via code completion.
enum ObjCMethodKind {
- MK_Any, //< Any kind of method, provided it means other specified criteria.
- MK_ZeroArgSelector, //< Zero-argument (unary) selector.
- MK_OneArgSelector //< One-argument selector.
+ MK_Any, ///< Any kind of method, provided it means other specified criteria.
+ MK_ZeroArgSelector, ///< Zero-argument (unary) selector.
+ MK_OneArgSelector ///< One-argument selector.
};
static bool isAcceptableObjCSelector(Selector Sel,
@@ -4673,8 +4730,8 @@ namespace {
///
/// \param Container the container in which we'll look to find methods.
///
-/// \param WantInstance whether to add instance methods (only); if false, this
-/// routine will add factory methods (only).
+/// \param WantInstanceMethods Whether to add instance methods (only); if
+/// false, this routine will add factory methods (only).
///
/// \param CurContext the context in which we're performing the lookup that
/// finds methods.
@@ -4694,17 +4751,18 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
ResultBuilder &Results,
bool InOriginalClass = true) {
typedef CodeCompletionResult Result;
+ Container = getContainerDef(Container);
for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
MEnd = Container->meth_end();
M != MEnd; ++M) {
- if ((*M)->isInstanceMethod() == WantInstanceMethods) {
+ if (M->isInstanceMethod() == WantInstanceMethods) {
// Check whether the selector identifiers we've been given are a
// subset of the identifiers for this particular method.
if (!isAcceptableObjCMethod(*M, WantKind, SelIdents, NumSelIdents,
AllowSameLength))
continue;
- if (!Selectors.insert((*M)->getSelector()))
+ if (!Selectors.insert(M->getSelector()))
continue;
Result R = Result(*M, 0);
@@ -5825,7 +5883,8 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) {
return;
// Ignore any properties that have already been implemented.
- for (DeclContext::decl_iterator D = Container->decls_begin(),
+ Container = getContainerDef(Container);
+ for (DeclContext::decl_iterator D = Container->decls_begin(),
DEnd = Container->decls_end();
D != DEnd; ++D)
if (ObjCPropertyImplDecl *PropertyImpl = dyn_cast<ObjCPropertyImplDecl>(*D))
@@ -5958,9 +6017,12 @@ static void FindImplementableMethods(ASTContext &Context,
KnownMethodsMap &KnownMethods,
bool InOriginalClass = true) {
if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)) {
- // Recurse into protocols.
+ // Make sure we have a definition; that's what we'll walk.
if (!IFace->hasDefinition())
return;
+
+ IFace = IFace->getDefinition();
+ Container = IFace;
const ObjCList<ObjCProtocolDecl> &Protocols
= IFace->getReferencedProtocols();
@@ -6002,16 +6064,20 @@ static void FindImplementableMethods(ASTContext &Context,
}
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
- if (Protocol->hasDefinition()) {
- // Recurse into protocols.
- const ObjCList<ObjCProtocolDecl> &Protocols
- = Protocol->getReferencedProtocols();
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
- E = Protocols.end();
- I != E; ++I)
- FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
- KnownMethods, false);
- }
+ // Make sure we have a definition; that's what we'll walk.
+ if (!Protocol->hasDefinition())
+ return;
+ Protocol = Protocol->getDefinition();
+ Container = Protocol;
+
+ // Recurse into protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = Protocol->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
+ KnownMethods, false);
}
// Add methods in this container. This operation occurs last because
@@ -6020,12 +6086,12 @@ static void FindImplementableMethods(ASTContext &Context,
for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
MEnd = Container->meth_end();
M != MEnd; ++M) {
- if ((*M)->isInstanceMethod() == WantInstanceMethods) {
+ if (M->isInstanceMethod() == WantInstanceMethods) {
if (!ReturnType.isNull() &&
- !Context.hasSameUnqualifiedType(ReturnType, (*M)->getResultType()))
+ !Context.hasSameUnqualifiedType(ReturnType, M->getResultType()))
continue;
- KnownMethods[(*M)->getSelector()] = std::make_pair(*M, InOriginalClass);
+ KnownMethods[M->getSelector()] = std::make_pair(*M, InOriginalClass);
}
}
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 1227e92..3aae99a 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -60,7 +61,8 @@ namespace {
class TypeNameValidatorCCC : public CorrectionCandidateCallback {
public:
- TypeNameValidatorCCC(bool AllowInvalid) : AllowInvalidDecl(AllowInvalid) {
+ TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false)
+ : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass) {
WantExpressionKeywords = false;
WantCXXNamedCasts = false;
WantRemainingKeywords = false;
@@ -71,15 +73,52 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback {
return (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) &&
(AllowInvalidDecl || !ND->isInvalidDecl());
else
- return candidate.isKeyword();
+ return !WantClassName && candidate.isKeyword();
}
private:
bool AllowInvalidDecl;
+ bool WantClassName;
};
}
+/// \brief Determine whether the token kind starts a simple-type-specifier.
+bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
+ switch (Kind) {
+ // FIXME: Take into account the current language when deciding whether a
+ // token kind is a valid type specifier
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_half:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw___underlying_type:
+ return true;
+
+ case tok::annot_typename:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_typeof:
+ case tok::kw_decltype:
+ return getLangOpts().CPlusPlus;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
/// \brief If the identifier refers to a type name within this scope,
/// return the declaration of that type.
///
@@ -173,7 +212,7 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (CorrectedII) {
- TypeNameValidatorCCC Validator(true);
+ TypeNameValidatorCCC Validator(true, isClassName);
TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(),
Kind, S, SS, Validator);
IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
@@ -202,8 +241,8 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
std::string CorrectedStr(Correction.getAsString(getLangOpts()));
std::string CorrectedQuotedStr(
Correction.getQuoted(getLangOpts()));
- Diag(NameLoc, diag::err_unknown_typename_suggest)
- << Result.getLookupName() << CorrectedQuotedStr
+ Diag(NameLoc, diag::err_unknown_type_or_class_name_suggest)
+ << Result.getLookupName() << CorrectedQuotedStr << isClassName
<< FixItHint::CreateReplacement(SourceRange(NameLoc),
CorrectedStr);
if (NamedDecl *FirstDecl = Correction.getCorrectionDecl())
@@ -359,7 +398,7 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) {
return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope();
}
-bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
+bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
SourceLocation IILoc,
Scope *S,
CXXScopeSpec *SS,
@@ -370,7 +409,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
// There may have been a typo in the name of the type. Look up typo
// results, in case we have something that we can suggest.
TypeNameValidatorCCC Validator(false);
- if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(&II, IILoc),
+ if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc),
LookupOrdinaryName, S, SS,
Validator)) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
@@ -378,19 +417,23 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
if (Corrected.isKeyword()) {
// We corrected to a keyword.
- // FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
+ IdentifierInfo *NewII = Corrected.getCorrectionAsIdentifierInfo();
+ if (!isSimpleTypeSpecifier(NewII->getTokenID()))
+ CorrectedQuotedStr = "the keyword " + CorrectedQuotedStr;
Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << CorrectedQuotedStr;
+ << II << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
+ II = NewII;
} else {
NamedDecl *Result = Corrected.getCorrectionDecl();
// We found a similarly-named type or interface; suggest that.
if (!SS || !SS->isSet())
Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << CorrectedQuotedStr
+ << II << CorrectedQuotedStr
<< FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_unknown_nested_typename_suggest)
- << &II << DC << CorrectedQuotedStr << SS->getRange()
+ << II << DC << CorrectedQuotedStr << SS->getRange()
<< FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
else
llvm_unreachable("could not have corrected a typo here");
@@ -409,7 +452,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
if (getLangOpts().CPlusPlus) {
// See if II is a class template that the user forgot to pass arguments to.
UnqualifiedId Name;
- Name.setIdentifier(&II, IILoc);
+ Name.setIdentifier(II, IILoc);
CXXScopeSpec EmptySS;
TemplateTy TemplateResult;
bool MemberOfUnknownSpecialization;
@@ -430,21 +473,21 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
// (struct, union, enum) from Parser::ParseImplicitInt here, instead?
if (!SS || (!SS->isSet() && !SS->isInvalid()))
- Diag(IILoc, diag::err_unknown_typename) << &II;
+ Diag(IILoc, diag::err_unknown_typename) << II;
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_typename_nested_not_found)
- << &II << DC << SS->getRange();
+ << II << DC << SS->getRange();
else if (isDependentScopeSpecifier(*SS)) {
unsigned DiagID = diag::err_typename_missing;
if (getLangOpts().MicrosoftMode && isMicrosoftMissingTypename(SS, S))
DiagID = diag::warn_typename_missing;
Diag(SS->getRange().getBegin(), DiagID)
- << (NestedNameSpecifier *)SS->getScopeRep() << II.getName()
+ << (NestedNameSpecifier *)SS->getScopeRep() << II->getName()
<< SourceRange(SS->getRange().getBegin(), IILoc)
<< FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
- SuggestedType = ActOnTypenameType(S, SourceLocation(), *SS, II, IILoc)
- .get();
+ SuggestedType = ActOnTypenameType(S, SourceLocation(),
+ *SS, *II, IILoc).get();
} else {
assert(SS && SS->isInvalid() &&
"Invalid scope specifier has already been diagnosed");
@@ -470,6 +513,55 @@ static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) {
return false;
}
+static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
+ Scope *S, CXXScopeSpec &SS,
+ IdentifierInfo *&Name,
+ SourceLocation NameLoc) {
+ Result.clear(Sema::LookupTagName);
+ SemaRef.LookupParsedName(Result, S, &SS);
+ if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
+ const char *TagName = 0;
+ const char *FixItTagName = 0;
+ switch (Tag->getTagKind()) {
+ case TTK_Class:
+ TagName = "class";
+ FixItTagName = "class ";
+ break;
+
+ case TTK_Enum:
+ TagName = "enum";
+ FixItTagName = "enum ";
+ break;
+
+ case TTK_Struct:
+ TagName = "struct";
+ FixItTagName = "struct ";
+ break;
+
+ case TTK_Union:
+ TagName = "union";
+ FixItTagName = "union ";
+ break;
+ }
+
+ SemaRef.Diag(NameLoc, diag::err_use_of_tag_name_without_tag)
+ << Name << TagName << SemaRef.getLangOpts().CPlusPlus
+ << FixItHint::CreateInsertion(NameLoc, FixItTagName);
+
+ LookupResult R(SemaRef, Name, NameLoc, Sema::LookupOrdinaryName);
+ if (SemaRef.LookupParsedName(R, S, &SS)) {
+ for (LookupResult::iterator I = R.begin(), IEnd = R.end();
+ I != IEnd; ++I)
+ SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
+ << Name << TagName;
+ }
+ return true;
+ }
+
+ Result.clear(Sema::LookupOrdinaryName);
+ return false;
+}
+
Sema::NameClassification Sema::ClassifyName(Scope *S,
CXXScopeSpec &SS,
IdentifierInfo *&Name,
@@ -533,41 +625,9 @@ Corrected:
// In C, we first see whether there is a tag type by the same name, in
// which case it's likely that the user just forget to write "enum",
// "struct", or "union".
- if (!getLangOpts().CPlusPlus && !SecondTry) {
- Result.clear(LookupTagName);
- LookupParsedName(Result, S, &SS);
- if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
- const char *TagName = 0;
- const char *FixItTagName = 0;
- switch (Tag->getTagKind()) {
- case TTK_Class:
- TagName = "class";
- FixItTagName = "class ";
- break;
-
- case TTK_Enum:
- TagName = "enum";
- FixItTagName = "enum ";
- break;
-
- case TTK_Struct:
- TagName = "struct";
- FixItTagName = "struct ";
- break;
-
- case TTK_Union:
- TagName = "union";
- FixItTagName = "union ";
- break;
- }
-
- Diag(NameLoc, diag::err_use_of_tag_name_without_tag)
- << Name << TagName << getLangOpts().CPlusPlus
- << FixItHint::CreateInsertion(NameLoc, FixItTagName);
- break;
- }
-
- Result.clear(LookupOrdinaryName);
+ if (!getLangOpts().CPlusPlus && !SecondTry &&
+ isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
+ break;
}
// Perform typo correction to determine if there is another name that is
@@ -575,6 +635,19 @@ Corrected:
if (!SecondTry) {
SecondTry = true;
CorrectionCandidateCallback DefaultValidator;
+ // Try to limit which sets of keywords should be included in typo
+ // correction based on what the next token is.
+ DefaultValidator.WantTypeSpecifiers =
+ NextToken.is(tok::l_paren) || NextToken.is(tok::less) ||
+ NextToken.is(tok::identifier) || NextToken.is(tok::star) ||
+ NextToken.is(tok::amp) || NextToken.is(tok::l_square);
+ DefaultValidator.WantExpressionKeywords =
+ NextToken.is(tok::l_paren) || NextToken.is(tok::identifier) ||
+ NextToken.is(tok::arrow) || NextToken.is(tok::period);
+ DefaultValidator.WantRemainingKeywords =
+ NextToken.is(tok::l_paren) || NextToken.is(tok::semi) ||
+ NextToken.is(tok::identifier) || NextToken.is(tok::l_brace);
+ DefaultValidator.WantCXXNamedCasts = false;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S,
&SS, DefaultValidator)) {
@@ -740,7 +813,7 @@ Corrected:
if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
DiagnoseUseOfDecl(Type, NameLoc);
QualType T = Context.getTypeDeclType(Type);
- return ParsedType::make(T);
+ return ParsedType::make(T);
}
ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl);
@@ -764,6 +837,23 @@ Corrected:
QualType T = Context.getObjCInterfaceType(Class);
return ParsedType::make(T);
}
+
+ // Check for a tag type hidden by a non-type decl in a few cases where it
+ // seems likely a type is wanted instead of the non-type that was found.
+ if (!getLangOpts().ObjC1 && FirstDecl && !isa<ClassTemplateDecl>(FirstDecl) &&
+ !isa<TypeAliasTemplateDecl>(FirstDecl)) {
+ bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star);
+ if ((NextToken.is(tok::identifier) ||
+ (NextIsOp && FirstDecl->isFunctionOrFunctionTemplate())) &&
+ isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
+ FirstDecl = (*Result.begin())->getUnderlyingDecl();
+ if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
+ DiagnoseUseOfDecl(Type, NameLoc);
+ QualType T = Context.getTypeDeclType(Type);
+ return ParsedType::make(T);
+ }
+ }
+ }
if (!Result.empty() && (*Result.begin())->isCXXClassMember())
return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, 0);
@@ -1132,9 +1222,9 @@ void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) {
return; // First should already be in the vector.
}
- if (ShouldWarnIfUnusedFileScopedDecl(D))
- UnusedFileScopedDecls.push_back(D);
- }
+ if (ShouldWarnIfUnusedFileScopedDecl(D))
+ UnusedFileScopedDecls.push_back(D);
+}
static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
if (D->isInvalidDecl())
@@ -1281,7 +1371,7 @@ void Sema::ActOnEndFunctionDeclarator() {
///
/// \param IdLoc The location of the name in the translation unit.
///
-/// \param TypoCorrection If true, this routine will attempt typo correction
+/// \param DoTypoCorrection If true, this routine will attempt typo correction
/// if there is no class with the given name.
///
/// \returns The declaration of the named Objective-C class, or NULL if the
@@ -1484,12 +1574,22 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
switch (TypeID->getLength()) {
default: break;
case 2:
- if (!TypeID->isStr("id"))
- break;
- Context.setObjCIdRedefinitionType(New->getUnderlyingType());
- // Install the built-in type for 'id', ignoring the current definition.
- New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
- return;
+ {
+ if (!TypeID->isStr("id"))
+ break;
+ QualType T = New->getUnderlyingType();
+ if (!T->isPointerType())
+ break;
+ if (!T->isVoidPointerType()) {
+ QualType PT = T->getAs<PointerType>()->getPointeeType();
+ if (!PT->isStructureType())
+ break;
+ }
+ Context.setObjCIdRedefinitionType(T);
+ // Install the built-in type for 'id', ignoring the current definition.
+ New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
+ return;
+ }
case 5:
if (!TypeID->isStr("Class"))
break;
@@ -1599,6 +1699,13 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
/// attribute.
static bool
DeclHasAttr(const Decl *D, const Attr *A) {
+ // There can be multiple AvailabilityAttr in a Decl. Make sure we copy
+ // all of them. It is mergeAvailabilityAttr in SemaDeclAttr.cpp that is
+ // responsible for making sure they are consistent.
+ const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(A);
+ if (AA)
+ return false;
+
const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A);
const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A);
for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i)
@@ -1617,9 +1724,90 @@ DeclHasAttr(const Decl *D, const Attr *A) {
return false;
}
+bool Sema::mergeDeclAttribute(Decl *D, InheritableAttr *Attr) {
+ InheritableAttr *NewAttr = NULL;
+ if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr))
+ NewAttr = mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
+ AA->getIntroduced(), AA->getDeprecated(),
+ AA->getObsoleted(), AA->getUnavailable(),
+ AA->getMessage());
+ else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr))
+ NewAttr = mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility());
+ else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))
+ NewAttr = mergeDLLImportAttr(D, ImportA->getRange());
+ else if (DLLExportAttr *ExportA = dyn_cast<DLLExportAttr>(Attr))
+ NewAttr = mergeDLLExportAttr(D, ExportA->getRange());
+ else if (FormatAttr *FA = dyn_cast<FormatAttr>(Attr))
+ NewAttr = mergeFormatAttr(D, FA->getRange(), FA->getType(),
+ FA->getFormatIdx(), FA->getFirstArg());
+ else if (SectionAttr *SA = dyn_cast<SectionAttr>(Attr))
+ NewAttr = mergeSectionAttr(D, SA->getRange(), SA->getName());
+ else if (!DeclHasAttr(D, Attr))
+ NewAttr = cast<InheritableAttr>(Attr->clone(Context));
+
+ if (NewAttr) {
+ NewAttr->setInherited(true);
+ D->addAttr(NewAttr);
+ return true;
+ }
+
+ return false;
+}
+
+static const Decl *getDefinition(const Decl *D) {
+ if (const TagDecl *TD = dyn_cast<TagDecl>(D))
+ return TD->getDefinition();
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ return VD->getDefinition();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ const FunctionDecl* Def;
+ if (FD->hasBody(Def))
+ return Def;
+ }
+ return NULL;
+}
+
+static bool hasAttribute(const Decl *D, attr::Kind Kind) {
+ for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
+ I != E; ++I) {
+ Attr *Attribute = *I;
+ if (Attribute->getKind() == Kind)
+ return true;
+ }
+ return false;
+}
+
+/// checkNewAttributesAfterDef - If we already have a definition, check that
+/// there are no new attributes in this declaration.
+static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
+ if (!New->hasAttrs())
+ return;
+
+ const Decl *Def = getDefinition(Old);
+ if (!Def || Def == New)
+ return;
+
+ AttrVec &NewAttributes = New->getAttrs();
+ for (unsigned I = 0, E = NewAttributes.size(); I != E;) {
+ const Attr *NewAttribute = NewAttributes[I];
+ if (hasAttribute(Def, NewAttribute->getKind())) {
+ ++I;
+ continue; // regular attr merging will take care of validating this.
+ }
+ S.Diag(NewAttribute->getLocation(),
+ diag::warn_attribute_precede_definition);
+ S.Diag(Def->getLocation(), diag::note_previous_definition);
+ NewAttributes.erase(NewAttributes.begin() + I);
+ --E;
+ }
+}
+
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
bool MergeDeprecation) {
+ // attributes declared post-definition are currently ignored
+ checkNewAttributesAfterDef(*this, New, Old);
+
if (!Old->hasAttrs())
return;
@@ -1640,12 +1828,8 @@ void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
isa<AvailabilityAttr>(*i)))
continue;
- if (!DeclHasAttr(New, *i)) {
- InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(Context));
- newAttr->setInherited(true);
- New->addAttr(newAttr);
+ if (mergeDeclAttribute(New, *i))
foundAny = true;
- }
}
if (!foundAny) New->dropAttrs();
@@ -1909,22 +2093,27 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
return true;
}
-
+
// C++ [class.mem]p1:
// [...] A member shall not be declared twice in the
// member-specification, except that a nested class or member
// class template can be declared and then later defined.
- unsigned NewDiag;
- if (isa<CXXConstructorDecl>(OldMethod))
- NewDiag = diag::err_constructor_redeclared;
- else if (isa<CXXDestructorDecl>(NewMethod))
- NewDiag = diag::err_destructor_redeclared;
- else if (isa<CXXConversionDecl>(NewMethod))
- NewDiag = diag::err_conv_function_redeclared;
- else
- NewDiag = diag::err_member_redeclared;
+ if (ActiveTemplateInstantiations.empty()) {
+ unsigned NewDiag;
+ if (isa<CXXConstructorDecl>(OldMethod))
+ NewDiag = diag::err_constructor_redeclared;
+ else if (isa<CXXDestructorDecl>(NewMethod))
+ NewDiag = diag::err_destructor_redeclared;
+ else if (isa<CXXConversionDecl>(NewMethod))
+ NewDiag = diag::err_conv_function_redeclared;
+ else
+ NewDiag = diag::err_member_redeclared;
- Diag(New->getLocation(), NewDiag);
+ Diag(New->getLocation(), NewDiag);
+ } else {
+ Diag(New->getLocation(), diag::err_member_redeclared_in_instantiation)
+ << New << New->getType();
+ }
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
// Complain if this is an explicit declaration of a special
@@ -1941,7 +2130,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
<< New << getSpecialMember(OldMethod);
return true;
}
- } else if (OldMethod->isExplicitlyDefaulted()) {
+ } else if (OldMethod->isExplicitlyDefaulted() && !isFriend) {
Diag(NewMethod->getLocation(),
diag::err_definition_of_explicitly_defaulted_member)
<< getSpecialMember(OldMethod);
@@ -2142,18 +2331,16 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
ObjCMethodDecl *oldMethod) {
- // We don't want to merge unavailable and deprecated attributes
- // except from interface to implementation.
- bool mergeDeprecation = isa<ObjCImplDecl>(newMethod->getDeclContext());
- // Merge the attributes.
- mergeDeclAttributes(newMethod, oldMethod, mergeDeprecation);
+ // Merge the attributes, including deprecated/unavailable
+ mergeDeclAttributes(newMethod, oldMethod, /* mergeDeprecation */true);
// Merge attributes from the parameters.
- ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin();
+ ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(),
+ oe = oldMethod->param_end();
for (ObjCMethodDecl::param_iterator
ni = newMethod->param_begin(), ne = newMethod->param_end();
- ni != ne; ++ni, ++oi)
+ ni != ne && oi != oe; ++ni, ++oi)
mergeParamDeclAttributes(*ni, *oi, Context);
CheckObjCMethodOverride(newMethod, oldMethod, true);
@@ -2552,6 +2739,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
}
+ ActOnDocumentableDecl(TagD);
+
return TagD;
}
@@ -2873,7 +3062,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Context.getTypeDeclType(Record),
TInfo,
/*BitWidth=*/0, /*Mutable=*/false,
- /*HasInit=*/false);
+ /*InitStyle=*/ICIS_NoInit);
Anon->setAccess(AS);
if (getLangOpts().CPlusPlus)
FieldCollector->Add(cast<FieldDecl>(Anon));
@@ -2970,7 +3159,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
Context.getTypeDeclType(Record),
TInfo,
/*BitWidth=*/0, /*Mutable=*/false,
- /*HasInit=*/false);
+ /*InitStyle=*/ICIS_NoInit);
Anon->setImplicit();
// Add the anonymous struct object to the current context.
@@ -3225,7 +3414,7 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg(*this));
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() &&
- Dcl->getDeclContext()->isFileContext())
+ Dcl && Dcl->getDeclContext()->isFileContext())
Dcl->setTopLevelDeclInObjCContainer();
return Dcl;
@@ -3794,8 +3983,6 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
Context.setsigjmp_bufDecl(NewTD);
else if (II->isStr("ucontext_t"))
Context.setucontext_tDecl(NewTD);
- else if (II->isStr("__builtin_va_list"))
- Context.setBuiltinVaListType(Context.getTypedefType(NewTD));
}
return NewTD;
@@ -4173,18 +4360,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
CheckMemberSpecialization(NewVD, Previous))
NewVD->setInvalidDecl();
}
-
- // attributes declared post-definition are currently ignored
- // FIXME: This should be handled in attribute merging, not
- // here.
- if (Previous.isSingleResult()) {
- VarDecl *Def = dyn_cast<VarDecl>(Previous.getFoundDecl());
- if (Def && (Def = Def->getDefinition()) &&
- Def != NewVD && D.hasAttributes()) {
- Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition);
- Diag(Def->getLocation(), diag::note_previous_definition);
- }
- }
// If this is a locally-scoped extern C variable, update the map of
// such variables.
@@ -4334,6 +4509,15 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
return false;
}
+ // OpenCL v1.2 s6.8 -- The static qualifier is valid only in program
+ // scope.
+ if ((getLangOpts().OpenCLVersion >= 120)
+ && NewVD->isStaticLocal()) {
+ Diag(NewVD->getLocation(), diag::err_static_function_scope);
+ NewVD->setInvalidDecl();
+ return false;
+ }
+
if (NewVD->hasLocalStorage() && T.isObjCGCWeak()
&& !NewVD->hasAttr<BlocksAttr>()) {
if (getLangOpts().getGC() != LangOptions::NonGC)
@@ -4418,7 +4602,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
if (NewVD->isConstexpr() && !T->isDependentType() &&
RequireLiteralType(NewVD->getLocation(), T,
- PDiag(diag::err_constexpr_var_non_literal))) {
+ diag::err_constexpr_var_non_literal)) {
NewVD->setInvalidDecl();
return false;
}
@@ -4471,11 +4655,6 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier,
return false;
}
-static bool hasDelayedExceptionSpec(CXXMethodDecl *Method) {
- const FunctionProtoType *Proto =Method->getType()->getAs<FunctionProtoType>();
- return Proto && Proto->getExceptionSpecType() == EST_Delayed;
-}
-
/// AddOverriddenMethods - See if a method overrides any in the base classes,
/// and if so, check that it's a valid override and remember it.
bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
@@ -4491,8 +4670,7 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
MD->addOverriddenMethod(OldMD->getCanonicalDecl());
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
- (hasDelayedExceptionSpec(MD) ||
- !CheckOverridingFunctionExceptionSpec(MD, OldMD)) &&
+ !CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
AddedAny = true;
}
@@ -4520,22 +4698,39 @@ namespace {
// Also only accept corrections that have the same parent decl.
class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
public:
- DifferentNameValidatorCCC(CXXRecordDecl *Parent)
- : ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) {}
+ DifferentNameValidatorCCC(ASTContext &Context, FunctionDecl *TypoFD,
+ CXXRecordDecl *Parent)
+ : Context(Context), OriginalFD(TypoFD),
+ ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) {}
virtual bool ValidateCandidate(const TypoCorrection &candidate) {
if (candidate.getEditDistance() == 0)
return false;
- if (CXXMethodDecl *MD = candidate.getCorrectionDeclAs<CXXMethodDecl>()) {
- CXXRecordDecl *Parent = MD->getParent();
- return Parent && Parent->getCanonicalDecl() == ExpectedParent;
+ llvm::SmallVector<unsigned, 1> MismatchedParams;
+ for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(),
+ CDeclEnd = candidate.end();
+ CDecl != CDeclEnd; ++CDecl) {
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(*CDecl);
+
+ if (FD && !FD->hasBody() &&
+ hasSimilarParameters(Context, FD, OriginalFD, MismatchedParams)) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ CXXRecordDecl *Parent = MD->getParent();
+ if (Parent && Parent->getCanonicalDecl() == ExpectedParent)
+ return true;
+ } else if (!ExpectedParent) {
+ return true;
+ }
+ }
}
- return !ExpectedParent;
+ return false;
}
private:
+ ASTContext &Context;
+ FunctionDecl *OriginalFD;
CXXRecordDecl *ExpectedParent;
};
@@ -4571,7 +4766,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
- DifferentNameValidatorCCC Validator(MD ? MD->getParent() : 0);
+ DifferentNameValidatorCCC Validator(SemaRef.Context, NewFD,
+ MD ? MD->getParent() : 0);
if (!Prev.empty()) {
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
Func != FuncEnd; ++Func) {
@@ -4601,8 +4797,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
CDeclEnd = Correction.end();
CDecl != CDeclEnd; ++CDecl) {
FunctionDecl *FD = dyn_cast<FunctionDecl>(*CDecl);
- if (FD && hasSimilarParameters(SemaRef.Context, FD, NewFD,
- MismatchedParams)) {
+ if (FD && !FD->hasBody() &&
+ hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) {
Previous.addDecl(FD);
}
}
@@ -4640,19 +4836,23 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
}
}
- if (Correction)
- SemaRef.Diag(NewFD->getLocation(), DiagMsg)
+ if (Correction) {
+ SourceRange FixItLoc(NewFD->getLocation());
+ CXXScopeSpec &SS = ExtraArgs.D.getCXXScopeSpec();
+ if (Correction.getCorrectionSpecifier() && SS.isValid())
+ FixItLoc.setBegin(SS.getBeginLoc());
+ SemaRef.Diag(NewFD->getLocStart(), DiagMsg)
<< Name << NewDC << Correction.getQuoted(SemaRef.getLangOpts())
<< FixItHint::CreateReplacement(
- NewFD->getLocation(),
- Correction.getAsString(SemaRef.getLangOpts()));
- else
+ FixItLoc, Correction.getAsString(SemaRef.getLangOpts()));
+ } else {
SemaRef.Diag(NewFD->getLocation(), DiagMsg)
<< Name << NewDC << NewFD->getLocation();
+ }
bool NewFDisConst = false;
if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
- NewFDisConst = NewMD->getTypeQualifiers() & Qualifiers::Const;
+ NewFDisConst = NewMD->isConst();
for (llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1>::iterator
NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();
@@ -4660,7 +4860,7 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
FunctionDecl *FD = NearMatch->first;
bool FDisConst = false;
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
- FDisConst = MD->getTypeQualifiers() & Qualifiers::Const;
+ FDisConst = MD->isConst();
if (unsigned Idx = NearMatch->second) {
ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);
@@ -4911,7 +5111,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FunctionTemplateDecl *FunctionTemplate = 0;
bool isExplicitSpecialization = false;
bool isFunctionTemplateSpecialization = false;
+
bool isDependentClassScopeExplicitSpecialization = false;
+ bool HasExplicitTemplateArgs = false;
+ TemplateArgumentListInfo TemplateArgs;
+
bool isVirtualOkay = false;
FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC,
@@ -5041,56 +5245,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FunctionTemplate->setInvalidDecl();
}
- // If we see "T var();" at block scope, where T is a class type, it is
- // probably an attempt to initialize a variable, not a function declaration.
- // We don't catch this case earlier, since there is no ambiguity here.
- if (!FunctionTemplate && D.getFunctionDefinitionKind() == FDK_Declaration &&
- CurContext->isFunctionOrMethod() &&
- D.getNumTypeObjects() == 1 && D.isFunctionDeclarator() &&
- D.getDeclSpec().getStorageClassSpecAsWritten()
- == DeclSpec::SCS_unspecified) {
- QualType T = R->getAs<FunctionType>()->getResultType();
- DeclaratorChunk &C = D.getTypeObject(0);
- if (!T->isVoidType() && C.Fun.NumArgs == 0 && !C.Fun.isVariadic &&
- !C.Fun.TrailingReturnType &&
- C.Fun.getExceptionSpecType() == EST_None) {
- SourceRange ParenRange(C.Loc, C.EndLoc);
- Diag(C.Loc, diag::warn_empty_parens_are_function_decl) << ParenRange;
-
- // If the declaration looks like:
- // T var1,
- // f();
- // and name lookup finds a function named 'f', then the ',' was
- // probably intended to be a ';'.
- if (!D.isFirstDeclarator() && D.getIdentifier()) {
- FullSourceLoc Comma(D.getCommaLoc(), SourceMgr);
- FullSourceLoc Name(D.getIdentifierLoc(), SourceMgr);
- if (Comma.getFileID() != Name.getFileID() ||
- Comma.getSpellingLineNumber() != Name.getSpellingLineNumber()) {
- LookupResult Result(*this, D.getIdentifier(), SourceLocation(),
- LookupOrdinaryName);
- if (LookupName(Result, S))
- Diag(D.getCommaLoc(), diag::note_empty_parens_function_call)
- << FixItHint::CreateReplacement(D.getCommaLoc(), ";") << NewFD;
- }
- }
- const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
- // Empty parens mean value-initialization, and no parens mean default
- // initialization. These are equivalent if the default constructor is
- // user-provided, or if zero-initialization is a no-op.
- if (RD && RD->hasDefinition() &&
- (RD->isEmpty() || RD->hasUserProvidedDefaultConstructor()))
- Diag(C.Loc, diag::note_empty_parens_default_ctor)
- << FixItHint::CreateRemoval(ParenRange);
- else if (const char *Init = getFixItZeroInitializerForType(T))
- Diag(C.Loc, diag::note_empty_parens_zero_initialize)
- << FixItHint::CreateReplacement(ParenRange, Init);
- else if (LangOpts.CPlusPlus0x)
- Diag(C.Loc, diag::note_empty_parens_zero_initialize)
- << FixItHint::CreateReplacement(ParenRange, "{}");
- }
- }
-
// C++ [dcl.fct.spec]p5:
// The virtual specifier shall only be used in declarations of
// nonstatic class member functions that appear within a
@@ -5333,6 +5487,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setInvalidDecl();
}
+ // Handle attributes.
+ ProcessDeclAttributes(S, NewFD, D,
+ /*NonInheritable=*/false, /*Inheritable=*/true);
+
if (!getLangOpts().CPlusPlus) {
// Perform semantic checking on the function declaration.
bool isExplicitSpecialization=false;
@@ -5348,8 +5506,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
} else {
// If the declarator is a template-id, translate the parser's template
// argument list into our AST format.
- bool HasExplicitTemplateArgs = false;
- TemplateArgumentListInfo TemplateArgs;
if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
@@ -5580,25 +5736,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< D.getCXXScopeSpec().getRange();
}
}
-
-
- // Handle attributes. We need to have merged decls when handling attributes
- // (for example to check for conflicts, etc).
- // FIXME: This needs to happen before we merge declarations. Then,
- // let attribute merging cope with attribute conflicts.
- ProcessDeclAttributes(S, NewFD, D,
- /*NonInheritable=*/false, /*Inheritable=*/true);
-
- // attributes declared post-definition are currently ignored
- // FIXME: This should happen during attribute merging
- if (D.isRedeclaration() && Previous.isSingleResult()) {
- const FunctionDecl *Def;
- FunctionDecl *PrevFD = dyn_cast<FunctionDecl>(Previous.getFoundDecl());
- if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) {
- Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition);
- Diag(Def->getLocation(), diag::note_previous_definition);
- }
- }
AddKnownFunctionAttributes(NewFD);
@@ -5644,6 +5781,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ // OpenCL v1.2 s6.8 static is invalid for kernel functions.
+ if ((getLangOpts().OpenCLVersion >= 120)
+ && NewFD->hasAttr<OpenCLKernelAttr>()
+ && (SC == SC_Static)) {
+ Diag(D.getIdentifierLoc(), diag::err_static_kernel);
+ D.setInvalidType();
+ }
+
MarkUnusedFileScopedDecl(NewFD);
if (getLangOpts().CUDA)
@@ -5664,8 +5809,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (isDependentClassScopeExplicitSpecialization) {
ClassScopeFunctionSpecializationDecl *NewSpec =
ClassScopeFunctionSpecializationDecl::Create(
- Context, CurContext, SourceLocation(),
- cast<CXXMethodDecl>(NewFD));
+ Context, CurContext, SourceLocation(),
+ cast<CXXMethodDecl>(NewFD),
+ HasExplicitTemplateArgs, TemplateArgs);
CurContext->addDecl(NewSpec);
AddToScope = false;
}
@@ -5683,12 +5829,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
/// that have been instantiated via C++ template instantiation (called
/// via InstantiateDecl).
///
-/// \param IsExplicitSpecialiation whether this new function declaration is
+/// \param IsExplicitSpecialization whether this new function declaration is
/// an explicit specialization of the previous declaration.
///
/// This sets NewFD->isInvalidDecl() to true if there was an error.
///
-/// Returns true if the function declaration is a redeclaration.
+/// \returns true if the function declaration is a redeclaration.
bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
LookupResult &Previous,
bool IsExplicitSpecialization) {
@@ -5882,10 +6028,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// compatible, and if it does, warn the user.
if (NewFD->isExternC()) {
QualType R = NewFD->getResultType();
- if (!R.isPODType(Context) &&
- !R->isVoidType())
- Diag( NewFD->getLocation(), diag::warn_return_value_udt )
- << NewFD << R;
+ if (R->isIncompleteType() && !R->isVoidType())
+ Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete)
+ << NewFD << R;
+ else if (!R.isPODType(Context) && !R->isVoidType() &&
+ !R->isObjCObjectPointerType())
+ Diag(NewFD->getLocation(), diag::warn_return_value_udt) << NewFD << R;
}
}
return Redeclaration;
@@ -6040,55 +6188,73 @@ namespace {
}
}
- void VisitExpr(Expr *E) {
- if (isa<ObjCMessageExpr>(*E)) return;
- if (isRecordType) {
- Expr *expr = E;
- if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- ValueDecl *VD = ME->getMemberDecl();
- if (isa<EnumConstantDecl>(VD) || isa<VarDecl>(VD)) return;
- expr = ME->getBase();
- }
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(expr)) {
+ // Sometimes, the expression passed in lacks the casts that are used
+ // to determine which DeclRefExpr's to check. Assume that the casts
+ // are present and continue visiting the expression.
+ void HandleExpr(Expr *E) {
+ // Skip checking T a = a where T is not a record type. Doing so is a
+ // way to silence uninitialized warnings.
+ if (isRecordType)
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
HandleDeclRefExpr(DRE);
- return;
- }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ HandleValue(CO->getTrueExpr());
+ HandleValue(CO->getFalseExpr());
+ }
+
+ Visit(E);
+ }
+
+ // For most expressions, the cast is directly above the DeclRefExpr.
+ // For conditional operators, the cast can be outside the conditional
+ // operator if both expressions are DeclRefExpr's.
+ void HandleValue(Expr *E) {
+ E = E->IgnoreParenImpCasts();
+ if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(E)) {
+ HandleDeclRefExpr(DRE);
+ return;
+ }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ HandleValue(CO->getTrueExpr());
+ HandleValue(CO->getFalseExpr());
}
- Inherited::VisitExpr(E);
+ }
+
+ void VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ if ((!isRecordType && E->getCastKind() == CK_LValueToRValue) ||
+ (isRecordType && E->getCastKind() == CK_NoOp))
+ HandleValue(E->getSubExpr());
+
+ Inherited::VisitImplicitCastExpr(E);
}
void VisitMemberExpr(MemberExpr *E) {
+ // Don't warn on arrays since they can be treated as pointers.
if (E->getType()->canDecayToPointerType()) return;
+
ValueDecl *VD = E->getMemberDecl();
- if (isa<FieldDecl>(VD) || isa<CXXMethodDecl>(VD))
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(VD);
+ if (isa<FieldDecl>(VD) || (MD && !MD->isStatic()))
if (DeclRefExpr *DRE
= dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) {
HandleDeclRefExpr(DRE);
return;
}
- Inherited::VisitMemberExpr(E);
- }
- void VisitImplicitCastExpr(ImplicitCastExpr *E) {
- if ((!isRecordType &&E->getCastKind() == CK_LValueToRValue) ||
- (isRecordType && E->getCastKind() == CK_NoOp)) {
- Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts();
- if (MemberExpr *ME = dyn_cast<MemberExpr>(SubExpr))
- SubExpr = ME->getBase()->IgnoreParenImpCasts();
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr)) {
- HandleDeclRefExpr(DRE);
- return;
- }
- }
- Inherited::VisitImplicitCastExpr(E);
+ Inherited::VisitMemberExpr(E);
}
void VisitUnaryOperator(UnaryOperator *E) {
// For POD record types, addresses of its own members are well-defined.
- if (isRecordType && isPODType) return;
+ if (E->getOpcode() == UO_AddrOf && isRecordType && isPODType &&
+ isa<MemberExpr>(E->getSubExpr()->IgnoreParens())) return;
Inherited::VisitUnaryOperator(E);
}
-
+
+ void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; }
+
void HandleDeclRefExpr(DeclRefExpr *DRE) {
Decl* ReferenceDecl = DRE->getDecl();
if (OrigDecl != ReferenceDecl) return;
@@ -6105,7 +6271,7 @@ namespace {
/// CheckSelfReference - Warns if OrigDecl is used in expression E.
void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) {
- SelfReferenceChecker(*this, OrigDecl).VisitExpr(E);
+ SelfReferenceChecker(*this, OrigDecl).HandleExpr(E);
}
/// AddInitializerToDecl - Adds the initializer Init to the
@@ -6145,13 +6311,19 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// Check for self-references within variable initializers.
// Variables declared within a function/method body are handled
// by a dataflow analysis.
- if (!VDecl->hasLocalStorage() && !VDecl->isStaticLocal())
+ // Record types initialized by initializer list are handled here.
+ // Initialization by constructors are handled in TryConstructorInitialization.
+ if (!VDecl->hasLocalStorage() && !VDecl->isStaticLocal() &&
+ (isa<InitListExpr>(Init) || !VDecl->getType()->isRecordType()))
CheckSelfReference(RealDecl, Init);
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
- if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
+ AutoType *Auto = 0;
+ if (TypeMayContainAuto &&
+ (Auto = VDecl->getType()->getContainedAutoType()) &&
+ !Auto->isDeduced()) {
Expr *DeduceInit = Init;
// Initializer could be a C++ direct-initializer. Deduction only works if it
// contains exactly one expression.
@@ -6192,6 +6364,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
VDecl->setInvalidDecl();
+ // Warn if we deduced 'id'. 'auto' usually implies type-safety, but using
+ // 'id' instead of a specific object type prevents most of our usual checks.
+ // We only want to warn outside of template instantiations, though:
+ // inside a template, the 'id' could have come from a parameter.
+ if (ActiveTemplateInstantiations.empty() &&
+ DeducedType->getType()->isObjCIdType()) {
+ SourceLocation Loc = DeducedType->getTypeLoc().getBeginLoc();
+ Diag(Loc, diag::warn_auto_var_is_id)
+ << VDecl->getDeclName() << DeduceInit->getSourceRange();
+ }
+
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl())
@@ -6906,9 +7089,55 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls,
}
}
+ ActOnDocumentableDecls(Group, NumDecls);
+
return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, NumDecls));
}
+void Sema::ActOnDocumentableDecl(Decl *D) {
+ ActOnDocumentableDecls(&D, 1);
+}
+
+void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) {
+ // Don't parse the comment if Doxygen diagnostics are ignored.
+ if (NumDecls == 0 || !Group[0])
+ return;
+
+ if (Diags.getDiagnosticLevel(diag::warn_doc_param_not_found,
+ Group[0]->getLocation())
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ if (NumDecls >= 2) {
+ // This is a decl group. Normally it will contain only declarations
+ // procuded from declarator list. But in case we have any definitions or
+ // additional declaration references:
+ // 'typedef struct S {} S;'
+ // 'typedef struct S *S;'
+ // 'struct S *pS;'
+ // FinalizeDeclaratorGroup adds these as separate declarations.
+ Decl *MaybeTagDecl = Group[0];
+ if (MaybeTagDecl && isa<TagDecl>(MaybeTagDecl)) {
+ Group++;
+ NumDecls--;
+ }
+ }
+
+ // See if there are any new comments that are not attached to a decl.
+ ArrayRef<RawComment *> Comments = Context.getRawCommentList().getComments();
+ if (!Comments.empty() &&
+ !Comments.back()->isAttached()) {
+ // There is at least one comment that not attached to a decl.
+ // Maybe it should be attached to one of these decls?
+ //
+ // Note that this way we pick up not only comments that precede the
+ // declaration, but also comments that *follow* the declaration -- thanks to
+ // the lookahead in the lexer: we've consumed the semicolon and looked
+ // ahead through comments.
+ for (unsigned i = 0; i != NumDecls; ++i)
+ Context.getCommentForDecl(Group[i]);
+ }
+}
/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
/// to introduce parameters into function prototype scope.
@@ -7132,9 +7361,10 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// Parameter declarators cannot be interface types. All ObjC objects are
// passed by reference.
if (T->isObjCObjectType()) {
+ SourceLocation TypeEndLoc = TSInfo->getTypeLoc().getLocEnd();
Diag(NameLoc,
diag::err_object_cannot_be_passed_returned_by_value) << 1 << T
- << FixItHint::CreateInsertion(NameLoc, "*");
+ << FixItHint::CreateInsertion(TypeEndLoc, "*");
T = Context.getObjCObjectPointerType(T);
New->setType(T);
}
@@ -7225,6 +7455,10 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) {
if (FD->isFunctionTemplateSpecialization())
return false;
+ // Don't warn for OpenCL kernels.
+ if (FD->hasAttr<OpenCLKernelAttr>())
+ return false;
+
bool MissingPrototype = true;
for (const FunctionDecl *Prev = FD->getPreviousDecl();
Prev; Prev = Prev->getPreviousDecl()) {
@@ -7253,6 +7487,7 @@ void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) {
else
Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
Diag(Definition->getLocation(), diag::note_previous_definition);
+ FD->setInvalidDecl();
}
}
@@ -7388,6 +7623,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
<< FD->getName() << "dllimport";
}
}
+ ActOnDocumentableDecl(FD);
return FD;
}
@@ -7463,7 +7699,12 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD))
MarkVTableUsed(FD->getLocation(), Constructor->getParent());
- computeNRVO(Body, getCurFunction());
+ // Try to apply the named return value optimization. We have to check
+ // if we can do this here because lambdas keep return statements around
+ // to deduce an implicit return type.
+ if (getLangOpts().CPlusPlus && FD->getResultType()->isRecordType() &&
+ !FD->isDependentContext())
+ computeNRVO(Body, getCurFunction());
}
assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) &&
@@ -7471,8 +7712,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
- if (Body)
- MD->setEndLoc(Body->getLocEnd());
if (!MD->isInvalidDecl()) {
DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(),
@@ -7481,22 +7720,24 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (Body)
computeNRVO(Body, getCurFunction());
}
- if (ObjCShouldCallSuperDealloc) {
+ if (getCurFunction()->ObjCShouldCallSuperDealloc) {
Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc);
- ObjCShouldCallSuperDealloc = false;
+ getCurFunction()->ObjCShouldCallSuperDealloc = false;
}
- if (ObjCShouldCallSuperFinalize) {
+ if (getCurFunction()->ObjCShouldCallSuperFinalize) {
Diag(MD->getLocEnd(), diag::warn_objc_missing_super_finalize);
- ObjCShouldCallSuperFinalize = false;
+ getCurFunction()->ObjCShouldCallSuperFinalize = false;
}
} else {
return 0;
}
- assert(!ObjCShouldCallSuperDealloc && "This should only be set for "
- "ObjC methods, which should have been handled in the block above.");
- assert(!ObjCShouldCallSuperFinalize && "This should only be set for "
- "ObjC methods, which should have been handled in the block above.");
+ assert(!getCurFunction()->ObjCShouldCallSuperDealloc &&
+ "This should only be set for ObjC methods, which should have been "
+ "handled in the block above.");
+ assert(!getCurFunction()->ObjCShouldCallSuperFinalize &&
+ "This should only be set for ObjC methods, which should have been "
+ "handled in the block above.");
// Verify and clean out per-function state.
if (Body) {
@@ -7630,10 +7871,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
(void)Error; // Silence warning.
assert(!Error && "Error setting up implicit decl!");
Declarator D(DS, Declarator::BlockContext);
- D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
- 0, 0, true, SourceLocation(),
+ D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, false,
+ SourceLocation(), 0, 0, 0, true,
+ SourceLocation(), SourceLocation(),
SourceLocation(), SourceLocation(),
- SourceLocation(),
EST_None, SourceLocation(),
0, 0, 0, 0, Loc, Loc, D),
DS.getAttributes(),
@@ -7733,6 +7974,13 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
"printf", 2,
Name->isStr("vasprintf") ? 0 : 3));
}
+
+ if (Name->isStr("__CFStringMakeConstantString")) {
+ // We already have a __builtin___CFStringMakeConstantString,
+ // but builds that use -fno-constant-cfstrings don't go through that.
+ if (!FD->getAttr<FormatArgAttr>())
+ FD->addAttr(::new (Context) FormatArgAttr(FD->getLocation(), Context, 1));
+ }
}
TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
@@ -8566,9 +8814,10 @@ CreateNewDecl:
// many points during the parsing of a struct declaration (because
// the #pragma tokens are effectively skipped over during the
// parsing of the struct).
- AddAlignmentAttributesForRecord(RD);
-
- AddMsStructLayoutForRecord(RD);
+ if (TUK == TUK_Definition) {
+ AddAlignmentAttributesForRecord(RD);
+ AddMsStructLayoutForRecord(RD);
+ }
}
if (ModulePrivateLoc.isValid()) {
@@ -8653,6 +8902,13 @@ CreateNewDecl:
InFunctionDeclarator && Name)
DeclsInPrototypeScope.push_back(New);
+ if (PrevDecl)
+ mergeDeclAttributes(New, PrevDecl);
+
+ // If there's a #pragma GCC visibility in scope, set the visibility of this
+ // record.
+ AddPushedVisibilityAttribute(New);
+
OwnedDecl = true;
return New;
}
@@ -8663,6 +8919,12 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
// Enter the tag context.
PushDeclContext(S, Tag);
+
+ ActOnDocumentableDecl(TagD);
+
+ // If there's a #pragma GCC visibility in scope, set the visibility of this
+ // record.
+ AddPushedVisibilityAttribute(Tag);
}
Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
@@ -8849,7 +9111,7 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
Declarator &D, Expr *BitfieldWidth) {
FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD),
DeclStart, D, static_cast<Expr*>(BitfieldWidth),
- /*HasInit=*/false, AS_public);
+ /*InitStyle=*/ICIS_NoInit, AS_public);
return Res;
}
@@ -8857,7 +9119,8 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
///
FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
SourceLocation DeclStart,
- Declarator &D, Expr *BitWidth, bool HasInit,
+ Declarator &D, Expr *BitWidth,
+ InClassInitStyle InitStyle,
AccessSpecifier AS) {
IdentifierInfo *II = D.getIdentifier();
SourceLocation Loc = DeclStart;
@@ -8919,7 +9182,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
= (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
SourceLocation TSSL = D.getLocStart();
FieldDecl *NewFD
- = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit,
+ = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, InitStyle,
TSSL, AS, PrevDecl, &D);
if (NewFD->isInvalidDecl())
@@ -8952,7 +9215,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
TypeSourceInfo *TInfo,
RecordDecl *Record, SourceLocation Loc,
- bool Mutable, Expr *BitWidth, bool HasInit,
+ bool Mutable, Expr *BitWidth,
+ InClassInitStyle InitStyle,
SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D) {
@@ -9042,7 +9306,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
- BitWidth, Mutable, HasInit);
+ BitWidth, Mutable, InitStyle);
if (InvalidDecl)
NewFD->setInvalidDecl();
@@ -9213,10 +9477,9 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
case CXXCopyAssignment:
if (RD->hasUserDeclaredCopyAssignment()) {
- // FIXME: this should use the location of the copy
- // assignment, not the type.
- SourceLocation TyLoc = RD->getLocStart();
- Diag(TyLoc, diag::note_nontrivial_user_defined) << QT << member;
+ SourceLocation AssignLoc =
+ RD->getCopyAssignmentOperator(0)->getLocation();
+ Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
return;
}
break;
@@ -9295,12 +9558,12 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
typedef RecordDecl::field_iterator field_iter;
for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
++fi) {
- QualType EltTy = Context.getBaseElementType((*fi)->getType());
+ QualType EltTy = Context.getBaseElementType(fi->getType());
if (const RecordType *EltRT = EltTy->getAs<RecordType>()) {
CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
if (!(EltRD->*hasTrivial)()) {
- SourceLocation FLoc = (*fi)->getLocation();
+ SourceLocation FLoc = fi->getLocation();
Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
DiagnoseNontrivial(EltRT, member);
return;
@@ -9316,7 +9579,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
case Qualifiers::OCL_Autoreleasing:
case Qualifiers::OCL_Weak:
case Qualifiers::OCL_Strong:
- Diag((*fi)->getLocation(), diag::note_nontrivial_objc_ownership)
+ Diag(fi->getLocation(), diag::note_nontrivial_objc_ownership)
<< QT << EltTy.getObjCLifetime();
return;
}
@@ -9390,7 +9653,7 @@ Decl *Sema::ActOnIvar(Scope *S,
ObjCContainerDecl *EnclosingContext;
if (ObjCImplementationDecl *IMPDecl =
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
- if (!LangOpts.ObjCNonFragileABI2) {
+ if (LangOpts.ObjCRuntime.isFragile()) {
// Case of ivar declared in an implementation. Context is that of its class.
EnclosingContext = IMPDecl->getClassInterface();
assert(EnclosingContext && "Implementation has no class interface!");
@@ -9400,7 +9663,7 @@ Decl *Sema::ActOnIvar(Scope *S,
} else {
if (ObjCCategoryDecl *CDecl =
dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
- if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) {
+ if (LangOpts.ObjCRuntime.isFragile() || !CDecl->IsClassExtension()) {
Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension();
return 0;
}
@@ -9443,7 +9706,11 @@ Decl *Sema::ActOnIvar(Scope *S,
S->AddDecl(NewID);
IdResolver.AddDecl(NewID);
}
-
+
+ if (LangOpts.ObjCRuntime.isNonFragile() &&
+ !NewID->isInvalidDecl() && isa<ObjCInterfaceDecl>(EnclosingDecl))
+ Diag(Loc, diag::warn_ivars_in_interface);
+
return NewID;
}
@@ -9453,7 +9720,7 @@ Decl *Sema::ActOnIvar(Scope *S,
/// then add an implicit `char :0` ivar to the end of that interface.
void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
SmallVectorImpl<Decl *> &AllIvarDecls) {
- if (!LangOpts.ObjCNonFragileABI2 || AllIvarDecls.empty())
+ if (LangOpts.ObjCRuntime.isFragile() || AllIvarDecls.empty())
return;
Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1];
@@ -9492,11 +9759,23 @@ void Sema::ActOnFields(Scope* S,
AttributeList *Attr) {
assert(EnclosingDecl && "missing record or interface decl");
- // If the decl this is being inserted into is invalid, then it may be a
- // redeclaration or some other bogus case. Don't try to add fields to it.
- if (EnclosingDecl->isInvalidDecl())
- return;
-
+ // If this is an Objective-C @implementation or category and we have
+ // new fields here we should reset the layout of the interface since
+ // it will now change.
+ if (!Fields.empty() && isa<ObjCContainerDecl>(EnclosingDecl)) {
+ ObjCContainerDecl *DC = cast<ObjCContainerDecl>(EnclosingDecl);
+ switch (DC->getKind()) {
+ default: break;
+ case Decl::ObjCCategory:
+ Context.ResetObjCLayout(cast<ObjCCategoryDecl>(DC)->getClassInterface());
+ break;
+ case Decl::ObjCImplementation:
+ Context.
+ ResetObjCLayout(cast<ObjCImplementationDecl>(DC)->getClassInterface());
+ break;
+ }
+ }
+
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
// Start counting up the number of named members; make sure to include
@@ -9704,7 +9983,7 @@ void Sema::ActOnFields(Scope* S,
// However, here we check whether this particular class is only
// non-POD because of the presence of an Objective-C pointer member.
// If so, objects of this type cannot be shared between code compiled
- // with instant objects and code compiled with manual retain/release.
+ // with ARC and code compiled with manual retain/release.
if (getLangOpts().ObjCAutoRefCount &&
CXXRecord->hasObjectMember() &&
CXXRecord->getLinkage() == ExternalLinkage) {
@@ -9848,11 +10127,6 @@ void Sema::ActOnFields(Scope* S,
if (Attr)
ProcessDeclAttributeList(S, Record, Attr);
-
- // If there's a #pragma GCC visibility in scope, and this isn't a subclass,
- // set the visibility of this record.
- if (Record && !Record->getDeclContext()->isRecord())
- AddPushedVisibilityAttribute(Record);
}
/// \brief Determine whether the given integral value is representable within
@@ -10106,15 +10380,16 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
}
}
- // C++ [class.mem]p13:
- // If T is the name of a class, then each of the following shall have a
- // name different from T:
- // - every enumerator of every member of class T that is an enumerated
- // type
+ // C++ [class.mem]p15:
+ // If T is the name of a class, then each of the following shall have a name
+ // different from T:
+ // - every enumerator of every member of class T that is an unscoped
+ // enumerated type
if (CXXRecordDecl *Record
= dyn_cast<CXXRecordDecl>(
TheEnumDecl->getDeclContext()->getRedeclContext()))
- if (Record->getIdentifier() && Record->getIdentifier() == Id)
+ if (!TheEnumDecl->isScoped() &&
+ Record->getIdentifier() && Record->getIdentifier() == Id)
Diag(IdLoc, diag::err_member_name_of_class) << Id;
EnumConstantDecl *New =
@@ -10129,9 +10404,62 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
PushOnScopeChains(New, S);
}
+ ActOnDocumentableDecl(New);
+
return New;
}
+// Emits a warning if every element in the enum is the same value and if
+// every element is initialized with a integer or boolean literal.
+static void CheckForUniqueEnumValues(Sema &S, Decl **Elements,
+ unsigned NumElements, EnumDecl *Enum,
+ QualType EnumType) {
+ if (S.Diags.getDiagnosticLevel(diag::warn_identical_enum_values,
+ Enum->getLocation()) ==
+ DiagnosticsEngine::Ignored)
+ return;
+
+ if (NumElements < 2)
+ return;
+
+ if (!Enum->getIdentifier())
+ return;
+
+ llvm::APSInt FirstVal;
+
+ for (unsigned i = 0; i != NumElements; ++i) {
+ EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]);
+ if (!ECD)
+ return;
+
+ Expr *InitExpr = ECD->getInitExpr();
+ if (!InitExpr)
+ return;
+ InitExpr = InitExpr->IgnoreImpCasts();
+ if (!isa<IntegerLiteral>(InitExpr) && !isa<CXXBoolLiteralExpr>(InitExpr))
+ return;
+
+ if (i == 0) {
+ FirstVal = ECD->getInitVal();
+ continue;
+ }
+
+ if (!llvm::APSInt::isSameValue(FirstVal, ECD->getInitVal()))
+ return;
+ }
+
+ S.Diag(Enum->getLocation(), diag::warn_identical_enum_values)
+ << EnumType << FirstVal.toString(10)
+ << Enum->getSourceRange();
+
+ EnumConstantDecl *Last = cast<EnumConstantDecl>(Elements[NumElements - 1]),
+ *Next = cast<EnumConstantDecl>(Elements[NumElements - 2]);
+
+ S.Diag(Last->getLocation(), diag::note_identical_enum_values)
+ << FixItHint::CreateReplacement(Last->getInitExpr()->getSourceRange(),
+ Next->getName());
+}
+
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, Decl *EnumDeclX,
Decl **Elements, unsigned NumElements,
@@ -10355,6 +10683,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
if (InFunctionDeclarator)
DeclsInPrototypeScope.push_back(Enum);
+ CheckForUniqueEnumValues(*this, Elements, NumElements, Enum, EnumType);
}
Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 5c6ddd2..22bff86 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -14,6 +14,7 @@
#include "clang/Sema/SemaInternal.h"
#include "TargetAttributesSema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclObjC.h"
@@ -42,7 +43,8 @@ enum AttributeDeclKind {
ExpectedMethod,
ExpectedVariableFunctionOrLabel,
ExpectedFieldOrGlobalVar,
- ExpectedStruct
+ ExpectedStruct,
+ ExpectedTLSVar
};
//===----------------------------------------------------------------------===//
@@ -82,7 +84,7 @@ static bool isFunction(const Decl *D) {
/// type (function or function-typed variable) or an Objective-C
/// method.
static bool isFunctionOrMethod(const Decl *D) {
- return isFunction(D)|| isa<ObjCMethodDecl>(D);
+ return isFunction(D) || isa<ObjCMethodDecl>(D);
}
/// isFunctionOrMethodOrBlock - Return true if the given decl has function
@@ -238,17 +240,45 @@ static bool isIntOrBool(Expr *Exp) {
return QT->isBooleanType() || QT->isIntegerType();
}
-///
+
+// Check to see if the type is a smart pointer of some kind. We assume
+// it's a smart pointer if it defines both operator-> and operator*.
+static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
+ DeclContextLookupConstResult Res1 = RT->getDecl()->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Star));
+ if (Res1.first == Res1.second)
+ return false;
+
+ DeclContextLookupConstResult Res2 = RT->getDecl()->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Arrow));
+ if (Res2.first == Res2.second)
+ return false;
+
+ return true;
+}
+
/// \brief Check if passed in Decl is a pointer type.
/// Note that this function may produce an error message.
/// \return true if the Decl is a pointer type; false otherwise
-///
-static bool checkIsPointer(Sema &S, const Decl *D, const AttributeList &Attr) {
+static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D,
+ const AttributeList &Attr) {
if (const ValueDecl *vd = dyn_cast<ValueDecl>(D)) {
QualType QT = vd->getType();
if (QT->isAnyPointerType())
return true;
- S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type)
+
+ if (const RecordType *RT = QT->getAs<RecordType>()) {
+ // If it's an incomplete type, it could be a smart pointer; skip it.
+ // (We don't want to force template instantiation if we can avoid it,
+ // since that would alter the order in which templates are instantiated.)
+ if (RT->isIncompleteType())
+ return true;
+
+ if (threadSafetyCheckIsSmartPointer(S, RT))
+ return true;
+ }
+
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer)
<< Attr.getName()->getName() << QT;
} else {
S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl)
@@ -270,35 +300,60 @@ static const RecordType *getRecordType(QualType QT) {
return 0;
}
+
+static bool checkBaseClassIsLockableCallback(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path, void *Unused) {
+ const RecordType *RT = Specifier->getType()->getAs<RecordType>();
+ if (RT->getDecl()->getAttr<LockableAttr>())
+ return true;
+ return false;
+}
+
+
/// \brief Thread Safety Analysis: Checks that the passed in RecordType
-/// resolves to a lockable object. May flag an error.
+/// resolves to a lockable object.
static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr,
QualType Ty) {
const RecordType *RT = getRecordType(Ty);
-
+
// Warn if could not get record type for this argument.
if (!RT) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_argument_not_class)
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_class)
<< Attr.getName() << Ty.getAsString();
return;
}
- // Don't check for lockable if the class hasn't been defined yet.
+
+ // Don't check for lockable if the class hasn't been defined yet.
if (RT->isIncompleteType())
return;
- // Warn if the type is not lockable.
- if (!RT->getDecl()->getAttr<LockableAttr>()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_argument_not_lockable)
- << Attr.getName() << Ty.getAsString();
+
+ // Allow smart pointers to be used as lockable objects.
+ // FIXME -- Check the type that the smart pointer points to.
+ if (threadSafetyCheckIsSmartPointer(S, RT))
+ return;
+
+ // Check if the type is lockable.
+ RecordDecl *RD = RT->getDecl();
+ if (RD->getAttr<LockableAttr>())
return;
+
+ // Else check if any base classes are lockable.
+ if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+ CXXBasePaths BPaths(false, false);
+ if (CRD->lookupInBases(checkBaseClassIsLockableCallback, 0, BPaths))
+ return;
}
+
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
+ << Attr.getName() << Ty.getAsString();
}
/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting
-/// from Sidx, resolve to a lockable object. May flag an error.
+/// from Sidx, resolve to a lockable object.
/// \param Sidx The attribute argument index to start checking with.
/// \param ParamIdxOk Whether an argument can be indexing into a function
/// parameter list.
-static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
+static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
const AttributeList &Attr,
SmallVectorImpl<Expr*> &Args,
int Sidx = 0,
@@ -307,13 +362,33 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
Expr *ArgExp = Attr.getArg(Idx);
if (ArgExp->isTypeDependent()) {
- // FIXME -- need to processs this again on template instantiation
+ // FIXME -- need to check this again on template instantiation
Args.push_back(ArgExp);
continue;
}
+ if (StringLiteral *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
+ // Ignore empty strings without warnings
+ if (StrLit->getLength() == 0)
+ continue;
+
+ // We allow constant strings to be used as a placeholder for expressions
+ // that are not valid C++ syntax, but warn that they are ignored.
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_ignored) <<
+ Attr.getName();
+ continue;
+ }
+
QualType ArgTy = ArgExp->getType();
+ // A pointer to member expression of the form &MyClass::mu is treated
+ // specially -- we need to look at the type of the member.
+ if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(ArgExp))
+ if (UOp->getOpcode() == UO_AddrOf)
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr()))
+ if (DRE->getDecl()->isCXXInstanceMember())
+ ArgTy = DRE->getDecl()->getType();
+
// First see if we can just cast to record type, or point to record type.
const RecordType *RT = getRecordType(ArgTy);
@@ -329,7 +404,7 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range)
<< Attr.getName() << Idx + 1 << NumParams;
- return false;
+ continue;
}
ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType();
}
@@ -339,7 +414,6 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
Args.push_back(ArgExp);
}
- return true;
}
//===----------------------------------------------------------------------===//
@@ -350,78 +424,125 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
// least add some helper functions to check most argument patterns (#
// and types of args).
-static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool pointer = false) {
+enum ThreadAttributeDeclKind {
+ ThreadExpectedFieldOrGlobalVar,
+ ThreadExpectedFunctionOrMethod,
+ ThreadExpectedClassOrStruct
+};
+
+static bool checkGuardedVarAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
- return;
+ return false;
// D must be either a member field or global (potentially shared) variable.
if (!mayBeSharedVariable(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFieldOrGlobalVar;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFieldOrGlobalVar;
+ return false;
}
- if (pointer && !checkIsPointer(S, D, Attr))
+ return true;
+}
+
+static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!checkGuardedVarAttrCommon(S, D, Attr))
return;
- if (pointer)
- D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getRange(), S.Context));
- else
- D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getRange(), S.Context));
}
-static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool pointer = false) {
- assert(!Attr.isInvalid());
+static void handlePtGuardedVarAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkGuardedVarAttrCommon(S, D, Attr))
+ return;
- if (!checkAttributeNumArgs(S, Attr, 1))
+ if (!threadSafetyCheckIsPointer(S, D, Attr))
return;
- Expr *Arg = Attr.getArg(0);
+ D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getRange(), S.Context));
+}
+
+static bool checkGuardedByAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ Expr* &Arg) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return false;
// D must be either a member field or global (potentially shared) variable.
if (!mayBeSharedVariable(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFieldOrGlobalVar;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFieldOrGlobalVar;
+ return false;
}
- if (pointer && !checkIsPointer(S, D, Attr))
- return;
+ SmallVector<Expr*, 1> Args;
+ // check that all arguments are lockable objects
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ unsigned Size = Args.size();
+ if (Size != 1)
+ return false;
- if (!Arg->isTypeDependent()) {
- checkForLockableRecord(S, D, Attr, Arg->getType());
- }
+ Arg = Args[0];
- if (pointer)
- D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(),
- S.Context, Arg));
- else
- D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg));
+ return true;
+}
+
+static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ Expr *Arg = 0;
+ if (!checkGuardedByAttrCommon(S, D, Attr, Arg))
+ return;
+
+ D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg));
}
+static void handlePtGuardedByAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ Expr *Arg = 0;
+ if (!checkGuardedByAttrCommon(S, D, Attr, Arg))
+ return;
+
+ if (!threadSafetyCheckIsPointer(S, D, Attr))
+ return;
+
+ D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(),
+ S.Context, Arg));
+}
-static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool scoped = false) {
+static bool checkLockableAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
- return;
+ return false;
// FIXME: Lockable structs for C code.
if (!isa<CXXRecordDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedClass;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedClassOrStruct;
+ return false;
}
- if (scoped)
- D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getRange(), S.Context));
- else
- D->addAttr(::new (S.Context) LockableAttr(Attr.getRange(), S.Context));
+ return true;
+}
+
+static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!checkLockableAttrCommon(S, D, Attr))
+ return;
+
+ D->addAttr(::new (S.Context) LockableAttr(Attr.getRange(), S.Context));
+}
+
+static void handleScopedLockableAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkLockableAttrCommon(S, D, Attr))
+ return;
+
+ D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getRange(), S.Context));
}
static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
@@ -432,8 +553,8 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
return;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
return;
}
@@ -442,7 +563,7 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
}
static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
@@ -455,154 +576,212 @@ static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context) NoAddressSafetyAnalysisAttr(Attr.getRange(),
- S.Context));
+ S.Context));
}
-static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool before) {
+static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVector<Expr*, 1> &Args) {
assert(!Attr.isInvalid());
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
- return;
+ return false;
// D must be either a member field or global (potentially shared) variable.
ValueDecl *VD = dyn_cast<ValueDecl>(D);
if (!VD || !mayBeSharedVariable(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFieldOrGlobalVar;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFieldOrGlobalVar;
+ return false;
}
- // Check that this attribute only applies to lockable types
+ // Check that this attribute only applies to lockable types.
QualType QT = VD->getType();
if (!QT->isDependentType()) {
const RecordType *RT = getRecordType(QT);
if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_decl_not_lockable)
- << Attr.getName();
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable)
+ << Attr.getName();
+ return false;
}
}
+ // Check that all arguments are lockable objects.
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ if (Args.size() == 0)
+ return false;
+
+ return true;
+}
+
+static void handleAcquiredAfterAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
SmallVector<Expr*, 1> Args;
- // check that all arguments are lockable objects
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
+ if (!checkAcquireOrderAttrCommon(S, D, Attr, Args))
return;
- unsigned Size = Args.size();
- assert(Size == Attr.getNumArgs());
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ Expr **StartArg = &Args[0];
+ D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size()));
+}
- if (before)
- D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context,
- StartArg, Size));
- else
- D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getRange(), S.Context,
- StartArg, Size));
+static void handleAcquiredBeforeAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkAcquireOrderAttrCommon(S, D, Attr, Args))
+ return;
+
+ Expr **StartArg = &Args[0];
+ D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size()));
}
-static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool exclusive = false) {
+static bool checkLockFunAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVector<Expr*, 1> &Args) {
assert(!Attr.isInvalid());
// zero or more arguments ok
// check that the attribute is applied to a function
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
+ return false;
}
// check that all arguments are lockable objects
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
+
+ return true;
+}
+
+static void handleSharedLockFunctionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
SmallVector<Expr*, 1> Args;
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true))
+ if (!checkLockFunAttrCommon(S, D, Attr, Args))
return;
unsigned Size = Args.size();
- assert(Size == Attr.getNumArgs());
Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getRange(),
+ S.Context,
+ StartArg, Size));
+}
- if (exclusive)
- D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getRange(),
- S.Context, StartArg,
- Size));
- else
- D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getRange(),
- S.Context, StartArg,
- Size));
+static void handleExclusiveLockFunctionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkLockFunAttrCommon(S, D, Attr, Args))
+ return;
+
+ unsigned Size = Args.size();
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getRange(),
+ S.Context,
+ StartArg, Size));
}
-static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool exclusive = false) {
+static bool checkTryLockFunAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVector<Expr*, 2> &Args) {
assert(!Attr.isInvalid());
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
- return;
-
+ return false;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
+ return false;
}
if (!isIntOrBool(Attr.getArg(0))) {
S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool)
- << Attr.getName();
- return;
+ << Attr.getName();
+ return false;
}
- SmallVector<Expr*, 2> Args;
// check that all arguments are lockable objects
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1))
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1);
+
+ return true;
+}
+
+static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 2> Args;
+ if (!checkTryLockFunAttrCommon(S, D, Attr, Args))
return;
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getRange(),
+ S.Context,
+ Attr.getArg(0),
+ StartArg, Size));
+}
- if (exclusive)
- D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getRange(),
- S.Context,
- Attr.getArg(0),
- StartArg, Size));
- else
- D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getRange(),
- S.Context,
- Attr.getArg(0),
- StartArg, Size));
+static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 2> Args;
+ if (!checkTryLockFunAttrCommon(S, D, Attr, Args))
+ return;
+
+ unsigned Size = Args.size();
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getRange(),
+ S.Context,
+ Attr.getArg(0),
+ StartArg, Size));
}
-static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool exclusive = false) {
+static bool checkLocksRequiredCommon(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVector<Expr*, 1> &Args) {
assert(!Attr.isInvalid());
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
- return;
+ return false;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
+ return false;
}
// check that all arguments are lockable objects
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ if (Args.size() == 0)
+ return false;
+
+ return true;
+}
+
+static void handleExclusiveLocksRequiredAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
SmallVector<Expr*, 1> Args;
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
+ if (!checkLocksRequiredCommon(S, D, Attr, Args))
return;
- unsigned Size = Args.size();
- assert(Size == Attr.getNumArgs());
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ Expr **StartArg = &Args[0];
+ D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(),
+ S.Context,
+ StartArg,
+ Args.size()));
+}
- if (exclusive)
- D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(),
- S.Context, StartArg,
- Size));
- else
- D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getRange(),
- S.Context, StartArg,
- Size));
+static void handleSharedLocksRequiredAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkLocksRequiredCommon(S, D, Attr, Args))
+ return;
+
+ Expr **StartArg = &Args[0];
+ D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getRange(),
+ S.Context,
+ StartArg,
+ Args.size()));
}
static void handleUnlockFunAttr(Sema &S, Decl *D,
@@ -612,18 +791,15 @@ static void handleUnlockFunAttr(Sema &S, Decl *D,
// zero or more arguments ok
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
return;
}
// check that all arguments are lockable objects
SmallVector<Expr*, 1> Args;
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true))
- return;
-
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
unsigned Size = Args.size();
- assert(Size == Attr.getNumArgs());
Expr **StartArg = Size == 0 ? 0 : &Args[0];
D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getRange(), S.Context,
@@ -639,8 +815,8 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
Expr *Arg = Attr.getArg(0);
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
return;
}
@@ -648,9 +824,14 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
return;
// check that the argument is lockable object
- checkForLockableRecord(S, D, Attr, Arg->getType());
+ SmallVector<Expr*, 1> Args;
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ unsigned Size = Args.size();
+ if (Size == 0)
+ return;
- D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getRange(), S.Context, Arg));
+ D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getRange(), S.Context,
+ Args[0]));
}
static void handleLocksExcludedAttr(Sema &S, Decl *D,
@@ -661,19 +842,18 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
return;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
return;
}
// check that all arguments are lockable objects
SmallVector<Expr*, 1> Args;
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
- return;
-
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
unsigned Size = Args.size();
- assert(Size == Attr.getNumArgs());
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ if (Size == 0)
+ return;
+ Expr **StartArg = &Args[0];
D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getRange(), S.Context,
StartArg, Size));
@@ -698,12 +878,12 @@ static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
SourceLocation TemplateKWLoc;
UnqualifiedId id;
id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
-
+
ExprResult Size = S.ActOnIdExpression(scope, SS, TemplateKWLoc, id,
false, false);
if (Size.isInvalid())
return;
-
+
sizeExpr = Size.get();
} else {
// check the attribute arguments.
@@ -854,6 +1034,75 @@ static void possibleTransparentUnionPointerType(QualType &T) {
}
}
+static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!isFunctionOrMethod(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << "alloc_size" << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ // In C++ the implicit 'this' function parameter also counts, and they are
+ // counted from one.
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
+
+ SmallVector<unsigned, 8> SizeArgs;
+
+ for (AttributeList::arg_iterator I = Attr.arg_begin(),
+ E = Attr.arg_end(); I!=E; ++I) {
+ // The argument must be an integer constant expression.
+ Expr *Ex = *I;
+ llvm::APSInt ArgNum;
+ if (Ex->isTypeDependent() || Ex->isValueDependent() ||
+ !Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "alloc_size" << Ex->getSourceRange();
+ return;
+ }
+
+ uint64_t x = ArgNum.getZExtValue();
+
+ if (x < 1 || x > NumArgs) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << "alloc_size" << I.getArgNum() << Ex->getSourceRange();
+ return;
+ }
+
+ --x;
+ if (HasImplicitThisParam) {
+ if (x == 0) {
+ S.Diag(Attr.getLoc(),
+ diag::err_attribute_invalid_implicit_this_argument)
+ << "alloc_size" << Ex->getSourceRange();
+ return;
+ }
+ --x;
+ }
+
+ // check if the function argument is of an integer type
+ QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();
+ if (!T->isIntegerType()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "alloc_size" << Ex->getSourceRange();
+ return;
+ }
+
+ SizeArgs.push_back(x);
+ }
+
+ // check if the function returns a pointer
+ if (!getFunctionType(D)->getResultType()->isAnyPointerType()) {
+ S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
+ << "alloc_size" << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange();
+ }
+
+ D->addAttr(::new (S.Context) AllocSizeAttr(Attr.getRange(), S.Context,
+ SizeArgs.data(), SizeArgs.size()));
+}
+
static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// GCC ignores the nonnull attribute on K&R style function prototypes, so we
// ignore it as well
@@ -1226,6 +1475,46 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Str->getString()));
}
+static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Check the attribute arguments.
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunction;
+ return;
+ }
+
+ if (D->hasAttr<HotAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << Attr.getName() << "hot";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context));
+}
+
+static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Check the attribute arguments.
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunction;
+ return;
+ }
+
+ if (D->hasAttr<ColdAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << Attr.getName() << "cold";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context));
+}
+
static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (!checkAttributeNumArgs(S, Attr, 0))
@@ -1257,6 +1546,42 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D,
D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), S.Context));
}
+static void handleTLSModelAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ Expr *Arg = Attr.getArg(0);
+ Arg = Arg->IgnoreParenCasts();
+ StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+
+ // Check that it is a string.
+ if (!Str) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_not_string) << "tls_model";
+ return;
+ }
+
+ if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->isThreadSpecified()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedTLSVar;
+ return;
+ }
+
+ // Check that the value.
+ StringRef Model = Str->getString();
+ if (Model != "global-dynamic" && Model != "local-dynamic"
+ && Model != "initial-exec" && Model != "local-exec") {
+ S.Diag(Attr.getLoc(), diag::err_attr_tlsmodel_arg);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) TLSModelAttr(Attr.getRange(), S.Context,
+ Model));
+}
+
static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
@@ -1427,7 +1752,7 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
if (!isa<VarDecl>(D) && !isa<ObjCIvarDecl>(D) && !isFunctionOrMethod(D) &&
- !isa<TypeDecl>(D) && !isa<LabelDecl>(D)) {
+ !isa<TypeDecl>(D) && !isa<LabelDecl>(D) && !isa<FieldDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableFunctionOrLabel;
return;
@@ -1534,47 +1859,28 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
priority));
}
-static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+template <typename AttrTy>
+static void handleAttrWithMessage(Sema &S, Decl *D, const AttributeList &Attr,
+ const char *Name) {
unsigned NumArgs = Attr.getNumArgs();
if (NumArgs > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
return;
}
-
- // Handle the case where deprecated attribute has a text message.
+
+ // Handle the case where the attribute has a text message.
StringRef Str;
if (NumArgs == 1) {
StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0));
if (!SE) {
S.Diag(Attr.getArg(0)->getLocStart(), diag::err_attribute_not_string)
- << "deprecated";
+ << Name;
return;
}
Str = SE->getString();
}
- D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str));
-}
-
-static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- unsigned NumArgs = Attr.getNumArgs();
- if (NumArgs > 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
- return;
- }
-
- // Handle the case where unavailable attribute has a text message.
- StringRef Str;
- if (NumArgs == 1) {
- StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0));
- if (!SE) {
- S.Diag(Attr.getArg(0)->getLocStart(),
- diag::err_attribute_not_string) << "unavailable";
- return;
- }
- Str = SE->getString();
- }
- D->addAttr(::new (S.Context) UnavailableAttr(Attr.getRange(), S.Context, Str));
+ D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str));
}
static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
@@ -1622,64 +1928,180 @@ static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
Attr.getRange(), S.Context));
}
-static void handleAvailabilityAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- IdentifierInfo *Platform = Attr.getParameterName();
- SourceLocation PlatformLoc = Attr.getParameterLoc();
-
+static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
+ IdentifierInfo *Platform,
+ VersionTuple Introduced,
+ VersionTuple Deprecated,
+ VersionTuple Obsoleted) {
StringRef PlatformName
= AvailabilityAttr::getPrettyPlatformName(Platform->getName());
- if (PlatformName.empty()) {
- S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
- << Platform;
-
+ if (PlatformName.empty())
PlatformName = Platform->getName();
- }
-
- AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
- AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
- AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
- bool IsUnavailable = Attr.getUnavailableLoc().isValid();
// Ensure that Introduced <= Deprecated <= Obsoleted (although not all
// of these steps are needed).
- if (Introduced.isValid() && Deprecated.isValid() &&
- !(Introduced.Version <= Deprecated.Version)) {
- S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering)
- << 1 << PlatformName << Deprecated.Version.getAsString()
- << 0 << Introduced.Version.getAsString();
- return;
+ if (!Introduced.empty() && !Deprecated.empty() &&
+ !(Introduced <= Deprecated)) {
+ S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
+ << 1 << PlatformName << Deprecated.getAsString()
+ << 0 << Introduced.getAsString();
+ return true;
}
- if (Introduced.isValid() && Obsoleted.isValid() &&
- !(Introduced.Version <= Obsoleted.Version)) {
- S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering)
- << 2 << PlatformName << Obsoleted.Version.getAsString()
- << 0 << Introduced.Version.getAsString();
- return;
+ if (!Introduced.empty() && !Obsoleted.empty() &&
+ !(Introduced <= Obsoleted)) {
+ S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
+ << 2 << PlatformName << Obsoleted.getAsString()
+ << 0 << Introduced.getAsString();
+ return true;
}
- if (Deprecated.isValid() && Obsoleted.isValid() &&
- !(Deprecated.Version <= Obsoleted.Version)) {
- S.Diag(Deprecated.KeywordLoc, diag::warn_availability_version_ordering)
- << 2 << PlatformName << Obsoleted.Version.getAsString()
- << 1 << Deprecated.Version.getAsString();
- return;
+ if (!Deprecated.empty() && !Obsoleted.empty() &&
+ !(Deprecated <= Obsoleted)) {
+ S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
+ << 2 << PlatformName << Obsoleted.getAsString()
+ << 1 << Deprecated.getAsString();
+ return true;
}
+ return false;
+}
+
+AvailabilityAttr *Sema::mergeAvailabilityAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Platform,
+ VersionTuple Introduced,
+ VersionTuple Deprecated,
+ VersionTuple Obsoleted,
+ bool IsUnavailable,
+ StringRef Message) {
+ VersionTuple MergedIntroduced = Introduced;
+ VersionTuple MergedDeprecated = Deprecated;
+ VersionTuple MergedObsoleted = Obsoleted;
+ bool FoundAny = false;
+
+ if (D->hasAttrs()) {
+ AttrVec &Attrs = D->getAttrs();
+ for (unsigned i = 0, e = Attrs.size(); i != e;) {
+ const AvailabilityAttr *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]);
+ if (!OldAA) {
+ ++i;
+ continue;
+ }
+
+ IdentifierInfo *OldPlatform = OldAA->getPlatform();
+ if (OldPlatform != Platform) {
+ ++i;
+ continue;
+ }
+
+ FoundAny = true;
+ VersionTuple OldIntroduced = OldAA->getIntroduced();
+ VersionTuple OldDeprecated = OldAA->getDeprecated();
+ VersionTuple OldObsoleted = OldAA->getObsoleted();
+ bool OldIsUnavailable = OldAA->getUnavailable();
+ StringRef OldMessage = OldAA->getMessage();
+
+ if ((!OldIntroduced.empty() && !Introduced.empty() &&
+ OldIntroduced != Introduced) ||
+ (!OldDeprecated.empty() && !Deprecated.empty() &&
+ OldDeprecated != Deprecated) ||
+ (!OldObsoleted.empty() && !Obsoleted.empty() &&
+ OldObsoleted != Obsoleted) ||
+ (OldIsUnavailable != IsUnavailable) ||
+ (OldMessage != Message)) {
+ Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
+ Diag(Range.getBegin(), diag::note_previous_attribute);
+ Attrs.erase(Attrs.begin() + i);
+ --e;
+ continue;
+ }
+
+ VersionTuple MergedIntroduced2 = MergedIntroduced;
+ VersionTuple MergedDeprecated2 = MergedDeprecated;
+ VersionTuple MergedObsoleted2 = MergedObsoleted;
+
+ if (MergedIntroduced2.empty())
+ MergedIntroduced2 = OldIntroduced;
+ if (MergedDeprecated2.empty())
+ MergedDeprecated2 = OldDeprecated;
+ if (MergedObsoleted2.empty())
+ MergedObsoleted2 = OldObsoleted;
+
+ if (checkAvailabilityAttr(*this, OldAA->getRange(), Platform,
+ MergedIntroduced2, MergedDeprecated2,
+ MergedObsoleted2)) {
+ Attrs.erase(Attrs.begin() + i);
+ --e;
+ continue;
+ }
+
+ MergedIntroduced = MergedIntroduced2;
+ MergedDeprecated = MergedDeprecated2;
+ MergedObsoleted = MergedObsoleted2;
+ ++i;
+ }
+ }
+
+ if (FoundAny &&
+ MergedIntroduced == Introduced &&
+ MergedDeprecated == Deprecated &&
+ MergedObsoleted == Obsoleted)
+ return NULL;
+
+ if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced,
+ MergedDeprecated, MergedObsoleted)) {
+ return ::new (Context) AvailabilityAttr(Range, Context, Platform,
+ Introduced, Deprecated,
+ Obsoleted, IsUnavailable, Message);
+ }
+ return NULL;
+}
+
+static void handleAvailabilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ IdentifierInfo *Platform = Attr.getParameterName();
+ SourceLocation PlatformLoc = Attr.getParameterLoc();
+
+ if (AvailabilityAttr::getPrettyPlatformName(Platform->getName()).empty())
+ S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
+ << Platform;
+
+ AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
+ AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
+ AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
+ bool IsUnavailable = Attr.getUnavailableLoc().isValid();
StringRef Str;
const StringLiteral *SE =
dyn_cast_or_null<const StringLiteral>(Attr.getMessageExpr());
if (SE)
Str = SE->getString();
-
- D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getRange(), S.Context,
- Platform,
- Introduced.Version,
- Deprecated.Version,
- Obsoleted.Version,
- IsUnavailable,
- Str));
+
+ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(D, Attr.getRange(),
+ Platform,
+ Introduced.Version,
+ Deprecated.Version,
+ Obsoleted.Version,
+ IsUnavailable, Str);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
+VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range,
+ VisibilityAttr::VisibilityType Vis) {
+ if (isa<TypedefNameDecl>(D)) {
+ Diag(Range.getBegin(), diag::warn_attribute_ignored) << "visibility";
+ return NULL;
+ }
+ VisibilityAttr *ExistingAttr = D->getAttr<VisibilityAttr>();
+ if (ExistingAttr) {
+ VisibilityAttr::VisibilityType ExistingVis = ExistingAttr->getVisibility();
+ if (ExistingVis == Vis)
+ return NULL;
+ Diag(ExistingAttr->getLocation(), diag::err_mismatched_visibility);
+ Diag(Range.getBegin(), diag::note_previous_attribute);
+ D->dropAttr<VisibilityAttr>();
+ }
+ return ::new (Context) VisibilityAttr(Range, Context, Vis);
}
static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1720,7 +2142,9 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) VisibilityAttr(Attr.getRange(), S.Context, type));
+ VisibilityAttr *NewAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type);
+ if (NewAttr)
+ D->addAttr(NewAttr);
}
static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
@@ -1803,7 +2227,15 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
}
- else if (!isa<ObjCPropertyDecl>(D)) {
+ else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) {
+ QualType T = PD->getType();
+ if (!T->isPointerType() ||
+ !T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
+ S.Diag(PD->getLocation(), diag::err_nsobject_attribute);
+ return;
+ }
+ }
+ else {
// It is okay to include this attribute on properties, e.g.:
//
// @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject));
@@ -2028,11 +2460,14 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
D->addAttr(::new (S.Context) WeakImportAttr(Attr.getRange(), S.Context));
}
-static void handleReqdWorkGroupSize(Sema &S, Decl *D,
- const AttributeList &Attr) {
+// Handles reqd_work_group_size and work_group_size_hint.
+static void handleWorkGroupSize(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize
+ || Attr.getKind() == AttributeList::AT_WorkGroupSizeHint);
+
// Attribute has 3 arguments.
- if (!checkAttributeNumArgs(S, Attr, 3))
- return;
+ if (!checkAttributeNumArgs(S, Attr, 3)) return;
unsigned WGSize[3];
for (unsigned i = 0; i < 3; ++i) {
@@ -2041,14 +2476,54 @@ static void handleReqdWorkGroupSize(Sema &S, Decl *D,
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();
+ << Attr.getName()->getName() << E->getSourceRange();
return;
}
WGSize[i] = (unsigned) ArgNum.getZExtValue();
}
- D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context,
- WGSize[0], WGSize[1],
- WGSize[2]));
+
+ if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize
+ && D->hasAttr<ReqdWorkGroupSizeAttr>()) {
+ ReqdWorkGroupSizeAttr *A = D->getAttr<ReqdWorkGroupSizeAttr>();
+ if (!(A->getXDim() == WGSize[0] &&
+ A->getYDim() == WGSize[1] &&
+ A->getZDim() == WGSize[2])) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) <<
+ Attr.getName();
+ }
+ }
+
+ if (Attr.getKind() == AttributeList::AT_WorkGroupSizeHint
+ && D->hasAttr<WorkGroupSizeHintAttr>()) {
+ WorkGroupSizeHintAttr *A = D->getAttr<WorkGroupSizeHintAttr>();
+ if (!(A->getXDim() == WGSize[0] &&
+ A->getYDim() == WGSize[1] &&
+ A->getZDim() == WGSize[2])) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) <<
+ Attr.getName();
+ }
+ }
+
+ if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize)
+ D->addAttr(::new (S.Context)
+ ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context,
+ WGSize[0], WGSize[1], WGSize[2]));
+ else
+ D->addAttr(::new (S.Context)
+ WorkGroupSizeHintAttr(Attr.getRange(), S.Context,
+ WGSize[0], WGSize[1], WGSize[2]));
+}
+
+SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
+ StringRef Name) {
+ if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
+ if (ExistingAttr->getName() == Name)
+ return NULL;
+ Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section);
+ Diag(Range.getBegin(), diag::note_previous_attribute);
+ return NULL;
+ }
+ return ::new (Context) SectionAttr(Range, Context, Name);
}
static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2078,9 +2553,10 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(SE->getLocStart(), diag::err_attribute_section_local_variable);
return;
}
-
- D->addAttr(::new (S.Context) SectionAttr(Attr.getRange(), S.Context,
- SE->getString()));
+ SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(),
+ SE->getString());
+ if (NewAttr)
+ D->addAttr(NewAttr);
}
@@ -2269,26 +2745,19 @@ enum FormatAttrKind {
/// getFormatAttrKind - Map from format attribute names to supported format
/// types.
static FormatAttrKind getFormatAttrKind(StringRef Format) {
- // Check for formats that get handled specially.
- if (Format == "NSString")
- return NSStringFormat;
- if (Format == "CFString")
- return CFStringFormat;
- if (Format == "strftime")
- return StrftimeFormat;
-
- // Otherwise, check for supported formats.
- if (Format == "scanf" || Format == "printf" || Format == "printf0" ||
- Format == "strfmon" || Format == "cmn_err" || Format == "vcmn_err" ||
- Format == "zcmn_err" ||
- Format == "kprintf") // OpenBSD.
- return SupportedFormat;
-
- if (Format == "gcc_diag" || Format == "gcc_cdiag" ||
- Format == "gcc_cxxdiag" || Format == "gcc_tdiag")
- return IgnoredFormat;
-
- return InvalidFormat;
+ return llvm::StringSwitch<FormatAttrKind>(Format)
+ // Check for formats that get handled specially.
+ .Case("NSString", NSStringFormat)
+ .Case("CFString", CFStringFormat)
+ .Case("strftime", StrftimeFormat)
+
+ // Otherwise, check for supported formats.
+ .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat)
+ .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat)
+ .Case("kprintf", SupportedFormat) // OpenBSD.
+
+ .Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat)
+ .Default(InvalidFormat);
}
/// Handle __attribute__((init_priority(priority))) attributes based on
@@ -2340,6 +2809,29 @@ static void handleInitPriorityAttr(Sema &S, Decl *D,
prioritynum));
}
+FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,
+ int FormatIdx, int FirstArg) {
+ // Check whether we already have an equivalent format attribute.
+ for (specific_attr_iterator<FormatAttr>
+ i = D->specific_attr_begin<FormatAttr>(),
+ e = D->specific_attr_end<FormatAttr>();
+ i != e ; ++i) {
+ FormatAttr *f = *i;
+ if (f->getType() == Format &&
+ f->getFormatIdx() == FormatIdx &&
+ f->getFirstArg() == FirstArg) {
+ // If we don't have a valid location for this attribute, adopt the
+ // location.
+ if (f->getLocation().isInvalid())
+ f->setRange(Range);
+ return NULL;
+ }
+ }
+
+ return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx,
+ FirstArg);
+}
+
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2475,26 +2967,11 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- // Check whether we already have an equivalent format attribute.
- for (specific_attr_iterator<FormatAttr>
- i = D->specific_attr_begin<FormatAttr>(),
- e = D->specific_attr_end<FormatAttr>();
- i != e ; ++i) {
- FormatAttr *f = *i;
- if (f->getType() == Format &&
- f->getFormatIdx() == (int)Idx.getZExtValue() &&
- f->getFirstArg() == (int)FirstArg.getZExtValue()) {
- // If we don't have a valid location for this attribute, adopt the
- // location.
- if (f->getLocation().isInvalid())
- f->setRange(Attr.getRange());
- return;
- }
- }
-
- D->addAttr(::new (S.Context) FormatAttr(Attr.getRange(), S.Context, Format,
+ FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), Format,
Idx.getZExtValue(),
- FirstArg.getZExtValue()));
+ FirstArg.getZExtValue());
+ if (NewAttr)
+ D->addAttr(NewAttr);
}
static void handleTransparentUnionAttr(Sema &S, Decl *D,
@@ -2596,37 +3073,41 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
-
+
//FIXME: The C++0x version of this attribute has more limited applicabilty
// than GNU's, and should error out when it is used to specify a
// weaker alignment, rather than being silently ignored.
if (Attr.getNumArgs() == 0) {
- D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, true, 0));
+ D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
+ true, 0, Attr.isDeclspecAttribute()));
return;
}
- S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0));
+ S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0),
+ Attr.isDeclspecAttribute());
}
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E) {
+void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
+ bool isDeclSpec) {
// FIXME: Handle pack-expansions here.
if (DiagnoseUnexpandedParameterPack(E))
return;
if (E->isTypeDependent() || E->isValueDependent()) {
// Save dependent expressions in the AST to be instantiated.
- D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E));
+ D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E,
+ isDeclSpec));
return;
}
-
+
SourceLocation AttrLoc = AttrRange.getBegin();
// FIXME: Cache the number on the Attr object?
llvm::APSInt Alignment(32);
- ExprResult ICE =
- VerifyIntegerConstantExpression(E, &Alignment,
- PDiag(diag::err_attribute_argument_not_int) << "aligned",
- /*AllowFold*/ false);
+ ExprResult ICE
+ = VerifyIntegerConstantExpression(E, &Alignment,
+ diag::err_aligned_attribute_argument_not_int,
+ /*AllowFold*/ false);
if (ICE.isInvalid())
return;
if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
@@ -2634,14 +3115,26 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E) {
<< E->getSourceRange();
return;
}
+ if (isDeclSpec) {
+ // We've already verified it's a power of 2, now let's make sure it's
+ // 8192 or less.
+ if (Alignment.getZExtValue() > 8192) {
+ Diag(AttrLoc, diag::err_attribute_aligned_greater_than_8192)
+ << E->getSourceRange();
+ return;
+ }
+ }
- D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, ICE.take()));
+ D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, ICE.take(),
+ isDeclSpec));
}
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS) {
+void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS,
+ bool isDeclSpec) {
// FIXME: Cache the number on the Attr object if non-dependent?
// FIXME: Perform checking of type validity
- D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, false, TS));
+ D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, false, TS,
+ isDeclSpec));
return;
}
@@ -2820,9 +3313,15 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- if (!isFunctionOrMethod(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (!VD->hasGlobalStorage())
+ S.Diag(Attr.getLoc(),
+ diag::warn_attribute_requires_functions_or_static_globals)
+ << Attr.getName();
+ } else if (!isFunctionOrMethod(D)) {
+ S.Diag(Attr.getLoc(),
+ diag::warn_attribute_requires_functions_or_static_globals)
+ << Attr.getName();
return;
}
@@ -3008,22 +3507,22 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
switch (Attr.getKind()) {
- case AttributeList::AT_fastcall:
+ case AttributeList::AT_FastCall:
D->addAttr(::new (S.Context) FastCallAttr(Attr.getRange(), S.Context));
return;
- case AttributeList::AT_stdcall:
+ case AttributeList::AT_StdCall:
D->addAttr(::new (S.Context) StdCallAttr(Attr.getRange(), S.Context));
return;
- case AttributeList::AT_thiscall:
+ case AttributeList::AT_ThisCall:
D->addAttr(::new (S.Context) ThisCallAttr(Attr.getRange(), S.Context));
return;
- case AttributeList::AT_cdecl:
+ case AttributeList::AT_CDecl:
D->addAttr(::new (S.Context) CDeclAttr(Attr.getRange(), S.Context));
return;
- case AttributeList::AT_pascal:
+ case AttributeList::AT_Pascal:
D->addAttr(::new (S.Context) PascalAttr(Attr.getRange(), S.Context));
return;
- case AttributeList::AT_pcs: {
+ case AttributeList::AT_Pcs: {
Expr *Arg = Attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
if (!Str || !Str->isAscii()) {
@@ -3062,7 +3561,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
return true;
if ((attr.getNumArgs() != 0 &&
- !(attr.getKind() == AttributeList::AT_pcs && attr.getNumArgs() == 1)) ||
+ !(attr.getKind() == AttributeList::AT_Pcs && attr.getNumArgs() == 1)) ||
attr.getParameterName()) {
Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
attr.setInvalid();
@@ -3072,12 +3571,12 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
// TODO: diagnose uses of these conventions on the wrong target. Or, better
// move to TargetAttributesSema one day.
switch (attr.getKind()) {
- case AttributeList::AT_cdecl: CC = CC_C; break;
- case AttributeList::AT_fastcall: CC = CC_X86FastCall; break;
- case AttributeList::AT_stdcall: CC = CC_X86StdCall; break;
- case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break;
- case AttributeList::AT_pascal: CC = CC_X86Pascal; break;
- case AttributeList::AT_pcs: {
+ case AttributeList::AT_CDecl: CC = CC_C; break;
+ case AttributeList::AT_FastCall: CC = CC_X86FastCall; break;
+ case AttributeList::AT_StdCall: CC = CC_X86StdCall; break;
+ case AttributeList::AT_ThisCall: CC = CC_X86ThisCall; break;
+ case AttributeList::AT_Pascal: CC = CC_X86Pascal; break;
+ case AttributeList::AT_Pcs: {
Expr *Arg = attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
if (!Str || !Str->isAscii()) {
@@ -3228,7 +3727,7 @@ static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
bool typeOK, cf;
- if (Attr.getKind() == AttributeList::AT_ns_consumed) {
+ if (Attr.getKind() == AttributeList::AT_NSConsumed) {
typeOK = isValidSubjectOfNSAttribute(S, param->getType());
cf = false;
} else {
@@ -3269,7 +3768,7 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
returnType = PD->getType();
else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) &&
- (Attr.getKind() == AttributeList::AT_ns_returns_retained))
+ (Attr.getKind() == AttributeList::AT_NSReturnsRetained))
return; // ignore: was handled as a type attribute
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
returnType = FD->getResultType();
@@ -3284,15 +3783,15 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
bool cf;
switch (Attr.getKind()) {
default: llvm_unreachable("invalid ownership attribute");
- case AttributeList::AT_ns_returns_autoreleased:
- case AttributeList::AT_ns_returns_retained:
- case AttributeList::AT_ns_returns_not_retained:
+ case AttributeList::AT_NSReturnsAutoreleased:
+ case AttributeList::AT_NSReturnsRetained:
+ case AttributeList::AT_NSReturnsNotRetained:
typeOK = isValidSubjectOfNSAttribute(S, returnType);
cf = false;
break;
- case AttributeList::AT_cf_returns_retained:
- case AttributeList::AT_cf_returns_not_retained:
+ case AttributeList::AT_CFReturnsRetained:
+ case AttributeList::AT_CFReturnsNotRetained:
typeOK = isValidSubjectOfCFAttribute(S, returnType);
cf = true;
break;
@@ -3307,23 +3806,23 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
switch (Attr.getKind()) {
default:
llvm_unreachable("invalid ownership attribute");
- case AttributeList::AT_ns_returns_autoreleased:
+ case AttributeList::AT_NSReturnsAutoreleased:
D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getRange(),
S.Context));
return;
- case AttributeList::AT_cf_returns_not_retained:
+ case AttributeList::AT_CFReturnsNotRetained:
D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getRange(),
S.Context));
return;
- case AttributeList::AT_ns_returns_not_retained:
+ case AttributeList::AT_NSReturnsNotRetained:
D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getRange(),
S.Context));
return;
- case AttributeList::AT_cf_returns_retained:
+ case AttributeList::AT_CFReturnsRetained:
D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getRange(),
S.Context));
return;
- case AttributeList::AT_ns_returns_retained:
+ case AttributeList::AT_NSReturnsRetained:
D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getRange(),
S.Context));
return;
@@ -3336,8 +3835,8 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);
- if (!isa<ObjCMethodDecl>(method)) {
- S.Diag(method->getLocStart(), diag::err_attribute_wrong_decl_type)
+ if (!method) {
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
<< SourceRange(loc, loc) << attr.getName() << ExpectedMethod;
return;
}
@@ -3367,7 +3866,7 @@ static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
return;
}
- bool IsAudited = (A.getKind() == AttributeList::AT_cf_audited_transfer);
+ bool IsAudited = (A.getKind() == AttributeList::AT_CFAuditedTransfer);
// Check whether there's a conflicting attribute already present.
Attr *Existing;
@@ -3478,22 +3977,6 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context));
}
-static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
- switch (Attr.getKind()) {
- default:
- return false;
- case AttributeList::AT_dllimport:
- case AttributeList::AT_dllexport:
- case AttributeList::AT_uuid:
- case AttributeList::AT_deprecated:
- case AttributeList::AT_noreturn:
- case AttributeList::AT_nothrow:
- case AttributeList::AT_naked:
- case AttributeList::AT_noinline:
- return true;
- }
-}
-
//===----------------------------------------------------------------------===//
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -3552,6 +4035,45 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid";
}
+static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (S.LangOpts.MicrosoftExt) {
+ AttributeList::Kind Kind = Attr.getKind();
+ if (Kind == AttributeList::AT_SingleInheritance)
+ D->addAttr(
+ ::new (S.Context) SingleInheritanceAttr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_MultipleInheritance)
+ D->addAttr(
+ ::new (S.Context) MultipleInheritanceAttr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_VirtualInheritance)
+ D->addAttr(
+ ::new (S.Context) VirtualInheritanceAttr(Attr.getRange(), S.Context));
+ } else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+
+static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (S.LangOpts.MicrosoftExt) {
+ AttributeList::Kind Kind = Attr.getKind();
+ if (Kind == AttributeList::AT_Ptr32)
+ D->addAttr(
+ ::new (S.Context) Ptr32Attr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_Ptr64)
+ D->addAttr(
+ ::new (S.Context) Ptr64Attr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_Win64)
+ D->addAttr(
+ ::new (S.Context) Win64Attr(Attr.getRange(), S.Context));
+ } else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+
+static void handleForceInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (S.LangOpts.MicrosoftExt)
+ D->addAttr(::new (S.Context) ForceInlineAttr(Attr.getRange(), S.Context));
+ else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -3559,9 +4081,9 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_device: handleDeviceAttr (S, D, Attr); break;
- case AttributeList::AT_host: handleHostAttr (S, D, Attr); break;
- case AttributeList::AT_overloadable:handleOverloadableAttr(S, D, Attr); break;
+ case AttributeList::AT_CUDADevice: handleDeviceAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDAHost: handleHostAttr (S, D, Attr); break;
+ case AttributeList::AT_Overloadable:handleOverloadableAttr(S, D, Attr); break;
default:
break;
}
@@ -3570,227 +4092,254 @@ static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_ibaction: handleIBAction(S, D, Attr); break;
- case AttributeList::AT_iboutlet: handleIBOutlet(S, D, Attr); break;
- case AttributeList::AT_iboutletcollection:
+ case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break;
+ case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break;
+ case AttributeList::AT_IBOutletCollection:
handleIBOutletCollection(S, D, Attr); break;
- case AttributeList::AT_address_space:
- case AttributeList::AT_opencl_image_access:
- case AttributeList::AT_objc_gc:
- case AttributeList::AT_vector_size:
- case AttributeList::AT_neon_vector_type:
- case AttributeList::AT_neon_polyvector_type:
+ case AttributeList::AT_AddressSpace:
+ case AttributeList::AT_OpenCLImageAccess:
+ case AttributeList::AT_ObjCGC:
+ case AttributeList::AT_VectorSize:
+ case AttributeList::AT_NeonVectorType:
+ case AttributeList::AT_NeonPolyVectorType:
// Ignore these, these are type attributes, handled by
// ProcessTypeAttributes.
break;
- case AttributeList::AT_device:
- case AttributeList::AT_host:
- case AttributeList::AT_overloadable:
+ case AttributeList::AT_CUDADevice:
+ case AttributeList::AT_CUDAHost:
+ case AttributeList::AT_Overloadable:
// Ignore, this is a non-inheritable attribute, handled
// by ProcessNonInheritableDeclAttr.
break;
- case AttributeList::AT_alias: handleAliasAttr (S, D, Attr); break;
- case AttributeList::AT_aligned: handleAlignedAttr (S, D, Attr); break;
- case AttributeList::AT_always_inline:
+ case AttributeList::AT_Alias: handleAliasAttr (S, D, Attr); break;
+ case AttributeList::AT_Aligned: handleAlignedAttr (S, D, Attr); break;
+ case AttributeList::AT_AllocSize: handleAllocSizeAttr (S, D, Attr); break;
+ case AttributeList::AT_AlwaysInline:
handleAlwaysInlineAttr (S, D, Attr); break;
- case AttributeList::AT_analyzer_noreturn:
+ case AttributeList::AT_AnalyzerNoReturn:
handleAnalyzerNoReturnAttr (S, D, Attr); break;
- case AttributeList::AT_annotate: handleAnnotateAttr (S, D, Attr); break;
- case AttributeList::AT_availability:handleAvailabilityAttr(S, D, Attr); break;
- case AttributeList::AT_carries_dependency:
+ case AttributeList::AT_TLSModel: handleTLSModelAttr (S, D, Attr); break;
+ case AttributeList::AT_Annotate: handleAnnotateAttr (S, D, Attr); break;
+ case AttributeList::AT_Availability:handleAvailabilityAttr(S, D, Attr); break;
+ case AttributeList::AT_CarriesDependency:
handleDependencyAttr (S, D, Attr); break;
- case AttributeList::AT_common: handleCommonAttr (S, D, Attr); break;
- case AttributeList::AT_constant: handleConstantAttr (S, D, Attr); break;
- case AttributeList::AT_constructor: handleConstructorAttr (S, D, Attr); break;
- case AttributeList::AT_deprecated: handleDeprecatedAttr (S, D, Attr); break;
- case AttributeList::AT_destructor: handleDestructorAttr (S, D, Attr); break;
- case AttributeList::AT_ext_vector_type:
+ case AttributeList::AT_Common: handleCommonAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDAConstant:handleConstantAttr (S, D, Attr); break;
+ case AttributeList::AT_Constructor: handleConstructorAttr (S, D, Attr); break;
+ case AttributeList::AT_Deprecated:
+ handleAttrWithMessage<DeprecatedAttr>(S, D, Attr, "deprecated");
+ break;
+ case AttributeList::AT_Destructor: handleDestructorAttr (S, D, Attr); break;
+ case AttributeList::AT_ExtVectorType:
handleExtVectorTypeAttr(S, scope, D, Attr);
break;
- case AttributeList::AT_format: handleFormatAttr (S, D, Attr); break;
- case AttributeList::AT_format_arg: handleFormatArgAttr (S, D, Attr); break;
- case AttributeList::AT_global: handleGlobalAttr (S, D, Attr); break;
- case AttributeList::AT_gnu_inline: handleGNUInlineAttr (S, D, Attr); break;
- case AttributeList::AT_launch_bounds:
+ case AttributeList::AT_Format: handleFormatAttr (S, D, Attr); break;
+ case AttributeList::AT_FormatArg: handleFormatArgAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDAGlobal: handleGlobalAttr (S, D, Attr); break;
+ case AttributeList::AT_GNUInline: handleGNUInlineAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDALaunchBounds:
handleLaunchBoundsAttr(S, D, Attr);
break;
- case AttributeList::AT_mode: handleModeAttr (S, D, Attr); break;
- case AttributeList::AT_malloc: handleMallocAttr (S, D, Attr); break;
- case AttributeList::AT_may_alias: handleMayAliasAttr (S, D, Attr); break;
- case AttributeList::AT_nocommon: handleNoCommonAttr (S, D, Attr); break;
- case AttributeList::AT_nonnull: handleNonNullAttr (S, D, Attr); break;
+ case AttributeList::AT_Mode: handleModeAttr (S, D, Attr); break;
+ case AttributeList::AT_Malloc: handleMallocAttr (S, D, Attr); break;
+ case AttributeList::AT_MayAlias: handleMayAliasAttr (S, D, Attr); break;
+ case AttributeList::AT_NoCommon: handleNoCommonAttr (S, D, Attr); break;
+ case AttributeList::AT_NonNull: handleNonNullAttr (S, D, Attr); break;
case AttributeList::AT_ownership_returns:
case AttributeList::AT_ownership_takes:
case AttributeList::AT_ownership_holds:
handleOwnershipAttr (S, D, Attr); break;
- case AttributeList::AT_naked: handleNakedAttr (S, D, Attr); break;
- case AttributeList::AT_noreturn: handleNoReturnAttr (S, D, Attr); break;
- case AttributeList::AT_nothrow: handleNothrowAttr (S, D, Attr); break;
- case AttributeList::AT_shared: handleSharedAttr (S, D, Attr); break;
- case AttributeList::AT_vecreturn: handleVecReturnAttr (S, D, Attr); break;
-
- case AttributeList::AT_objc_ownership:
+ case AttributeList::AT_Cold: handleColdAttr (S, D, Attr); break;
+ case AttributeList::AT_Hot: handleHotAttr (S, D, Attr); break;
+ case AttributeList::AT_Naked: handleNakedAttr (S, D, Attr); break;
+ case AttributeList::AT_NoReturn: handleNoReturnAttr (S, D, Attr); break;
+ case AttributeList::AT_NoThrow: handleNothrowAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDAShared: handleSharedAttr (S, D, Attr); break;
+ case AttributeList::AT_VecReturn: handleVecReturnAttr (S, D, Attr); break;
+
+ case AttributeList::AT_ObjCOwnership:
handleObjCOwnershipAttr(S, D, Attr); break;
- case AttributeList::AT_objc_precise_lifetime:
+ case AttributeList::AT_ObjCPreciseLifetime:
handleObjCPreciseLifetimeAttr(S, D, Attr); break;
- case AttributeList::AT_objc_returns_inner_pointer:
+ case AttributeList::AT_ObjCReturnsInnerPointer:
handleObjCReturnsInnerPointerAttr(S, D, Attr); break;
- case AttributeList::AT_ns_bridged:
+ case AttributeList::AT_NSBridged:
handleNSBridgedAttr(S, scope, D, Attr); break;
- case AttributeList::AT_cf_audited_transfer:
- case AttributeList::AT_cf_unknown_transfer:
+ case AttributeList::AT_CFAuditedTransfer:
+ case AttributeList::AT_CFUnknownTransfer:
handleCFTransferAttr(S, D, Attr); break;
// Checker-specific.
- case AttributeList::AT_cf_consumed:
- case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break;
- case AttributeList::AT_ns_consumes_self:
+ case AttributeList::AT_CFConsumed:
+ case AttributeList::AT_NSConsumed: handleNSConsumedAttr (S, D, Attr); break;
+ case AttributeList::AT_NSConsumesSelf:
handleNSConsumesSelfAttr(S, D, Attr); break;
- case AttributeList::AT_ns_returns_autoreleased:
- case AttributeList::AT_ns_returns_not_retained:
- case AttributeList::AT_cf_returns_not_retained:
- case AttributeList::AT_ns_returns_retained:
- case AttributeList::AT_cf_returns_retained:
+ case AttributeList::AT_NSReturnsAutoreleased:
+ case AttributeList::AT_NSReturnsNotRetained:
+ case AttributeList::AT_CFReturnsNotRetained:
+ case AttributeList::AT_NSReturnsRetained:
+ case AttributeList::AT_CFReturnsRetained:
handleNSReturnsRetainedAttr(S, D, Attr); break;
- case AttributeList::AT_reqd_work_group_size:
- handleReqdWorkGroupSize(S, D, Attr); break;
+ case AttributeList::AT_WorkGroupSizeHint:
+ case AttributeList::AT_ReqdWorkGroupSize:
+ handleWorkGroupSize(S, D, Attr); break;
- case AttributeList::AT_init_priority:
+ case AttributeList::AT_InitPriority:
handleInitPriorityAttr(S, D, Attr); break;
- case AttributeList::AT_packed: handlePackedAttr (S, D, Attr); break;
- case AttributeList::AT_ms_struct: handleMsStructAttr (S, D, Attr); break;
- case AttributeList::AT_section: handleSectionAttr (S, D, Attr); break;
- case AttributeList::AT_unavailable: handleUnavailableAttr (S, D, Attr); break;
- case AttributeList::AT_objc_arc_weak_reference_unavailable:
+ case AttributeList::AT_Packed: handlePackedAttr (S, D, Attr); break;
+ case AttributeList::AT_Section: handleSectionAttr (S, D, Attr); break;
+ case AttributeList::AT_Unavailable:
+ handleAttrWithMessage<UnavailableAttr>(S, D, Attr, "unavailable");
+ break;
+ case AttributeList::AT_ArcWeakrefUnavailable:
handleArcWeakrefUnavailableAttr (S, D, Attr);
break;
- case AttributeList::AT_objc_root_class:
+ case AttributeList::AT_ObjCRootClass:
handleObjCRootClassAttr(S, D, Attr);
break;
- case AttributeList::AT_objc_requires_property_definitions:
+ case AttributeList::AT_ObjCRequiresPropertyDefs:
handleObjCRequiresPropertyDefsAttr (S, D, Attr);
break;
- case AttributeList::AT_unused: handleUnusedAttr (S, D, Attr); break;
- case AttributeList::AT_returns_twice:
+ case AttributeList::AT_Unused: handleUnusedAttr (S, D, Attr); break;
+ case AttributeList::AT_ReturnsTwice:
handleReturnsTwiceAttr(S, D, Attr);
break;
- case AttributeList::AT_used: handleUsedAttr (S, D, Attr); break;
- case AttributeList::AT_visibility: handleVisibilityAttr (S, D, Attr); break;
- case AttributeList::AT_warn_unused_result: handleWarnUnusedResult(S, D, Attr);
+ case AttributeList::AT_Used: handleUsedAttr (S, D, Attr); break;
+ case AttributeList::AT_Visibility: handleVisibilityAttr (S, D, Attr); break;
+ case AttributeList::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, Attr);
break;
- case AttributeList::AT_weak: handleWeakAttr (S, D, Attr); break;
- case AttributeList::AT_weakref: handleWeakRefAttr (S, D, Attr); break;
- case AttributeList::AT_weak_import: handleWeakImportAttr (S, D, Attr); break;
- case AttributeList::AT_transparent_union:
+ case AttributeList::AT_Weak: handleWeakAttr (S, D, Attr); break;
+ case AttributeList::AT_WeakRef: handleWeakRefAttr (S, D, Attr); break;
+ case AttributeList::AT_WeakImport: handleWeakImportAttr (S, D, Attr); break;
+ case AttributeList::AT_TransparentUnion:
handleTransparentUnionAttr(S, D, Attr);
break;
- case AttributeList::AT_objc_exception:
+ case AttributeList::AT_ObjCException:
handleObjCExceptionAttr(S, D, Attr);
break;
- case AttributeList::AT_objc_method_family:
+ case AttributeList::AT_ObjCMethodFamily:
handleObjCMethodFamilyAttr(S, D, Attr);
break;
- case AttributeList::AT_NSObject: handleObjCNSObject (S, D, Attr); break;
- case AttributeList::AT_blocks: handleBlocksAttr (S, D, Attr); break;
- case AttributeList::AT_sentinel: handleSentinelAttr (S, D, Attr); break;
- case AttributeList::AT_const: handleConstAttr (S, D, Attr); break;
- case AttributeList::AT_pure: handlePureAttr (S, D, Attr); break;
- case AttributeList::AT_cleanup: handleCleanupAttr (S, D, Attr); break;
- case AttributeList::AT_nodebug: handleNoDebugAttr (S, D, Attr); break;
- case AttributeList::AT_noinline: handleNoInlineAttr (S, D, Attr); break;
- case AttributeList::AT_regparm: handleRegparmAttr (S, D, Attr); break;
+ case AttributeList::AT_ObjCNSObject:handleObjCNSObject (S, D, Attr); break;
+ case AttributeList::AT_Blocks: handleBlocksAttr (S, D, Attr); break;
+ case AttributeList::AT_Sentinel: handleSentinelAttr (S, D, Attr); break;
+ case AttributeList::AT_Const: handleConstAttr (S, D, Attr); break;
+ case AttributeList::AT_Pure: handlePureAttr (S, D, Attr); break;
+ case AttributeList::AT_Cleanup: handleCleanupAttr (S, D, Attr); break;
+ case AttributeList::AT_NoDebug: handleNoDebugAttr (S, D, Attr); break;
+ case AttributeList::AT_NoInline: handleNoInlineAttr (S, D, Attr); break;
+ case AttributeList::AT_Regparm: handleRegparmAttr (S, D, Attr); break;
case AttributeList::IgnoredAttribute:
// Just ignore
break;
- case AttributeList::AT_no_instrument_function: // Interacts with -pg.
+ case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg.
handleNoInstrumentFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_stdcall:
- case AttributeList::AT_cdecl:
- case AttributeList::AT_fastcall:
- case AttributeList::AT_thiscall:
- case AttributeList::AT_pascal:
- case AttributeList::AT_pcs:
+ case AttributeList::AT_StdCall:
+ case AttributeList::AT_CDecl:
+ case AttributeList::AT_FastCall:
+ case AttributeList::AT_ThisCall:
+ case AttributeList::AT_Pascal:
+ case AttributeList::AT_Pcs:
handleCallConvAttr(S, D, Attr);
break;
- case AttributeList::AT_opencl_kernel_function:
+ case AttributeList::AT_OpenCLKernel:
handleOpenCLKernelAttr(S, D, Attr);
break;
- case AttributeList::AT_uuid:
+
+ // Microsoft attributes:
+ case AttributeList::AT_MsStruct:
+ handleMsStructAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Uuid:
handleUuidAttr(S, D, Attr);
break;
+ case AttributeList::AT_SingleInheritance:
+ case AttributeList::AT_MultipleInheritance:
+ case AttributeList::AT_VirtualInheritance:
+ handleInheritanceAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Win64:
+ case AttributeList::AT_Ptr32:
+ case AttributeList::AT_Ptr64:
+ handlePortabilityAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_ForceInline:
+ handleForceInlineAttr(S, D, Attr);
+ break;
// Thread safety attributes:
- case AttributeList::AT_guarded_var:
+ case AttributeList::AT_GuardedVar:
handleGuardedVarAttr(S, D, Attr);
break;
- case AttributeList::AT_pt_guarded_var:
- handleGuardedVarAttr(S, D, Attr, /*pointer = */true);
+ case AttributeList::AT_PtGuardedVar:
+ handlePtGuardedVarAttr(S, D, Attr);
break;
- case AttributeList::AT_scoped_lockable:
- handleLockableAttr(S, D, Attr, /*scoped = */true);
+ case AttributeList::AT_ScopedLockable:
+ handleScopedLockableAttr(S, D, Attr);
break;
- case AttributeList::AT_no_address_safety_analysis:
+ case AttributeList::AT_NoAddressSafetyAnalysis:
handleNoAddressSafetyAttr(S, D, Attr);
break;
- case AttributeList::AT_no_thread_safety_analysis:
+ case AttributeList::AT_NoThreadSafetyAnalysis:
handleNoThreadSafetyAttr(S, D, Attr);
break;
- case AttributeList::AT_lockable:
+ case AttributeList::AT_Lockable:
handleLockableAttr(S, D, Attr);
break;
- case AttributeList::AT_guarded_by:
+ case AttributeList::AT_GuardedBy:
handleGuardedByAttr(S, D, Attr);
break;
- case AttributeList::AT_pt_guarded_by:
- handleGuardedByAttr(S, D, Attr, /*pointer = */true);
+ case AttributeList::AT_PtGuardedBy:
+ handlePtGuardedByAttr(S, D, Attr);
break;
- case AttributeList::AT_exclusive_lock_function:
- handleLockFunAttr(S, D, Attr, /*exclusive = */true);
+ case AttributeList::AT_ExclusiveLockFunction:
+ handleExclusiveLockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_exclusive_locks_required:
- handleLocksRequiredAttr(S, D, Attr, /*exclusive = */true);
+ case AttributeList::AT_ExclusiveLocksRequired:
+ handleExclusiveLocksRequiredAttr(S, D, Attr);
break;
- case AttributeList::AT_exclusive_trylock_function:
- handleTrylockFunAttr(S, D, Attr, /*exclusive = */true);
+ case AttributeList::AT_ExclusiveTrylockFunction:
+ handleExclusiveTrylockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_lock_returned:
+ case AttributeList::AT_LockReturned:
handleLockReturnedAttr(S, D, Attr);
break;
- case AttributeList::AT_locks_excluded:
+ case AttributeList::AT_LocksExcluded:
handleLocksExcludedAttr(S, D, Attr);
break;
- case AttributeList::AT_shared_lock_function:
- handleLockFunAttr(S, D, Attr);
+ case AttributeList::AT_SharedLockFunction:
+ handleSharedLockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_shared_locks_required:
- handleLocksRequiredAttr(S, D, Attr);
+ case AttributeList::AT_SharedLocksRequired:
+ handleSharedLocksRequiredAttr(S, D, Attr);
break;
- case AttributeList::AT_shared_trylock_function:
- handleTrylockFunAttr(S, D, Attr);
+ case AttributeList::AT_SharedTrylockFunction:
+ handleSharedTrylockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_unlock_function:
+ case AttributeList::AT_UnlockFunction:
handleUnlockFunAttr(S, D, Attr);
break;
- case AttributeList::AT_acquired_before:
- handleAcquireOrderAttr(S, D, Attr, /*before = */true);
+ case AttributeList::AT_AcquiredBefore:
+ handleAcquiredBeforeAttr(S, D, Attr);
break;
- case AttributeList::AT_acquired_after:
- handleAcquireOrderAttr(S, D, Attr, /*before = */false);
+ case AttributeList::AT_AcquiredAfter:
+ handleAcquiredAfterAttr(S, D, Attr);
break;
default:
// Ask target about the attribute.
const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S))
- S.Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored)
- << Attr.getName();
+ S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ?
+ diag::warn_unhandled_ms_attribute_ignored :
+ diag::warn_unknown_attribute_ignored) << Attr.getName();
break;
}
}
@@ -3805,8 +4354,11 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
if (Attr.isInvalid())
return;
- if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr))
- // FIXME: Try to deal with other __declspec attributes!
+ // Type attributes are still treated as declaration attributes by
+ // ParseMicrosoftTypeAttributes and ParseBorlandTypeAttributes. We don't
+ // want to process them, however, because we will simply warn about ignoring
+ // them. So instead, we will bail out early.
+ if (Attr.isMSTypespecAttribute())
return;
if (NonInheritable)
@@ -3840,7 +4392,7 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
const AttributeList *AttrList) {
for (const AttributeList* l = AttrList; l; l = l->getNext()) {
- if (l->getKind() == AttributeList::AT_annotate) {
+ if (l->getKind() == AttributeList::AT_Annotate) {
handleAnnotateAttr(*this, ASDecl, *l);
} else {
Diag(l->getLoc(), diag::err_only_annotate_after_access_spec);
@@ -3880,7 +4432,7 @@ void Sema::checkUnusedDeclAttributes(Declarator &D) {
}
/// DeclClonePragmaWeak - clone existing decl (maybe definition),
-/// #pragma weak needs a non-definition decl and source may not have one
+/// \#pragma weak needs a non-definition decl and source may not have one.
NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
SourceLocation Loc) {
assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
@@ -3930,7 +4482,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
return NewD;
}
-/// DeclApplyPragmaWeak - A declaration (maybe definition) needs #pragma weak
+/// DeclApplyPragmaWeak - A declaration (maybe definition) needs \#pragma weak
/// applied to it, possibly with an alias.
void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
if (W.getUsed()) return; // only do this once
@@ -4018,7 +4570,7 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
}
if (S.getLangOpts().ObjCAutoRefCount)
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(decl)) {
- // FIXME. we may want to supress diagnostics for all
+ // FIXME: we may want to suppress diagnostics for all
// kind of forbidden type messages on unavailable functions.
if (FD->hasAttr<UnavailableAttr>() &&
diag.getForbiddenTypeDiagnostic() ==
@@ -4033,57 +4585,29 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
diag.Triggered = true;
}
-// This duplicates a vector push_back but hides the need to know the
-// size of the type.
-void Sema::DelayedDiagnostics::add(const DelayedDiagnostic &diag) {
- assert(StackSize <= StackCapacity);
-
- // Grow the stack if necessary.
- if (StackSize == StackCapacity) {
- unsigned newCapacity = 2 * StackCapacity + 2;
- char *newBuffer = new char[newCapacity * sizeof(DelayedDiagnostic)];
- const char *oldBuffer = (const char*) Stack;
-
- if (StackCapacity)
- memcpy(newBuffer, oldBuffer, StackCapacity * sizeof(DelayedDiagnostic));
-
- delete[] oldBuffer;
- Stack = reinterpret_cast<sema::DelayedDiagnostic*>(newBuffer);
- StackCapacity = newCapacity;
- }
-
- assert(StackSize < StackCapacity);
- new (&Stack[StackSize++]) DelayedDiagnostic(diag);
-}
-
-void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
- Decl *decl) {
- DelayedDiagnostics &DD = S.DelayedDiagnostics;
-
- // Check the invariants.
- assert(DD.StackSize >= state.SavedStackSize);
- assert(state.SavedStackSize >= DD.ActiveStackBase);
- assert(DD.ParsingDepth > 0);
-
- // Drop the parsing depth.
- DD.ParsingDepth--;
-
- // If there are no active diagnostics, we're done.
- if (DD.StackSize == DD.ActiveStackBase)
- return;
-
- // We only want to actually emit delayed diagnostics when we
- // successfully parsed a decl.
- if (decl) {
- // We emit all the active diagnostics, not just those starting
- // from the saved state. The idea is this: we get one push for a
- // decl spec and another for each declarator; in a decl group like:
- // deprecated_typedef foo, *bar, baz();
- // only the declarator pops will be passed decls. This is correct;
- // we really do need to consider delayed diagnostics from the decl spec
- // for each of the different declarations.
- for (unsigned i = DD.ActiveStackBase, e = DD.StackSize; i != e; ++i) {
- DelayedDiagnostic &diag = DD.Stack[i];
+void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
+ assert(DelayedDiagnostics.getCurrentPool());
+ DelayedDiagnosticPool &poppedPool = *DelayedDiagnostics.getCurrentPool();
+ DelayedDiagnostics.popWithoutEmitting(state);
+
+ // When delaying diagnostics to run in the context of a parsed
+ // declaration, we only want to actually emit anything if parsing
+ // succeeds.
+ if (!decl) return;
+
+ // We emit all the active diagnostics in this pool or any of its
+ // parents. In general, we'll get one pool for the decl spec
+ // and a child pool for each declarator; in a decl group like:
+ // deprecated_typedef foo, *bar, baz();
+ // only the declarator pops will be passed decls. This is correct;
+ // we really do need to consider delayed diagnostics from the decl spec
+ // for each of the different declarations.
+ const DelayedDiagnosticPool *pool = &poppedPool;
+ do {
+ for (DelayedDiagnosticPool::pool_iterator
+ i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) {
+ // This const_cast is a bit lame. Really, Triggered should be mutable.
+ DelayedDiagnostic &diag = const_cast<DelayedDiagnostic&>(*i);
if (diag.Triggered)
continue;
@@ -4091,25 +4615,28 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
case DelayedDiagnostic::Deprecation:
// Don't bother giving deprecation diagnostics if the decl is invalid.
if (!decl->isInvalidDecl())
- S.HandleDelayedDeprecationCheck(diag, decl);
+ HandleDelayedDeprecationCheck(diag, decl);
break;
case DelayedDiagnostic::Access:
- S.HandleDelayedAccessCheck(diag, decl);
+ HandleDelayedAccessCheck(diag, decl);
break;
case DelayedDiagnostic::ForbiddenType:
- handleDelayedForbiddenType(S, diag, decl);
+ handleDelayedForbiddenType(*this, diag, decl);
break;
}
}
- }
-
- // Destroy all the delayed diagnostics we're about to pop off.
- for (unsigned i = state.SavedStackSize, e = DD.StackSize; i != e; ++i)
- DD.Stack[i].Destroy();
+ } while ((pool = pool->getParent()));
+}
- DD.StackSize = state.SavedStackSize;
+/// Given a set of delayed diagnostics, re-emit them as if they had
+/// been delayed in the current context instead of in the given pool.
+/// Essentially, this just moves them to the current pool.
+void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
+ DelayedDiagnosticPool *curPool = DelayedDiagnostics.getCurrentPool();
+ assert(curPool && "re-emitting in undelayed context not supported");
+ curPool->steal(pool);
}
static bool isDeclDeprecated(Decl *D) {
@@ -4123,24 +4650,36 @@ static bool isDeclDeprecated(Decl *D) {
return false;
}
+static void
+DoEmitDeprecationWarning(Sema &S, const NamedDecl *D, StringRef Message,
+ SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass) {
+ DeclarationName Name = D->getDeclName();
+ if (!Message.empty()) {
+ S.Diag(Loc, diag::warn_deprecated_message) << Name << Message;
+ S.Diag(D->getLocation(),
+ isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at
+ : diag::note_previous_decl) << Name;
+ } else if (!UnknownObjCClass) {
+ S.Diag(Loc, diag::warn_deprecated) << D->getDeclName();
+ S.Diag(D->getLocation(),
+ isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at
+ : diag::note_previous_decl) << Name;
+ } else {
+ S.Diag(Loc, diag::warn_deprecated_fwdclass_message) << Name;
+ S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
+ }
+}
+
void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD,
Decl *Ctx) {
if (isDeclDeprecated(Ctx))
return;
DD.Triggered = true;
- if (!DD.getDeprecationMessage().empty())
- Diag(DD.Loc, diag::warn_deprecated_message)
- << DD.getDeprecationDecl()->getDeclName()
- << DD.getDeprecationMessage();
- else if (DD.getUnknownObjCClass()) {
- Diag(DD.Loc, diag::warn_deprecated_fwdclass_message)
- << DD.getDeprecationDecl()->getDeclName();
- Diag(DD.getUnknownObjCClass()->getLocation(), diag::note_forward_class);
- }
- else
- Diag(DD.Loc, diag::warn_deprecated)
- << DD.getDeprecationDecl()->getDeclName();
+ DoEmitDeprecationWarning(*this, DD.getDeprecationDecl(),
+ DD.getDeprecationMessage(), DD.Loc,
+ DD.getUnknownObjCClass());
}
void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
@@ -4157,15 +4696,5 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
// Otherwise, don't warn if our current context is deprecated.
if (isDeclDeprecated(cast<Decl>(getCurLexicalContext())))
return;
- if (!Message.empty())
- Diag(Loc, diag::warn_deprecated_message) << D->getDeclName()
- << Message;
- else {
- if (!UnknownObjCClass)
- Diag(Loc, diag::warn_deprecated) << D->getDeclName();
- else {
- Diag(Loc, diag::warn_deprecated_fwdclass_message) << D->getDeclName();
- Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
- }
- }
+ DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index c861072..1d45a68 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
@@ -127,8 +128,8 @@ namespace {
void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
CXXMethodDecl *Method) {
- // If we have an MSAny or unknown spec already, don't bother.
- if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
+ // If we have an MSAny spec already, don't bother.
+ if (!Method || ComputedEST == EST_MSAny)
return;
const FunctionProtoType *Proto
@@ -140,7 +141,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
ExceptionSpecificationType EST = Proto->getExceptionSpecType();
// If this function can throw any exceptions, make a note of that.
- if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) {
+ if (EST == EST_MSAny || EST == EST_None) {
ClearExceptions();
ComputedEST = EST;
return;
@@ -197,7 +198,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
}
void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
- if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
+ if (!E || ComputedEST == EST_MSAny)
return;
// FIXME:
@@ -667,9 +668,9 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
SourceLocation ParamLoc = PD->getLocation();
if (!(*i)->isDependentType() &&
SemaRef.RequireLiteralType(ParamLoc, *i,
- SemaRef.PDiag(diag::err_constexpr_non_literal_param)
- << ArgIndex+1 << PD->getSourceRange()
- << isa<CXXConstructorDecl>(FD)))
+ diag::err_constexpr_non_literal_param,
+ ArgIndex+1, PD->getSourceRange(),
+ isa<CXXConstructorDecl>(FD)))
return false;
}
return true;
@@ -725,7 +726,7 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
QualType RT = NewFD->getResultType();
if (!RT->isDependentType() &&
RequireLiteralType(NewFD->getLocation(), RT,
- PDiag(diag::err_constexpr_non_literal_return)))
+ diag::err_constexpr_non_literal_return))
return false;
}
@@ -920,7 +921,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
unsigned Fields = 0;
for (CXXRecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I, ++Fields) {
- if ((*I)->isAnonymousStructOrUnion()) {
+ if (I->isAnonymousStructOrUnion()) {
AnyAnonStructUnionMembers = true;
break;
}
@@ -1055,8 +1056,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// The class-name in a base-specifier shall not be an incompletely
// defined class.
if (RequireCompleteType(BaseLoc, BaseType,
- PDiag(diag::err_incomplete_base_class)
- << SpecifierRange)) {
+ diag::err_incomplete_base_class, SpecifierRange)) {
Class->setInvalidDecl();
return 0;
}
@@ -1119,6 +1119,8 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
Virtual, Access, TInfo,
EllipsisLoc))
return BaseSpec;
+ else
+ Class->setInvalidDecl();
return true;
}
@@ -1403,32 +1405,50 @@ bool Sema::ActOnAccessSpecifier(AccessSpecifier Access,
return ProcessAccessDeclAttributeList(ASDecl, Attrs);
}
-/// CheckOverrideControl - Check C++0x override control semantics.
-void Sema::CheckOverrideControl(const Decl *D) {
+/// CheckOverrideControl - Check C++11 override control semantics.
+void Sema::CheckOverrideControl(Decl *D) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
- if (!MD || !MD->isVirtual())
+
+ // Do we know which functions this declaration might be overriding?
+ bool OverridesAreKnown = !MD ||
+ (!MD->getParent()->hasAnyDependentBases() &&
+ !MD->getType()->isDependentType());
+
+ if (!MD || !MD->isVirtual()) {
+ if (OverridesAreKnown) {
+ if (OverrideAttr *OA = D->getAttr<OverrideAttr>()) {
+ Diag(OA->getLocation(),
+ diag::override_keyword_only_allowed_on_virtual_member_functions)
+ << "override" << FixItHint::CreateRemoval(OA->getLocation());
+ D->dropAttr<OverrideAttr>();
+ }
+ if (FinalAttr *FA = D->getAttr<FinalAttr>()) {
+ Diag(FA->getLocation(),
+ diag::override_keyword_only_allowed_on_virtual_member_functions)
+ << "final" << FixItHint::CreateRemoval(FA->getLocation());
+ D->dropAttr<FinalAttr>();
+ }
+ }
return;
+ }
- if (MD->isDependentContext())
+ if (!OverridesAreKnown)
return;
- // C++0x [class.virtual]p3:
- // If a virtual function is marked with the virt-specifier override and does
- // not override a member function of a base class,
- // the program is ill-formed.
- bool HasOverriddenMethods =
+ // C++11 [class.virtual]p5:
+ // If a virtual function is marked with the virt-specifier override and
+ // does not override a member function of a base class, the program is
+ // ill-formed.
+ bool HasOverriddenMethods =
MD->begin_overridden_methods() != MD->end_overridden_methods();
- if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods) {
- Diag(MD->getLocation(),
- diag::err_function_marked_override_not_overriding)
+ if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods)
+ Diag(MD->getLocation(), diag::err_function_marked_override_not_overriding)
<< MD->getDeclName();
- return;
- }
}
-/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member
+/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member
/// function overrides a virtual member function marked 'final', according to
-/// C++0x [class.virtual]p3.
+/// C++11 [class.virtual]p4.
bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
if (!Old->hasAttr<FinalAttr>())
@@ -1440,16 +1460,26 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New,
return true;
}
+static bool InitializationHasSideEffects(const FieldDecl &FD) {
+ const Type *T = FD.getType()->getBaseElementTypeUnsafe();
+ // FIXME: Destruction of ObjC lifetime types has side-effects.
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return !RD->isCompleteDefinition() ||
+ !RD->hasTrivialDefaultConstructor() ||
+ !RD->hasTrivialDestructor();
+ return false;
+}
+
/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
/// bitfield width if there is one, 'InitExpr' specifies the initializer if
-/// one has been parsed, and 'HasDeferredInit' is true if an initializer is
-/// present but parsing it has been deferred.
+/// one has been parsed, and 'InitStyle' is set if an in-class initializer is
+/// present (but parsing it has been deferred).
Decl *
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
Expr *BW, const VirtSpecifiers &VS,
- bool HasDeferredInit) {
+ InClassInitStyle InitStyle) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -1507,12 +1537,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
CXXScopeSpec &SS = D.getCXXScopeSpec();
// Data members must have identifiers for names.
- if (Name.getNameKind() != DeclarationName::Identifier) {
+ if (!Name.isIdentifier()) {
Diag(Loc, diag::err_bad_variable_name)
<< Name;
return 0;
}
-
+
IdentifierInfo *II = Name.getAsIdentifierInfo();
// Member field could not be with "template" keyword.
@@ -1553,10 +1583,10 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
}
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
- HasDeferredInit, AS);
+ InitStyle, AS);
assert(Member && "HandleField never returns null");
} else {
- assert(!HasDeferredInit);
+ assert(InitStyle == ICIS_NoInit);
Member = HandleDeclarator(S, D, move(TemplateParameterLists));
if (!Member) {
@@ -1596,37 +1626,39 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
FunTmpl->getTemplatedDecl()->setAccess(AS);
}
- if (VS.isOverrideSpecified()) {
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member);
- if (!MD || !MD->isVirtual()) {
- Diag(Member->getLocStart(),
- diag::override_keyword_only_allowed_on_virtual_member_functions)
- << "override" << FixItHint::CreateRemoval(VS.getOverrideLoc());
- } else
- MD->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context));
- }
- if (VS.isFinalSpecified()) {
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member);
- if (!MD || !MD->isVirtual()) {
- Diag(Member->getLocStart(),
- diag::override_keyword_only_allowed_on_virtual_member_functions)
- << "final" << FixItHint::CreateRemoval(VS.getFinalLoc());
- } else
- MD->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context));
- }
+ if (VS.isOverrideSpecified())
+ Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context));
+ if (VS.isFinalSpecified())
+ Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context));
if (VS.getLastLocation().isValid()) {
// Update the end location of a method that has a virt-specifiers.
if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Member))
MD->setRangeEnd(VS.getLastLocation());
}
-
+
CheckOverrideControl(Member);
assert((Name || isInstField) && "No identifier for non-field ?");
- if (isInstField)
- FieldCollector->Add(cast<FieldDecl>(Member));
+ if (isInstField) {
+ FieldDecl *FD = cast<FieldDecl>(Member);
+ FieldCollector->Add(FD);
+
+ if (Diags.getDiagnosticLevel(diag::warn_unused_private_field,
+ FD->getLocation())
+ != DiagnosticsEngine::Ignored) {
+ // Remember all explicit private FieldDecls that have a name, no side
+ // effects and are not part of a dependent type declaration.
+ if (!FD->isImplicit() && FD->getDeclName() &&
+ FD->getAccess() == AS_private &&
+ !FD->hasAttr<UnusedAttr>() &&
+ !FD->getParent()->isDependentContext() &&
+ !InitializationHasSideEffects(*FD))
+ UnusedPrivateFields.insert(FD);
+ }
+ }
+
return Member;
}
@@ -1635,9 +1667,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
/// instantiating an in-class initializer in a class template. Such actions
/// are deferred until the class is complete.
void
-Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
+Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
Expr *InitExpr) {
FieldDecl *FD = cast<FieldDecl>(D);
+ assert(FD->getInClassInitStyle() != ICIS_NoInit &&
+ "must set init style when field is created");
if (!InitExpr) {
FD->setInvalidDecl();
@@ -1660,9 +1694,9 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
Expr **Inits = &InitExpr;
unsigned NumInits = 1;
InitializedEntity Entity = InitializedEntity::InitializeMember(FD);
- InitializationKind Kind = EqualLoc.isInvalid()
+ InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit
? InitializationKind::CreateDirectList(InitExpr->getLocStart())
- : InitializationKind::CreateCopy(InitExpr->getLocStart(), EqualLoc);
+ : InitializationKind::CreateCopy(InitExpr->getLocStart(), InitLoc);
InitializationSequence Seq(*this, Entity, Kind, Inits, NumInits);
Init = Seq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits));
if (Init.isInvalid()) {
@@ -1670,7 +1704,7 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
return;
}
- CheckImplicitConversions(Init.get(), EqualLoc);
+ CheckImplicitConversions(Init.get(), InitLoc);
}
// C++0x [class.base.init]p7:
@@ -2010,73 +2044,95 @@ static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member,
<< (unsigned)IsPointer;
}
-/// Checks an initializer expression for use of uninitialized fields, such as
-/// containing the field that is being initialized. Returns true if there is an
-/// uninitialized field was used an updates the SourceLocation parameter; false
-/// otherwise.
-static bool InitExprContainsUninitializedFields(const Stmt *S,
- const ValueDecl *LhsField,
- SourceLocation *L) {
- assert(isa<FieldDecl>(LhsField) || isa<IndirectFieldDecl>(LhsField));
-
- if (isa<CallExpr>(S)) {
- // Do not descend into function calls or constructors, as the use
- // of an uninitialized field may be valid. One would have to inspect
- // the contents of the function/ctor to determine if it is safe or not.
- // i.e. Pass-by-value is never safe, but pass-by-reference and pointers
- // may be safe, depending on what the function/ctor does.
- return false;
- }
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
- const NamedDecl *RhsField = ME->getMemberDecl();
-
- if (const VarDecl *VD = dyn_cast<VarDecl>(RhsField)) {
- // The member expression points to a static data member.
- assert(VD->isStaticDataMember() &&
- "Member points to non-static data member!");
- (void)VD;
- return false;
+namespace {
+ class UninitializedFieldVisitor
+ : public EvaluatedExprVisitor<UninitializedFieldVisitor> {
+ Sema &S;
+ ValueDecl *VD;
+ public:
+ typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
+ UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context),
+ S(S), VD(VD) {
}
-
- if (isa<EnumConstantDecl>(RhsField)) {
- // The member expression points to an enum.
- return false;
+
+ void HandleExpr(Expr *E) {
+ if (!E) return;
+
+ // Expressions like x(x) sometimes lack the surrounding expressions
+ // but need to be checked anyways.
+ HandleValue(E);
+ Visit(E);
}
- if (RhsField == LhsField) {
- // Initializing a field with itself. Throw a warning.
- // But wait; there are exceptions!
- // Exception #1: The field may not belong to this record.
- // e.g. Foo(const Foo& rhs) : A(rhs.A) {}
- const Expr *base = ME->getBase();
- if (base != NULL && !isa<CXXThisExpr>(base->IgnoreParenCasts())) {
- // Even though the field matches, it does not belong to this record.
- return false;
+ void HandleValue(Expr *E) {
+ E = E->IgnoreParens();
+
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (isa<EnumConstantDecl>(ME->getMemberDecl()))
+ return;
+ Expr *Base = E;
+ while (isa<MemberExpr>(Base)) {
+ ME = dyn_cast<MemberExpr>(Base);
+ if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl()))
+ if (VarD->hasGlobalStorage())
+ return;
+ Base = ME->getBase();
+ }
+
+ if (VD == ME->getMemberDecl() && isa<CXXThisExpr>(Base)) {
+ S.Diag(ME->getExprLoc(), diag::warn_field_is_uninit);
+ return;
+ }
+ }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ HandleValue(CO->getTrueExpr());
+ HandleValue(CO->getFalseExpr());
+ return;
+ }
+
+ if (BinaryConditionalOperator *BCO =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ HandleValue(BCO->getCommon());
+ HandleValue(BCO->getFalseExpr());
+ return;
+ }
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ switch (BO->getOpcode()) {
+ default:
+ return;
+ case(BO_PtrMemD):
+ case(BO_PtrMemI):
+ HandleValue(BO->getLHS());
+ return;
+ case(BO_Comma):
+ HandleValue(BO->getRHS());
+ return;
+ }
}
- // None of the exceptions triggered; return true to indicate an
- // uninitialized field was used.
- *L = ME->getMemberLoc();
- return true;
}
- } else if (isa<UnaryExprOrTypeTraitExpr>(S)) {
- // sizeof/alignof doesn't reference contents, do not warn.
- return false;
- } else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(S)) {
- // address-of doesn't reference contents (the pointer may be dereferenced
- // in the same expression but it would be rare; and weird).
- if (UOE->getOpcode() == UO_AddrOf)
- return false;
- }
- for (Stmt::const_child_range it = S->children(); it; ++it) {
- if (!*it) {
- // An expression such as 'member(arg ?: "")' may trigger this.
- continue;
+
+ void VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ if (E->getCastKind() == CK_LValueToRValue)
+ HandleValue(E->getSubExpr());
+
+ Inherited::VisitImplicitCastExpr(E);
}
- if (InitExprContainsUninitializedFields(*it, LhsField, L))
- return true;
+
+ void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ Expr *Callee = E->getCallee();
+ if (isa<MemberExpr>(Callee))
+ HandleValue(Callee);
+
+ Inherited::VisitCXXMemberCallExpr(E);
+ }
+ };
+ static void CheckInitExprContainsUninitializedFields(Sema &S, Expr *E,
+ ValueDecl *VD) {
+ UninitializedFieldVisitor(S, VD).HandleExpr(E);
}
- return false;
-}
+} // namespace
MemInitResult
Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
@@ -2106,18 +2162,17 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
Args = InitList->getInits();
NumArgs = InitList->getNumInits();
}
- for (unsigned i = 0; i < NumArgs; ++i) {
- SourceLocation L;
- if (InitExprContainsUninitializedFields(Args[i], Member, &L)) {
- // FIXME: Return true in the case when other fields are used before being
+
+ if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, IdLoc)
+ != DiagnosticsEngine::Ignored)
+ for (unsigned i = 0; i < NumArgs; ++i)
+ // FIXME: Warn about the case when other fields are used before being
// uninitialized. For example, let this field be the i'th field. When
// initializing the i'th field, throw a warning if any of the >= i'th
// fields are used, as they are not yet initialized.
// Right now we are only handling the case where the i'th field uses
// itself in its initializer.
- Diag(L, diag::warn_field_is_uninit);
- }
- }
+ CheckInitExprContainsUninitializedFields(*this, Args[i], Member);
SourceRange InitRange = Init->getSourceRange();
@@ -2235,6 +2290,16 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
if (DelegationInit.isInvalid())
return true;
+ // If we are in a dependent context, template instantiation will
+ // perform this type-checking again. Just save the arguments that we
+ // received in a ParenListExpr.
+ // FIXME: This isn't quite ideal, since our ASTs don't capture all
+ // of the information that we have about the base
+ // initializer. However, deconstructing the ASTs is a dicey process,
+ // and this approach is far more likely to get the corner cases right.
+ if (CurContext->isDependentContext())
+ DelegationInit = Owned(Init);
+
return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(),
DelegationInit.takeAs<Expr>(),
InitRange.getEnd());
@@ -2694,7 +2759,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
FieldBaseElementType->isObjCRetainableType() &&
FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
- // Instant objects:
+ // ARC:
// Default-initialize Objective-C pointers to NULL.
CXXMemberInit
= new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
@@ -2741,6 +2806,16 @@ struct BaseAndFieldInfo {
llvm_unreachable("Invalid ImplicitInitializerKind!");
}
+
+ bool addFieldInitializer(CXXCtorInitializer *Init) {
+ AllToInit.push_back(Init);
+
+ // Check whether this initializer makes the field "used".
+ if (Init->getInit() && Init->getInit()->HasSideEffects(S.Context))
+ S.UnusedPrivateFields.remove(Init->getAnyMember());
+
+ return false;
+ }
};
}
@@ -2778,12 +2853,10 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
IndirectFieldDecl *Indirect = 0) {
// Overwhelmingly common case: we have a direct initializer for this field.
- if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field)) {
- Info.AllToInit.push_back(Init);
- return false;
- }
+ if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field))
+ return Info.addFieldInitializer(Init);
- // C++0x [class.base.init]p8: if the entity is a non-static data member that
+ // C++11 [class.base.init]p8: if the entity is a non-static data member that
// has a brace-or-equal-initializer, the entity is initialized as specified
// in [dcl.init].
if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) {
@@ -2798,8 +2871,7 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
SourceLocation(),
SourceLocation(), 0,
SourceLocation());
- Info.AllToInit.push_back(Init);
- return false;
+ return Info.addFieldInitializer(Init);
}
// Don't build an implicit initializer for union members if none was
@@ -2823,10 +2895,10 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
Indirect, Init))
return true;
- if (Init)
- Info.AllToInit.push_back(Init);
+ if (!Init)
+ return false;
- return false;
+ return Info.addFieldInitializer(Init);
}
bool
@@ -3397,19 +3469,33 @@ void Sema::ActOnDefaultCtorInitializers(Decl *CDtorDecl) {
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
unsigned DiagID, AbstractDiagSelID SelID) {
- if (SelID == -1)
- return RequireNonAbstractType(Loc, T, PDiag(DiagID));
- else
- return RequireNonAbstractType(Loc, T, PDiag(DiagID) << SelID);
+ class NonAbstractTypeDiagnoser : public TypeDiagnoser {
+ unsigned DiagID;
+ AbstractDiagSelID SelID;
+
+ public:
+ NonAbstractTypeDiagnoser(unsigned DiagID, AbstractDiagSelID SelID)
+ : TypeDiagnoser(DiagID == 0), DiagID(DiagID), SelID(SelID) { }
+
+ virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) {
+ if (Suppressed) return;
+ if (SelID == -1)
+ S.Diag(Loc, DiagID) << T;
+ else
+ S.Diag(Loc, DiagID) << SelID << T;
+ }
+ } Diagnoser(DiagID, SelID);
+
+ return RequireNonAbstractType(Loc, T, Diagnoser);
}
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
- const PartialDiagnostic &PD) {
+ TypeDiagnoser &Diagnoser) {
if (!getLangOpts().CPlusPlus)
return false;
if (const ArrayType *AT = Context.getAsArrayType(T))
- return RequireNonAbstractType(Loc, AT->getElementType(), PD);
+ return RequireNonAbstractType(Loc, AT->getElementType(), Diagnoser);
if (const PointerType *PT = T->getAs<PointerType>()) {
// Find the innermost pointer type.
@@ -3417,7 +3503,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
PT = T;
if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType()))
- return RequireNonAbstractType(Loc, AT->getElementType(), PD);
+ return RequireNonAbstractType(Loc, AT->getElementType(), Diagnoser);
}
const RecordType *RT = T->getAs<RecordType>();
@@ -3436,7 +3522,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
if (!RD->isAbstract())
return false;
- Diag(Loc, PD) << RD->getDeclName();
+ Diagnoser.diagnose(*this, Loc, T);
DiagnoseAbstractType(RD);
return true;
@@ -3732,7 +3818,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
MEnd = Record->method_end();
M != MEnd; ++M) {
- if (!(*M)->isStatic())
+ if (!M->isStatic())
DiagnoseHiddenVirtualMethods(Record, *M);
}
}
@@ -3762,8 +3848,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
- RequireLiteralType((*M)->getLocation(), Context.getRecordType(Record),
- PDiag(diag::err_constexpr_method_non_literal));
+ RequireLiteralType(M->getLocation(), Context.getRecordType(Record),
+ diag::err_constexpr_method_non_literal);
break;
}
@@ -3781,558 +3867,354 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// instantiated (e.g. meta-functions). This doesn't apply to classes that
// have inherited constructors.
DeclareInheritedConstructors(Record);
-
- if (!Record->isDependentType())
- CheckExplicitlyDefaultedMethods(Record);
}
void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) {
for (CXXRecordDecl::method_iterator MI = Record->method_begin(),
ME = Record->method_end();
- MI != ME; ++MI) {
- if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) {
- switch (getSpecialMember(*MI)) {
- case CXXDefaultConstructor:
- CheckExplicitlyDefaultedDefaultConstructor(
- cast<CXXConstructorDecl>(*MI));
- break;
-
- case CXXDestructor:
- CheckExplicitlyDefaultedDestructor(cast<CXXDestructorDecl>(*MI));
- break;
-
- case CXXCopyConstructor:
- CheckExplicitlyDefaultedCopyConstructor(cast<CXXConstructorDecl>(*MI));
- break;
-
- case CXXCopyAssignment:
- CheckExplicitlyDefaultedCopyAssignment(*MI);
- break;
-
- case CXXMoveConstructor:
- CheckExplicitlyDefaultedMoveConstructor(cast<CXXConstructorDecl>(*MI));
- break;
-
- case CXXMoveAssignment:
- CheckExplicitlyDefaultedMoveAssignment(*MI);
- break;
-
- case CXXInvalid:
- llvm_unreachable("non-special member explicitly defaulted!");
- }
- }
- }
-
+ MI != ME; ++MI)
+ if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted())
+ CheckExplicitlyDefaultedSpecialMember(*MI);
+}
+
+/// Is the special member function which would be selected to perform the
+/// specified operation on the specified class type a constexpr constructor?
+static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
+ Sema::CXXSpecialMember CSM,
+ bool ConstArg) {
+ Sema::SpecialMemberOverloadResult *SMOR =
+ S.LookupSpecialMember(ClassDecl, CSM, ConstArg,
+ false, false, false, false);
+ if (!SMOR || !SMOR->getMethod())
+ // A constructor we wouldn't select can't be "involved in initializing"
+ // anything.
+ return true;
+ return SMOR->getMethod()->isConstexpr();
}
-void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
- assert(CD->isExplicitlyDefaulted() && CD->isDefaultConstructor());
-
- // Whether this was the first-declared instance of the constructor.
- // This affects whether we implicitly add an exception spec (and, eventually,
- // constexpr). It is also ill-formed to explicitly default a constructor such
- // that it would be deleted. (C++0x [decl.fct.def.default])
- bool First = CD == CD->getCanonicalDecl();
+/// Determine whether the specified special member function would be constexpr
+/// if it were implicitly defined.
+static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
+ Sema::CXXSpecialMember CSM,
+ bool ConstArg) {
+ if (!S.getLangOpts().CPlusPlus0x)
+ return false;
- bool HadError = false;
- if (CD->getNumParams() != 0) {
- Diag(CD->getLocation(), diag::err_defaulted_default_ctor_params)
- << CD->getSourceRange();
- HadError = true;
- }
+ // C++11 [dcl.constexpr]p4:
+ // In the definition of a constexpr constructor [...]
+ switch (CSM) {
+ case Sema::CXXDefaultConstructor:
+ // Since default constructor lookup is essentially trivial (and cannot
+ // involve, for instance, template instantiation), we compute whether a
+ // defaulted default constructor is constexpr directly within CXXRecordDecl.
+ //
+ // This is important for performance; we need to know whether the default
+ // constructor is constexpr to determine whether the type is a literal type.
+ return ClassDecl->defaultedDefaultConstructorIsConstexpr();
- ImplicitExceptionSpecification Spec
- = ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent());
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- if (EPI.ExceptionSpecType == EST_Delayed) {
- // Exception specification depends on some deferred part of the class. We'll
- // try again when the class's definition has been fully processed.
- return;
- }
- const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+ case Sema::CXXCopyConstructor:
+ case Sema::CXXMoveConstructor:
+ // For copy or move constructors, we need to perform overload resolution.
+ break;
- // C++11 [dcl.fct.def.default]p2:
- // An explicitly-defaulted function may be declared constexpr only if it
- // would have been implicitly declared as constexpr,
- // Do not apply this rule to templates, since core issue 1358 makes such
- // functions always instantiate to constexpr functions.
- if (CD->isConstexpr() &&
- CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
- if (!CD->getParent()->defaultedDefaultConstructorIsConstexpr()) {
- Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
- << CXXDefaultConstructor;
- HadError = true;
- }
- }
- // and may have an explicit exception-specification only if it is compatible
- // with the exception-specification on the implicit declaration.
- if (CtorType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXDefaultConstructor,
- PDiag(),
- ExceptionType, SourceLocation(),
- CtorType, CD->getLocation())) {
- HadError = true;
- }
+ case Sema::CXXCopyAssignment:
+ case Sema::CXXMoveAssignment:
+ case Sema::CXXDestructor:
+ case Sema::CXXInvalid:
+ return false;
}
- // If a function is explicitly defaulted on its first declaration,
- if (First) {
- // -- it is implicitly considered to be constexpr if the implicit
- // definition would be,
- CD->setConstexpr(CD->getParent()->defaultedDefaultConstructorIsConstexpr());
+ // -- if the class is a non-empty union, or for each non-empty anonymous
+ // union member of a non-union class, exactly one non-static data member
+ // shall be initialized; [DR1359]
+ //
+ // If we squint, this is guaranteed, since exactly one non-static data member
+ // will be initialized (if the constructor isn't deleted), we just don't know
+ // which one.
+ if (ClassDecl->isUnion())
+ return true;
- // -- it is implicitly considered to have the same
- // exception-specification as if it had been implicitly declared
- //
- // FIXME: a compatible, but different, explicit exception specification
- // will be silently overridden. We should issue a warning if this happens.
- EPI.ExtInfo = CtorType->getExtInfo();
+ // -- the class shall not have any virtual base classes;
+ if (ClassDecl->getNumVBases())
+ return false;
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- CD->setTrivial(CD->getParent()->hasTrivialDefaultConstructor());
- }
+ // -- every constructor involved in initializing [...] base class
+ // sub-objects shall be a constexpr constructor;
+ for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
+ BEnd = ClassDecl->bases_end();
+ B != BEnd; ++B) {
+ const RecordType *BaseType = B->getType()->getAs<RecordType>();
+ if (!BaseType) continue;
- if (HadError) {
- CD->setInvalidDecl();
- return;
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+ if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, ConstArg))
+ return false;
}
- if (ShouldDeleteSpecialMember(CD, CXXDefaultConstructor)) {
- if (First) {
- CD->setDeletedAsWritten();
- } else {
- Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXDefaultConstructor;
- CD->setInvalidDecl();
+ // -- every constructor involved in initializing non-static data members
+ // [...] shall be a constexpr constructor;
+ // -- every non-static data member and base class sub-object shall be
+ // initialized
+ for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
+ FEnd = ClassDecl->field_end();
+ F != FEnd; ++F) {
+ if (F->isInvalidDecl())
+ continue;
+ if (const RecordType *RecordTy =
+ S.Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
+ CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!specialMemberIsConstexpr(S, FieldRecDecl, CSM, ConstArg))
+ return false;
}
}
-}
-
-void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) {
- assert(CD->isExplicitlyDefaulted() && CD->isCopyConstructor());
-
- // Whether this was the first-declared instance of the constructor.
- bool First = CD == CD->getCanonicalDecl();
-
- bool HadError = false;
- if (CD->getNumParams() != 1) {
- Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_params)
- << CD->getSourceRange();
- HadError = true;
- }
-
- ImplicitExceptionSpecification Spec(*this);
- bool Const;
- llvm::tie(Spec, Const) =
- ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent());
-
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
- // Check for parameter type matching.
- // This is a copy ctor so we know it's a cv-qualified reference to T.
- QualType ArgType = CtorType->getArgType(0);
- if (ArgType->getPointeeType().isVolatileQualified()) {
- Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_volatile_param);
- HadError = true;
- }
- if (ArgType->getPointeeType().isConstQualified() && !Const) {
- Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_const_param);
- HadError = true;
- }
+ // All OK, it's constexpr!
+ return true;
+}
- // C++11 [dcl.fct.def.default]p2:
- // An explicitly-defaulted function may be declared constexpr only if it
- // would have been implicitly declared as constexpr,
- // Do not apply this rule to templates, since core issue 1358 makes such
- // functions always instantiate to constexpr functions.
- if (CD->isConstexpr() &&
- CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
- if (!CD->getParent()->defaultedCopyConstructorIsConstexpr()) {
- Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
- << CXXCopyConstructor;
- HadError = true;
- }
- }
- // and may have an explicit exception-specification only if it is compatible
- // with the exception-specification on the implicit declaration.
- if (CtorType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXCopyConstructor,
- PDiag(),
- ExceptionType, SourceLocation(),
- CtorType, CD->getLocation())) {
- HadError = true;
- }
+static Sema::ImplicitExceptionSpecification
+computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
+ switch (S.getSpecialMember(MD)) {
+ case Sema::CXXDefaultConstructor:
+ return S.ComputeDefaultedDefaultCtorExceptionSpec(Loc, MD);
+ case Sema::CXXCopyConstructor:
+ return S.ComputeDefaultedCopyCtorExceptionSpec(MD);
+ case Sema::CXXCopyAssignment:
+ return S.ComputeDefaultedCopyAssignmentExceptionSpec(MD);
+ case Sema::CXXMoveConstructor:
+ return S.ComputeDefaultedMoveCtorExceptionSpec(MD);
+ case Sema::CXXMoveAssignment:
+ return S.ComputeDefaultedMoveAssignmentExceptionSpec(MD);
+ case Sema::CXXDestructor:
+ return S.ComputeDefaultedDtorExceptionSpec(MD);
+ case Sema::CXXInvalid:
+ break;
}
+ llvm_unreachable("only special members have implicit exception specs");
+}
- // If a function is explicitly defaulted on its first declaration,
- if (First) {
- // -- it is implicitly considered to be constexpr if the implicit
- // definition would be,
- CD->setConstexpr(CD->getParent()->defaultedCopyConstructorIsConstexpr());
+static void
+updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
+ const Sema::ImplicitExceptionSpecification &ExceptSpec) {
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ ExceptSpec.getEPI(EPI);
+ const FunctionProtoType *NewFPT = cast<FunctionProtoType>(
+ S.Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
+ FPT->getNumArgs(), EPI));
+ FD->setType(QualType(NewFPT, 0));
+}
+
+void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) {
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+ if (FPT->getExceptionSpecType() != EST_Unevaluated)
+ return;
- // -- it is implicitly considered to have the same
- // exception-specification as if it had been implicitly declared, and
- //
- // FIXME: a compatible, but different, explicit exception specification
- // will be silently overridden. We should issue a warning if this happens.
- EPI.ExtInfo = CtorType->getExtInfo();
+ // Evaluate the exception specification.
+ ImplicitExceptionSpecification ExceptSpec =
+ computeImplicitExceptionSpec(*this, Loc, MD);
- // -- [...] it shall have the same parameter type as if it had been
- // implicitly declared.
- CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ // Update the type of the special member to use it.
+ updateExceptionSpec(*this, MD, FPT, ExceptSpec);
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- CD->setTrivial(CD->getParent()->hasTrivialCopyConstructor());
- }
+ // A user-provided destructor can be defined outside the class. When that
+ // happens, be sure to update the exception specification on both
+ // declarations.
+ const FunctionProtoType *CanonicalFPT =
+ MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>();
+ if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated)
+ updateExceptionSpec(*this, MD->getCanonicalDecl(),
+ CanonicalFPT, ExceptSpec);
+}
- if (HadError) {
- CD->setInvalidDecl();
- return;
- }
+static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl);
+static bool isImplicitCopyAssignmentArgConst(Sema &S, CXXRecordDecl *ClassDecl);
- if (ShouldDeleteSpecialMember(CD, CXXCopyConstructor)) {
- if (First) {
- CD->setDeletedAsWritten();
- } else {
- Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXCopyConstructor;
- CD->setInvalidDecl();
- }
- }
-}
+void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
+ CXXRecordDecl *RD = MD->getParent();
+ CXXSpecialMember CSM = getSpecialMember(MD);
-void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
- assert(MD->isExplicitlyDefaulted());
+ assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid &&
+ "not an explicitly-defaulted special member");
- // Whether this was the first-declared instance of the operator
+ // Whether this was the first-declared instance of the constructor.
+ // This affects whether we implicitly add an exception spec and constexpr.
bool First = MD == MD->getCanonicalDecl();
bool HadError = false;
- if (MD->getNumParams() != 1) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_params)
- << MD->getSourceRange();
- HadError = true;
- }
- QualType ReturnType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- if (!ReturnType->isLValueReferenceType() ||
- !Context.hasSameType(
- Context.getCanonicalType(ReturnType->getPointeeType()),
- Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_return_type);
+ // C++11 [dcl.fct.def.default]p1:
+ // A function that is explicitly defaulted shall
+ // -- be a special member function (checked elsewhere),
+ // -- have the same type (except for ref-qualifiers, and except that a
+ // copy operation can take a non-const reference) as an implicit
+ // declaration, and
+ // -- not have default arguments.
+ unsigned ExpectedParams = 1;
+ if (CSM == CXXDefaultConstructor || CSM == CXXDestructor)
+ ExpectedParams = 0;
+ if (MD->getNumParams() != ExpectedParams) {
+ // This also checks for default arguments: a copy or move constructor with a
+ // default argument is classified as a default constructor, and assignment
+ // operations and destructors can't have default arguments.
+ Diag(MD->getLocation(), diag::err_defaulted_special_member_params)
+ << CSM << MD->getSourceRange();
HadError = true;
}
- ImplicitExceptionSpecification Spec(*this);
- bool Const;
- llvm::tie(Spec, Const) =
- ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent());
-
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+ const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>();
- QualType ArgType = OperType->getArgType(0);
- if (!ArgType->isLValueReferenceType()) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref);
- HadError = true;
- } else {
- if (ArgType->getPointeeType().isVolatileQualified()) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_volatile_param);
+ // Compute argument constness, constexpr, and triviality.
+ bool CanHaveConstParam = false;
+ bool Trivial;
+ switch (CSM) {
+ case CXXDefaultConstructor:
+ Trivial = RD->hasTrivialDefaultConstructor();
+ break;
+ case CXXCopyConstructor:
+ CanHaveConstParam = isImplicitCopyCtorArgConst(*this, RD);
+ Trivial = RD->hasTrivialCopyConstructor();
+ break;
+ case CXXCopyAssignment:
+ CanHaveConstParam = isImplicitCopyAssignmentArgConst(*this, RD);
+ Trivial = RD->hasTrivialCopyAssignment();
+ break;
+ case CXXMoveConstructor:
+ Trivial = RD->hasTrivialMoveConstructor();
+ break;
+ case CXXMoveAssignment:
+ Trivial = RD->hasTrivialMoveAssignment();
+ break;
+ case CXXDestructor:
+ Trivial = RD->hasTrivialDestructor();
+ break;
+ case CXXInvalid:
+ llvm_unreachable("non-special member explicitly defaulted!");
+ }
+
+ QualType ReturnType = Context.VoidTy;
+ if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) {
+ // Check for return type matching.
+ ReturnType = Type->getResultType();
+ QualType ExpectedReturnType =
+ Context.getLValueReferenceType(Context.getTypeDeclType(RD));
+ if (!Context.hasSameType(ReturnType, ExpectedReturnType)) {
+ Diag(MD->getLocation(), diag::err_defaulted_special_member_return_type)
+ << (CSM == CXXMoveAssignment) << ExpectedReturnType;
HadError = true;
}
- if (ArgType->getPointeeType().isConstQualified() && !Const) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_const_param);
+
+ // A defaulted special member cannot have cv-qualifiers.
+ if (Type->getTypeQuals()) {
+ Diag(MD->getLocation(), diag::err_defaulted_special_member_quals)
+ << (CSM == CXXMoveAssignment);
HadError = true;
}
}
- if (OperType->getTypeQuals()) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_quals);
- HadError = true;
- }
-
- if (OperType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXCopyAssignment,
- PDiag(),
- ExceptionType, SourceLocation(),
- OperType, MD->getLocation())) {
+ // Check for parameter type matching.
+ QualType ArgType = ExpectedParams ? Type->getArgType(0) : QualType();
+ bool HasConstParam = false;
+ if (ExpectedParams && ArgType->isReferenceType()) {
+ // Argument must be reference to possibly-const T.
+ QualType ReferentType = ArgType->getPointeeType();
+ HasConstParam = ReferentType.isConstQualified();
+
+ if (ReferentType.isVolatileQualified()) {
+ Diag(MD->getLocation(),
+ diag::err_defaulted_special_member_volatile_param) << CSM;
HadError = true;
}
- }
- if (First) {
- // We set the declaration to have the computed exception spec here.
- // We duplicate the one parameter type.
- EPI.RefQualifier = OperType->getRefQualifier();
- EPI.ExtInfo = OperType->getExtInfo();
- MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI));
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment());
- }
-
- if (HadError) {
- MD->setInvalidDecl();
- return;
- }
-
- if (ShouldDeleteSpecialMember(MD, CXXCopyAssignment)) {
- if (First) {
- MD->setDeletedAsWritten();
- } else {
- Diag(MD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXCopyAssignment;
- MD->setInvalidDecl();
+ if (HasConstParam && !CanHaveConstParam) {
+ if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment) {
+ Diag(MD->getLocation(),
+ diag::err_defaulted_special_member_copy_const_param)
+ << (CSM == CXXCopyAssignment);
+ // FIXME: Explain why this special member can't be const.
+ } else {
+ Diag(MD->getLocation(),
+ diag::err_defaulted_special_member_move_const_param)
+ << (CSM == CXXMoveAssignment);
+ }
+ HadError = true;
}
- }
-}
-
-void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) {
- assert(CD->isExplicitlyDefaulted() && CD->isMoveConstructor());
- // Whether this was the first-declared instance of the constructor.
- bool First = CD == CD->getCanonicalDecl();
-
- bool HadError = false;
- if (CD->getNumParams() != 1) {
- Diag(CD->getLocation(), diag::err_defaulted_move_ctor_params)
- << CD->getSourceRange();
+ // If a function is explicitly defaulted on its first declaration, it shall
+ // have the same parameter type as if it had been implicitly declared.
+ // (Presumably this is to prevent it from being trivial?)
+ if (!HasConstParam && CanHaveConstParam && First)
+ Diag(MD->getLocation(),
+ diag::err_defaulted_special_member_copy_non_const_param)
+ << (CSM == CXXCopyAssignment);
+ } else if (ExpectedParams) {
+ // A copy assignment operator can take its argument by value, but a
+ // defaulted one cannot.
+ assert(CSM == CXXCopyAssignment && "unexpected non-ref argument");
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref);
HadError = true;
}
- ImplicitExceptionSpecification Spec(
- ComputeDefaultedMoveCtorExceptionSpec(CD->getParent()));
-
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
-
- // Check for parameter type matching.
- // This is a move ctor so we know it's a cv-qualified rvalue reference to T.
- QualType ArgType = CtorType->getArgType(0);
- if (ArgType->getPointeeType().isVolatileQualified()) {
- Diag(CD->getLocation(), diag::err_defaulted_move_ctor_volatile_param);
- HadError = true;
- }
- if (ArgType->getPointeeType().isConstQualified()) {
- Diag(CD->getLocation(), diag::err_defaulted_move_ctor_const_param);
- HadError = true;
+ // Rebuild the type with the implicit exception specification added, if we
+ // are going to need it.
+ const FunctionProtoType *ImplicitType = 0;
+ if (First || Type->hasExceptionSpec()) {
+ FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
+ computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
+ ImplicitType = cast<FunctionProtoType>(
+ Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI));
}
// C++11 [dcl.fct.def.default]p2:
// An explicitly-defaulted function may be declared constexpr only if it
// would have been implicitly declared as constexpr,
- // Do not apply this rule to templates, since core issue 1358 makes such
- // functions always instantiate to constexpr functions.
- if (CD->isConstexpr() &&
- CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
- if (!CD->getParent()->defaultedMoveConstructorIsConstexpr()) {
- Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
- << CXXMoveConstructor;
- HadError = true;
- }
+ // Do not apply this rule to members of class templates, since core issue 1358
+ // makes such functions always instantiate to constexpr functions. For
+ // non-constructors, this is checked elsewhere.
+ bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
+ HasConstParam);
+ if (isa<CXXConstructorDecl>(MD) && MD->isConstexpr() && !Constexpr &&
+ MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
+ Diag(MD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CSM;
+ // FIXME: Explain why the constructor can't be constexpr.
+ HadError = true;
}
// and may have an explicit exception-specification only if it is compatible
// with the exception-specification on the implicit declaration.
- if (CtorType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXMoveConstructor,
- PDiag(),
- ExceptionType, SourceLocation(),
- CtorType, CD->getLocation())) {
- HadError = true;
- }
- }
+ if (Type->hasExceptionSpec() &&
+ CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec) << CSM,
+ PDiag(), ImplicitType, SourceLocation(), Type, MD->getLocation()))
+ HadError = true;
// If a function is explicitly defaulted on its first declaration,
if (First) {
// -- it is implicitly considered to be constexpr if the implicit
// definition would be,
- CD->setConstexpr(CD->getParent()->defaultedMoveConstructorIsConstexpr());
-
- // -- it is implicitly considered to have the same
- // exception-specification as if it had been implicitly declared, and
- //
- // FIXME: a compatible, but different, explicit exception specification
- // will be silently overridden. We should issue a warning if this happens.
- EPI.ExtInfo = CtorType->getExtInfo();
+ MD->setConstexpr(Constexpr);
- // -- [...] it shall have the same parameter type as if it had been
- // implicitly declared.
- CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ // -- it is implicitly considered to have the same exception-specification
+ // as if it had been implicitly declared,
+ MD->setType(QualType(ImplicitType, 0));
// Such a function is also trivial if the implicitly-declared function
// would have been.
- CD->setTrivial(CD->getParent()->hasTrivialMoveConstructor());
+ MD->setTrivial(Trivial);
}
- if (HadError) {
- CD->setInvalidDecl();
- return;
- }
-
- if (ShouldDeleteSpecialMember(CD, CXXMoveConstructor)) {
+ if (ShouldDeleteSpecialMember(MD, CSM)) {
if (First) {
- CD->setDeletedAsWritten();
+ MD->setDeletedAsWritten();
} else {
- Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXMoveConstructor;
- CD->setInvalidDecl();
- }
- }
-}
-
-void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) {
- assert(MD->isExplicitlyDefaulted());
-
- // Whether this was the first-declared instance of the operator
- bool First = MD == MD->getCanonicalDecl();
-
- bool HadError = false;
- if (MD->getNumParams() != 1) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_params)
- << MD->getSourceRange();
- HadError = true;
- }
-
- QualType ReturnType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- if (!ReturnType->isLValueReferenceType() ||
- !Context.hasSameType(
- Context.getCanonicalType(ReturnType->getPointeeType()),
- Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_return_type);
- HadError = true;
- }
-
- ImplicitExceptionSpecification Spec(
- ComputeDefaultedMoveCtorExceptionSpec(MD->getParent()));
-
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
-
- QualType ArgType = OperType->getArgType(0);
- if (!ArgType->isRValueReferenceType()) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_not_ref);
- HadError = true;
- } else {
- if (ArgType->getPointeeType().isVolatileQualified()) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_volatile_param);
- HadError = true;
- }
- if (ArgType->getPointeeType().isConstQualified()) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_const_param);
+ // C++11 [dcl.fct.def.default]p4:
+ // [For a] user-provided explicitly-defaulted function [...] if such a
+ // function is implicitly defined as deleted, the program is ill-formed.
+ Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) << CSM;
HadError = true;
}
}
- if (OperType->getTypeQuals()) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_quals);
- HadError = true;
- }
-
- if (OperType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXMoveAssignment,
- PDiag(),
- ExceptionType, SourceLocation(),
- OperType, MD->getLocation())) {
- HadError = true;
- }
- }
- if (First) {
- // We set the declaration to have the computed exception spec here.
- // We duplicate the one parameter type.
- EPI.RefQualifier = OperType->getRefQualifier();
- EPI.ExtInfo = OperType->getExtInfo();
- MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI));
-
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment());
- }
-
- if (HadError) {
+ if (HadError)
MD->setInvalidDecl();
- return;
- }
-
- if (ShouldDeleteSpecialMember(MD, CXXMoveAssignment)) {
- if (First) {
- MD->setDeletedAsWritten();
- } else {
- Diag(MD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXMoveAssignment;
- MD->setInvalidDecl();
- }
- }
-}
-
-void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
- assert(DD->isExplicitlyDefaulted());
-
- // Whether this was the first-declared instance of the destructor.
- bool First = DD == DD->getCanonicalDecl();
-
- ImplicitExceptionSpecification Spec
- = ComputeDefaultedDtorExceptionSpec(DD->getParent());
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- const FunctionProtoType *DtorType = DD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
-
- if (DtorType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXDestructor,
- PDiag(),
- ExceptionType, SourceLocation(),
- DtorType, DD->getLocation())) {
- DD->setInvalidDecl();
- return;
- }
- }
- if (First) {
- // We set the declaration to have the computed exception spec here.
- // There are no parameters.
- EPI.ExtInfo = DtorType->getExtInfo();
- DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
-
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- DD->setTrivial(DD->getParent()->hasTrivialDestructor());
- }
-
- if (ShouldDeleteSpecialMember(DD, CXXDestructor)) {
- if (First) {
- DD->setDeletedAsWritten();
- } else {
- Diag(DD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXDestructor;
- DD->setInvalidDecl();
- }
- }
}
namespace {
@@ -4385,9 +4267,15 @@ struct SpecialMemberDeletionInfo {
bool inUnion() const { return MD->getParent()->isUnion(); }
/// Look up the corresponding special member in the given class.
- Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class) {
+ Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class,
+ unsigned Quals) {
unsigned TQ = MD->getTypeQualifiers();
- return S.LookupSpecialMember(Class, CSM, ConstArg, VolatileArg,
+ // cv-qualifiers on class members don't affect default ctor / dtor calls.
+ if (CSM == Sema::CXXDefaultConstructor || CSM == Sema::CXXDestructor)
+ Quals = 0;
+ return S.LookupSpecialMember(Class, CSM,
+ ConstArg || (Quals & Qualifiers::Const),
+ VolatileArg || (Quals & Qualifiers::Volatile),
MD->getRefQualifier() == RQ_RValue,
TQ & Qualifiers::Const,
TQ & Qualifiers::Volatile);
@@ -4399,7 +4287,8 @@ struct SpecialMemberDeletionInfo {
bool shouldDeleteForField(FieldDecl *FD);
bool shouldDeleteForAllConstMembers();
- bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj);
+ bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj,
+ unsigned Quals);
bool shouldDeleteForSubobjectCall(Subobject Subobj,
Sema::SpecialMemberOverloadResult *SMOR,
bool IsDtorCallInCtor);
@@ -4480,9 +4369,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
}
/// Check whether we should delete a special member function due to having a
-/// direct or virtual base class or static data member of class type M.
+/// direct or virtual base class or non-static data member of class type M.
bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
- CXXRecordDecl *Class, Subobject Subobj) {
+ CXXRecordDecl *Class, Subobject Subobj, unsigned Quals) {
FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
// C++11 [class.ctor]p5:
@@ -4501,7 +4390,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
// that is deleted or inaccessible
if (!(CSM == Sema::CXXDefaultConstructor &&
Field && Field->hasInClassInitializer()) &&
- shouldDeleteForSubobjectCall(Subobj, lookupIn(Class), false))
+ shouldDeleteForSubobjectCall(Subobj, lookupIn(Class, Quals), false))
return true;
// C++11 [class.ctor]p5, C++11 [class.copy]p11:
@@ -4522,7 +4411,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
/// having a particular direct or virtual base class.
bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
CXXRecordDecl *BaseClass = Base->getType()->getAsCXXRecordDecl();
- return shouldDeleteForClassSubobject(BaseClass, Base);
+ return shouldDeleteForClassSubobject(BaseClass, Base, 0);
}
/// Check whether we should delete a special member function due to the class
@@ -4549,7 +4438,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
(!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) {
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
- << MD->getParent() << FD << FieldType << /*Const*/1;
+ << MD->getParent() << FD << FD->getType() << /*Const*/1;
return true;
}
@@ -4577,7 +4466,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
// -- a non-static data member of const non-class type (or array thereof)
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_assign_field)
- << IsMove << MD->getParent() << FD << FieldType << /*Const*/1;
+ << IsMove << MD->getParent() << FD << FD->getType() << /*Const*/1;
return true;
}
}
@@ -4599,7 +4488,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl();
if (UnionFieldRecord &&
- shouldDeleteForClassSubobject(UnionFieldRecord, *UI))
+ shouldDeleteForClassSubobject(UnionFieldRecord, *UI,
+ UnionFieldType.getCVRQualifiers()))
return true;
}
@@ -4618,7 +4508,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
return false;
}
- if (shouldDeleteForClassSubobject(FieldRecord, FD))
+ if (shouldDeleteForClassSubobject(FieldRecord, FD,
+ FieldType.getCVRQualifiers()))
return true;
}
@@ -4647,7 +4538,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
/// C++11 [class.copy]p23, and C++11 [class.dtor]p5.
bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
bool Diagnose) {
- assert(!MD->isInvalidDecl());
+ if (MD->isInvalidDecl())
+ return false;
CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
@@ -4803,7 +4695,7 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual,
MD->getLocation()) == DiagnosticsEngine::Ignored)
return;
- if (MD->getDeclName().getNameKind() != DeclarationName::Identifier)
+ if (!MD->getDeclName().isIdentifier())
return;
CXXBasePaths Paths(/*FindAmbiguities=*/true, // true to look in all bases.
@@ -4850,6 +4742,14 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
AdjustDeclIfTemplate(TagDecl);
+ for (const AttributeList* l = AttrList; l; l = l->getNext()) {
+ if (l->getKind() != AttributeList::AT_Visibility)
+ continue;
+ l->setInvalid();
+ Diag(l->getLoc(), diag::warn_attribute_after_definition_ignored) <<
+ l->getName();
+ }
+
ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef(
// strict aliasing violation!
reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
@@ -5572,6 +5472,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
}
}
+ ActOnDocumentableDecl(Namespc);
+
// Although we could have an invalid decl (i.e. the namespace name is a
// redefinition), push it as current DeclContext and try to continue parsing.
// FIXME: We should be able to push Namespc here, so that the each DeclContext
@@ -6734,6 +6636,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (!Redeclaration)
PushOnScopeChains(NewND, S);
+ ActOnDocumentableDecl(NewND);
return NewND;
}
@@ -6816,7 +6719,10 @@ namespace {
}
Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
+Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
+ CXXMethodDecl *MD) {
+ CXXRecordDecl *ClassDecl = MD->getParent();
+
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
@@ -6863,7 +6769,21 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
if (Expr *E = F->getInClassInitializer())
ExceptSpec.CalledExpr(E);
else if (!F->isInvalidDecl())
- ExceptSpec.SetDelayed();
+ // DR1351:
+ // If the brace-or-equal-initializer of a non-static data member
+ // invokes a defaulted default constructor of its class or of an
+ // enclosing class in a potentially evaluated subexpression, the
+ // program is ill-formed.
+ //
+ // This resolution is unworkable: the exception specification of the
+ // default constructor can be needed in an unevaluated context, in
+ // particular, in the operand of a noexcept-expression, and we can be
+ // unable to compute an exception specification for an enclosed class.
+ //
+ // We do not allow an in-class initializer to require the evaluation
+ // of the exception specification for any in-class initializer whose
+ // definition is not lexically complete.
+ Diag(Loc, diag::err_in_class_initializer_references_def_ctor) << MD;
} else if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
@@ -6892,9 +6812,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
assert(!ClassDecl->hasUserDeclaredConstructor() &&
"Should not build implicit default constructor!");
- ImplicitExceptionSpecification Spec =
- ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
+ CXXDefaultConstructor,
+ false);
// Create the actual constructor declaration.
CanQualType ClassType
@@ -6904,16 +6824,20 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
= Context.DeclarationNames.getCXXConstructorName(ClassType);
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
- Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0,
+ Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(), /*TInfo=*/0,
/*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
- /*isConstexpr=*/ClassDecl->defaultedDefaultConstructorIsConstexpr() &&
- getLangOpts().CPlusPlus0x);
+ Constexpr);
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
DefaultCon->setImplicit();
DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
-
+
+ // Build an exception specification pointing back at this constructor.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = DefaultCon;
+ DefaultCon->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+
// Note that we have declared this constructor.
++ASTContext::NumImplicitDefaultConstructorsDeclared;
@@ -6948,7 +6872,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
}
SourceLocation Loc = Constructor->getLocation();
- Constructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc));
+ Constructor->setBody(new (Context) CompoundStmt(Loc));
Constructor->setUsed();
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -6958,58 +6882,14 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
}
}
-/// Get any existing defaulted default constructor for the given class. Do not
-/// implicitly define one if it does not exist.
-static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self,
- CXXRecordDecl *D) {
- ASTContext &Context = Self.Context;
- QualType ClassType = Context.getTypeDeclType(D);
- DeclarationName ConstructorName
- = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(ClassType.getUnqualifiedType()));
-
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- // A function template cannot be defaulted.
- if (isa<FunctionTemplateDecl>(*Con))
- continue;
-
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
- if (Constructor->isDefaultConstructor())
- return Constructor->isDefaulted() ? Constructor : 0;
- }
- return 0;
-}
-
void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
if (!D) return;
AdjustDeclIfTemplate(D);
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
- CXXConstructorDecl *CtorDecl
- = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl);
-
- if (!CtorDecl) return;
-
- // Compute the exception specification for the default constructor.
- const FunctionProtoType *CtorTy =
- CtorDecl->getType()->castAs<FunctionProtoType>();
- if (CtorTy->getExceptionSpecType() == EST_Delayed) {
- // FIXME: Don't do this unless the exception spec is needed.
- ImplicitExceptionSpecification Spec =
- ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- assert(EPI.ExceptionSpecType != EST_Delayed);
- CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
- }
-
- // If the default constructor is explicitly defaulted, checking the exception
- // specification is deferred until now.
- if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() &&
- !ClassDecl->isDependentType())
- CheckExplicitlyDefaultedDefaultConstructor(CtorDecl);
+ if (!ClassDecl->isDependentType())
+ CheckExplicitlyDefaultedMethods(ClassDecl);
}
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
@@ -7193,7 +7073,9 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
}
Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
+Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {
+ CXXRecordDecl *ClassDecl = MD->getParent();
+
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have
// an exception-specification.
@@ -7240,14 +7122,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
// If a class has no user-declared destructor, a destructor is
// declared implicitly. An implicitly-declared destructor is an
// inline public member of its class.
-
- ImplicitExceptionSpecification Spec =
- ComputeDefaultedDtorExceptionSpec(ClassDecl);
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
// Create the actual destructor declaration.
- QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
-
CanQualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
SourceLocation ClassLoc = ClassDecl->getLocation();
@@ -7255,24 +7131,27 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
= Context.DeclarationNames.getCXXDestructorName(ClassType);
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXDestructorDecl *Destructor
- = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0,
- /*isInline=*/true,
+ = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
+ QualType(), 0, /*isInline=*/true,
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
-
+
+ // Build an exception specification pointing back at this destructor.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = Destructor;
+ Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+
// Note that we have declared this destructor.
++ASTContext::NumImplicitDestructorsDeclared;
-
+
// Introduce this destructor into its scope.
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(Destructor, S, false);
ClassDecl->addDecl(Destructor);
-
- // This could be uniqued if it ever proves significant.
- Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
AddOverriddenMethods(ClassDecl, Destructor);
@@ -7309,7 +7188,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
SourceLocation Loc = Destructor->getLocation();
- Destructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc));
+ Destructor->setBody(new (Context) CompoundStmt(Loc));
Destructor->setImplicitlyDefined(true);
Destructor->setUsed();
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -7322,15 +7201,6 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
/// \brief Perform any semantic analysis which needs to be delayed until all
/// pending class member declarations have been parsed.
void Sema::ActOnFinishCXXMemberDecls() {
- // Now we have parsed all exception specifications, determine the implicit
- // exception specifications for destructors.
- for (unsigned i = 0, e = DelayedDestructorExceptionSpecs.size();
- i != e; ++i) {
- CXXDestructorDecl *Dtor = DelayedDestructorExceptionSpecs[i];
- AdjustDestructorExceptionSpec(Dtor->getParent(), Dtor, true);
- }
- DelayedDestructorExceptionSpecs.clear();
-
// Perform any deferred checking of exception specifications for virtual
// destructors.
for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size();
@@ -7345,44 +7215,33 @@ void Sema::ActOnFinishCXXMemberDecls() {
DelayedDestructorExceptionSpecChecks.clear();
}
-void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,
- CXXDestructorDecl *destructor,
- bool WasDelayed) {
+void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
+ CXXDestructorDecl *Destructor) {
+ assert(getLangOpts().CPlusPlus0x &&
+ "adjusting dtor exception specs was introduced in c++11");
+
// C++11 [class.dtor]p3:
// A declaration of a destructor that does not have an exception-
// specification is implicitly considered to have the same exception-
// specification as an implicit declaration.
- const FunctionProtoType *dtorType = destructor->getType()->
+ const FunctionProtoType *DtorType = Destructor->getType()->
getAs<FunctionProtoType>();
- if (!WasDelayed && dtorType->hasExceptionSpec())
+ if (DtorType->hasExceptionSpec())
return;
- ImplicitExceptionSpecification exceptSpec =
- ComputeDefaultedDtorExceptionSpec(classDecl);
-
// Replace the destructor's type, building off the existing one. Fortunately,
// the only thing of interest in the destructor type is its extended info.
// The return and arguments are fixed.
- FunctionProtoType::ExtProtoInfo epi = dtorType->getExtProtoInfo();
- epi.ExceptionSpecType = exceptSpec.getExceptionSpecType();
- epi.NumExceptions = exceptSpec.size();
- epi.Exceptions = exceptSpec.data();
- QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi);
-
- destructor->setType(ty);
-
- // If we can't compute the exception specification for this destructor yet
- // (because it depends on an exception specification which we have not parsed
- // yet), make a note that we need to try again when the class is complete.
- if (epi.ExceptionSpecType == EST_Delayed) {
- assert(!WasDelayed && "couldn't compute destructor exception spec");
- DelayedDestructorExceptionSpecs.push_back(destructor);
- }
+ FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = Destructor;
+ Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
// FIXME: If the destructor has a body that could throw, and the newly created
// spec doesn't allow exceptions, we should emit a warning, because this
// change in behavior can break conforming C++03 programs at runtime.
- // However, we don't have a body yet, so it needs to be done somewhere else.
+ // However, we don't have a body or an exception specification yet, so it
+ // needs to be done somewhere else.
}
/// \brief Builds a statement that copies/moves the given entity from \p From to
@@ -7584,11 +7443,13 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
Loc, Copy.take());
}
-std::pair<Sema::ImplicitExceptionSpecification, bool>
-Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
- CXXRecordDecl *ClassDecl) {
+/// Determine whether an implicit copy assignment operator for ClassDecl has a
+/// const argument.
+/// FIXME: It ought to be possible to store this on the record.
+static bool isImplicitCopyAssignmentArgConst(Sema &S,
+ CXXRecordDecl *ClassDecl) {
if (ClassDecl->isInvalidDecl())
- return std::make_pair(ImplicitExceptionSpecification(*this), false);
+ return true;
// C++ [class.copy]p10:
// If the class definition does not explicitly declare a copy
@@ -7599,37 +7460,34 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
// X& X::operator=(const X&)
//
// if
- bool HasConstCopyAssignment = true;
-
// -- each direct base class B of X has a copy assignment operator
// whose parameter is of type const B&, const volatile B& or B,
// and
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
BaseEnd = ClassDecl->bases_end();
- HasConstCopyAssignment && Base != BaseEnd; ++Base) {
+ Base != BaseEnd; ++Base) {
// We'll handle this below
- if (LangOpts.CPlusPlus0x && Base->isVirtual())
+ if (S.getLangOpts().CPlusPlus0x && Base->isVirtual())
continue;
assert(!Base->getType()->isDependentType() &&
"Cannot generate implicit members for class with dependent bases.");
CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
- HasConstCopyAssignment &=
- (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,
- false, 0);
+ if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0))
+ return false;
}
// In C++11, the above citation has "or virtual" added
- if (LangOpts.CPlusPlus0x) {
+ if (S.getLangOpts().CPlusPlus0x) {
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
BaseEnd = ClassDecl->vbases_end();
- HasConstCopyAssignment && Base != BaseEnd; ++Base) {
+ Base != BaseEnd; ++Base) {
assert(!Base->getType()->isDependentType() &&
"Cannot generate implicit members for class with dependent bases.");
CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
- HasConstCopyAssignment &=
- (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,
- false, 0);
+ if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,
+ false, 0))
+ return false;
}
}
@@ -7639,23 +7497,36 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
// const volatile M& or M.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
- HasConstCopyAssignment && Field != FieldEnd;
- ++Field) {
- QualType FieldType = Context.getBaseElementType((*Field)->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- HasConstCopyAssignment &=
- (bool)LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const,
- false, 0);
- }
+ Field != FieldEnd; ++Field) {
+ QualType FieldType = S.Context.getBaseElementType(Field->getType());
+ if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl())
+ if (!S.LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const,
+ false, 0))
+ return false;
}
// Otherwise, the implicitly declared copy assignment operator will
// have the form
//
// X& X::operator=(X&)
-
+
+ return true;
+}
+
+Sema::ImplicitExceptionSpecification
+Sema::ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD) {
+ CXXRecordDecl *ClassDecl = MD->getParent();
+
+ ImplicitExceptionSpecification ExceptSpec(*this);
+ if (ClassDecl->isInvalidDecl())
+ return ExceptSpec;
+
+ const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>();
+ assert(T->getNumArgs() == 1 && "not a copy assignment op");
+ unsigned ArgQuals = T->getArgType(0).getNonReferenceType().getCVRQualifiers();
+
// C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
+ // An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
// It is unspecified whether or not an implicit copy assignment operator
@@ -7664,8 +7535,6 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
// Based on a similar decision made for constness in C++0x, we're erring on
// the side of assuming such calls to be made regardless of whether they
// actually happen.
- ImplicitExceptionSpecification ExceptSpec(*this);
- unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0;
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
BaseEnd = ClassDecl->bases_end();
Base != BaseEnd; ++Base) {
@@ -7693,15 +7562,17 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
FieldEnd = ClassDecl->field_end();
Field != FieldEnd;
++Field) {
- QualType FieldType = Context.getBaseElementType((*Field)->getType());
+ QualType FieldType = Context.getBaseElementType(Field->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
if (CXXMethodDecl *CopyAssign =
- LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0))
+ LookupCopyingAssignment(FieldClassDecl,
+ ArgQuals | FieldType.getCVRQualifiers(),
+ false, 0))
ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign);
}
}
- return std::make_pair(ExceptSpec, HasConstCopyAssignment);
+ return ExceptSpec;
}
CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
@@ -7710,26 +7581,19 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// for determining the argument type of the operator. Note also that
// operators taking an object instead of a reference are allowed.
- ImplicitExceptionSpecification Spec(*this);
- bool Const;
- llvm::tie(Spec, Const) =
- ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl);
-
QualType ArgType = Context.getTypeDeclType(ClassDecl);
QualType RetType = Context.getLValueReferenceType(ArgType);
- if (Const)
+ if (isImplicitCopyAssignmentArgConst(*this, ClassDecl))
ArgType = ArgType.withConst();
ArgType = Context.getLValueReferenceType(ArgType);
// An implicitly-declared copy assignment operator is an inline public
// member of its class.
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXMethodDecl *CopyAssignment
- = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(RetType, &ArgType, 1, EPI),
+ = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
/*TInfo=*/0, /*isStatic=*/false,
/*StorageClassAsWritten=*/SC_None,
/*isInline=*/true, /*isConstexpr=*/false,
@@ -7738,7 +7602,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
-
+
+ // Build an exception specification pointing back at this member.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = CopyAssignment;
+ CopyAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));
+
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
ClassLoc, ClassLoc, /*Id=*/0,
@@ -8076,9 +7946,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
- ImplicitExceptionSpecification ExceptSpec(*this);
+Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) {
+ CXXRecordDecl *ClassDecl = MD->getParent();
+ ImplicitExceptionSpecification ExceptSpec(*this);
if (ClassDecl->isInvalidDecl())
return ExceptSpec;
@@ -8103,7 +7974,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
- false, 0))
+ 0, false, 0))
ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
}
@@ -8113,7 +7984,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
- false, 0))
+ 0, false, 0))
ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
}
@@ -8121,10 +7992,12 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
FieldEnd = ClassDecl->field_end();
Field != FieldEnd;
++Field) {
- QualType FieldType = Context.getBaseElementType((*Field)->getType());
+ QualType FieldType = Context.getBaseElementType(Field->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl,
- false, 0))
+ if (CXXMethodDecl *MoveAssign =
+ LookupMovingAssignment(FieldClassDecl,
+ FieldType.getCVRQualifiers(),
+ false, 0))
ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign);
}
}
@@ -8167,7 +8040,7 @@ hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) {
// reference types, are supposed to return false here, but that appears
// to be a standard defect.
CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl();
- if (!ClassDecl)
+ if (!ClassDecl || !ClassDecl->getDefinition())
return true;
if (Type.isTriviallyCopyableType(S.Context))
@@ -8209,7 +8082,7 @@ static bool subobjectsHaveMoveOrTrivialCopy(Sema &S, CXXRecordDecl *ClassDecl,
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
Field != FieldEnd; ++Field) {
- if (!hasMoveOrIsTriviallyCopyable(S, (*Field)->getType(), IsConstructor))
+ if (!hasMoveOrIsTriviallyCopyable(S, Field->getType(), IsConstructor))
return false;
}
@@ -8244,22 +8117,17 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// Note: The following rules are largely analoguous to the move
// constructor rules.
- ImplicitExceptionSpecification Spec(
- ComputeDefaultedMoveAssignmentExceptionSpec(ClassDecl));
-
QualType ArgType = Context.getTypeDeclType(ClassDecl);
QualType RetType = Context.getLValueReferenceType(ArgType);
ArgType = Context.getRValueReferenceType(ArgType);
// An implicitly-declared move assignment operator is an inline public
// member of its class.
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXMethodDecl *MoveAssignment
- = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(RetType, &ArgType, 1, EPI),
+ = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
/*TInfo=*/0, /*isStatic=*/false,
/*StorageClassAsWritten=*/SC_None,
/*isInline=*/true,
@@ -8270,6 +8138,12 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
MoveAssignment->setImplicit();
MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment());
+ // Build an exception specification pointing back at this member.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = MoveAssignment;
+ MoveAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));
+
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment,
ClassLoc, ClassLoc, /*Id=*/0,
@@ -8620,10 +8494,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
}
-std::pair<Sema::ImplicitExceptionSpecification, bool>
-Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
+/// Determine whether an implicit copy constructor for ClassDecl has a const
+/// argument.
+/// FIXME: It ought to be possible to store this on the record.
+static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl) {
if (ClassDecl->isInvalidDecl())
- return std::make_pair(ImplicitExceptionSpecification(*this), false);
+ return true;
// C++ [class.copy]p5:
// The implicitly-declared copy constructor for a class X will
@@ -8632,60 +8508,71 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
// X::X(const X&)
//
// if
- // FIXME: It ought to be possible to store this on the record.
- bool HasConstCopyConstructor = true;
-
// -- each direct or virtual base class B of X has a copy
// constructor whose first parameter is of type const B& or
// const volatile B&, and
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
BaseEnd = ClassDecl->bases_end();
- HasConstCopyConstructor && Base != BaseEnd;
- ++Base) {
+ Base != BaseEnd; ++Base) {
// Virtual bases are handled below.
if (Base->isVirtual())
continue;
-
+
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- HasConstCopyConstructor &=
- (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const);
+ // FIXME: This lookup is wrong. If the copy ctor for a member or base is
+ // ambiguous, we should still produce a constructor with a const-qualified
+ // parameter.
+ if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const))
+ return false;
}
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
BaseEnd = ClassDecl->vbases_end();
- HasConstCopyConstructor && Base != BaseEnd;
- ++Base) {
+ Base != BaseEnd; ++Base) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- HasConstCopyConstructor &=
- (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const);
+ if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const))
+ return false;
}
-
+
// -- for all the nonstatic data members of X that are of a
// class type M (or array thereof), each such class type
// has a copy constructor whose first parameter is of type
// const M& or const volatile M&.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
- HasConstCopyConstructor && Field != FieldEnd;
- ++Field) {
- QualType FieldType = Context.getBaseElementType((*Field)->getType());
+ Field != FieldEnd; ++Field) {
+ QualType FieldType = S.Context.getBaseElementType(Field->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- HasConstCopyConstructor &=
- (bool)LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const);
+ if (!S.LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const))
+ return false;
}
}
+
// Otherwise, the implicitly declared copy constructor will have
// the form
//
// X::X(X&)
-
+
+ return true;
+}
+
+Sema::ImplicitExceptionSpecification
+Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) {
+ CXXRecordDecl *ClassDecl = MD->getParent();
+
+ ImplicitExceptionSpecification ExceptSpec(*this);
+ if (ClassDecl->isInvalidDecl())
+ return ExceptSpec;
+
+ const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>();
+ assert(T->getNumArgs() >= 1 && "not a copy ctor");
+ unsigned Quals = T->getArgType(0).getNonReferenceType().getCVRQualifiers();
+
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
- ImplicitExceptionSpecification ExceptSpec(*this);
- unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0;
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
BaseEnd = ClassDecl->bases_end();
Base != BaseEnd;
@@ -8714,15 +8601,16 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
FieldEnd = ClassDecl->field_end();
Field != FieldEnd;
++Field) {
- QualType FieldType = Context.getBaseElementType((*Field)->getType());
+ QualType FieldType = Context.getBaseElementType(Field->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
if (CXXConstructorDecl *CopyConstructor =
- LookupCopyingConstructor(FieldClassDecl, Quals))
+ LookupCopyingConstructor(FieldClassDecl,
+ Quals | FieldType.getCVRQualifiers()))
ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor);
}
}
- return std::make_pair(ExceptSpec, HasConstCopyConstructor);
+ return ExceptSpec;
}
CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
@@ -8731,18 +8619,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// If the class definition does not explicitly declare a copy
// constructor, one is declared implicitly.
- ImplicitExceptionSpecification Spec(*this);
- bool Const;
- llvm::tie(Spec, Const) =
- ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl);
-
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
+ bool Const = isImplicitCopyCtorArgConst(*this, ClassDecl);
if (Const)
ArgType = ArgType.withConst();
ArgType = Context.getLValueReferenceType(ArgType);
-
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+
+ bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
+ CXXCopyConstructor,
+ Const);
DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(
@@ -8753,15 +8639,20 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// An implicitly-declared copy constructor is an inline public
// member of its class.
CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
- Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
+ Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0,
/*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
- /*isConstexpr=*/ClassDecl->defaultedCopyConstructorIsConstexpr() &&
- getLangOpts().CPlusPlus0x);
+ Constexpr);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
+ // Build an exception specification pointing back at this member.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = CopyConstructor;
+ CopyConstructor->setType(
+ Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+
// Note that we have declared this constructor.
++ASTContext::NumImplicitCopyConstructorsDeclared;
@@ -8825,7 +8716,9 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
}
Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
+Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD) {
+ CXXRecordDecl *ClassDecl = MD->getParent();
+
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
@@ -8842,7 +8735,8 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl);
+ CXXConstructorDecl *Constructor =
+ LookupMovingConstructor(BaseClassDecl, 0);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
if (Constructor)
@@ -8856,7 +8750,8 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
B != BEnd; ++B) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl);
+ CXXConstructorDecl *Constructor =
+ LookupMovingConstructor(BaseClassDecl, 0);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
if (Constructor)
@@ -8868,10 +8763,10 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
FEnd = ClassDecl->field_end();
F != FEnd; ++F) {
- if (const RecordType *RecordTy
- = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
- CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
- CXXConstructorDecl *Constructor = LookupMovingConstructor(FieldRecDecl);
+ QualType FieldType = Context.getBaseElementType(F->getType());
+ if (CXXRecordDecl *FieldRecDecl = FieldType->getAsCXXRecordDecl()) {
+ CXXConstructorDecl *Constructor =
+ LookupMovingConstructor(FieldRecDecl, FieldType.getCVRQualifiers());
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
// In particular, the problem is that this function never gets called. It
@@ -8906,13 +8801,12 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
return 0;
}
- ImplicitExceptionSpecification Spec(
- ComputeDefaultedMoveCtorExceptionSpec(ClassDecl));
-
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = Context.getRValueReferenceType(ClassType);
-
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+
+ bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
+ CXXMoveConstructor,
+ false);
DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(
@@ -8924,15 +8818,20 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
// An implicitly-declared copy/move constructor is an inline public
// member of its class.
CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
- Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
+ Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0,
/*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
- /*isConstexpr=*/ClassDecl->defaultedMoveConstructorIsConstexpr() &&
- getLangOpts().CPlusPlus0x);
+ Constexpr);
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();
MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());
+ // Build an exception specification pointing back at this member.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = MoveConstructor;
+ MoveConstructor->setType(
+ Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
ClassLoc, ClassLoc,
@@ -9046,8 +8945,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// will fill in the actual details.
Invoke->setUsed();
Invoke->setReferenced();
- Invoke->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(),
- Conv->getLocation()));
+ Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation()));
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
@@ -9171,13 +9069,6 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
- for (specific_attr_iterator<NonNullAttr>
- i = Constructor->specific_attr_begin<NonNullAttr>(),
- e = Constructor->specific_attr_end<NonNullAttr>(); i != e; ++i) {
- const NonNullAttr *NonNull = *i;
- CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc);
- }
-
MarkFunctionReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
@@ -9243,7 +9134,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
bool
Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
- SourceLocation Loc,
+ SourceLocation Loc,
ASTOwningVector<Expr*> &ConvertedArgs,
bool AllowExplicit) {
// FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
@@ -9271,7 +9162,8 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
- // FIXME: Missing call to CheckFunctionCall or equivalent
+ CheckConstructorCall(Constructor, AllArgs.data(), AllArgs.size(),
+ Proto, Loc);
return Invalid;
}
@@ -9329,7 +9221,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
diag::err_operator_new_delete_too_few_parameters)
<< FnDecl->getDeclName();
- // Check the the first parameter type is not dependent.
+ // Check the first parameter type is not dependent.
QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
if (FirstParamType->isDependentType())
return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag)
@@ -9568,7 +9460,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
TemplateParameterList *Params = TpDecl->getTemplateParameters();
if (Params->size() == 1) {
NonTypeTemplateParmDecl *PmDecl =
- cast<NonTypeTemplateParmDecl>(Params->getParam(0));
+ dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(0));
// The template parameter must be a char parameter pack.
if (PmDecl && PmDecl->isTemplateParameterPack() &&
@@ -9769,7 +9661,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Diag(Loc, diag::err_objc_object_catch);
Invalid = true;
} else if (T->isObjCObjectPointerType()) {
- if (!getLangOpts().ObjCNonFragileABI)
+ // FIXME: should this be a test for macosx-fragile specifically?
+ if (getLangOpts().ObjCRuntime.isFragile())
Diag(Loc, diag::warn_objc_pointer_cxx_catch_fragile);
}
}
@@ -9881,37 +9774,49 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr,
- Expr *AssertMessageExpr_,
+ Expr *AssertMessageExpr,
SourceLocation RParenLoc) {
- StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr_);
+ StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr);
+
+ if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression))
+ return 0;
- if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) {
+ return BuildStaticAssertDeclaration(StaticAssertLoc, AssertExpr,
+ AssertMessage, RParenLoc, false);
+}
+
+Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
+ Expr *AssertExpr,
+ StringLiteral *AssertMessage,
+ SourceLocation RParenLoc,
+ bool Failed) {
+ if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent() &&
+ !Failed) {
// In a static_assert-declaration, the constant-expression shall be a
// constant expression that can be contextually converted to bool.
ExprResult Converted = PerformContextuallyConvertToBool(AssertExpr);
if (Converted.isInvalid())
- return 0;
+ Failed = true;
llvm::APSInt Cond;
- if (VerifyIntegerConstantExpression(Converted.get(), &Cond,
- PDiag(diag::err_static_assert_expression_is_not_constant),
+ if (!Failed && VerifyIntegerConstantExpression(Converted.get(), &Cond,
+ diag::err_static_assert_expression_is_not_constant,
/*AllowFold=*/false).isInvalid())
- return 0;
+ Failed = true;
- if (!Cond) {
+ if (!Failed && !Cond) {
llvm::SmallString<256> MsgBuffer;
llvm::raw_svector_ostream Msg(MsgBuffer);
AssertMessage->printPretty(Msg, Context, 0, getPrintingPolicy());
Diag(StaticAssertLoc, diag::err_static_assert_failed)
<< Msg.str() << AssertExpr->getSourceRange();
+ Failed = true;
}
}
- if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression))
- return 0;
-
Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc,
- AssertExpr, AssertMessage, RParenLoc);
+ AssertExpr, AssertMessage, RParenLoc,
+ Failed);
CurContext->addDecl(Decl);
return Decl;
@@ -10116,7 +10021,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
/// friend class A<T>::B<unsigned>;
/// We permit this as a special case; if there are any template
/// parameters present at all, require proper matching, i.e.
-/// template <> template <class T> friend class A<int>::B;
+/// template <> template \<class T> friend class A<int>::B;
Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
MultiTemplateParamsArg TempParams) {
SourceLocation Loc = DS.getLocStart();
@@ -10438,9 +10343,11 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
FrD->setAccess(AS_public);
CurContext->addDecl(FrD);
- if (ND->isInvalidDecl())
+ if (ND->isInvalidDecl()) {
FrD->setInvalidDecl();
- else {
+ } else {
+ if (DC->isRecord()) CheckFriendAccess(ND);
+
FunctionDecl *FD;
if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
FD = FTD->getTemplatedDecl();
@@ -10464,8 +10371,13 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
return;
}
if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
- Diag(DelLoc, diag::err_deleted_decl_not_first);
- Diag(Prev->getLocation(), diag::note_previous_declaration);
+ // Don't consider the implicit declaration we generate for explicit
+ // specializations. FIXME: Do not generate these implicit declarations.
+ if ((Prev->getTemplateSpecializationKind() != TSK_ExplicitSpecialization
+ || Prev->getPreviousDecl()) && !Prev->isDefined()) {
+ Diag(DelLoc, diag::err_deleted_decl_not_first);
+ Diag(Prev->getLocation(), diag::note_previous_declaration);
+ }
// If the declaration wasn't the first, we delete the function anyway for
// recovery.
}
@@ -10531,10 +10443,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
if (Primary == Primary->getCanonicalDecl())
return;
+ CheckExplicitlyDefaultedSpecialMember(MD);
+
switch (Member) {
case CXXDefaultConstructor: {
CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
- CheckExplicitlyDefaultedDefaultConstructor(CD);
if (!CD->isInvalidDecl())
DefineImplicitDefaultConstructor(DefaultLoc, CD);
break;
@@ -10542,14 +10455,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
case CXXCopyConstructor: {
CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
- CheckExplicitlyDefaultedCopyConstructor(CD);
if (!CD->isInvalidDecl())
DefineImplicitCopyConstructor(DefaultLoc, CD);
break;
}
case CXXCopyAssignment: {
- CheckExplicitlyDefaultedCopyAssignment(MD);
if (!MD->isInvalidDecl())
DefineImplicitCopyAssignment(DefaultLoc, MD);
break;
@@ -10557,7 +10468,6 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
case CXXDestructor: {
CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD);
- CheckExplicitlyDefaultedDestructor(DD);
if (!DD->isInvalidDecl())
DefineImplicitDestructor(DefaultLoc, DD);
break;
@@ -10565,14 +10475,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
case CXXMoveConstructor: {
CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
- CheckExplicitlyDefaultedMoveConstructor(CD);
if (!CD->isInvalidDecl())
DefineImplicitMoveConstructor(DefaultLoc, CD);
break;
}
case CXXMoveAssignment: {
- CheckExplicitlyDefaultedMoveAssignment(MD);
if (!MD->isInvalidDecl())
DefineImplicitMoveAssignment(DefaultLoc, MD);
break;
@@ -10650,8 +10558,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
if (const RecordType *RT = NewClassTy->getAs<RecordType>()) {
if (!RT->isBeingDefined() &&
RequireCompleteType(New->getLocation(), NewClassTy,
- PDiag(diag::err_covariant_return_incomplete)
- << New->getDeclName()))
+ diag::err_covariant_return_incomplete,
+ New->getDeclName()))
return true;
}
@@ -10857,7 +10765,7 @@ bool Sema::DefineUsedVTables() {
// 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
+ // time through the loop and prefer indices (which are stable) to
// iterators (which are not).
bool DefinedAnything = false;
for (unsigned I = 0; I != VTableUses.size(); ++I) {
@@ -10867,6 +10775,8 @@ bool Sema::DefineUsedVTables() {
SourceLocation Loc = VTableUses[I].second;
+ bool DefineVTable = true;
+
// 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.
@@ -10877,7 +10787,8 @@ bool Sema::DefineUsedVTables() {
case TSK_ExplicitSpecialization:
case TSK_ExplicitInstantiationDeclaration:
// The key function is in another translation unit.
- continue;
+ DefineVTable = false;
+ break;
case TSK_ExplicitInstantiationDefinition:
case TSK_ImplicitInstantiation:
@@ -10906,7 +10817,15 @@ bool Sema::DefineUsedVTables() {
}
if (IsExplicitInstantiationDeclaration)
- continue;
+ DefineVTable = false;
+ }
+
+ // The exception specifications for all virtual members may be needed even
+ // if we are not providing an authoritative form of the vtable in this TU.
+ // We may choose to emit it available_externally anyway.
+ if (!DefineVTable) {
+ MarkVirtualMemberExceptionSpecsNeeded(Loc, Class);
+ continue;
}
// Mark all of the virtual members of this class as referenced, so
@@ -10935,16 +10854,33 @@ bool Sema::DefineUsedVTables() {
return DefinedAnything;
}
+void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,
+ const CXXRecordDecl *RD) {
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I)
+ if ((*I)->isVirtual() && !(*I)->isPure())
+ ResolveExceptionSpec(Loc, (*I)->getType()->castAs<FunctionProtoType>());
+}
+
void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
const CXXRecordDecl *RD) {
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end(); i != e; ++i) {
- CXXMethodDecl *MD = *i;
+ // Mark all functions which will appear in RD's vtable as used.
+ CXXFinalOverriderMap FinalOverriders;
+ RD->getFinalOverriders(FinalOverriders);
+ for (CXXFinalOverriderMap::const_iterator I = FinalOverriders.begin(),
+ E = FinalOverriders.end();
+ I != E; ++I) {
+ for (OverridingMethods::const_iterator OI = I->second.begin(),
+ OE = I->second.end();
+ OI != OE; ++OI) {
+ assert(OI->second.size() > 0 && "no final overrider");
+ CXXMethodDecl *Overrider = OI->second.front().Method;
- // C++ [basic.def.odr]p2:
- // [...] A virtual member function is used if it is not pure. [...]
- if (MD->isVirtual() && !MD->isPure())
- MarkFunctionReferenced(Loc, MD);
+ // C++ [basic.def.odr]p2:
+ // [...] A virtual member function is used if it is not pure. [...]
+ if (!Overrider->isPure())
+ MarkFunctionReferenced(Loc, Overrider);
+ }
}
// Only classes that have virtual bases need a VTT.
@@ -11162,8 +11098,8 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
switch (Proto->getExceptionSpecType()) {
case EST_Uninstantiated:
+ case EST_Unevaluated:
case EST_BasicNoexcept:
- case EST_Delayed:
case EST_DynamicNone:
case EST_MSAny:
case EST_None:
@@ -11290,7 +11226,7 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
if (!NoexceptExpr->isValueDependent())
NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, 0,
- PDiag(diag::err_noexcept_needs_constant_expression),
+ diag::err_noexcept_needs_constant_expression,
/*AllowFold*/ false).take();
EPI.NoexceptExpr = NoexceptExpr;
}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index a942d49..9da4d69 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -173,10 +173,11 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
Diag(Overridden->getLocation(), diag::note_previous_decl)
<< "method";
}
- ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin();
+ ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin(),
+ oe = Overridden->param_end();
for (ObjCMethodDecl::param_iterator
ni = NewMethod->param_begin(), ne = NewMethod->param_end();
- ni != ne; ++ni, ++oi) {
+ ni != ne && oi != oe; ++ni, ++oi) {
const ParmVarDecl *oldDecl = (*oi);
ParmVarDecl *newDecl = (*ni);
if (newDecl->hasAttr<NSConsumedAttr>() !=
@@ -196,7 +197,6 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
ObjCMethodFamily family = method->getMethodFamily();
switch (family) {
case OMF_None:
- case OMF_dealloc:
case OMF_finalize:
case OMF_retain:
case OMF_release:
@@ -206,6 +206,24 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
case OMF_performSelector:
return false;
+ case OMF_dealloc:
+ if (!S.Context.hasSameType(method->getResultType(), S.Context.VoidTy)) {
+ SourceRange ResultTypeRange;
+ if (const TypeSourceInfo *ResultTypeInfo
+ = method->getResultTypeSourceInfo())
+ ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+ if (ResultTypeRange.isInvalid())
+ S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
+ << method->getResultType()
+ << FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)");
+ else
+ S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
+ << method->getResultType()
+ << FixItHint::CreateReplacement(ResultTypeRange, "void");
+ return true;
+ }
+ return false;
+
case OMF_init:
// If the method doesn't obey the init rules, don't bother annotating it.
if (S.checkInitMethod(method, QualType()))
@@ -267,9 +285,9 @@ void Sema::AddAnyMethodToGlobalPool(Decl *D) {
/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
/// and user declared, in the method definition's AST.
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
- assert(getCurMethodDecl() == 0 && "Method parsing confused");
+ assert((getCurMethodDecl() == 0) && "Methodparsing confused");
ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D);
-
+
// If we don't have a valid method decl, simply return.
if (!MDecl)
return;
@@ -338,11 +356,11 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
// Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set.
// Only do this if the current class actually has a superclass.
if (IC->getSuperClass()) {
- ObjCShouldCallSuperDealloc =
+ getCurFunction()->ObjCShouldCallSuperDealloc =
!(Context.getLangOpts().ObjCAutoRefCount ||
Context.getLangOpts().getGC() == LangOptions::GCOnly) &&
MDecl->getMethodFamily() == OMF_dealloc;
- ObjCShouldCallSuperFinalize =
+ getCurFunction()->ObjCShouldCallSuperFinalize =
Context.getLangOpts().getGC() != LangOptions::NonGC &&
MDecl->getMethodFamily() == OMF_finalize;
}
@@ -474,11 +492,11 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
Diag(SuperLoc, diag::err_undef_superclass)
<< SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
else if (RequireCompleteType(SuperLoc,
- Context.getObjCInterfaceType(SuperClassDecl),
- PDiag(diag::err_forward_superclass)
- << SuperClassDecl->getDeclName()
- << ClassName
- << SourceRange(AtInterfaceLoc, ClassLoc))) {
+ Context.getObjCInterfaceType(SuperClassDecl),
+ diag::err_forward_superclass,
+ SuperClassDecl->getDeclName(),
+ ClassName,
+ SourceRange(AtInterfaceLoc, ClassLoc))) {
SuperClassDecl = 0;
}
}
@@ -501,13 +519,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
return ActOnObjCContainerStartDefinition(IDecl);
}
-/// ActOnCompatiblityAlias - this action is called after complete parsing of
-/// @compatibility_alias declaration. It sets up the alias relationships.
-Decl *Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
- IdentifierInfo *AliasName,
- SourceLocation AliasLocation,
- IdentifierInfo *ClassName,
- SourceLocation ClassLocation) {
+/// ActOnCompatibilityAlias - this action is called after complete parsing of
+/// a \@compatibility_alias declaration. It sets up the alias relationships.
+Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
+ IdentifierInfo *AliasName,
+ SourceLocation AliasLocation,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLocation) {
// Look for previous declaration of alias name
NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation,
LookupOrdinaryName, ForRedeclaration);
@@ -712,7 +730,7 @@ void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
}
}
-/// ActOnForwardProtocolDeclaration - Handle @protocol foo;
+/// ActOnForwardProtocolDeclaration - Handle \@protocol foo;
Sema::DeclGroupPtrTy
Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
const IdentifierLocPair *IdentList,
@@ -759,8 +777,8 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
if (!IDecl
|| RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
- PDiag(diag::err_category_forward_interface)
- << (CategoryName == 0))) {
+ diag::err_category_forward_interface,
+ CategoryName == 0)) {
// Create an invalid ObjCCategoryDecl to serve as context for
// the enclosing method declarations. We mark the decl invalid
// to make it clear that this isn't a valid AST.
@@ -1019,8 +1037,8 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
ObjCInterfaceDecl* IDecl = ImpDecl->getClassInterface();
if (!IDecl)
return;
- /// Check case of non-existing @interface decl.
- /// (legacy objective-c @implementation decl without an @interface decl).
+ /// Check case of non-existing \@interface decl.
+ /// (legacy objective-c \@implementation decl without an \@interface decl).
/// Add implementations's ivar to the synthesize class's ivar list.
if (IDecl->isImplicitInterfaceDecl()) {
IDecl->setEndOfDefinitionLoc(RBrace);
@@ -1038,7 +1056,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
return;
assert(ivars && "missing @implementation ivars");
- if (LangOpts.ObjCNonFragileABI2) {
+ if (LangOpts.ObjCRuntime.isNonFragile()) {
if (ImpDecl->getSuperClass())
Diag(ImpDecl->getLocation(), diag::warn_on_superclass_use);
for (unsigned i = 0; i < numIvars; i++) {
@@ -1094,7 +1112,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
if (numIvars > 0)
Diag(ivars[j]->getLocation(), diag::err_inconsistant_ivar_count);
else if (IVI != IVE)
- Diag((*IVI)->getLocation(), diag::err_inconsistant_ivar_count);
+ Diag(IVI->getLocation(), diag::err_inconsistant_ivar_count);
}
void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
@@ -1399,8 +1417,9 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
true);
for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(),
- IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
- IM != EM; ++IM, ++IF) {
+ IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end(),
+ EF = MethodDecl->param_end();
+ IM != EM && IF != EF; ++IM, ++IF) {
CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, *IM, *IF,
IsProtocolMethodDecl, false, true);
}
@@ -1421,8 +1440,9 @@ void Sema::CheckConflictingOverridingMethod(ObjCMethodDecl *Method,
true);
for (ObjCMethodDecl::param_iterator IM = Method->param_begin(),
- IF = Overridden->param_begin(), EM = Method->param_end();
- IM != EM; ++IM, ++IF) {
+ IF = Overridden->param_begin(), EM = Method->param_end(),
+ EF = Overridden->param_end();
+ IM != EM && IF != EF; ++IM, ++IF) {
CheckMethodOverrideParam(*this, Method, Overridden, *IM, *IF,
IsProtocolMethodDecl, true, true);
}
@@ -1454,8 +1474,9 @@ void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl,
IsProtocolMethodDecl, false, false);
if (match)
for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(),
- IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
- IM != EM; ++IM, ++IF) {
+ IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end(),
+ EF = MethodDecl->param_end();
+ IM != EM && IF != EF; ++IM, ++IF) {
match = CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl,
*IM, *IF,
IsProtocolMethodDecl, false, false);
@@ -1487,8 +1508,8 @@ void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl,
void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
ObjCProtocolDecl *PDecl,
bool& IncompleteImpl,
- const llvm::DenseSet<Selector> &InsMap,
- const llvm::DenseSet<Selector> &ClsMap,
+ const SelectorSet &InsMap,
+ const SelectorSet &ClsMap,
ObjCContainerDecl *CDecl) {
ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
ObjCInterfaceDecl *IDecl = C ? C->getClassInterface()
@@ -1497,7 +1518,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
ObjCInterfaceDecl *Super = IDecl->getSuperClass();
ObjCInterfaceDecl *NSIDecl = 0;
- if (getLangOpts().NeXTRuntime) {
+ if (getLangOpts().ObjCRuntime.isNeXTFamily()) {
// check to see if class implements forwardInvocation method and objects
// of this class are derived from 'NSProxy' so that to forward requests
// from one object to another.
@@ -1584,10 +1605,10 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
/// MatchAllMethodDeclarations - Check methods declared in interface
/// or protocol against those declared in their implementations.
///
-void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
- const llvm::DenseSet<Selector> &ClsMap,
- llvm::DenseSet<Selector> &InsMapSeen,
- llvm::DenseSet<Selector> &ClsMapSeen,
+void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
+ const SelectorSet &ClsMap,
+ SelectorSet &InsMapSeen,
+ SelectorSet &ClsMapSeen,
ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool &IncompleteImpl,
@@ -1683,7 +1704,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
/// warns each time an exact match is found.
void Sema::CheckCategoryVsClassMethodMatches(
ObjCCategoryImplDecl *CatIMPDecl) {
- llvm::DenseSet<Selector> InsMap, ClsMap;
+ SelectorSet InsMap, ClsMap;
for (ObjCImplementationDecl::instmeth_iterator
I = CatIMPDecl->instmeth_begin(),
@@ -1704,7 +1725,7 @@ void Sema::CheckCategoryVsClassMethodMatches(
ObjCInterfaceDecl *IDecl = CatDecl->getClassInterface();
if (!IDecl)
return;
- llvm::DenseSet<Selector> InsMapSeen, ClsMapSeen;
+ SelectorSet InsMapSeen, ClsMapSeen;
bool IncompleteImpl = false;
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
CatIMPDecl, IDecl,
@@ -1715,7 +1736,7 @@ void Sema::CheckCategoryVsClassMethodMatches(
void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool IncompleteImpl) {
- llvm::DenseSet<Selector> InsMap;
+ SelectorSet InsMap;
// Check and see if instance methods in class interface have been
// implemented in the implementation class.
for (ObjCImplementationDecl::instmeth_iterator
@@ -1726,11 +1747,12 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
// an implementation or 2) there is a @synthesize/@dynamic implementation
// of the property in the @implementation.
if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))
- if (!(LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2) ||
- IDecl->isObjCRequiresPropertyDefs())
+ if (!(LangOpts.ObjCDefaultSynthProperties &&
+ LangOpts.ObjCRuntime.isNonFragile()) ||
+ IDecl->isObjCRequiresPropertyDefs())
DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
- llvm::DenseSet<Selector> ClsMap;
+ SelectorSet ClsMap;
for (ObjCImplementationDecl::classmeth_iterator
I = IMPDecl->classmeth_begin(),
E = IMPDecl->classmeth_end(); I != E; ++I)
@@ -1738,7 +1760,7 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
// Check for type conflict of methods declared in a class/protocol and
// its implementation; if any.
- llvm::DenseSet<Selector> InsMapSeen, ClsMapSeen;
+ SelectorSet InsMapSeen, ClsMapSeen;
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl, CDecl,
IncompleteImpl, true);
@@ -1954,9 +1976,10 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
return false;
ObjCMethodDecl::param_const_iterator
- li = left->param_begin(), le = left->param_end(), ri = right->param_begin();
+ li = left->param_begin(), le = left->param_end(), ri = right->param_begin(),
+ re = right->param_end();
- for (; li != le; ++li, ++ri) {
+ for (; li != le && ri != re; ++li, ++ri) {
assert(ri != right->param_end() && "Param mismatch");
const ParmVarDecl *lparm = *li, *rparm = *ri;
@@ -2140,53 +2163,16 @@ ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
return 0;
}
-/// CompareMethodParamsInBaseAndSuper - This routine compares methods with
-/// identical selector names in current and its super classes and issues
-/// a warning if any of their argument types are incompatible.
-void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl,
- ObjCMethodDecl *Method,
- bool IsInstance) {
- ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
- if (ID == 0) return;
-
- while (ObjCInterfaceDecl *SD = ID->getSuperClass()) {
- ObjCMethodDecl *SuperMethodDecl =
- SD->lookupMethod(Method->getSelector(), IsInstance);
- if (SuperMethodDecl == 0) {
- ID = SD;
- continue;
- }
- ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
- E = Method->param_end();
- ObjCMethodDecl::param_iterator PrevI = SuperMethodDecl->param_begin();
- for (; ParamI != E; ++ParamI, ++PrevI) {
- // Number of parameters are the same and is guaranteed by selector match.
- assert(PrevI != SuperMethodDecl->param_end() && "Param mismatch");
- QualType T1 = Context.getCanonicalType((*ParamI)->getType());
- QualType T2 = Context.getCanonicalType((*PrevI)->getType());
- // If type of argument of method in this class does not match its
- // respective argument type in the super class method, issue warning;
- if (!Context.typesAreCompatible(T1, T2)) {
- Diag((*ParamI)->getLocation(), diag::ext_typecheck_base_super)
- << T1 << T2;
- Diag(SuperMethodDecl->getLocation(), diag::note_previous_declaration);
- return;
- }
- }
- ID = SD;
- }
-}
-
/// DiagnoseDuplicateIvars -
/// Check for duplicate ivars in the entire class at the start of
-/// @implementation. This becomes necesssary because class extension can
+/// \@implementation. This becomes necesssary because class extension can
/// add ivars to a class in random order which will not be known until
-/// class's @implementation is seen.
+/// class's \@implementation is seen.
void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
ObjCInterfaceDecl *SID) {
for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(),
IVE = ID->ivar_end(); IVI != IVE; ++IVI) {
- ObjCIvarDecl* Ivar = (*IVI);
+ ObjCIvarDecl* Ivar = *IVI;
if (Ivar->isInvalidDecl())
continue;
if (IdentifierInfo *II = Ivar->getIdentifier()) {
@@ -2273,9 +2259,6 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
InsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "id".
AddInstanceMethodToGlobalPool(Method);
- // verify that the instance method conforms to the same definition of
- // parent methods if it shadows one.
- CompareMethodParamsInBaseAndSuper(ClassDecl, Method, true);
}
} else {
/// Check for class method of the same name with incompatible types
@@ -2298,11 +2281,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
}
ClsMap[Method->getSelector()] = Method;
- /// The following allows us to typecheck messages to "Class".
AddFactoryMethodToGlobalPool(Method);
- // verify that the class method conforms to the same definition of
- // parent methods if it shadows one.
- CompareMethodParamsInBaseAndSuper(ClassDecl, Method, false);
}
}
}
@@ -2347,7 +2326,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
for (ObjCContainerDecl::prop_iterator I = ClsExtDecl->prop_begin(),
E = ClsExtDecl->prop_end(); I != E; ++I) {
- ObjCPropertyDecl *Property = (*I);
+ ObjCPropertyDecl *Property = *I;
// Skip over properties declared @dynamic
if (const ObjCPropertyImplDecl *PIDecl
= IC->FindPropertyImplDecl(Property->getIdentifier()))
@@ -2399,7 +2378,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Diag(IDecl->getLocation(), diag::err_objc_root_class_subclass);
}
- if (LangOpts.ObjCNonFragileABI2) {
+ if (LangOpts.ObjCRuntime.isNonFragile()) {
while (IDecl->getSuperClass()) {
DiagnoseDuplicateIvars(IDecl, IDecl->getSuperClass());
IDecl = IDecl->getSuperClass();
@@ -2443,6 +2422,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Consumer.HandleTopLevelDeclInObjCContainer(DG);
}
+ ActOnDocumentableDecl(ClassDecl);
return ClassDecl;
}
@@ -2488,19 +2468,10 @@ bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD,
return false;
}
-namespace {
- /// \brief Describes the compatibility of a result type with its method.
- enum ResultTypeCompatibilityKind {
- RTC_Compatible,
- RTC_Incompatible,
- RTC_Unknown
- };
-}
-
/// \brief Check whether the declared result type of the given Objective-C
/// method declaration is compatible with the method's class.
///
-static ResultTypeCompatibilityKind
+static Sema::ResultTypeCompatibilityKind
CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
ObjCInterfaceDecl *CurrentClass) {
QualType ResultType = Method->getResultType();
@@ -2513,27 +2484,27 @@ CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
// - it is id or qualified id, or
if (ResultObjectType->isObjCIdType() ||
ResultObjectType->isObjCQualifiedIdType())
- return RTC_Compatible;
+ return Sema::RTC_Compatible;
if (CurrentClass) {
if (ObjCInterfaceDecl *ResultClass
= ResultObjectType->getInterfaceDecl()) {
// - it is the same as the method's class type, or
if (declaresSameEntity(CurrentClass, ResultClass))
- return RTC_Compatible;
+ return Sema::RTC_Compatible;
// - it is a superclass of the method's class type
if (ResultClass->isSuperClassOf(CurrentClass))
- return RTC_Compatible;
+ return Sema::RTC_Compatible;
}
} else {
// Any Objective-C pointer type might be acceptable for a protocol
// method; we just don't know.
- return RTC_Unknown;
+ return Sema::RTC_Unknown;
}
}
- return RTC_Incompatible;
+ return Sema::RTC_Incompatible;
}
namespace {
@@ -2543,7 +2514,6 @@ class OverrideSearch {
public:
Sema &S;
ObjCMethodDecl *Method;
- llvm::SmallPtrSet<ObjCContainerDecl*, 128> Searched;
llvm::SmallPtrSet<ObjCMethodDecl*, 4> Overridden;
bool Recursive;
@@ -2572,8 +2542,13 @@ public:
// Prevent the search from reaching this container again. This is
// important with categories, which override methods from the
// interface and each other.
- Searched.insert(container);
- searchFromContainer(container);
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(container)) {
+ searchFromContainer(container);
+ if (ObjCInterfaceDecl *Interface = Category->getClassInterface())
+ searchFromContainer(Interface);
+ } else {
+ searchFromContainer(container);
+ }
}
typedef llvm::SmallPtrSet<ObjCMethodDecl*, 128>::iterator iterator;
@@ -2609,7 +2584,7 @@ private:
void searchFrom(ObjCCategoryDecl *category) {
// A method in a category declaration overrides declarations from
// the main class and from protocols the category references.
- search(category->getClassInterface());
+ // The main class is handled in the constructor.
search(category->getReferencedProtocols());
}
@@ -2619,10 +2594,12 @@ private:
// declaration.
if (ObjCCategoryDecl *category = impl->getCategoryDecl()) {
search(category);
+ if (ObjCInterfaceDecl *Interface = category->getClassInterface())
+ search(Interface);
// Otherwise it overrides declarations from the class.
- } else {
- search(impl->getClassInterface());
+ } else if (ObjCInterfaceDecl *Interface = impl->getClassInterface()) {
+ search(Interface);
}
}
@@ -2647,7 +2624,8 @@ private:
void searchFrom(ObjCImplementationDecl *impl) {
// A method in a class implementation overrides declarations from
// the class interface.
- search(impl->getClassInterface());
+ if (ObjCInterfaceDecl *Interface = impl->getClassInterface())
+ search(Interface);
}
@@ -2658,9 +2636,6 @@ private:
}
void search(ObjCContainerDecl *container) {
- // Abort if we've already searched this container.
- if (!Searched.insert(container)) return;
-
// Check for a method in this container which matches this selector.
ObjCMethodDecl *meth = container->getMethod(Method->getSelector(),
Method->isInstanceMethod());
@@ -2682,6 +2657,68 @@ private:
};
}
+void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
+ ObjCInterfaceDecl *CurrentClass,
+ ResultTypeCompatibilityKind RTC) {
+ // Search for overridden methods and merge information down from them.
+ OverrideSearch overrides(*this, ObjCMethod);
+ // Keep track if the method overrides any method in the class's base classes,
+ // its protocols, or its categories' protocols; we will keep that info
+ // in the ObjCMethodDecl.
+ // For this info, a method in an implementation is not considered as
+ // overriding the same method in the interface or its categories.
+ bool hasOverriddenMethodsInBaseOrProtocol = false;
+ for (OverrideSearch::iterator
+ i = overrides.begin(), e = overrides.end(); i != e; ++i) {
+ ObjCMethodDecl *overridden = *i;
+
+ if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
+ CurrentClass != overridden->getClassInterface() ||
+ overridden->isOverriding())
+ hasOverriddenMethodsInBaseOrProtocol = true;
+
+ // Propagate down the 'related result type' bit from overridden methods.
+ if (RTC != Sema::RTC_Incompatible && overridden->hasRelatedResultType())
+ ObjCMethod->SetRelatedResultType();
+
+ // Then merge the declarations.
+ mergeObjCMethodDecls(ObjCMethod, overridden);
+
+ if (ObjCMethod->isImplicit() && overridden->isImplicit())
+ continue; // Conflicting properties are detected elsewhere.
+
+ // Check for overriding methods
+ if (isa<ObjCInterfaceDecl>(ObjCMethod->getDeclContext()) ||
+ isa<ObjCImplementationDecl>(ObjCMethod->getDeclContext()))
+ CheckConflictingOverridingMethod(ObjCMethod, overridden,
+ isa<ObjCProtocolDecl>(overridden->getDeclContext()));
+
+ if (CurrentClass && overridden->getDeclContext() != CurrentClass &&
+ isa<ObjCInterfaceDecl>(overridden->getDeclContext()) &&
+ !overridden->isImplicit() /* not meant for properties */) {
+ ObjCMethodDecl::param_iterator ParamI = ObjCMethod->param_begin(),
+ E = ObjCMethod->param_end();
+ ObjCMethodDecl::param_iterator PrevI = overridden->param_begin(),
+ PrevE = overridden->param_end();
+ for (; ParamI != E && PrevI != PrevE; ++ParamI, ++PrevI) {
+ assert(PrevI != overridden->param_end() && "Param mismatch");
+ QualType T1 = Context.getCanonicalType((*ParamI)->getType());
+ QualType T2 = Context.getCanonicalType((*PrevI)->getType());
+ // If type of argument of method in this class does not match its
+ // respective argument type in the super class method, issue warning;
+ if (!Context.typesAreCompatible(T1, T2)) {
+ Diag((*ParamI)->getLocation(), diag::ext_typecheck_base_super)
+ << T1 << T2;
+ Diag(overridden->getLocation(), diag::note_previous_declaration);
+ break;
+ }
+ }
+ }
+ }
+
+ ObjCMethod->setOverriding(hasOverriddenMethodsInBaseOrProtocol);
+}
+
Decl *Sema::ActOnMethodDeclaration(
Scope *S,
SourceLocation MethodLoc, SourceLocation EndLoc,
@@ -2871,32 +2908,14 @@ Decl *Sema::ActOnMethodDeclaration(
ResultTypeCompatibilityKind RTC
= CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass);
- // Search for overridden methods and merge information down from them.
- OverrideSearch overrides(*this, ObjCMethod);
- for (OverrideSearch::iterator
- i = overrides.begin(), e = overrides.end(); i != e; ++i) {
- ObjCMethodDecl *overridden = *i;
-
- // Propagate down the 'related result type' bit from overridden methods.
- if (RTC != RTC_Incompatible && overridden->hasRelatedResultType())
- ObjCMethod->SetRelatedResultType();
+ CheckObjCMethodOverrides(ObjCMethod, CurrentClass, RTC);
- // Then merge the declarations.
- mergeObjCMethodDecls(ObjCMethod, overridden);
-
- // Check for overriding methods
- if (isa<ObjCInterfaceDecl>(ObjCMethod->getDeclContext()) ||
- isa<ObjCImplementationDecl>(ObjCMethod->getDeclContext()))
- CheckConflictingOverridingMethod(ObjCMethod, overridden,
- isa<ObjCProtocolDecl>(overridden->getDeclContext()));
- }
-
bool ARCError = false;
if (getLangOpts().ObjCAutoRefCount)
ARCError = CheckARCMethodDecl(*this, ObjCMethod);
// Infer the related result type when possible.
- if (!ARCError && RTC == RTC_Compatible &&
+ if (!ARCError && RTC == Sema::RTC_Compatible &&
!ObjCMethod->hasRelatedResultType() &&
LangOpts.ObjCInferRelatedResultType) {
bool InferRelatedResultType = false;
@@ -2927,7 +2946,9 @@ Decl *Sema::ActOnMethodDeclaration(
if (InferRelatedResultType)
ObjCMethod->SetRelatedResultType();
}
-
+
+ ActOnDocumentableDecl(ObjCMethod);
+
return ObjCMethod;
}
@@ -2948,7 +2969,7 @@ bool Sema::CheckObjCDeclScope(Decl *D) {
return true;
}
-/// Called whenever @defs(ClassName) is encountered in the source. Inserts the
+/// Called whenever \@defs(ClassName) is encountered in the source. Inserts the
/// instance variables of ClassName into Decls.
void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart,
IdentifierInfo *ClassName,
@@ -2959,7 +2980,7 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart,
Diag(DeclStart, diag::err_undef_interface) << ClassName;
return;
}
- if (LangOpts.ObjCNonFragileABI) {
+ if (LangOpts.ObjCRuntime.isNonFragile()) {
Diag(DeclStart, diag::err_atdef_nonfragile_interface);
return;
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 14b2434..63bfa9d 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -51,7 +51,8 @@ bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
// C++ 15.4p2: A type denoted in an exception-specification shall not denote
// an incomplete type.
if (RequireCompleteType(Range.getBegin(), T,
- PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/0 << Range))
+ diag::err_incomplete_in_exception_spec,
+ /*direct*/0, Range))
return true;
// C++ 15.4p2: A type denoted in an exception-specification shall not denote
@@ -71,8 +72,9 @@ bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
return false;
- if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T,
- PDiag(diag::err_incomplete_in_exception_spec) << kind << Range))
+ if (!T->isVoidType() &&
+ RequireCompleteType(Range.getBegin(), T,
+ diag::err_incomplete_in_exception_spec, kind, Range))
return true;
return false;
@@ -98,20 +100,22 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
const FunctionProtoType *
Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
- // FIXME: If FD is a special member, we should delay computing its exception
- // specification until this point.
- if (FPT->getExceptionSpecType() != EST_Uninstantiated)
+ if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
return FPT;
FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();
const FunctionProtoType *SourceFPT =
SourceDecl->getType()->castAs<FunctionProtoType>();
- if (SourceFPT->getExceptionSpecType() != EST_Uninstantiated)
+ // If the exception specification has already been resolved, just return it.
+ if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType()))
return SourceFPT;
- // Instantiate the exception specification now.
- InstantiateExceptionSpec(Loc, SourceDecl);
+ // Compute or instantiate the exception specification now.
+ if (FPT->getExceptionSpecType() == EST_Unevaluated)
+ EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
+ else
+ InstantiateExceptionSpec(Loc, SourceDecl);
return SourceDecl->getType()->castAs<FunctionProtoType>();
}
@@ -344,8 +348,8 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
ExceptionSpecificationType NewEST = New->getExceptionSpecType();
- assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&
- OldEST != EST_Uninstantiated && NewEST != EST_Uninstantiated &&
+ assert(!isUnresolvedExceptionSpec(OldEST) &&
+ !isUnresolvedExceptionSpec(NewEST) &&
"Shouldn't see unknown exception specifications here");
// Shortcut the case where both have no spec.
@@ -542,8 +546,8 @@ bool Sema::CheckExceptionSpecSubset(
ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
- assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&
- SuperEST != EST_Uninstantiated && SubEST != EST_Uninstantiated &&
+ assert(!isUnresolvedExceptionSpec(SuperEST) &&
+ !isUnresolvedExceptionSpec(SubEST) &&
"Shouldn't see unknown exception specifications here");
// It does not. If the subset contains everything, we've failed.
@@ -806,15 +810,6 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E,
if (!FT)
return CT_Can;
- if (FT->getExceptionSpecType() == EST_Delayed) {
- // FIXME: Try to resolve a delayed exception spec in ResolveExceptionSpec.
- assert(isa<CXXConstructorDecl>(D) &&
- "only constructor exception specs can be unknown");
- S.Diag(E->getLocStart(), diag::err_exception_spec_unknown)
- << E->getSourceRange();
- return CT_Can;
- }
-
return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;
}
@@ -964,7 +959,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
// possibility.
case Expr::ObjCArrayLiteralClass:
case Expr::ObjCDictionaryLiteralClass:
- case Expr::ObjCNumericLiteralClass:
+ case Expr::ObjCBoxedExprClass:
return CT_Can;
// Many other things have subexpressions, so we have to test those.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d2e0e6b..6a503ee 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -130,6 +130,77 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
<< 1 << Decl->isDeleted();
}
+/// \brief Determine whether a FunctionDecl was ever declared with an
+/// explicit storage class.
+static bool hasAnyExplicitStorageClass(const FunctionDecl *D) {
+ for (FunctionDecl::redecl_iterator I = D->redecls_begin(),
+ E = D->redecls_end();
+ I != E; ++I) {
+ if (I->getStorageClassAsWritten() != SC_None)
+ return true;
+ }
+ return false;
+}
+
+/// \brief Check whether we're in an extern inline function and referring to a
+/// variable or function with internal linkage (C11 6.7.4p3).
+///
+/// This is only a warning because we used to silently accept this code, but
+/// in many cases it will not behave correctly. This is not enabled in C++ mode
+/// because the restriction language is a bit weaker (C++11 [basic.def.odr]p6)
+/// and so while there may still be user mistakes, most of the time we can't
+/// prove that there are errors.
+static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S,
+ const NamedDecl *D,
+ SourceLocation Loc) {
+ // This is disabled under C++; there are too many ways for this to fire in
+ // contexts where the warning is a false positive, or where it is technically
+ // correct but benign.
+ if (S.getLangOpts().CPlusPlus)
+ return;
+
+ // Check if this is an inlined function or method.
+ FunctionDecl *Current = S.getCurFunctionDecl();
+ if (!Current)
+ return;
+ if (!Current->isInlined())
+ return;
+ if (Current->getLinkage() != ExternalLinkage)
+ return;
+
+ // Check if the decl has internal linkage.
+ if (D->getLinkage() != InternalLinkage)
+ return;
+
+ // Downgrade from ExtWarn to Extension if
+ // (1) the supposedly external inline function is in the main file,
+ // and probably won't be included anywhere else.
+ // (2) the thing we're referencing is a pure function.
+ // (3) the thing we're referencing is another inline function.
+ // This last can give us false negatives, but it's better than warning on
+ // wrappers for simple C library functions.
+ const FunctionDecl *UsedFn = dyn_cast<FunctionDecl>(D);
+ bool DowngradeWarning = S.getSourceManager().isFromMainFile(Loc);
+ if (!DowngradeWarning && UsedFn)
+ DowngradeWarning = UsedFn->isInlined() || UsedFn->hasAttr<ConstAttr>();
+
+ S.Diag(Loc, DowngradeWarning ? diag::ext_internal_in_extern_inline
+ : diag::warn_internal_in_extern_inline)
+ << /*IsVar=*/!UsedFn << D;
+
+ // Suggest "static" on the inline function, if possible.
+ if (!hasAnyExplicitStorageClass(Current)) {
+ const FunctionDecl *FirstDecl = Current->getCanonicalDecl();
+ SourceLocation DeclBegin = FirstDecl->getSourceRange().getBegin();
+ S.Diag(DeclBegin, diag::note_convert_inline_to_static)
+ << Current << FixItHint::CreateInsertion(DeclBegin, "static ");
+ }
+
+ S.Diag(D->getCanonicalDecl()->getLocation(),
+ diag::note_internal_decl_declared_here)
+ << D;
+}
+
/// \brief Determine whether the use of this declaration is valid, and
/// emit any corresponding diagnostics.
///
@@ -182,6 +253,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
// Warn if this is used but marked unused.
if (D->hasAttr<UnusedAttr>())
Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
+
+ diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
+
return false;
}
@@ -510,8 +584,7 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
// is a prvalue for the temporary.
// FIXME: add some way to gate this entire thing for correctness in
// potentially potentially evaluated contexts.
- if (getLangOpts().CPlusPlus && E->isGLValue() &&
- ExprEvalContexts.back().Context != Unevaluated) {
+ if (getLangOpts().CPlusPlus && E->isGLValue() && !isUnevaluatedContext()) {
ExprResult Temp = PerformCopyInitialization(
InitializedEntity::InitializeTemporary(E->getType()),
E->getExprLoc(),
@@ -524,9 +597,66 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
return Owned(E);
}
+/// Determine the degree of POD-ness for an expression.
+/// Incomplete types are considered POD, since this check can be performed
+/// when we're in an unevaluated context.
+Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
+ if (Ty->isIncompleteType()) {
+ if (Ty->isObjCObjectType())
+ return VAK_Invalid;
+ return VAK_Valid;
+ }
+
+ if (Ty.isCXX98PODType(Context))
+ return VAK_Valid;
+
+ // C++0x [expr.call]p7:
+ // Passing a potentially-evaluated argument of class type (Clause 9)
+ // having a non-trivial copy constructor, a non-trivial move constructor,
+ // or a non-trivial destructor, with no corresponding parameter,
+ // is conditionally-supported with implementation-defined semantics.
+ if (getLangOpts().CPlusPlus0x && !Ty->isDependentType())
+ if (CXXRecordDecl *Record = Ty->getAsCXXRecordDecl())
+ if (Record->hasTrivialCopyConstructor() &&
+ Record->hasTrivialMoveConstructor() &&
+ Record->hasTrivialDestructor())
+ return VAK_ValidInCXX11;
+
+ if (getLangOpts().ObjCAutoRefCount && Ty->isObjCLifetimeType())
+ return VAK_Valid;
+ return VAK_Invalid;
+}
+
+bool Sema::variadicArgumentPODCheck(const Expr *E, VariadicCallType CT) {
+ // Don't allow one to pass an Objective-C interface to a vararg.
+ const QualType & Ty = E->getType();
+
+ // Complain about passing non-POD types through varargs.
+ switch (isValidVarArgType(Ty)) {
+ case VAK_Valid:
+ break;
+ case VAK_ValidInCXX11:
+ DiagRuntimeBehavior(E->getLocStart(), 0,
+ PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg)
+ << E->getType() << CT);
+ break;
+ case VAK_Invalid: {
+ if (Ty->isObjCObjectType())
+ return DiagRuntimeBehavior(E->getLocStart(), 0,
+ PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
+ << Ty << CT);
+
+ return DiagRuntimeBehavior(E->getLocStart(), 0,
+ PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
+ << getLangOpts().CPlusPlus0x << Ty << CT);
+ }
+ }
+ // c++ rules are enforced elsewhere.
+ return false;
+}
+
/// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
-/// will warn if the resulting type is not a POD type, and rejects ObjC
-/// interfaces passed by value.
+/// will create a trap if the resulting type is not a POD type.
ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
FunctionDecl *FDecl) {
if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) {
@@ -550,76 +680,38 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
return ExprError();
E = ExprRes.take();
- // Don't allow one to pass an Objective-C interface to a vararg.
- if (E->getType()->isObjCObjectType() &&
- DiagRuntimeBehavior(E->getLocStart(), 0,
- PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
- << E->getType() << CT))
- return ExprError();
-
- // Complain about passing non-POD types through varargs. However, don't
- // perform this check for incomplete types, which we can get here when we're
- // in an unevaluated context.
- if (!E->getType()->isIncompleteType() && !E->getType().isPODType(Context)) {
- // C++0x [expr.call]p7:
- // Passing a potentially-evaluated argument of class type (Clause 9)
- // having a non-trivial copy constructor, a non-trivial move constructor,
- // or a non-trivial destructor, with no corresponding parameter,
- // is conditionally-supported with implementation-defined semantics.
- bool TrivialEnough = false;
- if (getLangOpts().CPlusPlus0x && !E->getType()->isDependentType()) {
- if (CXXRecordDecl *Record = E->getType()->getAsCXXRecordDecl()) {
- if (Record->hasTrivialCopyConstructor() &&
- Record->hasTrivialMoveConstructor() &&
- Record->hasTrivialDestructor()) {
- DiagRuntimeBehavior(E->getLocStart(), 0,
- PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg)
- << E->getType() << CT);
- TrivialEnough = true;
- }
- }
- }
+ // Diagnostics regarding non-POD argument types are
+ // emitted along with format string checking in Sema::CheckFunctionCall().
+ if (isValidVarArgType(E->getType()) == VAK_Invalid) {
+ // Turn this into a trap.
+ CXXScopeSpec SS;
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId Name;
+ Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
+ E->getLocStart());
+ ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc,
+ Name, true, false);
+ if (TrapFn.isInvalid())
+ return ExprError();
- if (!TrivialEnough &&
- getLangOpts().ObjCAutoRefCount &&
- E->getType()->isObjCLifetimeType())
- TrivialEnough = true;
-
- if (TrivialEnough) {
- // Nothing to diagnose. This is okay.
- } else if (DiagRuntimeBehavior(E->getLocStart(), 0,
- PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << getLangOpts().CPlusPlus0x << E->getType()
- << CT)) {
- // Turn this into a trap.
- CXXScopeSpec SS;
- SourceLocation TemplateKWLoc;
- UnqualifiedId Name;
- Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
- E->getLocStart());
- ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, Name,
- true, false);
- if (TrapFn.isInvalid())
- return ExprError();
+ ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(),
+ E->getLocStart(), MultiExprArg(),
+ E->getLocEnd());
+ if (Call.isInvalid())
+ return ExprError();
- ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), E->getLocStart(),
- MultiExprArg(), E->getLocEnd());
- if (Call.isInvalid())
- return ExprError();
-
- ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma,
- Call.get(), E);
- if (Comma.isInvalid())
- return ExprError();
- E = Comma.get();
- }
+ ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma,
+ Call.get(), E);
+ if (Comma.isInvalid())
+ return ExprError();
+ return Comma.get();
}
- // c++ rules are enforced elsewhere.
+
if (!getLangOpts().CPlusPlus &&
RequireCompleteType(E->getExprLoc(), E->getType(),
diag::err_call_incomplete_argument))
return ExprError();
-
+
return Owned(E);
}
@@ -942,6 +1034,10 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
QualType RHSType =
Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType();
+ // For conversion purposes, we ignore any atomic qualifier on the LHS.
+ if (const AtomicType *AtomicLHS = LHSType->getAs<AtomicType>())
+ LHSType = AtomicLHS->getValueType();
+
// If both types are identical, no conversion is needed.
if (LHSType == RHSType)
return LHSType;
@@ -949,7 +1045,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
// If either side is a non-arithmetic type (e.g. a pointer), we are done.
// The caller can deal with this (e.g. pointer + int).
if (!LHSType->isArithmeticType() || !RHSType->isArithmeticType())
- return LHSType;
+ return QualType();
// Apply unary and bitfield promotions to the LHS's type.
QualType LHSUnpromotedType = LHSType;
@@ -1370,7 +1466,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// unqualified lookup. This is useful when (for example) the
// original lookup would not have found something because it was a
// dependent name.
- DeclContext *DC = SS.isEmpty() ? CurContext : 0;
+ DeclContext *DC = (SS.isEmpty() && !CallsUndergoingInstantiation.empty())
+ ? CurContext : 0;
while (DC) {
if (isa<CXXRecordDecl>(DC)) {
LookupQualifiedName(R, DC);
@@ -1394,42 +1491,44 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// Give a code modification hint to insert 'this->'.
// TODO: fixit for inserting 'Base<T>::' in the other cases.
// Actually quite difficult!
+ if (getLangOpts().MicrosoftMode)
+ diagnostic = diag::warn_found_via_dependent_bases_lookup;
if (isInstance) {
+ Diag(R.getNameLoc(), diagnostic) << Name
+ << FixItHint::CreateInsertion(R.getNameLoc(), "this->");
UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(
CallsUndergoingInstantiation.back()->getCallee());
- CXXMethodDecl *DepMethod = cast_or_null<CXXMethodDecl>(
- CurMethod->getInstantiatedFromMemberFunction());
- if (DepMethod) {
- if (getLangOpts().MicrosoftMode)
- diagnostic = diag::warn_found_via_dependent_bases_lookup;
- Diag(R.getNameLoc(), diagnostic) << Name
- << FixItHint::CreateInsertion(R.getNameLoc(), "this->");
- QualType DepThisType = DepMethod->getThisType(Context);
- CheckCXXThisCapture(R.getNameLoc());
- CXXThisExpr *DepThis = new (Context) CXXThisExpr(
- R.getNameLoc(), DepThisType, false);
- TemplateArgumentListInfo TList;
- if (ULE->hasExplicitTemplateArgs())
- ULE->copyTemplateArgumentsInto(TList);
-
- CXXScopeSpec SS;
- SS.Adopt(ULE->getQualifierLoc());
- CXXDependentScopeMemberExpr *DepExpr =
- CXXDependentScopeMemberExpr::Create(
- Context, DepThis, DepThisType, true, SourceLocation(),
- SS.getWithLocInContext(Context),
- ULE->getTemplateKeywordLoc(), 0,
- R.getLookupNameInfo(),
- ULE->hasExplicitTemplateArgs() ? &TList : 0);
- CallsUndergoingInstantiation.back()->setCallee(DepExpr);
- } else {
- // FIXME: we should be able to handle this case too. It is correct
- // to add this-> here. This is a workaround for PR7947.
- Diag(R.getNameLoc(), diagnostic) << Name;
- }
+
+
+ CXXMethodDecl *DepMethod;
+ if (CurMethod->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization)
+ DepMethod = cast<CXXMethodDecl>(CurMethod->getPrimaryTemplate()->
+ getInstantiatedFromMemberTemplate()->getTemplatedDecl());
+ else
+ DepMethod = cast<CXXMethodDecl>(
+ CurMethod->getInstantiatedFromMemberFunction());
+ assert(DepMethod && "No template pattern found");
+
+ QualType DepThisType = DepMethod->getThisType(Context);
+ CheckCXXThisCapture(R.getNameLoc());
+ CXXThisExpr *DepThis = new (Context) CXXThisExpr(
+ R.getNameLoc(), DepThisType, false);
+ TemplateArgumentListInfo TList;
+ if (ULE->hasExplicitTemplateArgs())
+ ULE->copyTemplateArgumentsInto(TList);
+
+ CXXScopeSpec SS;
+ SS.Adopt(ULE->getQualifierLoc());
+ CXXDependentScopeMemberExpr *DepExpr =
+ CXXDependentScopeMemberExpr::Create(
+ Context, DepThis, DepThisType, true, SourceLocation(),
+ SS.getWithLocInContext(Context),
+ ULE->getTemplateKeywordLoc(), 0,
+ R.getLookupNameInfo(),
+ ULE->hasExplicitTemplateArgs() ? &TList : 0);
+ CallsUndergoingInstantiation.back()->setCallee(DepExpr);
} else {
- if (getLangOpts().MicrosoftMode)
- diagnostic = diag::warn_found_via_dependent_bases_lookup;
Diag(R.getNameLoc(), diagnostic) << Name;
}
@@ -1862,6 +1961,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
return ExprError();
MarkAnyDeclReferenced(Loc, IV);
+
+ ObjCMethodFamily MF = CurMethod->getMethodFamily();
+ if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize)
+ Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
return Owned(new (Context)
ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.take(), true, true));
@@ -2303,7 +2406,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// FIXME: Does the addition of const really only apply in
// potentially-evaluated contexts? Since the variable isn't actually
// captured in an unevaluated context, it seems that the answer is no.
- if (ExprEvalContexts.back().Context != Sema::Unevaluated) {
+ if (!isUnevaluatedContext()) {
QualType CapturedType = getCapturedDeclRefType(cast<VarDecl>(VD), Loc);
if (!CapturedType.isNull())
type = CapturedType;
@@ -2381,6 +2484,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
default: llvm_unreachable("Unknown simple primary expr!");
case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2]
case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break;
+ case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break;
case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break;
}
@@ -2402,7 +2506,10 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
llvm::APInt LengthI(32, Length + 1);
- ResTy = Context.CharTy.withConst();
+ if (IT == PredefinedExpr::LFunction)
+ ResTy = Context.WCharTy.withConst();
+ else
+ ResTy = Context.CharTy.withConst();
ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
}
return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
@@ -2603,7 +2710,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
llvm::APSInt Value(CharBits, CharIsUnsigned);
for (unsigned I = 0, N = Literal.getUDSuffixOffset(); I != N; ++I) {
Value = ThisTokBegin[I];
- TemplateArgument Arg(Value, Context.CharTy);
+ TemplateArgument Arg(Context, Value, Context.CharTy);
TemplateArgumentLocInfo ArgInfo;
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
}
@@ -2647,7 +2754,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
diag::warn_cxx98_compat_longlong : diag::ext_longlong);
// Get the value in the widest-possible width.
- llvm::APInt ResultVal(Context.getTargetInfo().getIntMaxTWidth(), 0);
+ unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth();
+ // The microsoft literal suffix extensions support 128-bit literals, which
+ // may be wider than [u]intmax_t.
+ if (Literal.isMicrosoftInteger && MaxWidth < 128)
+ MaxWidth = 128;
+ llvm::APInt ResultVal(MaxWidth, 0);
if (Literal.GetIntegerValue(ResultVal)) {
// If this value didn't fit into uintmax_t, warn and force to ull.
@@ -2695,7 +2807,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
}
}
- // Finally, check long long if needed.
+ // Check long long if needed.
if (Ty.isNull()) {
unsigned LongLongSize = Context.getTargetInfo().getLongLongWidth();
@@ -2712,6 +2824,16 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Width = LongLongSize;
}
}
+
+ // If it doesn't fit in unsigned long long, and we're using Microsoft
+ // extensions, then its a 128-bit integer literal.
+ if (Ty.isNull() && Literal.isMicrosoftInteger) {
+ if (Literal.isUnsigned)
+ Ty = Context.UnsignedInt128Ty;
+ else
+ Ty = Context.Int128Ty;
+ Width = 128;
+ }
// If we still couldn't decide a type, we probably have something that
// does not fit in a signed long long, but has no U suffix.
@@ -2783,8 +2905,9 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T,
SourceLocation Loc,
SourceRange ArgRange,
UnaryExprOrTypeTrait TraitKind) {
- // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
- if (S.LangOpts.ObjCNonFragileABI && T->isObjCObjectType()) {
+ // Reject sizeof(interface) and sizeof(interface<proto>) if the
+ // runtime doesn't allow it.
+ if (!S.LangOpts.ObjCRuntime.allowsSizeofAlignof() && T->isObjCObjectType()) {
S.Diag(Loc, diag::err_sizeof_nonfragile_interface)
<< T << (TraitKind == UETT_SizeOf)
<< ArgRange;
@@ -2822,9 +2945,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
return false;
if (RequireCompleteExprType(E,
- PDiag(diag::err_sizeof_alignof_incomplete_type)
- << ExprKind << E->getSourceRange(),
- std::make_pair(SourceLocation(), PDiag(0))))
+ diag::err_sizeof_alignof_incomplete_type,
+ ExprKind, E->getSourceRange()))
return true;
// Completeing the expression's type may have changed it.
@@ -2891,8 +3013,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
return false;
if (RequireCompleteType(OpLoc, ExprType,
- PDiag(diag::err_sizeof_alignof_incomplete_type)
- << ExprKind << ExprRange))
+ diag::err_sizeof_alignof_incomplete_type,
+ ExprKind, ExprRange))
return true;
if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange,
@@ -3075,6 +3197,22 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
return BuildUnaryOp(S, OpLoc, Opc, Input);
}
+/// \brief Diagnose if arithmetic on the given ObjC pointer is illegal.
+///
+/// \return true on error
+static bool checkArithmeticOnObjCPointer(Sema &S,
+ SourceLocation opLoc,
+ Expr *op) {
+ assert(op->getType()->isObjCObjectPointerType());
+ if (S.LangOpts.ObjCRuntime.allowsPointerArithmetic())
+ return false;
+
+ S.Diag(opLoc, diag::err_arithmetic_nonfragile_interface)
+ << op->getType()->castAs<ObjCObjectPointerType>()->getPointeeType()
+ << op->getSourceRange();
+ return true;
+}
+
ExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc) {
@@ -3105,7 +3243,6 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
return CreateBuiltinArraySubscriptExpr(Base, LLoc, Idx, RLoc);
}
-
ExprResult
Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc) {
@@ -3143,13 +3280,21 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
IndexExpr = RHSExp;
ResultType = PTy->getPointeeType();
} else if (const ObjCObjectPointerType *PTy =
- LHSTy->getAs<ObjCObjectPointerType>()) {
+ LHSTy->getAs<ObjCObjectPointerType>()) {
BaseExpr = LHSExp;
IndexExpr = RHSExp;
- Result = BuildObjCSubscriptExpression(RLoc, BaseExpr, IndexExpr, 0, 0);
- if (!Result.isInvalid())
- return Owned(Result.take());
+
+ // Use custom logic if this should be the pseudo-object subscript
+ // expression.
+ if (!LangOpts.ObjCRuntime.isSubscriptPointerArithmetic())
+ return BuildObjCSubscriptExpression(RLoc, BaseExpr, IndexExpr, 0, 0);
+
ResultType = PTy->getPointeeType();
+ if (!LangOpts.ObjCRuntime.allowsPointerArithmetic()) {
+ Diag(LLoc, diag::err_subscript_nonfragile_interface)
+ << ResultType << BaseExpr->getSourceRange();
+ return ExprError();
+ }
} else if (const PointerType *PTy = RHSTy->getAs<PointerType>()) {
// Handle the uncommon case of "123[Ptr]".
BaseExpr = RHSExp;
@@ -3161,6 +3306,11 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
BaseExpr = RHSExp;
IndexExpr = LHSExp;
ResultType = PTy->getPointeeType();
+ if (!LangOpts.ObjCRuntime.allowsPointerArithmetic()) {
+ Diag(LLoc, diag::err_subscript_nonfragile_interface)
+ << ResultType << BaseExpr->getSourceRange();
+ return ExprError();
+ }
} else if (const VectorType *VTy = LHSTy->getAs<VectorType>()) {
BaseExpr = LHSExp; // vectors: V[123]
IndexExpr = RHSExp;
@@ -3230,16 +3380,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
if (!ResultType.hasQualifiers()) VK = VK_RValue;
} else if (!ResultType->isDependentType() &&
RequireCompleteType(LLoc, ResultType,
- PDiag(diag::err_subscript_incomplete_type)
- << BaseExpr->getSourceRange()))
- return ExprError();
-
- // Diagnose bad cases where we step over interface counts.
- if (ResultType->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
- Diag(LLoc, diag::err_subscript_nonfragile_interface)
- << ResultType << BaseExpr->getSourceRange();
+ diag::err_subscript_incomplete_type, BaseExpr))
return ExprError();
- }
assert(VK == VK_RValue || LangOpts.CPlusPlus ||
!ResultType.isCForbiddenLValueType());
@@ -3263,14 +3405,20 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
if (Param->hasUninstantiatedDefaultArg()) {
Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
+ EnterExpressionEvaluationContext EvalContext(*this, PotentiallyEvaluated,
+ Param);
+
// Instantiate the expression.
MultiLevelTemplateArgumentList ArgList
= getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true);
std::pair<const TemplateArgument *, unsigned> Innermost
= ArgList.getInnermost();
- InstantiatingTemplate Inst(*this, CallLoc, Param, Innermost.first,
- Innermost.second);
+ InstantiatingTemplate Inst(*this, CallLoc, Param,
+ ArrayRef<TemplateArgument>(Innermost.first,
+ Innermost.second));
+ if (Inst)
+ return ExprError();
ExprResult Result;
{
@@ -3299,9 +3447,10 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
if (Result.isInvalid())
return ExprError();
+ Expr *Arg = Result.takeAs<Expr>();
+ CheckImplicitConversions(Arg, Param->getOuterLocStart());
// Build the default argument expression.
- return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param,
- Result.takeAs<Expr>()));
+ return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, Arg));
}
// If the default expression creates temporaries, we need to
@@ -3331,6 +3480,25 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param));
}
+
+Sema::VariadicCallType
+Sema::getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto,
+ Expr *Fn) {
+ if (Proto && Proto->isVariadic()) {
+ if (dyn_cast_or_null<CXXConstructorDecl>(FDecl))
+ return VariadicConstructor;
+ else if (Fn && Fn->getType()->isBlockPointerType())
+ return VariadicBlock;
+ else if (FDecl) {
+ if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl))
+ if (Method->isInstance())
+ return VariadicMethod;
+ }
+ return VariadicFunction;
+ }
+ return VariadicDoesNotApply;
+}
+
/// ConvertArgumentsForCall - Converts the arguments specified in
/// Args/NumArgs to the parameter types of the function FDecl with
/// function prototype Proto. Call is the call expression itself, and
@@ -3365,11 +3533,18 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// arguments for the remaining parameters), don't make the call.
if (NumArgs < NumArgsInProto) {
if (NumArgs < MinArgs) {
- Diag(RParenLoc, MinArgs == NumArgsInProto
- ? diag::err_typecheck_call_too_few_args
- : diag::err_typecheck_call_too_few_args_at_least)
- << FnKind
- << MinArgs << NumArgs << Fn->getSourceRange();
+ if (MinArgs == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName())
+ Diag(RParenLoc, MinArgs == NumArgsInProto && !Proto->isVariadic()
+ ? diag::err_typecheck_call_too_few_args_one
+ : diag::err_typecheck_call_too_few_args_at_least_one)
+ << FnKind
+ << FDecl->getParamDecl(0) << Fn->getSourceRange();
+ else
+ Diag(RParenLoc, MinArgs == NumArgsInProto && !Proto->isVariadic()
+ ? diag::err_typecheck_call_too_few_args
+ : diag::err_typecheck_call_too_few_args_at_least)
+ << FnKind
+ << MinArgs << NumArgs << Fn->getSourceRange();
// Emit the location of the prototype.
if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
@@ -3385,14 +3560,24 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// them.
if (NumArgs > NumArgsInProto) {
if (!Proto->isVariadic()) {
- Diag(Args[NumArgsInProto]->getLocStart(),
- MinArgs == NumArgsInProto
- ? diag::err_typecheck_call_too_many_args
- : diag::err_typecheck_call_too_many_args_at_most)
- << FnKind
- << NumArgsInProto << NumArgs << Fn->getSourceRange()
- << SourceRange(Args[NumArgsInProto]->getLocStart(),
- Args[NumArgs-1]->getLocEnd());
+ if (NumArgsInProto == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName())
+ Diag(Args[NumArgsInProto]->getLocStart(),
+ MinArgs == NumArgsInProto
+ ? diag::err_typecheck_call_too_many_args_one
+ : diag::err_typecheck_call_too_many_args_at_most_one)
+ << FnKind
+ << FDecl->getParamDecl(0) << NumArgs << Fn->getSourceRange()
+ << SourceRange(Args[NumArgsInProto]->getLocStart(),
+ Args[NumArgs-1]->getLocEnd());
+ else
+ Diag(Args[NumArgsInProto]->getLocStart(),
+ MinArgs == NumArgsInProto
+ ? diag::err_typecheck_call_too_many_args
+ : diag::err_typecheck_call_too_many_args_at_most)
+ << FnKind
+ << NumArgsInProto << NumArgs << Fn->getSourceRange()
+ << SourceRange(Args[NumArgsInProto]->getLocStart(),
+ Args[NumArgs-1]->getLocEnd());
// Emit the location of the prototype.
if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
@@ -3405,12 +3590,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
}
}
SmallVector<Expr *, 8> AllArgs;
- VariadicCallType CallType =
- Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
- if (Fn->getType()->isBlockPointerType())
- CallType = VariadicBlock; // Block
- else if (isa<MemberExpr>(Fn))
- CallType = VariadicMethod;
+ VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn);
+
Invalid = GatherArgumentsForCall(Call->getLocStart(), FDecl,
Proto, 0, Args, NumArgs, AllArgs, CallType);
if (Invalid)
@@ -3448,8 +3629,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
if (RequireCompleteType(Arg->getLocStart(),
ProtoArgType,
- PDiag(diag::err_call_incomplete_argument)
- << Arg->getSourceRange()))
+ diag::err_call_incomplete_argument, Arg))
return true;
// Pass the argument
@@ -3500,7 +3680,6 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
// If this is a variadic call, handle args passed through "...".
if (CallType != VariadicDoesNotApply) {
-
// Assume that extern "C" functions with variadic arguments that
// return __unknown_anytype aren't *really* variadic.
if (Proto->getResultType() == Context.UnknownAnyTy &&
@@ -3763,20 +3942,19 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// Make the call expr early, before semantic checks. This guarantees cleanup
// of arguments and function on error.
CallExpr *TheCall;
- if (Config) {
+ if (Config)
TheCall = new (Context) CUDAKernelCallExpr(Context, Fn,
cast<CallExpr>(Config),
Args, NumArgs,
Context.BoolTy,
VK_RValue,
RParenLoc);
- } else {
+ else
TheCall = new (Context) CallExpr(Context, Fn,
Args, NumArgs,
Context.BoolTy,
VK_RValue,
RParenLoc);
- }
unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
@@ -3839,7 +4017,8 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
TheCall->setType(FuncT->getCallResultType(Context));
TheCall->setValueKind(Expr::getValueKindForType(FuncT->getResultType()));
- if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) {
+ const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT);
+ if (Proto) {
if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs,
RParenLoc, IsExecConfig))
return ExprError();
@@ -3851,8 +4030,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// on our knowledge of the function definition.
const FunctionDecl *Def = 0;
if (FDecl->hasBody(Def) && NumArgs != Def->param_size()) {
- const FunctionProtoType *Proto
- = Def->getType()->getAs<FunctionProtoType>();
+ Proto = Def->getType()->getAs<FunctionProtoType>();
if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size()))
Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
<< (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
@@ -3892,8 +4070,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (RequireCompleteType(Arg->getLocStart(),
Arg->getType(),
- PDiag(diag::err_call_incomplete_argument)
- << Arg->getSourceRange()))
+ diag::err_call_incomplete_argument, Arg))
return ExprError();
TheCall->setArg(i, Arg);
@@ -3911,13 +4088,13 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// Do special checking on direct calls to functions.
if (FDecl) {
- if (CheckFunctionCall(FDecl, TheCall))
+ if (CheckFunctionCall(FDecl, TheCall, Proto))
return ExprError();
if (BuiltinID)
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
} else if (NDecl) {
- if (CheckBlockCall(NDecl, TheCall))
+ if (CheckBlockCall(NDecl, TheCall, Proto))
return ExprError();
}
@@ -3946,18 +4123,17 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
if (literalType->isArrayType()) {
if (RequireCompleteType(LParenLoc, Context.getBaseElementType(literalType),
- PDiag(diag::err_illegal_decl_array_incomplete_type)
- << SourceRange(LParenLoc,
- LiteralExpr->getSourceRange().getEnd())))
+ diag::err_illegal_decl_array_incomplete_type,
+ SourceRange(LParenLoc,
+ LiteralExpr->getSourceRange().getEnd())))
return ExprError();
if (literalType->isVariableArrayType())
return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init)
<< SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()));
} else if (!literalType->isDependentType() &&
RequireCompleteType(LParenLoc, literalType,
- PDiag(diag::err_typecheck_decl_incomplete_type)
- << SourceRange(LParenLoc,
- LiteralExpr->getSourceRange().getEnd())))
+ diag::err_typecheck_decl_incomplete_type,
+ SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd())))
return ExprError();
InitializedEntity Entity
@@ -4054,11 +4230,6 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
// pointers. Everything else should be possible.
QualType SrcTy = Src.get()->getType();
- if (const AtomicType *SrcAtomicTy = SrcTy->getAs<AtomicType>())
- SrcTy = SrcAtomicTy->getValueType();
- if (const AtomicType *DestAtomicTy = DestTy->getAs<AtomicType>())
- DestTy = DestAtomicTy->getValueType();
-
if (Context.hasSameUnqualifiedType(SrcTy, DestTy))
return CK_NoOp;
@@ -4461,7 +4632,10 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
if (NullKind == Expr::NPCK_NotNull)
return false;
- if (NullKind == Expr::NPCK_ZeroInteger) {
+ if (NullKind == Expr::NPCK_ZeroExpression)
+ return false;
+
+ if (NullKind == Expr::NPCK_ZeroLiteral) {
// In this case, check to make sure that we got here from a "NULL"
// string in the source code.
NullExpr = NullExpr->IgnoreParenImpCasts();
@@ -5382,21 +5556,19 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
return Compatible;
}
+ // If we have an atomic type, try a non-atomic assignment, then just add an
+ // atomic qualification step.
if (const AtomicType *AtomicTy = dyn_cast<AtomicType>(LHSType)) {
- if (AtomicTy->getValueType() == RHSType) {
- Kind = CK_NonAtomicToAtomic;
- return Compatible;
- }
- }
-
- if (const AtomicType *AtomicTy = dyn_cast<AtomicType>(RHSType)) {
- if (AtomicTy->getValueType() == LHSType) {
- Kind = CK_AtomicToNonAtomic;
- return Compatible;
- }
+ Sema::AssignConvertType result =
+ CheckAssignmentConstraints(AtomicTy->getValueType(), RHS, Kind);
+ if (result != Compatible)
+ return result;
+ if (Kind != CK_NoOp)
+ RHS = ImpCastExprToType(RHS.take(), AtomicTy->getValueType(), Kind);
+ Kind = CK_NonAtomicToAtomic;
+ return Compatible;
}
-
// If the left-hand side is a reference type, then we are in a
// (rare!) case where we've allowed the use of references in C,
// e.g., as a parameter type in a built-in function. In this case,
@@ -5936,14 +6108,8 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
return QualType();
- if (!LHS.get()->getType()->isArithmeticType() ||
- !RHS.get()->getType()->isArithmeticType()) {
- if (IsCompAssign &&
- LHS.get()->getType()->isAtomicType() &&
- RHS.get()->getType()->isArithmeticType())
- return compType;
+ if (compType.isNull() || !compType->isArithmeticType())
return InvalidOperands(Loc, LHS, RHS);
- }
// Check for division by zero.
if (IsDiv &&
@@ -5971,8 +6137,7 @@ QualType Sema::CheckRemainderOperands(
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
- if (!LHS.get()->getType()->isIntegerType() ||
- !RHS.get()->getType()->isIntegerType())
+ if (compType.isNull() || !compType->isIntegerType())
return InvalidOperands(Loc, LHS, RHS);
// Check for remainder by zero.
@@ -6036,17 +6201,12 @@ static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
/// \returns True if pointer has incomplete type
static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc,
Expr *Operand) {
- if ((Operand->getType()->isPointerType() &&
- !Operand->getType()->isDependentType()) ||
- Operand->getType()->isObjCObjectPointerType()) {
- QualType PointeeTy = Operand->getType()->getPointeeType();
- if (S.RequireCompleteType(
- Loc, PointeeTy,
- S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
- << PointeeTy << Operand->getSourceRange()))
- return true;
- }
- return false;
+ assert(Operand->getType()->isAnyPointerType() &&
+ !Operand->getType()->isDependentType());
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ return S.RequireCompleteType(Loc, PointeeTy,
+ diag::err_typecheck_arithmetic_incomplete_type,
+ PointeeTy, Operand->getSourceRange());
}
/// \brief Check the validity of an arithmetic pointer operand.
@@ -6117,26 +6277,14 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
return !S.getLangOpts().CPlusPlus;
}
- if (checkArithmeticIncompletePointerType(S, Loc, LHSExpr)) return false;
- if (checkArithmeticIncompletePointerType(S, Loc, RHSExpr)) return false;
+ if (isLHSPointer && checkArithmeticIncompletePointerType(S, Loc, LHSExpr))
+ return false;
+ if (isRHSPointer && checkArithmeticIncompletePointerType(S, Loc, RHSExpr))
+ return false;
return true;
}
-/// \brief Check bad cases where we step over interface counts.
-static bool checkArithmethicPointerOnNonFragileABI(Sema &S,
- SourceLocation OpLoc,
- Expr *Op) {
- assert(Op->getType()->isAnyPointerType());
- QualType PointeeTy = Op->getType()->getPointeeType();
- if (!PointeeTy->isObjCObjectType() || !S.LangOpts.ObjCNonFragileABI)
- return true;
-
- S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
- << PointeeTy << Op->getSourceRange();
- return false;
-}
-
/// diagnoseStringPlusInt - Emit a warning when adding an integer to a string
/// literal.
static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc,
@@ -6208,25 +6356,31 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
diagnoseStringPlusInt(*this, Loc, LHS.get(), RHS.get());
// handle the common case first (both operands are arithmetic).
- if (LHS.get()->getType()->isArithmeticType() &&
- RHS.get()->getType()->isArithmeticType()) {
+ if (!compType.isNull() && compType->isArithmeticType()) {
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
- if (LHS.get()->getType()->isAtomicType() &&
- RHS.get()->getType()->isArithmeticType()) {
- *CompLHSTy = LHS.get()->getType();
- return compType;
- }
+ // Type-checking. Ultimately the pointer's going to be in PExp;
+ // note that we bias towards the LHS being the pointer.
+ Expr *PExp = LHS.get(), *IExp = RHS.get();
- // Put any potential pointer into PExp
- Expr* PExp = LHS.get(), *IExp = RHS.get();
- if (IExp->getType()->isAnyPointerType())
+ bool isObjCPointer;
+ if (PExp->getType()->isPointerType()) {
+ isObjCPointer = false;
+ } else if (PExp->getType()->isObjCObjectPointerType()) {
+ isObjCPointer = true;
+ } else {
std::swap(PExp, IExp);
-
- if (!PExp->getType()->isAnyPointerType())
- return InvalidOperands(Loc, LHS, RHS);
+ if (PExp->getType()->isPointerType()) {
+ isObjCPointer = false;
+ } else if (PExp->getType()->isObjCObjectPointerType()) {
+ isObjCPointer = true;
+ } else {
+ return InvalidOperands(Loc, LHS, RHS);
+ }
+ }
+ assert(PExp->getType()->isAnyPointerType());
if (!IExp->getType()->isIntegerType())
return InvalidOperands(Loc, LHS, RHS);
@@ -6234,8 +6388,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
return QualType();
- // Diagnose bad cases where we step over interface counts.
- if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, PExp))
+ if (isObjCPointer && checkArithmeticOnObjCPointer(*this, Loc, PExp))
return QualType();
// Check array bounds for pointer arithemtic
@@ -6274,24 +6427,18 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
// Enforce type constraints: C99 6.5.6p3.
// Handle the common case first (both operands are arithmetic).
- if (LHS.get()->getType()->isArithmeticType() &&
- RHS.get()->getType()->isArithmeticType()) {
+ if (!compType.isNull() && compType->isArithmeticType()) {
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
- if (LHS.get()->getType()->isAtomicType() &&
- RHS.get()->getType()->isArithmeticType()) {
- *CompLHSTy = LHS.get()->getType();
- return compType;
- }
-
// Either ptr - int or ptr - ptr.
if (LHS.get()->getType()->isAnyPointerType()) {
QualType lpointee = LHS.get()->getType()->getPointeeType();
// Diagnose bad cases where we step over interface counts.
- if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, LHS.get()))
+ if (LHS.get()->getType()->isObjCObjectPointerType() &&
+ checkArithmeticOnObjCPointer(*this, Loc, LHS.get()))
return QualType();
// The result type of a pointer-int computation is the pointer type.
@@ -6560,6 +6707,163 @@ static void diagnoseFunctionPointerToVoidComparison(Sema &S, SourceLocation Loc,
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
+static bool isObjCObjectLiteral(ExprResult &E) {
+ switch (E.get()->getStmtClass()) {
+ case Stmt::ObjCArrayLiteralClass:
+ case Stmt::ObjCDictionaryLiteralClass:
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::ObjCBoxedExprClass:
+ return true;
+ default:
+ // Note that ObjCBoolLiteral is NOT an object literal!
+ return false;
+ }
+}
+
+static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
+ // Get the LHS object's interface type.
+ QualType Type = LHS->getType();
+ QualType InterfaceType;
+ if (const ObjCObjectPointerType *PTy = Type->getAs<ObjCObjectPointerType>()) {
+ InterfaceType = PTy->getPointeeType();
+ if (const ObjCObjectType *iQFaceTy =
+ InterfaceType->getAsObjCQualifiedInterfaceType())
+ InterfaceType = iQFaceTy->getBaseType();
+ } else {
+ // If this is not actually an Objective-C object, bail out.
+ return false;
+ }
+
+ // If the RHS isn't an Objective-C object, bail out.
+ if (!RHS->getType()->isObjCObjectPointerType())
+ return false;
+
+ // Try to find the -isEqual: method.
+ Selector IsEqualSel = S.NSAPIObj->getIsEqualSelector();
+ ObjCMethodDecl *Method = S.LookupMethodInObjectType(IsEqualSel,
+ InterfaceType,
+ /*instance=*/true);
+ if (!Method) {
+ if (Type->isObjCIdType()) {
+ // For 'id', just check the global pool.
+ Method = S.LookupInstanceMethodInGlobalPool(IsEqualSel, SourceRange(),
+ /*receiverId=*/true,
+ /*warn=*/false);
+ } else {
+ // Check protocols.
+ Method = S.LookupMethodInQualifiedType(IsEqualSel,
+ cast<ObjCObjectPointerType>(Type),
+ /*instance=*/true);
+ }
+ }
+
+ if (!Method)
+ return false;
+
+ QualType T = Method->param_begin()[0]->getType();
+ if (!T->isObjCObjectPointerType())
+ return false;
+
+ QualType R = Method->getResultType();
+ if (!R->isScalarType())
+ return false;
+
+ return true;
+}
+
+static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc,
+ ExprResult &LHS, ExprResult &RHS,
+ BinaryOperator::Opcode Opc){
+ Expr *Literal;
+ Expr *Other;
+ if (isObjCObjectLiteral(LHS)) {
+ Literal = LHS.get();
+ Other = RHS.get();
+ } else {
+ Literal = RHS.get();
+ Other = LHS.get();
+ }
+
+ // Don't warn on comparisons against nil.
+ Other = Other->IgnoreParenCasts();
+ if (Other->isNullPointerConstant(S.getASTContext(),
+ Expr::NPC_ValueDependentIsNotNull))
+ return;
+
+ // This should be kept in sync with warn_objc_literal_comparison.
+ // LK_String should always be last, since it has its own warning flag.
+ enum {
+ LK_Array,
+ LK_Dictionary,
+ LK_Numeric,
+ LK_Boxed,
+ LK_String
+ } LiteralKind;
+
+ switch (Literal->getStmtClass()) {
+ case Stmt::ObjCStringLiteralClass:
+ // "string literal"
+ LiteralKind = LK_String;
+ break;
+ case Stmt::ObjCArrayLiteralClass:
+ // "array literal"
+ LiteralKind = LK_Array;
+ break;
+ case Stmt::ObjCDictionaryLiteralClass:
+ // "dictionary literal"
+ LiteralKind = LK_Dictionary;
+ break;
+ case Stmt::ObjCBoxedExprClass: {
+ Expr *Inner = cast<ObjCBoxedExpr>(Literal)->getSubExpr();
+ switch (Inner->getStmtClass()) {
+ case Stmt::IntegerLiteralClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::ObjCBoolLiteralExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ // "numeric literal"
+ LiteralKind = LK_Numeric;
+ break;
+ case Stmt::ImplicitCastExprClass: {
+ CastKind CK = cast<CastExpr>(Inner)->getCastKind();
+ // Boolean literals can be represented by implicit casts.
+ if (CK == CK_IntegralToBoolean || CK == CK_IntegralCast) {
+ LiteralKind = LK_Numeric;
+ break;
+ }
+ // FALLTHROUGH
+ }
+ default:
+ // "boxed expression"
+ LiteralKind = LK_Boxed;
+ break;
+ }
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown Objective-C object literal kind");
+ }
+
+ if (LiteralKind == LK_String)
+ S.Diag(Loc, diag::warn_objc_string_literal_comparison)
+ << Literal->getSourceRange();
+ else
+ S.Diag(Loc, diag::warn_objc_literal_comparison)
+ << LiteralKind << Literal->getSourceRange();
+
+ if (BinaryOperator::isEqualityOp(Opc) &&
+ hasIsEqualMethod(S, LHS.get(), RHS.get())) {
+ SourceLocation Start = LHS.get()->getLocStart();
+ SourceLocation End = S.PP.getLocForEndOfToken(RHS.get()->getLocEnd());
+ SourceRange OpRange(Loc, S.PP.getLocForEndOfToken(Loc));
+
+ S.Diag(Loc, diag::note_objc_literal_comparison_isequal)
+ << FixItHint::CreateInsertion(Start, Opc == BO_EQ ? "[" : "![")
+ << FixItHint::CreateReplacement(OpRange, "isEqual:")
+ << FixItHint::CreateInsertion(End, "]");
+ }
+}
+
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, unsigned OpaqueOpc,
@@ -6884,6 +7188,9 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (!Context.areComparableObjCPointerTypes(LHSType, RHSType))
diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS,
/*isError*/false);
+ if (isObjCObjectLiteral(LHS) || isObjCObjectLiteral(RHS))
+ diagnoseObjCLiteralComparison(*this, Loc, LHS, RHS, Opc);
+
if (LHSIsNull && !RHSIsNull)
LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast);
else
@@ -7037,8 +7344,7 @@ inline QualType Sema::CheckBitwiseOperands(
LHS = LHSResult.take();
RHS = RHSResult.take();
- if (LHS.get()->getType()->isIntegralOrUnscopedEnumerationType() &&
- RHS.get()->getType()->isIntegralOrUnscopedEnumerationType())
+ if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType())
return compType;
return InvalidOperands(Loc, LHS, RHS);
}
@@ -7251,6 +7557,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
break;
case Expr::MLV_ArrayType:
+ case Expr::MLV_ArrayTemporary:
Diag = diag::err_typecheck_array_not_modifiable_lvalue;
NeedType = true;
break;
@@ -7271,8 +7578,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_IncompleteType:
case Expr::MLV_IncompleteVoidType:
return S.RequireCompleteType(Loc, E->getType(),
- S.PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue)
- << E->getSourceRange());
+ diag::err_typecheck_incomplete_type_not_modifiable_lvalue, E);
case Expr::MLV_DuplicateVectorComponents:
Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
break;
@@ -7297,7 +7603,27 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
return true;
}
+static void CheckIdentityFieldAssignment(Expr *LHSExpr, Expr *RHSExpr,
+ SourceLocation Loc,
+ Sema &Sema) {
+ // C / C++ fields
+ MemberExpr *ML = dyn_cast<MemberExpr>(LHSExpr);
+ MemberExpr *MR = dyn_cast<MemberExpr>(RHSExpr);
+ if (ML && MR && ML->getMemberDecl() == MR->getMemberDecl()) {
+ if (isa<CXXThisExpr>(ML->getBase()) && isa<CXXThisExpr>(MR->getBase()))
+ Sema.Diag(Loc, diag::warn_identity_field_assign) << 0;
+ }
+ // Objective-C instance variables
+ ObjCIvarRefExpr *OL = dyn_cast<ObjCIvarRefExpr>(LHSExpr);
+ ObjCIvarRefExpr *OR = dyn_cast<ObjCIvarRefExpr>(RHSExpr);
+ if (OL && OR && OL->getDecl() == OR->getDecl()) {
+ DeclRefExpr *RL = dyn_cast<DeclRefExpr>(OL->getBase()->IgnoreImpCasts());
+ DeclRefExpr *RR = dyn_cast<DeclRefExpr>(OR->getBase()->IgnoreImpCasts());
+ if (RL && RR && RL->getDecl() == RR->getDecl())
+ Sema.Diag(Loc, diag::warn_identity_field_assign) << 1;
+ }
+}
// C99 6.5.16.1
QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
@@ -7314,6 +7640,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
CompoundType;
AssignConvertType ConvTy;
if (CompoundType.isNull()) {
+ Expr *RHSCheck = RHS.get();
+
+ CheckIdentityFieldAssignment(LHSExpr, RHSCheck, Loc, *this);
+
QualType LHSTy(LHSType);
ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
if (RHS.isInvalid())
@@ -7334,7 +7664,6 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// If the RHS is a unary plus or minus, check to see if they = and + are
// right next to each other. If so, the user may have typo'd "x =+ 4"
// instead of "x += 4".
- Expr *RHSCheck = RHS.get();
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RHSCheck))
RHSCheck = ICE->getSubExpr();
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(RHSCheck)) {
@@ -7384,8 +7713,6 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// C99 6.5.17
static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc) {
- S.DiagnoseUnusedExprResult(LHS.get());
-
LHS = S.CheckPlaceholderExpr(LHS.take());
RHS = S.CheckPlaceholderExpr(RHS.take());
if (LHS.isInvalid() || RHS.isInvalid())
@@ -7401,6 +7728,8 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
if (LHS.isInvalid())
return QualType();
+ S.DiagnoseUnusedExprResult(LHS.get());
+
if (!S.getLangOpts().CPlusPlus) {
RHS = S.DefaultFunctionArrayLvalueConversion(RHS.take());
if (RHS.isInvalid())
@@ -7441,14 +7770,16 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
S.Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
} else if (ResType->isRealType()) {
// OK!
- } else if (ResType->isAnyPointerType()) {
+ } else if (ResType->isPointerType()) {
// C99 6.5.2.4p2, 6.5.6p2
if (!checkArithmeticOpPointerOperand(S, OpLoc, Op))
return QualType();
-
- // Diagnose bad cases where we step over interface counts.
- else if (!checkArithmethicPointerOnNonFragileABI(S, OpLoc, Op))
- return QualType();
+ } else if (ResType->isObjCObjectPointerType()) {
+ // On modern runtimes, ObjC pointer arithmetic is forbidden.
+ // Otherwise, we just need a complete type.
+ if (checkArithmeticIncompletePointerType(S, OpLoc, Op) ||
+ checkArithmeticOnObjCPointer(S, OpLoc, Op))
+ return QualType();
} else if (ResType->isAnyComplexType()) {
// C99 does not support ++/-- on complex types, we allow as an extension.
S.Diag(OpLoc, diag::ext_integer_increment_complex)
@@ -8064,7 +8395,7 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
<< DiagRange << BinOp::getOpcodeStr(Opc) << OpStr;
SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_bitwise_silence) << OpStr,
- RHSExpr->getSourceRange());
+ (isLeftComp ? LHSExpr : RHSExpr)->getSourceRange());
SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc),
ParensRange);
@@ -8669,8 +9000,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
// with an incomplete type would be ill-formed.
if (!Dependent
&& RequireCompleteType(BuiltinLoc, ArgTy,
- PDiag(diag::err_offsetof_incomplete_type)
- << TypeRange))
+ diag::err_offsetof_incomplete_type, TypeRange))
return ExprError();
// offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a
@@ -8743,10 +9073,18 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
// The macro offsetof accepts a restricted set of type arguments in this
// International Standard. type shall be a POD structure or a POD union
// (clause 9).
+ // C++11 [support.types]p4:
+ // If type is not a standard-layout class (Clause 9), the results are
+ // undefined.
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
- if (!CRD->isPOD() && !DidWarnAboutNonPOD &&
+ bool IsSafe = LangOpts.CPlusPlus0x? CRD->isStandardLayout() : CRD->isPOD();
+ unsigned DiagID =
+ LangOpts.CPlusPlus0x? diag::warn_offsetof_non_standardlayout_type
+ : diag::warn_offsetof_non_pod_type;
+
+ if (!IsSafe && !DidWarnAboutNonPOD &&
DiagRuntimeBehavior(BuiltinLoc, 0,
- PDiag(diag::warn_offsetof_non_pod_type)
+ PDiag(DiagID)
<< SourceRange(CompPtr[0].LocStart, OC.LocEnd)
<< CurrentType))
DidWarnAboutNonPOD = true;
@@ -8850,8 +9188,9 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
} else {
// The conditional expression is required to be a constant expression.
llvm::APSInt condEval(32);
- ExprResult CondICE = VerifyIntegerConstantExpression(CondExpr, &condEval,
- PDiag(diag::err_typecheck_choose_expr_requires_constant), false);
+ ExprResult CondICE
+ = VerifyIntegerConstantExpression(CondExpr, &condEval,
+ diag::err_typecheck_choose_expr_requires_constant, false);
if (CondICE.isInvalid())
return ExprError();
CondExpr = CondICE.take();
@@ -8892,7 +9231,8 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
PushExpressionEvaluationContext(PotentiallyEvaluated);
}
-void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
+void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
+ Scope *CurScope) {
assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!");
assert(ParamInfo.getContext() == Declarator::BlockLiteralContext);
BlockScopeInfo *CurBlock = getCurBlock();
@@ -8900,6 +9240,18 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo, CurScope);
QualType T = Sig->getType();
+ // FIXME: We should allow unexpanded parameter packs here, but that would,
+ // in turn, make the block expression contain unexpanded parameter packs.
+ if (DiagnoseUnexpandedParameterPack(CaretLoc, Sig, UPPC_Block)) {
+ // Drop the parameters.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.HasTrailingReturn = false;
+ EPI.TypeQuals |= DeclSpec::TQ_const;
+ T = Context.getFunctionType(Context.DependentTy, /*Args=*/0, /*NumArgs=*/0,
+ EPI);
+ Sig = Context.getTrivialTypeSourceInfo(T);
+ }
+
// GetTypeForDeclarator always produces a function type for a block
// literal signature. Furthermore, it is always a FunctionProtoType
// unless the function was written with a typedef.
@@ -9038,7 +9390,10 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
PopExpressionEvaluationContext();
BlockScopeInfo *BSI = cast<BlockScopeInfo>(FunctionScopes.back());
-
+
+ if (BSI->HasImplicitReturnType)
+ deduceClosureReturnType(*BSI);
+
PopDeclContext();
QualType RetTy = Context.VoidTy;
@@ -9111,7 +9466,12 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
BSI->TheDecl->setBody(cast<CompoundStmt>(Body));
- computeNRVO(Body, getCurBlock());
+ // Try to apply the named return value optimization. We have to check again
+ // if we can do this, though, because blocks keep return statements around
+ // to deduce an implicit return type.
+ if (getLangOpts().CPlusPlus && RetTy->isRecordType() &&
+ !BSI->TheDecl->isDependentContext())
+ computeNRVO(Body, getCurBlock());
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
@@ -9182,14 +9542,14 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
if (!TInfo->getType()->isDependentType()) {
if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(),
- PDiag(diag::err_second_parameter_to_va_arg_incomplete)
- << TInfo->getTypeLoc().getSourceRange()))
+ diag::err_second_parameter_to_va_arg_incomplete,
+ TInfo->getTypeLoc()))
return ExprError();
if (RequireNonAbstractType(TInfo->getTypeLoc().getBeginLoc(),
- TInfo->getType(),
- PDiag(diag::err_second_parameter_to_va_arg_abstract)
- << TInfo->getTypeLoc().getSourceRange()))
+ TInfo->getType(),
+ diag::err_second_parameter_to_va_arg_abstract,
+ TInfo->getTypeLoc()))
return ExprError();
if (!TInfo->getType().isPODType(Context)) {
@@ -9291,7 +9651,10 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
bool MayHaveFunctionDiff = false;
switch (ConvTy) {
- case Compatible: return false;
+ case Compatible:
+ DiagnoseAssignmentEnum(DstType, SrcType, SrcExpr);
+ return false;
+
case PointerToInt:
DiagKind = diag::ext_typecheck_convert_pointer_int;
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
@@ -9434,15 +9797,44 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
ExprResult Sema::VerifyIntegerConstantExpression(Expr *E,
llvm::APSInt *Result) {
- return VerifyIntegerConstantExpression(E, Result,
- PDiag(diag::err_expr_not_ice) << LangOpts.CPlusPlus);
+ class SimpleICEDiagnoser : public VerifyICEDiagnoser {
+ public:
+ virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) {
+ S.Diag(Loc, diag::err_expr_not_ice) << S.LangOpts.CPlusPlus << SR;
+ }
+ } Diagnoser;
+
+ return VerifyIntegerConstantExpression(E, Result, Diagnoser);
+}
+
+ExprResult Sema::VerifyIntegerConstantExpression(Expr *E,
+ llvm::APSInt *Result,
+ unsigned DiagID,
+ bool AllowFold) {
+ class IDDiagnoser : public VerifyICEDiagnoser {
+ unsigned DiagID;
+
+ public:
+ IDDiagnoser(unsigned DiagID)
+ : VerifyICEDiagnoser(DiagID == 0), DiagID(DiagID) { }
+
+ virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) {
+ S.Diag(Loc, DiagID) << SR;
+ }
+ } Diagnoser(DiagID);
+
+ return VerifyIntegerConstantExpression(E, Result, Diagnoser, AllowFold);
+}
+
+void Sema::VerifyICEDiagnoser::diagnoseFold(Sema &S, SourceLocation Loc,
+ SourceRange SR) {
+ S.Diag(Loc, diag::ext_expr_not_ice) << SR << S.LangOpts.CPlusPlus;
}
ExprResult
Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
- const PartialDiagnostic &NotIceDiag,
- bool AllowFold,
- const PartialDiagnostic &FoldDiag) {
+ VerifyICEDiagnoser &Diagnoser,
+ bool AllowFold) {
SourceLocation DiagLoc = E->getLocStart();
if (getLangOpts().CPlusPlus0x) {
@@ -9452,23 +9844,111 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
// have a single non-explicit conversion function to an integral or
// unscoped enumeration type
ExprResult Converted;
- if (NotIceDiag.getDiagID()) {
- Converted = ConvertToIntegralOrEnumerationType(
- DiagLoc, E,
- PDiag(diag::err_ice_not_integral),
- PDiag(diag::err_ice_incomplete_type),
- PDiag(diag::err_ice_explicit_conversion),
- PDiag(diag::note_ice_conversion_here),
- PDiag(diag::err_ice_ambiguous_conversion),
- PDiag(diag::note_ice_conversion_here),
- PDiag(0),
- /*AllowScopedEnumerations*/ false);
+ if (!Diagnoser.Suppress) {
+ class CXX11ConvertDiagnoser : public ICEConvertDiagnoser {
+ public:
+ CXX11ConvertDiagnoser() : ICEConvertDiagnoser(false, true) { }
+
+ virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_ice_not_integral) << T;
+ }
+
+ virtual DiagnosticBuilder diagnoseIncomplete(Sema &S,
+ SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_ice_incomplete_type) << T;
+ }
+
+ virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S,
+ SourceLocation Loc,
+ QualType T,
+ QualType ConvTy) {
+ return S.Diag(Loc, diag::err_ice_explicit_conversion) << T << ConvTy;
+ }
+
+ virtual DiagnosticBuilder noteExplicitConv(Sema &S,
+ CXXConversionDecl *Conv,
+ QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+
+ virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_ice_ambiguous_conversion) << T;
+ }
+
+ virtual DiagnosticBuilder noteAmbiguous(Sema &S,
+ CXXConversionDecl *Conv,
+ QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+
+ virtual DiagnosticBuilder diagnoseConversion(Sema &S,
+ SourceLocation Loc,
+ QualType T,
+ QualType ConvTy) {
+ return DiagnosticBuilder::getEmpty();
+ }
+ } ConvertDiagnoser;
+
+ Converted = ConvertToIntegralOrEnumerationType(DiagLoc, E,
+ ConvertDiagnoser,
+ /*AllowScopedEnumerations*/ false);
} else {
// The caller wants to silently enquire whether this is an ICE. Don't
// produce any diagnostics if it isn't.
- Converted = ConvertToIntegralOrEnumerationType(
- DiagLoc, E, PDiag(), PDiag(), PDiag(), PDiag(),
- PDiag(), PDiag(), PDiag(), false);
+ class SilentICEConvertDiagnoser : public ICEConvertDiagnoser {
+ public:
+ SilentICEConvertDiagnoser() : ICEConvertDiagnoser(true, true) { }
+
+ virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return DiagnosticBuilder::getEmpty();
+ }
+
+ virtual DiagnosticBuilder diagnoseIncomplete(Sema &S,
+ SourceLocation Loc,
+ QualType T) {
+ return DiagnosticBuilder::getEmpty();
+ }
+
+ virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S,
+ SourceLocation Loc,
+ QualType T,
+ QualType ConvTy) {
+ return DiagnosticBuilder::getEmpty();
+ }
+
+ virtual DiagnosticBuilder noteExplicitConv(Sema &S,
+ CXXConversionDecl *Conv,
+ QualType ConvTy) {
+ return DiagnosticBuilder::getEmpty();
+ }
+
+ virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return DiagnosticBuilder::getEmpty();
+ }
+
+ virtual DiagnosticBuilder noteAmbiguous(Sema &S,
+ CXXConversionDecl *Conv,
+ QualType ConvTy) {
+ return DiagnosticBuilder::getEmpty();
+ }
+
+ virtual DiagnosticBuilder diagnoseConversion(Sema &S,
+ SourceLocation Loc,
+ QualType T,
+ QualType ConvTy) {
+ return DiagnosticBuilder::getEmpty();
+ }
+ } ConvertDiagnoser;
+
+ Converted = ConvertToIntegralOrEnumerationType(DiagLoc, E,
+ ConvertDiagnoser, false);
}
if (Converted.isInvalid())
return Converted;
@@ -9477,8 +9957,8 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
return ExprError();
} else if (!E->getType()->isIntegralOrUnscopedEnumerationType()) {
// An ICE must be of integral or unscoped enumeration type.
- if (NotIceDiag.getDiagID())
- Diag(DiagLoc, NotIceDiag) << E->getSourceRange();
+ if (!Diagnoser.Suppress)
+ Diagnoser.diagnoseNotICE(*this, DiagLoc, E->getSourceRange());
return ExprError();
}
@@ -9518,8 +9998,8 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
}
if (!Folded || !AllowFold) {
- if (NotIceDiag.getDiagID()) {
- Diag(DiagLoc, NotIceDiag) << E->getSourceRange();
+ if (!Diagnoser.Suppress) {
+ Diagnoser.diagnoseNotICE(*this, DiagLoc, E->getSourceRange());
for (unsigned I = 0, N = Notes.size(); I != N; ++I)
Diag(Notes[I].first, Notes[I].second);
}
@@ -9527,11 +10007,7 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
return ExprError();
}
- if (FoldDiag.getDiagID())
- Diag(DiagLoc, FoldDiag) << E->getSourceRange();
- else
- Diag(DiagLoc, diag::ext_expr_not_ice)
- << E->getSourceRange() << LangOpts.CPlusPlus;
+ Diagnoser.diagnoseFold(*this, DiagLoc, E->getSourceRange());
for (unsigned I = 0, N = Notes.size(); I != N; ++I)
Diag(Notes[I].first, Notes[I].second);
@@ -9569,7 +10045,7 @@ namespace {
// Error on DeclRefExprs referring to FieldDecls.
ExprResult TransformDeclRefExpr(DeclRefExpr *E) {
if (isa<FieldDecl>(E->getDecl()) &&
- SemaRef.ExprEvalContexts.back().Context != Sema::Unevaluated)
+ !SemaRef.isUnevaluatedContext())
return SemaRef.Diag(E->getLocation(),
diag::err_invalid_non_static_member_use)
<< E->getDecl() << E->getSourceRange();
@@ -9774,11 +10250,11 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
// FIXME: Is this really right?
if (CurContext == Func) return;
- // Instantiate the exception specification for any function which is
+ // Resolve the exception specification for any function which is
// used: CodeGen will need it.
const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
- if (FPT && FPT->getExceptionSpecType() == EST_Uninstantiated)
- InstantiateExceptionSpec(Loc, Func);
+ if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
+ ResolveExceptionSpec(Loc, FPT);
// Implicit instantiation of function templates and member functions of
// class templates.
@@ -9891,14 +10367,15 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
VarDecl *Var, QualType FieldType,
QualType DeclRefType,
- SourceLocation Loc) {
+ SourceLocation Loc,
+ bool RefersToEnclosingLocal) {
CXXRecordDecl *Lambda = LSI->Lambda;
// Build the non-static data member.
FieldDecl *Field
= FieldDecl::Create(S.Context, Lambda, Loc, Loc, 0, FieldType,
S.Context.getTrivialTypeSourceInfo(FieldType, Loc),
- 0, false, false);
+ 0, false, ICIS_NoInit);
Field->setImplicit(true);
Field->setAccess(AS_private);
Lambda->addDecl(Field);
@@ -9920,8 +10397,8 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
// C++ [expr.prim.labda]p12:
// An entity captured by a lambda-expression is odr-used (3.2) in
// the scope containing the lambda-expression.
- Expr *Ref = new (S.Context) DeclRefExpr(Var, false, DeclRefType,
- VK_LValue, Loc);
+ Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal,
+ DeclRefType, VK_LValue, Loc);
Var->setReferenced(true);
Var->setUsed(true);
@@ -10264,7 +10741,8 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
Expr *CopyExpr = 0;
if (BuildAndDiagnose) {
ExprResult Result = captureInLambda(*this, LSI, Var, CaptureType,
- DeclRefType, Loc);
+ DeclRefType, Loc,
+ I == N-1);
if (!Result.isInvalid())
CopyExpr = Result.take();
}
@@ -10439,6 +10917,23 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
}
SemaRef.MarkAnyDeclReferenced(Loc, D);
+
+ // If this is a call to a method via a cast, also mark the method in the
+ // derived class used in case codegen can devirtualize the call.
+ const MemberExpr *ME = dyn_cast<MemberExpr>(E);
+ if (!ME)
+ return;
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ME->getMemberDecl());
+ if (!MD)
+ return;
+ const Expr *Base = ME->getBase();
+ const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType();
+ if (!MostDerivedClassDecl)
+ return;
+ CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl);
+ if (!DM)
+ return;
+ SemaRef.MarkAnyDeclReferenced(Loc, DM);
}
/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.
@@ -10645,18 +11140,30 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
return false;
}
- PartialDiagnostic Note =
- FD ? PDiag(diag::note_function_with_incomplete_return_type_declared_here)
- << FD->getDeclName() : PDiag();
- SourceLocation NoteLoc = FD ? FD->getLocation() : SourceLocation();
-
- if (RequireCompleteType(Loc, ReturnType,
- FD ?
- PDiag(diag::err_call_function_incomplete_return)
- << CE->getSourceRange() << FD->getDeclName() :
- PDiag(diag::err_call_incomplete_return)
- << CE->getSourceRange(),
- std::make_pair(NoteLoc, Note)))
+ class CallReturnIncompleteDiagnoser : public TypeDiagnoser {
+ FunctionDecl *FD;
+ CallExpr *CE;
+
+ public:
+ CallReturnIncompleteDiagnoser(FunctionDecl *FD, CallExpr *CE)
+ : FD(FD), CE(CE) { }
+
+ virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) {
+ if (!FD) {
+ S.Diag(Loc, diag::err_call_incomplete_return)
+ << T << CE->getSourceRange();
+ return;
+ }
+
+ S.Diag(Loc, diag::err_call_function_incomplete_return)
+ << CE->getSourceRange() << FD->getDeclName() << T;
+ S.Diag(FD->getLocation(),
+ diag::note_function_with_incomplete_return_type_declared_here)
+ << FD->getDeclName();
+ }
+ } Diagnoser(FD, CE);
+
+ if (RequireCompleteType(Loc, ReturnType, Diagnoser))
return true;
return false;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index af86cb2..2740259 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -6,9 +6,10 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file implements semantic analysis for C++ expressions.
-//
+///
+/// \file
+/// \brief Implements semantic analysis for C++ expressions.
+///
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
@@ -332,7 +333,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
// When typeid is applied to an expression other than an glvalue of a
// polymorphic class type [...] [the] expression is an unevaluated
// operand. [...]
- if (RecordD->isPolymorphic() && E->Classify(Context).isGLValue()) {
+ if (RecordD->isPolymorphic() && E->isGLValue()) {
// The subexpression is potentially evaluated; switch the context
// and recheck the subexpression.
ExprResult Result = TranformToPotentiallyEvaluated(E);
@@ -375,10 +376,20 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName);
LookupQualifiedName(R, getStdNamespace());
CXXTypeInfoDecl = R.getAsSingle<RecordDecl>();
+ // Microsoft's typeinfo doesn't have type_info in std but in the global
+ // namespace if _HAS_EXCEPTIONS is defined to 0. See PR13153.
+ if (!CXXTypeInfoDecl && LangOpts.MicrosoftMode) {
+ LookupQualifiedName(R, Context.getTranslationUnitDecl());
+ CXXTypeInfoDecl = R.getAsSingle<RecordDecl>();
+ }
if (!CXXTypeInfoDecl)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
}
+ if (!getLangOpts().RTTI) {
+ return ExprError(Diag(OpLoc, diag::err_no_typeid_with_fno_rtti));
+ }
+
QualType TypeInfoType = Context.getTypeDeclType(CXXTypeInfoDecl);
if (isType) {
@@ -584,14 +595,13 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
}
if (!isPointer || !Ty->isVoidType()) {
if (RequireCompleteType(ThrowLoc, Ty,
- PDiag(isPointer ? diag::err_throw_incomplete_ptr
- : diag::err_throw_incomplete)
- << E->getSourceRange()))
+ isPointer? diag::err_throw_incomplete_ptr
+ : diag::err_throw_incomplete,
+ E->getSourceRange()))
return ExprError();
if (RequireNonAbstractType(ThrowLoc, E->getType(),
- PDiag(diag::err_throw_abstract_type)
- << E->getSourceRange()))
+ diag::err_throw_abstract_type, E))
return ExprError();
}
@@ -737,7 +747,7 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
FieldDecl *Field
= FieldDecl::Create(Context, Lambda, Loc, Loc, 0, ThisTy,
Context.getTrivialTypeSourceInfo(ThisTy, Loc),
- 0, false, false);
+ 0, false, ICIS_NoInit);
Field->setImplicit(true);
Field->setAccess(AS_private);
Lambda->addDecl(Field);
@@ -839,8 +849,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
if (!Ty->isVoidType() &&
RequireCompleteType(TyBeginLoc, ElemTy,
- PDiag(diag::err_invalid_incomplete_type_use)
- << FullRange))
+ diag::err_invalid_incomplete_type_use, FullRange))
return ExprError();
if (RequireNonAbstractType(TyBeginLoc, Ty,
@@ -932,7 +941,7 @@ static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc,
}
/// \brief Parsed a C++ 'new' expression (C++ 5.3.4).
-
+///
/// E.g.:
/// @code new (memory) int[size][4] @endcode
/// or
@@ -945,10 +954,8 @@ static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc,
/// \param PlacementRParen Closing paren of the placement arguments.
/// \param TypeIdParens If the type is in parens, the source range.
/// \param D The type to be allocated, as well as array dimensions.
-/// \param ConstructorLParen Opening paren of the constructor args, empty if
-/// initializer-list syntax is used.
-/// \param ConstructorArgs Constructor/initialization arguments.
-/// \param ConstructorRParen Closing paren of the constructor args.
+/// \param Initializer The initializing expression or initializer-list, or null
+/// if there is none.
ExprResult
Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
@@ -960,7 +967,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
// If the specified type is an array, unwrap it and save the expression.
if (D.getNumTypeObjects() > 0 &&
D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
- DeclaratorChunk &Chunk = D.getTypeObject(0);
+ DeclaratorChunk &Chunk = D.getTypeObject(0);
if (TypeContainsAuto)
return ExprError(Diag(Chunk.Loc, diag::err_new_array_of_auto)
<< D.getSourceRange());
@@ -984,8 +991,10 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr;
if (Expr *NumElts = (Expr *)Array.NumElts) {
if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) {
- Array.NumElts = VerifyIntegerConstantExpression(NumElts, 0,
- PDiag(diag::err_new_array_nonconst)).take();
+ Array.NumElts
+ = VerifyIntegerConstantExpression(NumElts, 0,
+ diag::err_new_array_nonconst)
+ .take();
if (!Array.NumElts)
return ExprError();
}
@@ -1084,8 +1093,10 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
- if (TypeMayContainAuto && AllocType->getContainedAutoType()) {
+ // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
+ AutoType *AT = 0;
+ if (TypeMayContainAuto &&
+ (AT = AllocType->getContainedAutoType()) && !AT->isDeduced()) {
if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
<< AllocType << TypeRange);
@@ -1101,8 +1112,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
Expr *Deduce = Inits[0];
TypeSourceInfo *DeducedType = 0;
- if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) ==
- DAR_Failed)
+ if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
<< AllocType << Deduce->getType()
<< TypeRange << Deduce->getSourceRange());
@@ -1150,19 +1160,64 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
// enumeration type, or a class type for which a single non-explicit
// conversion function to integral or unscoped enumeration type exists.
if (ArraySize && !ArraySize->isTypeDependent()) {
- ExprResult ConvertedSize = ConvertToIntegralOrEnumerationType(
- StartLoc, ArraySize,
- PDiag(diag::err_array_size_not_integral) << getLangOpts().CPlusPlus0x,
- PDiag(diag::err_array_size_incomplete_type)
- << ArraySize->getSourceRange(),
- PDiag(diag::err_array_size_explicit_conversion),
- PDiag(diag::note_array_size_conversion),
- PDiag(diag::err_array_size_ambiguous_conversion),
- PDiag(diag::note_array_size_conversion),
- PDiag(getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_array_size_conversion :
- diag::ext_array_size_conversion),
- /*AllowScopedEnumerations*/ false);
+ class SizeConvertDiagnoser : public ICEConvertDiagnoser {
+ Expr *ArraySize;
+
+ public:
+ SizeConvertDiagnoser(Expr *ArraySize)
+ : ICEConvertDiagnoser(false, false), ArraySize(ArraySize) { }
+
+ virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_array_size_not_integral)
+ << S.getLangOpts().CPlusPlus0x << T;
+ }
+
+ virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_array_size_incomplete_type)
+ << T << ArraySize->getSourceRange();
+ }
+
+ virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S,
+ SourceLocation Loc,
+ QualType T,
+ QualType ConvTy) {
+ return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy;
+ }
+
+ virtual DiagnosticBuilder noteExplicitConv(Sema &S,
+ CXXConversionDecl *Conv,
+ QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_array_size_conversion)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+
+ virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T;
+ }
+
+ virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
+ QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_array_size_conversion)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+
+ virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
+ QualType T,
+ QualType ConvTy) {
+ return S.Diag(Loc,
+ S.getLangOpts().CPlusPlus0x
+ ? diag::warn_cxx98_compat_array_size_conversion
+ : diag::ext_array_size_conversion)
+ << T << ConvTy->isEnumeralType() << ConvTy;
+ }
+ } SizeDiagnoser(ArraySize);
+
+ ExprResult ConvertedSize
+ = ConvertToIntegralOrEnumerationType(StartLoc, ArraySize, SizeDiagnoser,
+ /*AllowScopedEnumerations*/ false);
if (ConvertedSize.isInvalid())
return ExprError();
@@ -1401,9 +1456,7 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
return Diag(Loc, diag::err_bad_new_type)
<< AllocType << 1 << R;
else if (!AllocType->isDependentType() &&
- RequireCompleteType(Loc, AllocType,
- PDiag(diag::err_new_incomplete_type)
- << R))
+ RequireCompleteType(Loc, AllocType, diag::err_new_incomplete_type,R))
return true;
else if (RequireNonAbstractType(Loc, AllocType,
diag::err_allocation_of_abstract_type))
@@ -2014,7 +2067,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (const RecordType *Record = Type->getAs<RecordType>()) {
if (RequireCompleteType(StartLoc, Type,
- PDiag(diag::err_delete_incomplete_class_type)))
+ diag::err_delete_incomplete_class_type))
return ExprError();
SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions;
@@ -2084,8 +2137,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
<< Type << Ex.get()->getSourceRange());
} else if (!Pointee->isDependentType()) {
if (!RequireCompleteType(StartLoc, Pointee,
- PDiag(diag::warn_delete_incomplete)
- << Ex.get()->getSourceRange())) {
+ diag::warn_delete_incomplete, Ex.get())) {
if (const RecordType *RT = PointeeElem->getAs<RecordType>())
PointeeRD = cast<CXXRecordDecl>(RT->getDecl());
}
@@ -2096,9 +2148,6 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// delete-expression; it is not necessary to cast away the constness
// (5.2.11) of the pointer expression before it is used as the operand
// of the delete-expression. ]
- if (!Context.hasSameType(Ex.get()->getType(), Context.VoidPtrTy))
- Ex = Owned(ImplicitCastExpr::Create(Context, Context.VoidPtrTy,
- CK_BitCast, Ex.take(), 0, VK_RValue));
if (Pointee->isArrayType() && !ArrayForm) {
Diag(StartLoc, diag::warn_delete_array_type)
@@ -2176,6 +2225,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
DeclareGlobalNewDelete();
DeclContext *TUDecl = Context.getTranslationUnitDecl();
Expr *Arg = Ex.get();
+ if (!Context.hasSameType(Arg->getType(), Context.VoidPtrTy))
+ Arg = ImplicitCastExpr::Create(Context, Context.VoidPtrTy,
+ CK_BitCast, Arg, 0, VK_RValue);
if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName,
&Arg, 1, TUDecl, /*AllowMissing=*/false,
OperatorDelete))
@@ -3138,8 +3190,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT)
return false;
- if (CPT->getExceptionSpecType() == EST_Delayed)
- return false;
if (!CPT->isNothrow(Self.Context))
return false;
}
@@ -3180,8 +3230,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT)
return false;
- if (CPT->getExceptionSpecType() == EST_Delayed)
- return false;
// FIXME: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1)
@@ -3218,8 +3266,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT)
return false;
- if (CPT->getExceptionSpecType() == EST_Delayed)
- return false;
// TODO: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
@@ -3284,6 +3330,25 @@ ExprResult Sema::ActOnBinaryTypeTrait(BinaryTypeTrait BTT,
return BuildBinaryTypeTrait(BTT, KWLoc, LhsTSInfo, RhsTSInfo, RParen);
}
+/// \brief Determine whether T has a non-trivial Objective-C lifetime in
+/// ARC mode.
+static bool hasNontrivialObjCLifetime(QualType T) {
+ switch (T.getObjCLifetime()) {
+ case Qualifiers::OCL_ExplicitNone:
+ return false;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Autoreleasing:
+ return true;
+
+ case Qualifiers::OCL_None:
+ return T->isObjCLifetimeType();
+ }
+
+ llvm_unreachable("Unknown ObjC lifetime qualifier");
+}
+
static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc) {
@@ -3357,8 +3422,14 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
ArgExprs.size()));
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
return false;
-
- // The initialization succeeded; not make sure there are no non-trivial
+
+ // Under Objective-C ARC, if the destination has non-trivial Objective-C
+ // lifetime, this is a non-trivial construction.
+ if (S.getLangOpts().ObjCAutoRefCount &&
+ hasNontrivialObjCLifetime(Args[0]->getType().getNonReferenceType()))
+ return false;
+
+ // The initialization succeeded; now make sure there are no non-trivial
// calls.
return !Result.get()->hasNonTrivialCall(S.Context);
}
@@ -3471,9 +3542,25 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
// We model the initialization as a copy-initialization of a temporary
// of the appropriate type, which for this expression is identical to the
// return statement (since NRVO doesn't apply).
+
+ // Functions aren't allowed to return function or array types.
+ if (RhsT->isFunctionType() || RhsT->isArrayType())
+ return false;
+
+ // A return statement in a void function must have void type.
+ if (RhsT->isVoidType())
+ return LhsT->isVoidType();
+
+ // A function definition requires a complete, non-abstract return type.
+ if (Self.RequireCompleteType(KeyLoc, RhsT, 0) ||
+ Self.RequireNonAbstractType(KeyLoc, RhsT, 0))
+ return false;
+
+ // Compute the result of add_rvalue_reference.
if (LhsT->isObjectType() || LhsT->isFunctionType())
LhsT = Self.Context.getRValueReferenceType(LhsT);
-
+
+ // Build a fake source and destination for initialization.
InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT));
OpaqueValueExpr From(KeyLoc, LhsT.getNonLValueExprType(Self.Context),
Expr::getValueKindForType(LhsT));
@@ -3539,6 +3626,12 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
return false;
+ // Under Objective-C ARC, if the destination has non-trivial Objective-C
+ // lifetime, this is a non-trivial assignment.
+ if (Self.getLangOpts().ObjCAutoRefCount &&
+ hasNontrivialObjCLifetime(LhsT.getNonReferenceType()))
+ return false;
+
return !Result.get()->hasNonTrivialCall(Self.Context);
}
}
@@ -3615,7 +3708,7 @@ static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT,
llvm::APSInt Value;
uint64_t Dim;
if (Self.VerifyIntegerConstantExpression(DimExpr, &Value,
- Self.PDiag(diag::err_dimension_expr_not_constant_integer),
+ diag::err_dimension_expr_not_constant_integer,
false).isInvalid())
return 0;
if (Value.isSigned() && Value.isNegative()) {
@@ -3767,8 +3860,8 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
if (!Context.hasSameUnqualifiedType(Class, LHSType)) {
// If we want to check the hierarchy, we need a complete type.
- if (RequireCompleteType(Loc, LHSType, PDiag(diag::err_bad_memptr_lhs)
- << OpSpelling << (int)isIndirect)) {
+ if (RequireCompleteType(Loc, LHSType, diag::err_bad_memptr_lhs,
+ OpSpelling, (int)isIndirect)) {
return QualType();
}
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
@@ -4023,13 +4116,14 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) {
///
/// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y
/// extension. In this case, LHS == Cond. (But they're not aliases.)
-QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS,
- ExprValueKind &VK, ExprObjectKind &OK,
+QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
+ ExprResult &RHS, ExprValueKind &VK,
+ ExprObjectKind &OK,
SourceLocation QuestionLoc) {
// FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++
// interface pointers.
- // C++0x 5.16p1
+ // C++11 [expr.cond]p1
// The first expression is contextually converted to bool.
if (!Cond.get()->isTypeDependent()) {
ExprResult CondRes = CheckCXXBooleanCondition(Cond.take());
@@ -4046,7 +4140,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent())
return Context.DependentTy;
- // C++0x 5.16p2
+ // C++11 [expr.cond]p2
// If either the second or the third operand has type (cv) void, ...
QualType LTy = LHS.get()->getType();
QualType RTy = RHS.get()->getType();
@@ -4059,12 +4153,26 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
+
+ // Finish off the lvalue-to-rvalue conversion by copy-initializing a
+ // temporary if necessary. DefaultFunctionArrayLvalueConversion doesn't
+ // do this part for us.
+ ExprResult &NonVoid = LVoid ? RHS : LHS;
+ if (NonVoid.get()->getType()->isRecordType() &&
+ NonVoid.get()->isGLValue()) {
+ InitializedEntity Entity =
+ InitializedEntity::InitializeTemporary(NonVoid.get()->getType());
+ NonVoid = PerformCopyInitialization(Entity, SourceLocation(), NonVoid);
+ if (NonVoid.isInvalid())
+ return QualType();
+ }
+
LTy = LHS.get()->getType();
RTy = RHS.get()->getType();
// ... and one of the following shall hold:
// -- The second or the third operand (but not both) is a throw-
- // expression; the result is of the type of the other and is an rvalue.
+ // expression; the result is of the type of the other and is a prvalue.
bool LThrow = isa<CXXThrowExpr>(LHS.get());
bool RThrow = isa<CXXThrowExpr>(RHS.get());
if (LThrow && !RThrow)
@@ -4073,7 +4181,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
return LTy;
// -- Both the second and third operands have type void; the result is of
- // type void and is an rvalue.
+ // type void and is a prvalue.
if (LVoid && RVoid)
return Context.VoidTy;
@@ -4086,10 +4194,10 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
// Neither is void.
- // C++0x 5.16p3
+ // C++11 [expr.cond]p3
// Otherwise, if the second and third operand have different types, and
- // either has (cv) class type, and attempt is made to convert each of those
- // operands to the other.
+ // either has (cv) class type [...] an attempt is made to convert each of
+ // those operands to the type of the other.
if (!Context.hasSameType(LTy, RTy) &&
(LTy->isRecordType() || RTy->isRecordType())) {
ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft;
@@ -4122,7 +4230,31 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
}
}
- // C++0x 5.16p4
+ // C++11 [expr.cond]p3
+ // if both are glvalues of the same value category and the same type except
+ // for cv-qualification, an attempt is made to convert each of those
+ // operands to the type of the other.
+ ExprValueKind LVK = LHS.get()->getValueKind();
+ ExprValueKind RVK = RHS.get()->getValueKind();
+ if (!Context.hasSameType(LTy, RTy) &&
+ Context.hasSameUnqualifiedType(LTy, RTy) &&
+ LVK == RVK && LVK != VK_RValue) {
+ // Since the unqualified types are reference-related and we require the
+ // result to be as if a reference bound directly, the only conversion
+ // we can perform is to add cv-qualifiers.
+ Qualifiers LCVR = Qualifiers::fromCVRMask(LTy.getCVRQualifiers());
+ Qualifiers RCVR = Qualifiers::fromCVRMask(RTy.getCVRQualifiers());
+ if (RCVR.isStrictSupersetOf(LCVR)) {
+ LHS = ImpCastExprToType(LHS.take(), RTy, CK_NoOp, LVK);
+ LTy = LHS.get()->getType();
+ }
+ else if (LCVR.isStrictSupersetOf(RCVR)) {
+ RHS = ImpCastExprToType(RHS.take(), LTy, CK_NoOp, RVK);
+ RTy = RHS.get()->getType();
+ }
+ }
+
+ // C++11 [expr.cond]p4
// If the second and third operands are glvalues of the same value
// category and have the same type, the result is of that type and
// value category and it is a bit-field if the second or the third
@@ -4130,9 +4262,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
// We only extend this to bitfields, not to the crazy other kinds of
// l-values.
bool Same = Context.hasSameType(LTy, RTy);
- if (Same &&
- LHS.get()->isGLValue() &&
- LHS.get()->getValueKind() == RHS.get()->getValueKind() &&
+ if (Same && LVK == RVK && LVK != VK_RValue &&
LHS.get()->isOrdinaryOrBitFieldObject() &&
RHS.get()->isOrdinaryOrBitFieldObject()) {
VK = LHS.get()->getValueKind();
@@ -4142,8 +4272,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
return LTy;
}
- // C++0x 5.16p5
- // Otherwise, the result is an rvalue. If the second and third operands
+ // C++11 [expr.cond]p5
+ // Otherwise, the result is a prvalue. If the second and third operands
// do not have the same type, and either has (cv) class type, ...
if (!Same && (LTy->isRecordType() || RTy->isRecordType())) {
// ... overload resolution is used to determine the conversions (if any)
@@ -4153,8 +4283,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
return QualType();
}
- // C++0x 5.16p6
- // LValue-to-rvalue, array-to-pointer, and function-to-pointer standard
+ // C++11 [expr.cond]p6
+ // Lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard
// conversions are performed on the second and third operands.
LHS = DefaultFunctionArrayLvalueConversion(LHS.take());
RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
@@ -4207,9 +4337,11 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
}
// -- The second and third operands have pointer type, or one has pointer
- // type and the other is a null pointer constant; pointer conversions
- // and qualification conversions are performed to bring them to their
- // composite pointer type. The result is of the composite pointer type.
+ // type and the other is a null pointer constant, or both are null
+ // pointer constants, at least one of which is non-integral; pointer
+ // conversions and qualification conversions are performed to bring them
+ // to their composite pointer type. The result is of the composite
+ // pointer type.
// -- The second and third operands have pointer to member type, or one has
// pointer to member type and the other is a null pointer constant;
// pointer to member conversions and qualification conversions are
@@ -4247,7 +4379,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
/// \brief Find a merged pointer type and convert the two expressions to it.
///
/// This finds the composite pointer type (or member pointer type) for @p E1
-/// and @p E2 according to C++0x 5.9p2. It converts both expressions to this
+/// and @p E2 according to C++11 5.9p2. It converts both expressions to this
/// type and returns it.
/// It does not emit diagnostics.
///
@@ -4267,15 +4399,27 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
assert(getLangOpts().CPlusPlus && "This function assumes C++");
QualType T1 = E1->getType(), T2 = E2->getType();
- if (!T1->isAnyPointerType() && !T1->isMemberPointerType() &&
- !T2->isAnyPointerType() && !T2->isMemberPointerType())
- return QualType();
-
- // C++0x 5.9p2
+ // C++11 5.9p2
// Pointer conversions and qualification conversions are performed on
// pointer operands to bring them to their composite pointer type. If
// one operand is a null pointer constant, the composite pointer type is
- // the type of the other operand.
+ // std::nullptr_t if the other operand is also a null pointer constant or,
+ // if the other operand is a pointer, the type of the other operand.
+ if (!T1->isAnyPointerType() && !T1->isMemberPointerType() &&
+ !T2->isAnyPointerType() && !T2->isMemberPointerType()) {
+ if (T1->isNullPtrType() &&
+ E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
+ E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).take();
+ return T1;
+ }
+ if (T2->isNullPtrType() &&
+ E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
+ E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).take();
+ return T2;
+ }
+ return QualType();
+ }
+
if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
if (T2->isMemberPointerType())
E1 = ImpCastExprToType(E1, T2, CK_NullToMemberPointer).take();
@@ -4522,8 +4666,8 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
ObjCMethodDecl *D = 0;
if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
D = Send->getMethodDecl();
- } else if (ObjCNumericLiteral *NumLit = dyn_cast<ObjCNumericLiteral>(E)) {
- D = NumLit->getObjCNumericLiteralMethod();
+ } else if (ObjCBoxedExpr *BoxedExpr = dyn_cast<ObjCBoxedExpr>(E)) {
+ D = BoxedExpr->getBoxingMethod();
} else if (ObjCArrayLiteral *ArrayLit = dyn_cast<ObjCArrayLiteral>(E)) {
D = ArrayLit->getArrayWithObjectsMethod();
} else if (ObjCDictionaryLiteral *DictLit
@@ -4706,6 +4850,11 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
// Disable the special decltype handling now.
Rec.IsDecltype = false;
+ // In MS mode, don't perform any extra checking of call return types within a
+ // decltype expression.
+ if (getLangOpts().MicrosoftMode)
+ return Owned(E);
+
// Perform the semantic checks we delayed until this point.
CallExpr *TopCall = dyn_cast<CallExpr>(E);
for (unsigned I = 0, N = Rec.DelayedDecltypeCalls.size(); I != N; ++I) {
@@ -4733,11 +4882,11 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
CXXDestructorDecl *Destructor = LookupDestructor(RD);
Temp->setDestructor(Destructor);
- MarkFunctionReferenced(E->getExprLoc(), Destructor);
- CheckDestructorAccess(E->getExprLoc(), Destructor,
+ MarkFunctionReferenced(Bind->getExprLoc(), Destructor);
+ CheckDestructorAccess(Bind->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_temp)
- << E->getType());
- DiagnoseUseOfDecl(Destructor, E->getExprLoc());
+ << Bind->getType());
+ DiagnoseUseOfDecl(Destructor, Bind->getExprLoc());
// We need a cleanup, but we don't need to remember the temporary.
ExprNeedsCleanups = true;
@@ -4833,8 +4982,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
// the member function body.
if (!BaseType->isDependentType() &&
!isThisOutsideMemberFunctionBody(BaseType) &&
- RequireCompleteType(OpLoc, BaseType,
- PDiag(diag::err_incomplete_member_access)))
+ RequireCompleteType(OpLoc, BaseType, diag::err_incomplete_member_access))
return ExprError();
// C++ [basic.lookup.classref]p2:
@@ -5222,6 +5370,61 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen);
}
+static bool IsSpecialDiscardedValue(Expr *E) {
+ // In C++11, discarded-value expressions of a certain form are special,
+ // according to [expr]p10:
+ // The lvalue-to-rvalue conversion (4.1) is applied only if the
+ // expression is an lvalue of volatile-qualified type and it has
+ // one of the following forms:
+ E = E->IgnoreParens();
+
+ // - id-expression (5.1.1),
+ if (isa<DeclRefExpr>(E))
+ return true;
+
+ // - subscripting (5.2.1),
+ if (isa<ArraySubscriptExpr>(E))
+ return true;
+
+ // - class member access (5.2.5),
+ if (isa<MemberExpr>(E))
+ return true;
+
+ // - indirection (5.3.1),
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
+ if (UO->getOpcode() == UO_Deref)
+ return true;
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ // - pointer-to-member operation (5.5),
+ if (BO->isPtrMemOp())
+ return true;
+
+ // - comma expression (5.18) where the right operand is one of the above.
+ if (BO->getOpcode() == BO_Comma)
+ return IsSpecialDiscardedValue(BO->getRHS());
+ }
+
+ // - conditional expression (5.16) where both the second and the third
+ // operands are one of the above, or
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
+ return IsSpecialDiscardedValue(CO->getTrueExpr()) &&
+ IsSpecialDiscardedValue(CO->getFalseExpr());
+ // The related edge case of "*x ?: *x".
+ if (BinaryConditionalOperator *BCO =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(BCO->getTrueExpr()))
+ return IsSpecialDiscardedValue(OVE->getSourceExpr()) &&
+ IsSpecialDiscardedValue(BCO->getFalseExpr());
+ }
+
+ // Objective-C++ extensions to the rule.
+ if (isa<PseudoObjectExpr>(E) || isa<ObjCIvarRefExpr>(E))
+ return true;
+
+ return false;
+}
+
/// Perform the conversions required for an expression used in a
/// context that ignores the result.
ExprResult Sema::IgnoredValueConversions(Expr *E) {
@@ -5246,8 +5449,21 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
return Owned(E);
}
- // Otherwise, this rule does not apply in C++, at least not for the moment.
- if (getLangOpts().CPlusPlus) return Owned(E);
+ if (getLangOpts().CPlusPlus) {
+ // The C++11 standard defines the notion of a discarded-value expression;
+ // normally, we don't need to do anything to handle it, but if it is a
+ // volatile lvalue with a special form, we perform an lvalue-to-rvalue
+ // conversion.
+ if (getLangOpts().CPlusPlus0x && E->isGLValue() &&
+ E->getType().isVolatileQualified() &&
+ IsSpecialDiscardedValue(E)) {
+ ExprResult Res = DefaultLvalueConversion(E);
+ if (Res.isInvalid())
+ return Owned(E);
+ E = Res.take();
+ }
+ return Owned(E);
+ }
// GCC seems to also exclude expressions of incomplete enum type.
if (const EnumType *T = E->getType()->getAs<EnumType>()) {
@@ -5269,7 +5485,7 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
return Owned(E);
}
-ExprResult Sema::ActOnFinishFullExpr(Expr *FE) {
+ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC) {
ExprResult FullExpr = Owned(FE);
if (!FullExpr.get())
@@ -5295,7 +5511,7 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE) {
if (FullExpr.isInvalid())
return ExprError();
- CheckImplicitConversions(FullExpr.get(), FullExpr.get()->getExprLoc());
+ CheckImplicitConversions(FullExpr.get(), CC);
return MaybeCreateExprWithCleanups(FullExpr);
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 6c84caa..53f22f6 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -115,7 +115,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
NamedDecl *D = *I;
if (D->isCXXInstanceMember()) {
- if (dyn_cast<FieldDecl>(D))
+ if (dyn_cast<FieldDecl>(D) || dyn_cast<IndirectFieldDecl>(D))
isField = true;
CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
@@ -436,8 +436,8 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
if (PT && (!getLangOpts().ObjC1 ||
PT->getPointeeType()->isRecordType())) {
assert(BaseExpr && "cannot happen with implicit member accesses");
- Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr->getSourceRange();
+ Diag(OpLoc, diag::err_typecheck_member_reference_struct_union)
+ << BaseType << BaseExpr->getSourceRange() << NameInfo.getSourceRange();
return ExprError();
}
}
@@ -548,8 +548,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
RecordDecl *RDecl = RTy->getDecl();
if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) &&
SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
- SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
- << BaseRange))
+ diag::err_typecheck_incomplete_tag,
+ BaseRange))
return true;
if (HasTemplateArgs) {
@@ -813,8 +813,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs,
- bool SuppressQualifierCheck) {
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool SuppressQualifierCheck,
+ ActOnMemberAccessExtraArgs *ExtraArgs) {
QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
@@ -835,6 +836,32 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
? computeDeclContext(SS, false)
: BaseType->getAs<RecordType>()->getDecl());
+ if (ExtraArgs) {
+ ExprResult RetryExpr;
+ if (!IsArrow && BaseExpr) {
+ SFINAETrap Trap(*this, true);
+ ParsedType ObjectType;
+ bool MayBePseudoDestructor = false;
+ RetryExpr = ActOnStartCXXMemberReference(getCurScope(), BaseExpr,
+ OpLoc, tok::arrow, ObjectType,
+ MayBePseudoDestructor);
+ if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) {
+ CXXScopeSpec TempSS(SS);
+ RetryExpr = ActOnMemberAccessExpr(
+ ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS,
+ TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl,
+ ExtraArgs->HasTrailingLParen);
+ }
+ if (Trap.hasErrorOccurred())
+ RetryExpr = ExprError();
+ }
+ if (RetryExpr.isUsable()) {
+ Diag(OpLoc, diag::err_no_member_overloaded_arrow)
+ << MemberName << DC << FixItHint::CreateReplacement(OpLoc, "->");
+ return RetryExpr;
+ }
+ }
+
Diag(R.getNameLoc(), diag::err_no_member)
<< MemberName << DC
<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
@@ -1122,10 +1149,22 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
ObjCImpDecl, HasTemplateArgs);
goto fail;
}
-
- if (RequireCompleteType(OpLoc, BaseType,
- PDiag(diag::err_typecheck_incomplete_tag)
- << BaseExpr.get()->getSourceRange()))
+ else if (Member && Member->isStr("isa")) {
+ // If an ivar is (1) the first ivar in a root class and (2) named `isa`,
+ // then issue the same deprecated warning that id->isa gets.
+ ObjCInterfaceDecl *ClassDeclared = 0;
+ if (ObjCIvarDecl *IV =
+ IDecl->lookupInstanceVariable(Member, ClassDeclared)) {
+ if (!ClassDeclared->getSuperClass()
+ && (*ClassDeclared->ivar_begin()) == IV) {
+ Diag(MemberLoc, diag::warn_objc_isa_use);
+ Diag(IV->getLocation(), diag::note_ivar_decl);
+ }
+ }
+ }
+
+ if (RequireCompleteType(OpLoc, BaseType, diag::err_typecheck_incomplete_tag,
+ BaseExpr.get()))
return ExprError();
ObjCInterfaceDecl *ClassDeclared = 0;
@@ -1211,6 +1250,7 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
<< IV->getDeclName();
}
}
+ bool warn = true;
if (getLangOpts().ObjCAutoRefCount) {
Expr *BaseExp = BaseExpr.get()->IgnoreParenImpCasts();
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BaseExp))
@@ -1218,10 +1258,20 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
BaseExp = UO->getSubExpr()->IgnoreParenCasts();
if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(BaseExp))
- if (DE->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
+ if (DE->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
Diag(DE->getLocation(), diag::error_arc_weak_ivar_access);
+ warn = false;
+ }
+ }
+ if (warn) {
+ if (ObjCMethodDecl *MD = getCurMethodDecl()) {
+ ObjCMethodFamily MF = MD->getMethodFamily();
+ warn = (MF != OMF_init && MF != OMF_dealloc &&
+ MF != OMF_finalize);
+ }
+ if (warn)
+ Diag(MemberLoc, diag::warn_direct_ivar_access) << IV->getDeclName();
}
-
return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
MemberLoc, BaseExpr.take(),
IsArrow));
@@ -1327,9 +1377,6 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// methods.
Setter = IFace->lookupPrivateMethod(SetterSel, false);
}
- // Look through local category implementations associated with the class.
- if (!Setter)
- Setter = IFace->getCategoryClassMethod(SetterSel);
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
@@ -1418,8 +1465,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
ObjCImpDecl, HasTemplateArgs);
}
- Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr.get()->getSourceRange();
+ Diag(OpLoc, diag::err_typecheck_member_reference_struct_union)
+ << BaseType << BaseExpr.get()->getSourceRange() << MemberLoc;
return ExprError();
}
@@ -1434,9 +1481,9 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
/// \param HasTrailingLParen whether the next token is '(', which
/// is used to diagnose mis-uses of special members that can
/// only be called
-/// \param ObjCImpDecl the current ObjC @implementation decl;
-/// this is an ugly hack around the fact that ObjC @implementations
-/// aren't properly put in the context chain
+/// \param ObjCImpDecl the current Objective-C \@implementation
+/// decl; this is an ugly hack around the fact that Objective-C
+/// \@implementations aren't properly put in the context chain
ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
@@ -1506,9 +1553,11 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
return move(Result);
}
+ ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl, HasTrailingLParen};
Result = BuildMemberReferenceExpr(Base, Base->getType(),
OpLoc, IsArrow, SS, TemplateKWLoc,
- FirstQualifierInScope, R, TemplateArgs);
+ FirstQualifierInScope, R, TemplateArgs,
+ false, &ExtraArgs);
}
return move(Result);
@@ -1563,6 +1612,8 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
MemberType = S.Context.getQualifiedType(MemberType, Combined);
}
+ S.UnusedPrivateFields.remove(Field);
+
ExprResult Base =
S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
FoundDecl, Field);
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index b62d56e..0aabf8b 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -111,7 +111,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
Ty = Context.getObjCIdType();
}
} else {
- IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
+ IdentifierInfo *NSIdent = NSAPIObj->getNSClassId(NSAPI::ClassId_NSString);
NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc,
LookupOrdinaryName);
if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
@@ -140,20 +140,47 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
return new (Context) ObjCStringLiteral(S, Ty, AtLoc);
}
+/// \brief Emits an error if the given method does not exist, or if the return
+/// type is not an Objective-C object.
+static bool validateBoxingMethod(Sema &S, SourceLocation Loc,
+ const ObjCInterfaceDecl *Class,
+ Selector Sel, const ObjCMethodDecl *Method) {
+ if (!Method) {
+ // FIXME: Is there a better way to avoid quotes than using getName()?
+ S.Diag(Loc, diag::err_undeclared_boxing_method) << Sel << Class->getName();
+ return false;
+ }
+
+ // Make sure the return type is reasonable.
+ QualType ReturnType = Method->getResultType();
+ if (!ReturnType->isObjCObjectPointerType()) {
+ S.Diag(Loc, diag::err_objc_literal_method_sig)
+ << Sel;
+ S.Diag(Method->getLocation(), diag::note_objc_literal_method_return)
+ << ReturnType;
+ return false;
+ }
+
+ return true;
+}
+
/// \brief Retrieve the NSNumber factory method that should be used to create
/// an Objective-C literal for the given type.
static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
- QualType T, QualType ReturnType,
- SourceRange Range) {
+ QualType NumberType,
+ bool isLiteral = false,
+ SourceRange R = SourceRange()) {
llvm::Optional<NSAPI::NSNumberLiteralMethodKind> Kind
- = S.NSAPIObj->getNSNumberFactoryMethodKind(T);
+ = S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType);
if (!Kind) {
- S.Diag(Loc, diag::err_invalid_nsnumber_type)
- << T << Range;
+ if (isLiteral) {
+ S.Diag(Loc, diag::err_invalid_nsnumber_type)
+ << NumberType << R;
+ }
return 0;
}
-
+
// If we already looked up this method, we're done.
if (S.NSNumberLiteralMethods[*Kind])
return S.NSNumberLiteralMethods[*Kind];
@@ -161,39 +188,62 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
Selector Sel = S.NSAPIObj->getNSNumberLiteralSelector(*Kind,
/*Instance=*/false);
+ ASTContext &CX = S.Context;
+
+ // Look up the NSNumber class, if we haven't done so already. It's cached
+ // in the Sema instance.
+ if (!S.NSNumberDecl) {
+ IdentifierInfo *NSNumberId =
+ S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber);
+ NamedDecl *IF = S.LookupSingleName(S.TUScope, NSNumberId,
+ Loc, Sema::LookupOrdinaryName);
+ S.NSNumberDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (!S.NSNumberDecl) {
+ if (S.getLangOpts().DebuggerObjCLiteral) {
+ // Create a stub definition of NSNumber.
+ S.NSNumberDecl = ObjCInterfaceDecl::Create(CX,
+ CX.getTranslationUnitDecl(),
+ SourceLocation(), NSNumberId,
+ 0, SourceLocation());
+ } else {
+ // Otherwise, require a declaration of NSNumber.
+ S.Diag(Loc, diag::err_undeclared_nsnumber);
+ return 0;
+ }
+ } else if (!S.NSNumberDecl->hasDefinition()) {
+ S.Diag(Loc, diag::err_undeclared_nsnumber);
+ return 0;
+ }
+
+ // generate the pointer to NSNumber type.
+ QualType NSNumberObject = CX.getObjCInterfaceType(S.NSNumberDecl);
+ S.NSNumberPointer = CX.getObjCObjectPointerType(NSNumberObject);
+ }
+
// Look for the appropriate method within NSNumber.
- ObjCMethodDecl *Method = S.NSNumberDecl->lookupClassMethod(Sel);;
+ ObjCMethodDecl *Method = S.NSNumberDecl->lookupClassMethod(Sel);
if (!Method && S.getLangOpts().DebuggerObjCLiteral) {
+ // create a stub definition this NSNumber factory method.
TypeSourceInfo *ResultTInfo = 0;
- Method = ObjCMethodDecl::Create(S.Context, SourceLocation(), SourceLocation(), Sel,
- ReturnType,
- ResultTInfo,
- S.Context.getTranslationUnitDecl(),
- false /*Instance*/, false/*isVariadic*/,
- /*isSynthesized=*/false,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- ObjCMethodDecl::Required,
- false);
+ Method = ObjCMethodDecl::Create(CX, SourceLocation(), SourceLocation(), Sel,
+ S.NSNumberPointer, ResultTInfo,
+ S.NSNumberDecl,
+ /*isInstance=*/false, /*isVariadic=*/false,
+ /*isSynthesized=*/false,
+ /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false,
+ ObjCMethodDecl::Required,
+ /*HasRelatedResultType=*/false);
ParmVarDecl *value = ParmVarDecl::Create(S.Context, Method,
SourceLocation(), SourceLocation(),
- &S.Context.Idents.get("value"),
- T, /*TInfo=*/0, SC_None, SC_None, 0);
+ &CX.Idents.get("value"),
+ NumberType, /*TInfo=*/0, SC_None,
+ SC_None, 0);
Method->setMethodParams(S.Context, value, ArrayRef<SourceLocation>());
}
- if (!Method) {
- S.Diag(Loc, diag::err_undeclared_nsnumber_method) << Sel;
- return 0;
- }
-
- // Make sure the return type is reasonable.
- if (!Method->getResultType()->isObjCObjectPointerType()) {
- S.Diag(Loc, diag::err_objc_literal_method_sig)
- << Sel;
- S.Diag(Method->getLocation(), diag::note_objc_literal_method_return)
- << Method->getResultType();
+ if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method))
return 0;
- }
// Note: if the parameter type is out-of-line, we'll catch it later in the
// implicit conversion.
@@ -202,29 +252,9 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
return Method;
}
-/// BuildObjCNumericLiteral - builds an ObjCNumericLiteral AST node for the
-/// numeric literal expression. Type of the expression will be "NSNumber *"
-/// or "id" if NSNumber is unavailable.
+/// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the
+/// numeric literal expression. Type of the expression will be "NSNumber *".
ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
- // Look up the NSNumber class, if we haven't done so already.
- if (!NSNumberDecl) {
- NamedDecl *IF = LookupSingleName(TUScope,
- NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber),
- AtLoc, LookupOrdinaryName);
- NSNumberDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
-
- if (!NSNumberDecl && getLangOpts().DebuggerObjCLiteral)
- NSNumberDecl = ObjCInterfaceDecl::Create (Context,
- Context.getTranslationUnitDecl(),
- SourceLocation(),
- NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber),
- 0, SourceLocation());
- if (!NSNumberDecl) {
- Diag(AtLoc, diag::err_undeclared_nsnumber);
- return ExprError();
- }
- }
-
// Determine the type of the literal.
QualType NumberType = Number->getType();
if (CharacterLiteral *Char = dyn_cast<CharacterLiteral>(Number)) {
@@ -249,29 +279,29 @@ ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
}
}
- ObjCMethodDecl *Method = 0;
// Look for the appropriate method within NSNumber.
// Construct the literal.
- QualType Ty
- = Context.getObjCObjectPointerType(
- Context.getObjCInterfaceType(NSNumberDecl));
- Method = getNSNumberFactoryMethod(*this, AtLoc,
- NumberType, Ty,
- Number->getSourceRange());
-
+ SourceRange NR(Number->getSourceRange());
+ ObjCMethodDecl *Method = getNSNumberFactoryMethod(*this, AtLoc, NumberType,
+ true, NR);
if (!Method)
return ExprError();
// Convert the number to the type that the parameter expects.
- QualType ElementT = Method->param_begin()[0]->getType();
- ExprResult ConvertedNumber = PerformImplicitConversion(Number, ElementT,
- AA_Sending);
+ ParmVarDecl *ParamDecl = Method->param_begin()[0];
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
+ ParamDecl);
+ ExprResult ConvertedNumber = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(Number));
if (ConvertedNumber.isInvalid())
return ExprError();
Number = ConvertedNumber.get();
+ // Use the effective source range of the literal, including the leading '@'.
return MaybeBindToTemporary(
- new (Context) ObjCNumericLiteral(Number, Ty, Method, AtLoc));
+ new (Context) ObjCBoxedExpr(Number, NSNumberPointer, Method,
+ SourceRange(AtLoc, NR.getEnd())));
}
ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc,
@@ -308,9 +338,11 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
// type.
if (S.getLangOpts().CPlusPlus && Element->getType()->isRecordType()) {
InitializedEntity Entity
- = InitializedEntity::InitializeParameter(S.Context, T, /*Consumed=*/false);
+ = InitializedEntity::InitializeParameter(S.Context, T,
+ /*Consumed=*/false);
InitializationKind Kind
- = InitializationKind::CreateCopy(Element->getLocStart(), SourceLocation());
+ = InitializationKind::CreateCopy(Element->getLocStart(),
+ SourceLocation());
InitializationSequence Seq(S, Entity, Kind, &Element, 1);
if (!Seq.Failed())
return Seq.Perform(S, Entity, Kind, MultiExprArg(S, &Element, 1));
@@ -385,26 +417,191 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
Element->getLocStart(), Element);
}
+ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
+ if (ValueExpr->isTypeDependent()) {
+ ObjCBoxedExpr *BoxedExpr =
+ new (Context) ObjCBoxedExpr(ValueExpr, Context.DependentTy, NULL, SR);
+ return Owned(BoxedExpr);
+ }
+ ObjCMethodDecl *BoxingMethod = NULL;
+ QualType BoxedType;
+ // Convert the expression to an RValue, so we can check for pointer types...
+ ExprResult RValue = DefaultFunctionArrayLvalueConversion(ValueExpr);
+ if (RValue.isInvalid()) {
+ return ExprError();
+ }
+ ValueExpr = RValue.get();
+ QualType ValueType(ValueExpr->getType());
+ if (const PointerType *PT = ValueType->getAs<PointerType>()) {
+ QualType PointeeType = PT->getPointeeType();
+ if (Context.hasSameUnqualifiedType(PointeeType, Context.CharTy)) {
+
+ if (!NSStringDecl) {
+ IdentifierInfo *NSStringId =
+ NSAPIObj->getNSClassId(NSAPI::ClassId_NSString);
+ NamedDecl *Decl = LookupSingleName(TUScope, NSStringId,
+ SR.getBegin(), LookupOrdinaryName);
+ NSStringDecl = dyn_cast_or_null<ObjCInterfaceDecl>(Decl);
+ if (!NSStringDecl) {
+ if (getLangOpts().DebuggerObjCLiteral) {
+ // Support boxed expressions in the debugger w/o NSString declaration.
+ DeclContext *TU = Context.getTranslationUnitDecl();
+ NSStringDecl = ObjCInterfaceDecl::Create(Context, TU,
+ SourceLocation(),
+ NSStringId,
+ 0, SourceLocation());
+ } else {
+ Diag(SR.getBegin(), diag::err_undeclared_nsstring);
+ return ExprError();
+ }
+ } else if (!NSStringDecl->hasDefinition()) {
+ Diag(SR.getBegin(), diag::err_undeclared_nsstring);
+ return ExprError();
+ }
+ assert(NSStringDecl && "NSStringDecl should not be NULL");
+ QualType NSStringObject = Context.getObjCInterfaceType(NSStringDecl);
+ NSStringPointer = Context.getObjCObjectPointerType(NSStringObject);
+ }
+
+ if (!StringWithUTF8StringMethod) {
+ IdentifierInfo *II = &Context.Idents.get("stringWithUTF8String");
+ Selector stringWithUTF8String = Context.Selectors.getUnarySelector(II);
+
+ // Look for the appropriate method within NSString.
+ BoxingMethod = NSStringDecl->lookupClassMethod(stringWithUTF8String);
+ if (!BoxingMethod && getLangOpts().DebuggerObjCLiteral) {
+ // Debugger needs to work even if NSString hasn't been defined.
+ TypeSourceInfo *ResultTInfo = 0;
+ ObjCMethodDecl *M =
+ ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(),
+ stringWithUTF8String, NSStringPointer,
+ ResultTInfo, NSStringDecl,
+ /*isInstance=*/false, /*isVariadic=*/false,
+ /*isSynthesized=*/false,
+ /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false,
+ ObjCMethodDecl::Required,
+ /*HasRelatedResultType=*/false);
+ QualType ConstCharType = Context.CharTy.withConst();
+ ParmVarDecl *value =
+ ParmVarDecl::Create(Context, M,
+ SourceLocation(), SourceLocation(),
+ &Context.Idents.get("value"),
+ Context.getPointerType(ConstCharType),
+ /*TInfo=*/0,
+ SC_None, SC_None, 0);
+ M->setMethodParams(Context, value, ArrayRef<SourceLocation>());
+ BoxingMethod = M;
+ }
+
+ if (!validateBoxingMethod(*this, SR.getBegin(), NSStringDecl,
+ stringWithUTF8String, BoxingMethod))
+ return ExprError();
+
+ StringWithUTF8StringMethod = BoxingMethod;
+ }
+
+ BoxingMethod = StringWithUTF8StringMethod;
+ BoxedType = NSStringPointer;
+ }
+ } else if (ValueType->isBuiltinType()) {
+ // The other types we support are numeric, char and BOOL/bool. We could also
+ // provide limited support for structure types, such as NSRange, NSRect, and
+ // NSSize. See NSValue (NSValueGeometryExtensions) in <Foundation/NSGeometry.h>
+ // for more details.
+
+ // Check for a top-level character literal.
+ if (const CharacterLiteral *Char =
+ dyn_cast<CharacterLiteral>(ValueExpr->IgnoreParens())) {
+ // In C, character literals have type 'int'. That's not the type we want
+ // to use to determine the Objective-c literal kind.
+ switch (Char->getKind()) {
+ case CharacterLiteral::Ascii:
+ ValueType = Context.CharTy;
+ break;
+
+ case CharacterLiteral::Wide:
+ ValueType = Context.getWCharType();
+ break;
+
+ case CharacterLiteral::UTF16:
+ ValueType = Context.Char16Ty;
+ break;
+
+ case CharacterLiteral::UTF32:
+ ValueType = Context.Char32Ty;
+ break;
+ }
+ }
+
+ // FIXME: Do I need to do anything special with BoolTy expressions?
+
+ // Look for the appropriate method within NSNumber.
+ BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(), ValueType);
+ BoxedType = NSNumberPointer;
+
+ } else if (const EnumType *ET = ValueType->getAs<EnumType>()) {
+ if (!ET->getDecl()->isComplete()) {
+ Diag(SR.getBegin(), diag::err_objc_incomplete_boxed_expression_type)
+ << ValueType << ValueExpr->getSourceRange();
+ return ExprError();
+ }
+
+ BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(),
+ ET->getDecl()->getIntegerType());
+ BoxedType = NSNumberPointer;
+ }
+
+ if (!BoxingMethod) {
+ Diag(SR.getBegin(), diag::err_objc_illegal_boxed_expression_type)
+ << ValueType << ValueExpr->getSourceRange();
+ return ExprError();
+ }
+
+ // Convert the expression to the type that the parameter requires.
+ ParmVarDecl *ParamDecl = BoxingMethod->param_begin()[0];
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
+ ParamDecl);
+ ExprResult ConvertedValueExpr = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(ValueExpr));
+ if (ConvertedValueExpr.isInvalid())
+ return ExprError();
+ ValueExpr = ConvertedValueExpr.get();
+
+ ObjCBoxedExpr *BoxedExpr =
+ new (Context) ObjCBoxedExpr(ValueExpr, BoxedType,
+ BoxingMethod, SR);
+ return MaybeBindToTemporary(BoxedExpr);
+}
+
+/// Build an ObjC subscript pseudo-object expression, given that
+/// that's supported by the runtime.
ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
Expr *IndexExpr,
ObjCMethodDecl *getterMethod,
ObjCMethodDecl *setterMethod) {
- // Feature support is for modern abi.
- if (!LangOpts.ObjCNonFragileABI)
- return ExprError();
- // If the expression is type-dependent, there's nothing for us to do.
- assert ((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) &&
- "base or index cannot have dependent type here");
+ assert(!LangOpts.ObjCRuntime.isSubscriptPointerArithmetic());
+
+ // We can't get dependent types here; our callers should have
+ // filtered them out.
+ assert((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) &&
+ "base or index cannot have dependent type here");
+
+ // Filter out placeholders in the index. In theory, overloads could
+ // be preserved here, although that might not actually work correctly.
ExprResult Result = CheckPlaceholderExpr(IndexExpr);
if (Result.isInvalid())
return ExprError();
IndexExpr = Result.get();
- // Perform lvalue-to-rvalue conversion.
+ // Perform lvalue-to-rvalue conversion on the base.
Result = DefaultLvalueConversion(BaseExpr);
if (Result.isInvalid())
return ExprError();
BaseExpr = Result.get();
+
+ // Build the pseudo-object expression.
return Owned(ObjCSubscriptRefExpr::Create(Context,
BaseExpr,
IndexExpr,
@@ -440,11 +637,10 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
if (!ArrayWithObjectsMethod) {
Selector
Sel = NSAPIObj->getNSArraySelector(NSAPI::NSArr_arrayWithObjectsCount);
- ArrayWithObjectsMethod = NSArrayDecl->lookupClassMethod(Sel);
- if (!ArrayWithObjectsMethod && getLangOpts().DebuggerObjCLiteral) {
+ ObjCMethodDecl *Method = NSArrayDecl->lookupClassMethod(Sel);
+ if (!Method && getLangOpts().DebuggerObjCLiteral) {
TypeSourceInfo *ResultTInfo = 0;
- ArrayWithObjectsMethod =
- ObjCMethodDecl::Create(Context,
+ Method = ObjCMethodDecl::Create(Context,
SourceLocation(), SourceLocation(), Sel,
IdT,
ResultTInfo,
@@ -455,80 +651,68 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
ObjCMethodDecl::Required,
false);
SmallVector<ParmVarDecl *, 2> Params;
- ParmVarDecl *objects = ParmVarDecl::Create(Context, ArrayWithObjectsMethod,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("objects"),
- Context.getPointerType(IdT),
- /*TInfo=*/0,
- SC_None,
- SC_None,
- 0);
+ ParmVarDecl *objects = ParmVarDecl::Create(Context, Method,
+ SourceLocation(),
+ SourceLocation(),
+ &Context.Idents.get("objects"),
+ Context.getPointerType(IdT),
+ /*TInfo=*/0, SC_None, SC_None,
+ 0);
Params.push_back(objects);
- ParmVarDecl *cnt = ParmVarDecl::Create(Context, ArrayWithObjectsMethod,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("cnt"),
- Context.UnsignedLongTy,
- /*TInfo=*/0,
- SC_None,
- SC_None,
- 0);
+ ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
+ SourceLocation(),
+ SourceLocation(),
+ &Context.Idents.get("cnt"),
+ Context.UnsignedLongTy,
+ /*TInfo=*/0, SC_None, SC_None,
+ 0);
Params.push_back(cnt);
- ArrayWithObjectsMethod->setMethodParams(Context, Params,
- ArrayRef<SourceLocation>());
-
-
+ Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>());
}
- if (!ArrayWithObjectsMethod) {
- Diag(SR.getBegin(), diag::err_undeclared_arraywithobjects) << Sel;
+ if (!validateBoxingMethod(*this, SR.getBegin(), NSArrayDecl, Sel, Method))
+ return ExprError();
+
+ // Dig out the type that all elements should be converted to.
+ QualType T = Method->param_begin()[0]->getType();
+ const PointerType *PtrT = T->getAs<PointerType>();
+ if (!PtrT ||
+ !Context.hasSameUnqualifiedType(PtrT->getPointeeType(), IdT)) {
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << Sel;
+ Diag(Method->param_begin()[0]->getLocation(),
+ diag::note_objc_literal_method_param)
+ << 0 << T
+ << Context.getPointerType(IdT.withConst());
return ExprError();
}
- }
- // Make sure the return type is reasonable.
- if (!ArrayWithObjectsMethod->getResultType()->isObjCObjectPointerType()) {
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << ArrayWithObjectsMethod->getSelector();
- Diag(ArrayWithObjectsMethod->getLocation(),
- diag::note_objc_literal_method_return)
- << ArrayWithObjectsMethod->getResultType();
- return ExprError();
- }
+ // Check that the 'count' parameter is integral.
+ if (!Method->param_begin()[1]->getType()->isIntegerType()) {
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << Sel;
+ Diag(Method->param_begin()[1]->getLocation(),
+ diag::note_objc_literal_method_param)
+ << 1
+ << Method->param_begin()[1]->getType()
+ << "integral";
+ return ExprError();
+ }
- // Dig out the type that all elements should be converted to.
- QualType T = ArrayWithObjectsMethod->param_begin()[0]->getType();
- const PointerType *PtrT = T->getAs<PointerType>();
- if (!PtrT ||
- !Context.hasSameUnqualifiedType(PtrT->getPointeeType(), IdT)) {
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << ArrayWithObjectsMethod->getSelector();
- Diag(ArrayWithObjectsMethod->param_begin()[0]->getLocation(),
- diag::note_objc_literal_method_param)
- << 0 << T
- << Context.getPointerType(IdT.withConst());
- return ExprError();
- }
- T = PtrT->getPointeeType();
-
- // Check that the 'count' parameter is integral.
- if (!ArrayWithObjectsMethod->param_begin()[1]->getType()->isIntegerType()) {
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << ArrayWithObjectsMethod->getSelector();
- Diag(ArrayWithObjectsMethod->param_begin()[1]->getLocation(),
- diag::note_objc_literal_method_param)
- << 1
- << ArrayWithObjectsMethod->param_begin()[1]->getType()
- << "integral";
- return ExprError();
+ // We've found a good +arrayWithObjects:count: method. Save it!
+ ArrayWithObjectsMethod = Method;
}
+ QualType ObjectsType = ArrayWithObjectsMethod->param_begin()[0]->getType();
+ QualType RequiredType = ObjectsType->castAs<PointerType>()->getPointeeType();
+
// Check that each of the elements provided is valid in a collection literal,
// performing conversions as necessary.
Expr **ElementsBuffer = Elements.get();
for (unsigned I = 0, N = Elements.size(); I != N; ++I) {
ExprResult Converted = CheckObjCCollectionLiteralElement(*this,
ElementsBuffer[I],
- T);
+ RequiredType);
if (Converted.isInvalid())
return ExprError();
@@ -573,11 +757,10 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
QualType IdT = Context.getObjCIdType();
if (!DictionaryWithObjectsMethod) {
Selector Sel = NSAPIObj->getNSDictionarySelector(
- NSAPI::NSDict_dictionaryWithObjectsForKeysCount);
- DictionaryWithObjectsMethod = NSDictionaryDecl->lookupClassMethod(Sel);
- if (!DictionaryWithObjectsMethod && getLangOpts().DebuggerObjCLiteral) {
- DictionaryWithObjectsMethod =
- ObjCMethodDecl::Create(Context,
+ NSAPI::NSDict_dictionaryWithObjectsForKeysCount);
+ ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel);
+ if (!Method && getLangOpts().DebuggerObjCLiteral) {
+ Method = ObjCMethodDecl::Create(Context,
SourceLocation(), SourceLocation(), Sel,
IdT,
0 /*TypeSourceInfo */,
@@ -588,117 +771,107 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
ObjCMethodDecl::Required,
false);
SmallVector<ParmVarDecl *, 3> Params;
- ParmVarDecl *objects = ParmVarDecl::Create(Context, DictionaryWithObjectsMethod,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("objects"),
- Context.getPointerType(IdT),
- /*TInfo=*/0,
- SC_None,
- SC_None,
- 0);
+ ParmVarDecl *objects = ParmVarDecl::Create(Context, Method,
+ SourceLocation(),
+ SourceLocation(),
+ &Context.Idents.get("objects"),
+ Context.getPointerType(IdT),
+ /*TInfo=*/0, SC_None, SC_None,
+ 0);
Params.push_back(objects);
- ParmVarDecl *keys = ParmVarDecl::Create(Context, DictionaryWithObjectsMethod,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("keys"),
- Context.getPointerType(IdT),
- /*TInfo=*/0,
- SC_None,
- SC_None,
- 0);
+ ParmVarDecl *keys = ParmVarDecl::Create(Context, Method,
+ SourceLocation(),
+ SourceLocation(),
+ &Context.Idents.get("keys"),
+ Context.getPointerType(IdT),
+ /*TInfo=*/0, SC_None, SC_None,
+ 0);
Params.push_back(keys);
- ParmVarDecl *cnt = ParmVarDecl::Create(Context, DictionaryWithObjectsMethod,
- SourceLocation(), SourceLocation(),
- &Context.Idents.get("cnt"),
- Context.UnsignedLongTy,
- /*TInfo=*/0,
- SC_None,
- SC_None,
- 0);
+ ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
+ SourceLocation(),
+ SourceLocation(),
+ &Context.Idents.get("cnt"),
+ Context.UnsignedLongTy,
+ /*TInfo=*/0, SC_None, SC_None,
+ 0);
Params.push_back(cnt);
- DictionaryWithObjectsMethod->setMethodParams(Context, Params,
- ArrayRef<SourceLocation>());
+ Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>());
}
- if (!DictionaryWithObjectsMethod) {
- Diag(SR.getBegin(), diag::err_undeclared_dictwithobjects) << Sel;
- return ExprError();
+ if (!validateBoxingMethod(*this, SR.getBegin(), NSDictionaryDecl, Sel,
+ Method))
+ return ExprError();
+
+ // Dig out the type that all values should be converted to.
+ QualType ValueT = Method->param_begin()[0]->getType();
+ const PointerType *PtrValue = ValueT->getAs<PointerType>();
+ if (!PtrValue ||
+ !Context.hasSameUnqualifiedType(PtrValue->getPointeeType(), IdT)) {
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << Sel;
+ Diag(Method->param_begin()[0]->getLocation(),
+ diag::note_objc_literal_method_param)
+ << 0 << ValueT
+ << Context.getPointerType(IdT.withConst());
+ return ExprError();
}
- }
-
- // Make sure the return type is reasonable.
- if (!DictionaryWithObjectsMethod->getResultType()->isObjCObjectPointerType()){
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << DictionaryWithObjectsMethod->getSelector();
- Diag(DictionaryWithObjectsMethod->getLocation(),
- diag::note_objc_literal_method_return)
- << DictionaryWithObjectsMethod->getResultType();
- return ExprError();
- }
- // Dig out the type that all values should be converted to.
- QualType ValueT = DictionaryWithObjectsMethod->param_begin()[0]->getType();
- const PointerType *PtrValue = ValueT->getAs<PointerType>();
- if (!PtrValue ||
- !Context.hasSameUnqualifiedType(PtrValue->getPointeeType(), IdT)) {
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << DictionaryWithObjectsMethod->getSelector();
- Diag(DictionaryWithObjectsMethod->param_begin()[0]->getLocation(),
- diag::note_objc_literal_method_param)
- << 0 << ValueT
- << Context.getPointerType(IdT.withConst());
- return ExprError();
- }
- ValueT = PtrValue->getPointeeType();
-
- // Dig out the type that all keys should be converted to.
- QualType KeyT = DictionaryWithObjectsMethod->param_begin()[1]->getType();
- const PointerType *PtrKey = KeyT->getAs<PointerType>();
- if (!PtrKey ||
- !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
- IdT)) {
- bool err = true;
- if (PtrKey) {
- if (QIDNSCopying.isNull()) {
- // key argument of selector is id<NSCopying>?
- if (ObjCProtocolDecl *NSCopyingPDecl =
- LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) {
- ObjCProtocolDecl *PQ[] = {NSCopyingPDecl};
- QIDNSCopying =
- Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
- (ObjCProtocolDecl**) PQ,1);
- QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying);
+ // Dig out the type that all keys should be converted to.
+ QualType KeyT = Method->param_begin()[1]->getType();
+ const PointerType *PtrKey = KeyT->getAs<PointerType>();
+ if (!PtrKey ||
+ !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
+ IdT)) {
+ bool err = true;
+ if (PtrKey) {
+ if (QIDNSCopying.isNull()) {
+ // key argument of selector is id<NSCopying>?
+ if (ObjCProtocolDecl *NSCopyingPDecl =
+ LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) {
+ ObjCProtocolDecl *PQ[] = {NSCopyingPDecl};
+ QIDNSCopying =
+ Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
+ (ObjCProtocolDecl**) PQ,1);
+ QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying);
+ }
}
+ if (!QIDNSCopying.isNull())
+ err = !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
+ QIDNSCopying);
}
- if (!QIDNSCopying.isNull())
- err = !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
- QIDNSCopying);
- }
- if (err) {
+ if (err) {
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << Sel;
+ Diag(Method->param_begin()[1]->getLocation(),
+ diag::note_objc_literal_method_param)
+ << 1 << KeyT
+ << Context.getPointerType(IdT.withConst());
+ return ExprError();
+ }
+ }
+
+ // Check that the 'count' parameter is integral.
+ QualType CountType = Method->param_begin()[2]->getType();
+ if (!CountType->isIntegerType()) {
Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << DictionaryWithObjectsMethod->getSelector();
- Diag(DictionaryWithObjectsMethod->param_begin()[1]->getLocation(),
+ << Sel;
+ Diag(Method->param_begin()[2]->getLocation(),
diag::note_objc_literal_method_param)
- << 1 << KeyT
- << Context.getPointerType(IdT.withConst());
+ << 2 << CountType
+ << "integral";
return ExprError();
}
- }
- KeyT = PtrKey->getPointeeType();
- // Check that the 'count' parameter is integral.
- if (!DictionaryWithObjectsMethod->param_begin()[2]->getType()
- ->isIntegerType()) {
- Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
- << DictionaryWithObjectsMethod->getSelector();
- Diag(DictionaryWithObjectsMethod->param_begin()[2]->getLocation(),
- diag::note_objc_literal_method_param)
- << 2
- << DictionaryWithObjectsMethod->param_begin()[2]->getType()
- << "integral";
- return ExprError();
+ // We've found a good +dictionaryWithObjects:keys:count: method; save it!
+ DictionaryWithObjectsMethod = Method;
}
+ QualType ValuesT = DictionaryWithObjectsMethod->param_begin()[0]->getType();
+ QualType ValueT = ValuesT->castAs<PointerType>()->getPointeeType();
+ QualType KeysT = DictionaryWithObjectsMethod->param_begin()[1]->getType();
+ QualType KeyT = KeysT->castAs<PointerType>()->getPointeeType();
+
// Check that each of the keys and values provided is valid in a collection
// literal, performing conversions as necessary.
bool HasPackExpansions = false;
@@ -757,8 +930,8 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
if (!EncodedType->getAsArrayTypeUnsafe() && //// Incomplete array is handled.
!EncodedType->isVoidType()) // void is handled too.
if (RequireCompleteType(AtLoc, EncodedType,
- PDiag(diag::err_incomplete_type_objc_at_encode)
- << EncodedTypeInfo->getTypeLoc().getSourceRange()))
+ diag::err_incomplete_type_objc_at_encode,
+ EncodedTypeInfo->getTypeLoc()))
return ExprError();
std::string Str;
@@ -846,8 +1019,9 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
SourceLocation AtLoc,
SourceLocation ProtoLoc,
SourceLocation LParenLoc,
+ SourceLocation ProtoIdLoc,
SourceLocation RParenLoc) {
- ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoLoc);
+ ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoIdLoc);
if (!PDecl) {
Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId;
return true;
@@ -857,7 +1031,7 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
if (Ty.isNull())
return true;
Ty = Context.getObjCObjectPointerType(Ty);
- return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc);
+ return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, ProtoIdLoc, RParenLoc);
}
/// Try to capture an implicit reference to 'self'.
@@ -1023,8 +1197,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
param->getType(),
- PDiag(diag::err_call_incomplete_argument)
- << argExpr->getSourceRange()))
+ diag::err_call_incomplete_argument, argExpr))
return true;
InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
@@ -1042,7 +1215,8 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
if (Args[i]->isTypeDependent())
continue;
- ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0);
+ ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
+ 0);
IsError |= Arg.isInvalid();
Args[i] = Arg.take();
}
@@ -1079,57 +1253,6 @@ bool Sema::isSelfExpr(Expr *receiver) {
return false;
}
-// Helper method for ActOnClassMethod/ActOnInstanceMethod.
-// Will search "local" class/category implementations for a method decl.
-// If failed, then we search in class's root for an instance method.
-// Returns 0 if no method is found.
-ObjCMethodDecl *Sema::LookupPrivateClassMethod(Selector Sel,
- ObjCInterfaceDecl *ClassDecl) {
- ObjCMethodDecl *Method = 0;
- // lookup in class and all superclasses
- while (ClassDecl && !Method) {
- if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
- Method = ImpDecl->getClassMethod(Sel);
-
- // Look through local category implementations associated with the class.
- if (!Method)
- Method = ClassDecl->getCategoryClassMethod(Sel);
-
- // Before we give up, check if the selector is an instance method.
- // But only in the root. This matches gcc's behaviour and what the
- // runtime expects.
- if (!Method && !ClassDecl->getSuperClass()) {
- Method = ClassDecl->lookupInstanceMethod(Sel);
- // Look through local category implementations associated
- // with the root class.
- if (!Method)
- Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
- }
-
- ClassDecl = ClassDecl->getSuperClass();
- }
- return Method;
-}
-
-ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
- ObjCInterfaceDecl *ClassDecl) {
- if (!ClassDecl->hasDefinition())
- return 0;
-
- ObjCMethodDecl *Method = 0;
- while (ClassDecl && !Method) {
- // If we have implementations in scope, check "private" methods.
- if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
- Method = ImpDecl->getInstanceMethod(Sel);
-
- // Look through local category implementations associated with the class.
- if (!Method)
- Method = ClassDecl->getCategoryInstanceMethod(Sel);
- ClassDecl = ClassDecl->getSuperClass();
- }
- return Method;
-}
-
/// LookupMethodInType - Look up a method in an ObjCObjectType.
ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type,
bool isInstance) {
@@ -1141,13 +1264,8 @@ ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type,
// Okay, look for "private" methods declared in any
// @implementations we've seen.
- if (isInstance) {
- if (ObjCMethodDecl *method = LookupPrivateInstanceMethod(sel, iface))
- return method;
- } else {
- if (ObjCMethodDecl *method = LookupPrivateClassMethod(sel, iface))
- return method;
- }
+ if (ObjCMethodDecl *method = iface->lookupPrivateMethod(sel, isInstance))
+ return method;
}
// Check qualifiers.
@@ -1176,6 +1294,69 @@ ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
return 0;
}
+static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) {
+ if (!Receiver)
+ return;
+
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Receiver))
+ Receiver = OVE->getSourceExpr();
+
+ Expr *RExpr = Receiver->IgnoreParenImpCasts();
+ SourceLocation Loc = RExpr->getLocStart();
+ QualType T = RExpr->getType();
+ ObjCPropertyDecl *PDecl = 0;
+ ObjCMethodDecl *GDecl = 0;
+ if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(RExpr)) {
+ RExpr = POE->getSyntacticForm();
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(RExpr)) {
+ if (PRE->isImplicitProperty()) {
+ GDecl = PRE->getImplicitPropertyGetter();
+ if (GDecl) {
+ T = GDecl->getResultType();
+ }
+ }
+ else {
+ PDecl = PRE->getExplicitProperty();
+ if (PDecl) {
+ T = PDecl->getType();
+ }
+ }
+ }
+ }
+ else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RExpr)) {
+ // See if receiver is a method which envokes a synthesized getter
+ // backing a 'weak' property.
+ ObjCMethodDecl *Method = ME->getMethodDecl();
+ if (Method && Method->isSynthesized()) {
+ Selector Sel = Method->getSelector();
+ if (Sel.getNumArgs() == 0) {
+ const DeclContext *Container = Method->getDeclContext();
+ PDecl =
+ S.LookupPropertyDecl(cast<ObjCContainerDecl>(Container),
+ Sel.getIdentifierInfoForSlot(0));
+ }
+ if (PDecl)
+ T = PDecl->getType();
+ }
+ }
+
+ if (T.getObjCLifetime() == Qualifiers::OCL_Weak) {
+ S.Diag(Loc, diag::warn_receiver_is_weak)
+ << ((!PDecl && !GDecl) ? 0 : (PDecl ? 1 : 2));
+ if (PDecl)
+ S.Diag(PDecl->getLocation(), diag::note_property_declare);
+ else if (GDecl)
+ S.Diag(GDecl->getLocation(), diag::note_method_declared_at) << GDecl;
+ return;
+ }
+
+ if (PDecl &&
+ (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)) {
+ S.Diag(Loc, diag::warn_receiver_is_weak) << 1;
+ S.Diag(PDecl->getLocation(), diag::note_property_declare);
+ }
+}
+
/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
/// objective C interface. This is a property reference expression.
ExprResult Sema::
@@ -1187,19 +1368,20 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
bool Super) {
const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
ObjCInterfaceDecl *IFace = IFaceT->getDecl();
-
- if (MemberName.getNameKind() != DeclarationName::Identifier) {
+
+ if (!MemberName.isIdentifier()) {
Diag(MemberLoc, diag::err_invalid_property_name)
<< MemberName << QualType(OPT, 0);
return ExprError();
}
-
+
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+
SourceRange BaseRange = Super? SourceRange(SuperLoc)
: BaseExpr->getSourceRange();
if (RequireCompleteType(MemberLoc, OPT->getPointeeType(),
- PDiag(diag::err_property_not_found_forward_class)
- << MemberName << BaseRange))
+ diag::err_property_not_found_forward_class,
+ MemberName, BaseRange))
return ExprError();
// Search for a declared property first.
@@ -1207,7 +1389,6 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
-
if (Super)
return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty,
@@ -1225,7 +1406,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
-
+
if (Super)
return Owned(new (Context) ObjCPropertyRefExpr(PD,
Context.PseudoObjectTy,
@@ -1258,9 +1439,6 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (!Getter)
Getter = IFace->lookupPrivateMethod(Sel);
- // Look through local category implementations associated with the class.
- if (!Getter)
- Getter = IFace->getCategoryInstanceMethod(Sel);
if (Getter) {
// Check if we can reference this property.
if (DiagnoseUseOfDecl(Getter, MemberLoc))
@@ -1272,7 +1450,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
SelectorTable::constructSetterName(PP.getIdentifierTable(),
PP.getSelectorTable(), Member);
ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
-
+
// May be founf in property's qualified list.
if (!Setter)
Setter = LookupMethodInQualifiedType(SetterSel, OPT, true);
@@ -1282,9 +1460,6 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// methods.
Setter = IFace->lookupPrivateMethod(SetterSel);
}
- // Look through local category implementations associated with the class.
- if (!Setter)
- Setter = IFace->getCategoryInstanceMethod(SetterSel);
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
@@ -1328,8 +1503,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (const ObjCObjectPointerType * OBJPT =
T->getAsObjCInterfacePointerType()) {
if (RequireCompleteType(MemberLoc, OBJPT->getPointeeType(),
- PDiag(diag::err_property_not_as_forward_class)
- << MemberName << BaseExpr->getSourceRange()))
+ diag::err_property_not_as_forward_class,
+ MemberName, BaseExpr))
return ExprError();
}
Diag(MemberLoc,
@@ -1603,9 +1778,9 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
// is acting as a keyword.
if (Method->isInstanceMethod()) {
if (Sel.getMethodFamily() == OMF_dealloc)
- ObjCShouldCallSuperDealloc = false;
+ getCurFunction()->ObjCShouldCallSuperDealloc = false;
if (Sel.getMethodFamily() == OMF_finalize)
- ObjCShouldCallSuperFinalize = false;
+ getCurFunction()->ObjCShouldCallSuperFinalize = false;
// Since we are in an instance method, this is an instance
// message to the superclass instance.
@@ -1711,9 +1886,9 @@ static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) {
///
/// \param LBracLoc The location of the opening square bracket ']'.
///
-/// \param RBrac The location of the closing square bracket ']'.
+/// \param RBracLoc The location of the closing square bracket ']'.
///
-/// \param Args The message arguments.
+/// \param ArgsIn The message arguments.
ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
QualType ReceiverType,
SourceLocation SuperLoc,
@@ -1762,11 +1937,11 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
SourceRange TypeRange
= SuperLoc.isValid()? SourceRange(SuperLoc)
: ReceiverTypeInfo->getTypeLoc().getSourceRange();
- if (RequireCompleteType(Loc, Context.getObjCInterfaceType(Class),
+ if (RequireCompleteType(Loc, Context.getObjCInterfaceType(Class),
(getLangOpts().ObjCAutoRefCount
- ? PDiag(diag::err_arc_receiver_forward_class)
- : PDiag(diag::warn_receiver_forward_class))
- << TypeRange)) {
+ ? diag::err_arc_receiver_forward_class
+ : diag::warn_receiver_forward_class),
+ TypeRange)) {
// A forward class used in messaging is treated as a 'Class'
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc));
@@ -1779,7 +1954,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
// If we have an implementation in scope, check "private" methods.
if (!Method)
- Method = LookupPrivateClassMethod(Sel, Class);
+ Method = Class->lookupPrivateClassMethod(Sel);
if (Method && DiagnoseUseOfDecl(Method, Loc))
return ExprError();
@@ -1881,9 +2056,9 @@ ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
///
/// \param LBracLoc The location of the opening square bracket ']'.
///
-/// \param RBrac The location of the closing square bracket ']'.
+/// \param RBracLoc The location of the closing square bracket ']'.
///
-/// \param Args The message arguments.
+/// \param ArgsIn The message arguments.
ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
QualType ReceiverType,
SourceLocation SuperLoc,
@@ -1948,7 +2123,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
receiverIsId);
if (!Method)
Method = LookupFactoryMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc),
+ SourceRange(LBracLoc,RBracLoc),
receiverIsId);
} else if (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType()) {
@@ -1976,7 +2151,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
Method = ClassDecl->lookupClassMethod(Sel);
if (!Method)
- Method = LookupPrivateClassMethod(Sel, ClassDecl);
+ Method = ClassDecl->lookupPrivateClassMethod(Sel);
}
if (Method && DiagnoseUseOfDecl(Method, Loc))
return ExprError();
@@ -2009,12 +2184,15 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// We allow sending a message to a qualified ID ("id<foo>"), which is ok as
// long as one of the protocols implements the selector (if not, warn).
+ // And as long as message is not deprecated/unavailable (warn if it is).
if (const ObjCObjectPointerType *QIdTy
= ReceiverType->getAsObjCQualifiedIdType()) {
// Search protocols for instance methods.
Method = LookupMethodInQualifiedType(Sel, QIdTy, true);
if (!Method)
Method = LookupMethodInQualifiedType(Sel, QIdTy, false);
+ if (Method && DiagnoseUseOfDecl(Method, Loc))
+ return ExprError();
} else if (const ObjCObjectPointerType *OCIType
= ReceiverType->getAsObjCInterfacePointerType()) {
// We allow sending a message to a pointer to an interface (an object).
@@ -2025,12 +2203,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
const ObjCInterfaceDecl *forwardClass = 0;
if (RequireCompleteType(Loc, OCIType->getPointeeType(),
getLangOpts().ObjCAutoRefCount
- ? PDiag(diag::err_arc_receiver_forward_instance)
- << (Receiver ? Receiver->getSourceRange()
- : SourceRange(SuperLoc))
- : PDiag(diag::warn_receiver_forward_instance)
- << (Receiver ? Receiver->getSourceRange()
- : SourceRange(SuperLoc)))) {
+ ? diag::err_arc_receiver_forward_instance
+ : diag::warn_receiver_forward_instance,
+ Receiver? Receiver->getSourceRange()
+ : SourceRange(SuperLoc))) {
if (getLangOpts().ObjCAutoRefCount)
return ExprError();
@@ -2048,7 +2224,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (!Method) {
// If we have implementations in scope, check "private" methods.
- Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
+ Method = ClassDecl->lookupPrivateMethod(Sel);
if (!Method && getLangOpts().ObjCAutoRefCount) {
Diag(Loc, diag::err_arc_may_not_respond)
@@ -2062,7 +2238,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// compatibility. FIXME: should we deviate??
if (OCIType->qual_empty()) {
Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc));
+ SourceRange(LBracLoc, RBracLoc));
if (Method && !forwardClass)
Diag(Loc, diag::warn_maynot_respond)
<< OCIType->getInterfaceDecl()->getIdentifier() << Sel;
@@ -2087,8 +2263,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// TODO: specialized warning on null receivers?
bool IsNull = Receiver->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
+ CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer;
Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- IsNull ? CK_NullToPointer : CK_IntegralToPointer).take();
+ Kind).take();
}
ReceiverType = Receiver->getType();
} else {
@@ -2232,10 +2409,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
if (getLangOpts().ObjCAutoRefCount) {
- if (Receiver &&
- (Receiver->IgnoreParenImpCasts()->getType().getObjCLifetime()
- == Qualifiers::OCL_Weak))
- Diag(Receiver->getLocStart(), diag::warn_receiver_is_weak);
+ DiagnoseARCUseOfWeakReceiver(*this, Receiver);
// In ARC, annotate delegate init calls.
if (Result->getMethodFamily() == OMF_init &&
@@ -2373,6 +2547,7 @@ namespace {
ASTContext &Context;
ARCConversionTypeClass SourceClass;
ARCConversionTypeClass TargetClass;
+ bool Diagnose;
static bool isCFType(QualType type) {
// Someday this can use ns_bridged. For now, it has to do this.
@@ -2381,8 +2556,9 @@ namespace {
public:
ARCCastChecker(ASTContext &Context, ARCConversionTypeClass source,
- ARCConversionTypeClass target)
- : Context(Context), SourceClass(source), TargetClass(target) {}
+ ARCConversionTypeClass target, bool diagnose)
+ : Context(Context), SourceClass(source), TargetClass(target),
+ Diagnose(diagnose) {}
using super::Visit;
ACCResult Visit(Expr *e) {
@@ -2500,7 +2676,8 @@ namespace {
// now we're not going to permit implicit handling of +1 results,
// because it's a bit frightening.
if (fn->hasAttr<CFReturnsRetainedAttr>())
- return ACC_invalid; // ACC_plusOne if we start accepting this
+ return Diagnose ? ACC_plusOne
+ : ACC_invalid; // ACC_plusOne if we start accepting this
// Recognize this specific builtin function, which is used by CFSTR.
unsigned builtinID = fn->getBuiltinID();
@@ -2510,10 +2687,11 @@ namespace {
// Otherwise, don't do anything implicit with an unaudited function.
if (!fn->hasAttr<CFAuditedTransferAttr>())
return ACC_invalid;
-
+
// Otherwise, it's +0 unless it follows the create convention.
if (ento::coreFoundation::followsCreateRule(fn))
- return ACC_invalid; // ACC_plusOne if we start accepting this
+ return Diagnose ? ACC_plusOne
+ : ACC_invalid; // ACC_plusOne if we start accepting this
return ACC_plusZero;
}
@@ -2564,11 +2742,12 @@ namespace {
};
}
-static bool
-KnownName(Sema &S, const char *name) {
- LookupResult R(S, &S.Context.Idents.get(name), SourceLocation(),
+bool Sema::isKnownName(StringRef name) {
+ if (name.empty())
+ return false;
+ LookupResult R(*this, &Context.Idents.get(name), SourceLocation(),
Sema::LookupOrdinaryName);
- return S.LookupName(R, S.TUScope, false);
+ return LookupName(R, TUScope, false);
}
static void addFixitForObjCARCConversion(Sema &S,
@@ -2595,14 +2774,23 @@ static void addFixitForObjCARCConversion(Sema &S,
castedE = CCE->getSubExpr();
castedE = castedE->IgnoreImpCasts();
SourceRange range = castedE->getSourceRange();
+
+ SmallString<32> BridgeCall;
+
+ SourceManager &SM = S.getSourceManager();
+ char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1));
+ if (Lexer::isIdentifierBodyChar(PrevChar, S.getLangOpts()))
+ BridgeCall += ' ';
+
+ BridgeCall += CFBridgeName;
+
if (isa<ParenExpr>(castedE)) {
DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
- CFBridgeName));
+ BridgeCall));
} else {
- std::string namePlusParen = CFBridgeName;
- namePlusParen += "(";
+ BridgeCall += '(';
DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
- namePlusParen));
+ BridgeCall));
DiagB.AddFixItHint(FixItHint::CreateInsertion(
S.PP.getLocForEndOfToken(range.getEnd()),
")"));
@@ -2677,14 +2865,20 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
<< castType
<< castRange
<< castExpr->getSourceRange();
- bool br = KnownName(S, "CFBridgingRelease");
+ bool br = S.isKnownName("CFBridgingRelease");
+ ACCResult CreateRule =
+ ARCCastChecker(S.Context, exprACTC, castACTC, true).Visit(castExpr);
+ assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
+ if (CreateRule != ACC_plusOne)
{
DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge);
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
castType, castExpr, "__bridge ", 0);
}
+ if (CreateRule != ACC_plusZero)
{
- DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge_transfer)
+ DiagnosticBuilder DiagB = S.Diag(br ? castExpr->getExprLoc() : noteLoc,
+ diag::note_arc_bridge_transfer)
<< castExprType << br;
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
castType, castExpr, "__bridge_transfer ",
@@ -2696,7 +2890,7 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
// Bridge from a CF type to an ARC type.
if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) {
- bool br = KnownName(S, "CFBridgingRetain");
+ bool br = S.isKnownName("CFBridgingRetain");
S.Diag(loc, diag::err_arc_cast_requires_bridge)
<< unsigned(CCK == Sema::CCK_ImplicitConversion) // cast|implicit
<< unsigned(castExprType->isBlockPointerType()) // of ObjC|block type
@@ -2705,14 +2899,19 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
<< castType
<< castRange
<< castExpr->getSourceRange();
-
+ ACCResult CreateRule =
+ ARCCastChecker(S.Context, exprACTC, castACTC, true).Visit(castExpr);
+ assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
+ if (CreateRule != ACC_plusOne)
{
DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge);
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
castType, castExpr, "__bridge ", 0);
}
+ if (CreateRule != ACC_plusZero)
{
- DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge_retained)
+ DiagnosticBuilder DiagB = S.Diag(br ? castExpr->getExprLoc() : noteLoc,
+ diag::note_arc_bridge_retained)
<< castType << br;
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
castType, castExpr, "__bridge_retained ",
@@ -2785,7 +2984,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
CCK != CCK_ImplicitConversion)
return ACR_okay;
- switch (ARCCastChecker(Context, exprACTC, castACTC).Visit(castExpr)) {
+ switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) {
// For invalid casts, fall through.
case ACC_invalid:
break;
@@ -2949,7 +3148,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
break;
case OBC_BridgeRetained: {
- bool br = KnownName(*this, "CFBridgingRelease");
+ bool br = isKnownName("CFBridgingRelease");
Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
<< 2
<< FromType
@@ -2992,7 +3191,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
break;
case OBC_BridgeTransfer: {
- bool br = KnownName(*this, "CFBridgingRetain");
+ bool br = isKnownName("CFBridgingRetain");
Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
<< (FromType->isBlockPointerType()? 1 : 0)
<< FromType
diff --git a/lib/Sema/SemaFixItUtils.cpp b/lib/Sema/SemaFixItUtils.cpp
index b78ea7d..b61b930 100644
--- a/lib/Sema/SemaFixItUtils.cpp
+++ b/lib/Sema/SemaFixItUtils.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTContext.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/Preprocessor.h"
@@ -163,42 +164,54 @@ static bool isMacroDefined(const Sema &S, StringRef Name) {
return S.PP.getMacroInfo(&S.getASTContext().Idents.get(Name));
}
-const char *Sema::getFixItZeroInitializerForType(QualType T) const {
+static std::string getScalarZeroExpressionForType(const Type& T, const Sema& S) {
+ assert(T.isScalarType() && "use scalar types only");
+ // Suggest "0" for non-enumeration scalar types, unless we can find a
+ // better initializer.
+ if (T.isEnumeralType())
+ return std::string();
+ if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
+ isMacroDefined(S, "nil"))
+ return "nil";
+ if (T.isRealFloatingType())
+ return "0.0";
+ if (T.isBooleanType() && S.LangOpts.CPlusPlus)
+ return "false";
+ if (T.isPointerType() || T.isMemberPointerType()) {
+ if (S.LangOpts.CPlusPlus0x)
+ return "nullptr";
+ if (isMacroDefined(S, "NULL"))
+ return "NULL";
+ }
+ if (T.isCharType())
+ return "'\\0'";
+ if (T.isWideCharType())
+ return "L'\\0'";
+ if (T.isChar16Type())
+ return "u'\\0'";
+ if (T.isChar32Type())
+ return "U'\\0'";
+ return "0";
+}
+
+std::string Sema::getFixItZeroInitializerForType(QualType T) const {
if (T->isScalarType()) {
- // Suggest " = 0" for non-enumeration scalar types, unless we can find a
- // better initializer.
- if (T->isEnumeralType())
- return 0;
- if ((T->isObjCObjectPointerType() || T->isBlockPointerType()) &&
- isMacroDefined(*this, "nil"))
- return " = nil";
- if (T->isRealFloatingType())
- return " = 0.0";
- if (T->isBooleanType() && LangOpts.CPlusPlus)
- return " = false";
- if (T->isPointerType() || T->isMemberPointerType()) {
- if (LangOpts.CPlusPlus0x)
- return " = nullptr";
- else if (isMacroDefined(*this, "NULL"))
- return " = NULL";
- }
- if (T->isCharType())
- return " = '\\0'";
- if (T->isWideCharType())
- return " = L'\\0'";
- if (T->isChar16Type())
- return " = u'\\0'";
- if (T->isChar32Type())
- return " = U'\\0'";
- return " = 0";
+ std::string s = getScalarZeroExpressionForType(*T, *this);
+ if (!s.empty())
+ s = " = " + s;
+ return s;
}
const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
if (!RD || !RD->hasDefinition())
- return 0;
+ return std::string();
if (LangOpts.CPlusPlus0x && !RD->hasUserProvidedDefaultConstructor())
return "{}";
if (RD->isAggregate())
return " = {}";
- return 0;
+ return std::string();
+}
+
+std::string Sema::getFixItZeroLiteralForType(QualType T) const {
+ return getScalarZeroExpressionForType(*T, *this);
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index a65b41f..62ab1e6 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -92,8 +92,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) {
// C99 6.7.8p14. We have an array of character type with unknown size
// being initialized to a string literal.
- llvm::APSInt ConstVal(32);
- ConstVal = StrLength;
+ llvm::APInt ConstVal(32, StrLength);
// Return a new array type (C99 6.7.8p22).
DeclT = S.Context.getConstantArrayType(IAT->getElementType(),
ConstVal,
@@ -687,22 +686,21 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isVectorType()) {
CheckVectorType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
- } else if (DeclType->isAggregateType()) {
- if (DeclType->isRecordType()) {
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
- CheckStructUnionTypes(Entity, IList, DeclType, RD->field_begin(),
- SubobjectIsDesignatorContext, Index,
- StructuredList, StructuredIndex,
- TopLevelObject);
- } else if (DeclType->isArrayType()) {
- llvm::APSInt Zero(
- SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()),
- false);
- CheckArrayType(Entity, IList, DeclType, Zero,
- SubobjectIsDesignatorContext, Index,
- StructuredList, StructuredIndex);
- } else
- llvm_unreachable("Aggregate that isn't a structure or array?!");
+ } else if (DeclType->isRecordType()) {
+ assert(DeclType->isAggregateType() &&
+ "non-aggregate records should be handed in CheckSubElementType");
+ RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ CheckStructUnionTypes(Entity, IList, DeclType, RD->field_begin(),
+ SubobjectIsDesignatorContext, Index,
+ StructuredList, StructuredIndex,
+ TopLevelObject);
+ } else if (DeclType->isArrayType()) {
+ llvm::APSInt Zero(
+ SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()),
+ false);
+ CheckArrayType(Entity, IList, DeclType, Zero,
+ SubobjectIsDesignatorContext, Index,
+ StructuredList, StructuredIndex);
} else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
// This type is invalid, issue a diagnostic.
++Index;
@@ -710,19 +708,6 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
<< DeclType;
hadError = true;
- } else if (DeclType->isRecordType()) {
- // C++ [dcl.init]p14:
- // [...] If the class is an aggregate (8.5.1), and the initializer
- // is a brace-enclosed list, see 8.5.1.
- //
- // Note: 8.5.1 is handled below; here, we diagnose the case where
- // we have an initializer list and a destination type that is not
- // an aggregate.
- // FIXME: In C++0x, this is yet another form of initialization.
- if (!VerifyOnly)
- SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
- << DeclType << IList->getSourceRange();
- hadError = true;
} else if (DeclType->isReferenceType()) {
CheckReferenceType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
@@ -747,18 +732,25 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
unsigned &StructuredIndex) {
Expr *expr = IList->getInit(Index);
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
- unsigned newIndex = 0;
- unsigned newStructuredIndex = 0;
- InitListExpr *newStructuredList
- = getStructuredSubobjectInit(IList, Index, ElemType,
- StructuredList, StructuredIndex,
- SubInitList->getSourceRange());
- CheckExplicitInitList(Entity, SubInitList, ElemType, newIndex,
- newStructuredList, newStructuredIndex);
- ++StructuredIndex;
- ++Index;
- return;
- } else if (ElemType->isScalarType()) {
+ if (!ElemType->isRecordType() || ElemType->isAggregateType()) {
+ unsigned newIndex = 0;
+ unsigned newStructuredIndex = 0;
+ InitListExpr *newStructuredList
+ = getStructuredSubobjectInit(IList, Index, ElemType,
+ StructuredList, StructuredIndex,
+ SubInitList->getSourceRange());
+ CheckExplicitInitList(Entity, SubInitList, ElemType, newIndex,
+ newStructuredList, newStructuredIndex);
+ ++StructuredIndex;
+ ++Index;
+ return;
+ }
+ assert(SemaRef.getLangOpts().CPlusPlus &&
+ "non-aggregate records are only possible in C++");
+ // C++ initialization is handled later.
+ }
+
+ if (ElemType->isScalarType()) {
return CheckScalarType(Entity, IList, ElemType, Index,
StructuredList, StructuredIndex);
} else if (ElemType->isReferenceType()) {
@@ -1859,7 +1851,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
}
} else {
// Recurse to check later designated subobjects.
- QualType FieldType = (*Field)->getType();
+ QualType FieldType = Field->getType();
unsigned newStructuredIndex = FieldIndex;
InitializedEntity MemberEntity =
@@ -2708,84 +2700,39 @@ static void MaybeProduceObjCObject(Sema &S,
}
}
-/// \brief When initializing from init list via constructor, deal with the
-/// empty init list and std::initializer_list special cases.
+/// \brief When initializing from init list via constructor, handle
+/// initialization of an object of type std::initializer_list<T>.
///
-/// \return True if this was a special case, false otherwise.
-static bool TryListConstructionSpecialCases(Sema &S,
- InitListExpr *List,
- CXXRecordDecl *DestRecordDecl,
- QualType DestType,
- InitializationSequence &Sequence) {
- // C++11 [dcl.init.list]p3:
- // List-initialization of an object or reference of type T is defined as
- // follows:
- // - If T is an aggregate, aggregate initialization is performed.
- if (DestType->isAggregateType())
+/// \return true if we have handled initialization of an object of type
+/// std::initializer_list<T>, false otherwise.
+static bool TryInitializerListConstruction(Sema &S,
+ InitListExpr *List,
+ QualType DestType,
+ InitializationSequence &Sequence) {
+ QualType E;
+ if (!S.isStdInitializerList(DestType, &E))
return false;
- // - Otherwise, if the initializer list has no elements and T is a class
- // type with a default constructor, the object is value-initialized.
- if (List->getNumInits() == 0) {
- if (CXXConstructorDecl *DefaultConstructor =
- S.LookupDefaultConstructor(DestRecordDecl)) {
- if (DefaultConstructor->isDeleted() ||
- S.isFunctionConsideredUnavailable(DefaultConstructor)) {
- // Fake an overload resolution failure.
- OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
- DeclAccessPair FoundDecl = DeclAccessPair::make(DefaultConstructor,
- DefaultConstructor->getAccess());
- if (FunctionTemplateDecl *ConstructorTmpl =
- dyn_cast<FunctionTemplateDecl>(DefaultConstructor))
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
- ArrayRef<Expr*>(), CandidateSet,
- /*SuppressUserConversions*/ false);
- else
- S.AddOverloadCandidate(DefaultConstructor, FoundDecl,
- ArrayRef<Expr*>(), CandidateSet,
- /*SuppressUserConversions*/ false);
- Sequence.SetOverloadFailure(
- InitializationSequence::FK_ListConstructorOverloadFailed,
- OR_Deleted);
- } else
- Sequence.AddConstructorInitializationStep(DefaultConstructor,
- DefaultConstructor->getAccess(),
- DestType,
- /*MultipleCandidates=*/false,
- /*FromInitList=*/true,
- /*AsInitList=*/false);
+ // Check that each individual element can be copy-constructed. But since we
+ // have no place to store further information, we'll recalculate everything
+ // later.
+ InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
+ S.Context.getConstantArrayType(E,
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ List->getNumInits()),
+ ArrayType::Normal, 0));
+ InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
+ 0, HiddenArray);
+ for (unsigned i = 0, n = List->getNumInits(); i < n; ++i) {
+ Element.setElementIndex(i);
+ if (!S.CanPerformCopyInitialization(Element, List->getInit(i))) {
+ Sequence.SetFailed(
+ InitializationSequence::FK_InitListElementCopyFailure);
return true;
}
}
-
- // - Otherwise, if T is a specialization of std::initializer_list, [...]
- QualType E;
- if (S.isStdInitializerList(DestType, &E)) {
- // Check that each individual element can be copy-constructed. But since we
- // have no place to store further information, we'll recalculate everything
- // later.
- InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
- S.Context.getConstantArrayType(E,
- llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
- List->getNumInits()),
- ArrayType::Normal, 0));
- InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
- 0, HiddenArray);
- for (unsigned i = 0, n = List->getNumInits(); i < n; ++i) {
- Element.setElementIndex(i);
- if (!S.CanPerformCopyInitialization(Element, List->getInit(i))) {
- Sequence.SetFailed(
- InitializationSequence::FK_InitListElementCopyFailure);
- return true;
- }
- }
- Sequence.AddStdInitializerListConstructionStep(DestType);
- return true;
- }
-
- // Not a special case.
- return false;
+ Sequence.AddStdInitializerListConstructionStep(DestType);
+ return true;
}
static OverloadingResult
@@ -2886,11 +2833,6 @@ static void TryConstructorInitialization(Sema &S,
CXXRecordDecl *DestRecordDecl
= cast<CXXRecordDecl>(DestRecordType->getDecl());
- if (InitListSyntax &&
- TryListConstructionSpecialCases(S, cast<InitListExpr>(Args[0]),
- DestRecordDecl, DestType, Sequence))
- return;
-
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
@@ -2917,15 +2859,21 @@ static void TryConstructorInitialization(Sema &S,
// constructors of the class T and the argument list consists of the
// initializer list as a single argument.
if (InitListSyntax) {
+ InitListExpr *ILE = cast<InitListExpr>(Args[0]);
AsInitializerList = true;
- Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs,
- CandidateSet, ConStart, ConEnd, Best,
- CopyInitialization, AllowExplicit,
- /*OnlyListConstructor=*/true,
- InitListSyntax);
+
+ // If the initializer list has no elements and T has a default constructor,
+ // the first phase is omitted.
+ if (ILE->getNumInits() != 0 ||
+ (!DestRecordDecl->hasDeclaredDefaultConstructor() &&
+ !DestRecordDecl->needsImplicitDefaultConstructor()))
+ Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs,
+ CandidateSet, ConStart, ConEnd, Best,
+ CopyInitialization, AllowExplicit,
+ /*OnlyListConstructor=*/true,
+ InitListSyntax);
// Time to unwrap the init list.
- InitListExpr *ILE = cast<InitListExpr>(Args[0]);
Args = ILE->getInits();
NumArgs = ILE->getNumInits();
}
@@ -2933,7 +2881,7 @@ static void TryConstructorInitialization(Sema &S,
// C++11 [over.match.list]p1:
// - If no viable initializer-list constructor is found, overload resolution
// is performed again, where the candidate functions are all the
- // constructors of the class T nad the argument list consists of the
+ // constructors of the class T and the argument list consists of the
// elements of the initializer list.
if (Result == OR_No_Viable_Function) {
AsInitializerList = false;
@@ -2951,13 +2899,13 @@ static void TryConstructorInitialization(Sema &S,
return;
}
- // C++0x [dcl.init]p6:
+ // C++11 [dcl.init]p6:
// If a program calls for the default initialization of an object
// of a const-qualified type T, T shall be a class type with a
// user-provided default constructor.
if (Kind.getKind() == InitializationKind::IK_Default &&
Entity.getType().isConstQualified() &&
- cast<CXXConstructorDecl>(Best->Function)->isImplicit()) {
+ !cast<CXXConstructorDecl>(Best->Function)->isUserProvided()) {
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
return;
}
@@ -3018,6 +2966,12 @@ static void TryReferenceInitializationCore(Sema &S,
Qualifiers T2Quals,
InitializationSequence &Sequence);
+static void TryValueInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ InitializationSequence &Sequence,
+ InitListExpr *InitList = 0);
+
static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -3108,19 +3062,36 @@ static void TryListInitialization(Sema &S,
return;
}
if (DestType->isRecordType()) {
- if (S.RequireCompleteType(InitList->getLocStart(), DestType, S.PDiag())) {
+ if (S.RequireCompleteType(InitList->getLocStart(), DestType, 0)) {
Sequence.setIncompleteTypeFailure(DestType);
return;
}
+ // C++11 [dcl.init.list]p3:
+ // - If T is an aggregate, aggregate initialization is performed.
if (!DestType->isAggregateType()) {
if (S.getLangOpts().CPlusPlus0x) {
+ // - Otherwise, if the initializer list has no elements and T is a
+ // class type with a default constructor, the object is
+ // value-initialized.
+ if (InitList->getNumInits() == 0) {
+ CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
+ if (RD->hasDeclaredDefaultConstructor() ||
+ RD->needsImplicitDefaultConstructor()) {
+ TryValueInitialization(S, Entity, Kind, Sequence, InitList);
+ return;
+ }
+ }
+
+ // - Otherwise, if T is a specialization of std::initializer_list<E>,
+ // an initializer_list object constructed [...]
+ if (TryInitializerListConstruction(S, InitList, DestType, Sequence))
+ return;
+
+ // - Otherwise, if T is a class type, constructors are considered.
Expr *Arg = InitList;
- // A direct-initializer is not list-syntax, i.e. there's no special
- // treatment of "A a({1, 2});".
- TryConstructorInitialization(S, Entity, Kind, &Arg, 1, DestType,
- Sequence,
- Kind.getKind() != InitializationKind::IK_Direct);
+ TryConstructorInitialization(S, Entity, Kind, &Arg, 1, DestType,
+ Sequence, /*InitListSyntax*/true);
} else
Sequence.SetFailed(
InitializationSequence::FK_InitListBadDestinationType);
@@ -3605,7 +3576,11 @@ static void TryStringLiteralInitialization(Sema &S,
static void TryValueInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
- InitializationSequence &Sequence) {
+ InitializationSequence &Sequence,
+ InitListExpr *InitList) {
+ assert((!InitList || InitList->getNumInits() == 0) &&
+ "Shouldn't use value-init for non-empty init lists");
+
// C++98 [dcl.init]p5, C++11 [dcl.init]p7:
//
// To value-initialize an object of type T means:
@@ -3616,17 +3591,15 @@ static void TryValueInitialization(Sema &S,
if (const RecordType *RT = T->getAs<RecordType>()) {
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // C++98:
- // -- if T is a class type (clause 9) with a user-declared
- // constructor (12.1), then the default constructor for T is
- // called (and the initialization is ill-formed if T has no
- // accessible default constructor);
+ bool NeedZeroInitialization = true;
if (!S.getLangOpts().CPlusPlus0x) {
+ // C++98:
+ // -- if T is a class type (clause 9) with a user-declared constructor
+ // (12.1), then the default constructor for T is called (and the
+ // initialization is ill-formed if T has no accessible default
+ // constructor);
if (ClassDecl->hasUserDeclaredConstructor())
- // FIXME: we really want to refer to a single subobject of the array,
- // but Entity doesn't have a way to capture that (yet).
- return TryConstructorInitialization(S, Entity, Kind, 0, 0,
- T, Sequence);
+ NeedZeroInitialization = false;
} else {
// C++11:
// -- if T is a class type (clause 9) with either no default constructor
@@ -3634,19 +3607,28 @@ static void TryValueInitialization(Sema &S,
// or deleted, then the object is default-initialized;
CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl);
if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted())
- return TryConstructorInitialization(S, Entity, Kind, 0, 0,
- T, Sequence);
+ NeedZeroInitialization = false;
}
// -- if T is a (possibly cv-qualified) non-union class type without a
// user-provided or deleted default constructor, then the object is
// zero-initialized and, if T has a non-trivial default constructor,
// default-initialized;
- if ((ClassDecl->getTagKind() == TTK_Class ||
- ClassDecl->getTagKind() == TTK_Struct)) {
+ // FIXME: The 'non-union' here is a defect (not yet assigned an issue
+ // number). Update the quotation when the defect is resolved.
+ if (NeedZeroInitialization)
Sequence.AddZeroInitializationStep(Entity.getType());
- return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
- }
+
+ // If this is list-value-initialization, pass the empty init list on when
+ // building the constructor call. This affects the semantics of a few
+ // things (such as whether an explicit default constructor can be called).
+ Expr *InitListAsExpr = InitList;
+ Expr **Args = InitList ? &InitListAsExpr : 0;
+ unsigned NumArgs = InitList ? 1 : 0;
+ bool InitListSyntax = InitList;
+
+ return TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, T,
+ Sequence, InitListSyntax);
}
}
@@ -4101,8 +4083,8 @@ InitializationSequence::InitializationSequence(Sema &S,
AddArrayInitStep(DestType);
}
}
- // Note: as a GNU C++ extension, we allow initialization of a
- // class member from a parenthesized initializer list.
+ // Note: as a GNU C++ extension, we allow list-initialization of a
+ // class member of array type from a parenthesized initializer list.
else if (S.getLangOpts().CPlusPlus &&
Entity.getKind() == InitializedEntity::EK_Member &&
Initializer && isa<InitListExpr>(Initializer)) {
@@ -4409,7 +4391,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
/// \param T The type of the temporary object, which must either be
/// the type of the initializer expression or a superclass thereof.
///
-/// \param Enter The entity being initialized.
+/// \param Entity The entity being initialized.
///
/// \param CurInit The initializer expression.
///
@@ -4452,7 +4434,7 @@ static ExprResult CopyObject(Sema &S,
SourceLocation Loc = getInitializationLoc(Entity, CurInit.get());
// Make sure that the type we are copying is complete.
- if (S.RequireCompleteType(Loc, T, S.PDiag(diag::err_temp_copy_incomplete)))
+ if (S.RequireCompleteType(Loc, T, diag::err_temp_copy_incomplete))
return move(CurInit);
// Perform overload resolution using the class's copy/move constructors.
@@ -4516,7 +4498,7 @@ static ExprResult CopyObject(Sema &S,
for (unsigned I = 1, N = Constructor->getNumParams(); I != N; ++I) {
ParmVarDecl *Parm = Constructor->getParamDecl(I);
if (S.RequireCompleteType(Loc, Parm->getType(),
- S.PDiag(diag::err_call_incomplete_argument)))
+ diag::err_call_incomplete_argument))
break;
// Build the default argument expression; we don't actually care
@@ -4748,6 +4730,43 @@ PerformConstructorInitialization(Sema &S,
return move(CurInit);
}
+/// Determine whether the specified InitializedEntity definitely has a lifetime
+/// longer than the current full-expression. Conservatively returns false if
+/// it's unclear.
+static bool
+InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
+ const InitializedEntity *Top = &Entity;
+ while (Top->getParent())
+ Top = Top->getParent();
+
+ switch (Top->getKind()) {
+ case InitializedEntity::EK_Variable:
+ case InitializedEntity::EK_Result:
+ case InitializedEntity::EK_Exception:
+ case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_New:
+ case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Delegating:
+ return true;
+
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_VectorElement:
+ case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_ComplexElement:
+ // Could not determine what the full initialization is. Assume it might not
+ // outlive the full-expression.
+ return false;
+
+ case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Temporary:
+ case InitializedEntity::EK_LambdaCapture:
+ // The entity being initialized might not outlive the full-expression.
+ return false;
+ }
+
+ llvm_unreachable("unknown entity kind");
+}
+
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@@ -4816,6 +4835,29 @@ InitializationSequence::Perform(Sema &S,
if (Steps.empty())
return S.Owned((Expr *)0);
+ if (S.getLangOpts().CPlusPlus0x && Entity.getType()->isReferenceType() &&
+ Args.size() == 1 && isa<InitListExpr>(Args.get()[0]) &&
+ Entity.getKind() != InitializedEntity::EK_Parameter) {
+ // Produce a C++98 compatibility warning if we are initializing a reference
+ // from an initializer list. For parameters, we produce a better warning
+ // elsewhere.
+ Expr *Init = Args.get()[0];
+ S.Diag(Init->getLocStart(), diag::warn_cxx98_compat_reference_list_init)
+ << Init->getSourceRange();
+ }
+
+ // Diagnose cases where we initialize a pointer to an array temporary, and the
+ // pointer obviously outlives the temporary.
+ if (Args.size() == 1 && Args.get()[0]->getType()->isArrayType() &&
+ Entity.getType()->isPointerType() &&
+ InitializedEntityOutlivesFullExpression(Entity)) {
+ Expr *Init = Args.get()[0];
+ Expr::LValueClassification Kind = Init->ClassifyLValue(S.Context);
+ if (Kind == Expr::LV_ClassTemporary || Kind == Expr::LV_ArrayTemporary)
+ S.Diag(Init->getLocStart(), diag::warn_temporary_array_to_pointer_decay)
+ << Init->getSourceRange();
+ }
+
QualType DestType = Entity.getType().getNonReferenceType();
// FIXME: Ugly hack around the fact that Entity.getType() is not
// the same as Entity.getDecl()->getType() in cases involving type merging,
@@ -4842,7 +4884,6 @@ InitializationSequence::Perform(Sema &S,
case SK_QualificationConversionXValue:
case SK_QualificationConversionRValue:
case SK_ConversionSequence:
- case SK_ListConstructorCall:
case SK_ListInitialization:
case SK_UnwrapInitList:
case SK_RewrapInitList:
@@ -4862,6 +4903,7 @@ InitializationSequence::Perform(Sema &S,
}
case SK_ConstructorInitialization:
+ case SK_ListConstructorCall:
case SK_ZeroInitialization:
break;
}
@@ -5152,7 +5194,10 @@ InitializationSequence::Perform(Sema &S,
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(
Entity.getType().getNonReferenceType());
bool UseTemporary = Entity.getType()->isReferenceType();
- InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
+ assert(Args.size() == 1 && "expected a single argument for list init");
+ InitListExpr *InitList = cast<InitListExpr>(Args.get()[0]);
+ S.Diag(InitList->getExprLoc(), diag::warn_cxx98_compat_ctor_list_init)
+ << InitList->getSourceRange();
MultiExprArg Arg(InitList->getInits(), InitList->getNumInits());
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity :
Entity,
@@ -5198,7 +5243,8 @@ InitializationSequence::Perform(Sema &S,
step_iterator NextStep = Step;
++NextStep;
if (NextStep != StepEnd &&
- NextStep->Kind == SK_ConstructorInitialization) {
+ (NextStep->Kind == SK_ConstructorInitialization ||
+ NextStep->Kind == SK_ListConstructorCall)) {
// The need for zero-initialization is recorded directly into
// the call to the object's constructor within the next step.
ConstructorInitRequiresZeroInit = true;
@@ -5330,6 +5376,8 @@ InitializationSequence::Perform(Sema &S,
}
InitListExpr *ILE = cast<InitListExpr>(CurInit.take());
+ S.Diag(ILE->getExprLoc(), diag::warn_cxx98_compat_initializer_list_init)
+ << ILE->getSourceRange();
unsigned NumInits = ILE->getNumInits();
SmallVector<Expr*, 16> Converted(NumInits);
InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
@@ -6130,8 +6178,8 @@ Sema::CanPerformCopyInitialization(const InitializedEntity &Entity,
Expr *InitE = Init.get();
assert(InitE && "No initialization expression");
- InitializationKind Kind = InitializationKind::CreateCopy(SourceLocation(),
- SourceLocation());
+ InitializationKind Kind
+ = InitializationKind::CreateCopy(InitE->getLocStart(), SourceLocation());
InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
return !Seq.Failed();
}
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 6ef8d88..6414c6f 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -54,9 +54,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
SourceLocation EndLoc,
- llvm::ArrayRef<ParmVarDecl *> Params,
- llvm::Optional<unsigned> ManglingNumber,
- Decl *ContextDecl) {
+ llvm::ArrayRef<ParmVarDecl *> Params) {
// C++11 [expr.prim.lambda]p5:
// The closure type for a lambda-expression has a public inline function
// call operator (13.5.4) whose parameters and return type are described by
@@ -98,64 +96,76 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
P != PEnd; ++P)
(*P)->setOwningFunction(Method);
}
-
- // If we don't already have a mangling number for this lambda expression,
- // allocate one now.
- if (!ManglingNumber) {
- ContextDecl = ExprEvalContexts.back().LambdaContextDecl;
-
- enum ContextKind {
- Normal,
- DefaultArgument,
- DataMember,
- StaticDataMember
- } Kind = Normal;
-
- // Default arguments of member function parameters that appear in a class
- // definition, as well as the initializers of data members, receive special
- // treatment. Identify them.
- if (ContextDecl) {
- if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) {
- if (const DeclContext *LexicalDC
- = Param->getDeclContext()->getLexicalParent())
- if (LexicalDC->isRecord())
- Kind = DefaultArgument;
- } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) {
- if (Var->getDeclContext()->isRecord())
- Kind = StaticDataMember;
- } else if (isa<FieldDecl>(ContextDecl)) {
- Kind = DataMember;
- }
- }
-
- switch (Kind) {
- case Normal:
- if (CurContext->isDependentContext() || isInInlineFunction(CurContext))
- ManglingNumber = Context.getLambdaManglingNumber(Method);
- else
- ManglingNumber = 0;
-
- // There is no special context for this lambda.
- ContextDecl = 0;
- break;
-
- case StaticDataMember:
- if (!CurContext->isDependentContext()) {
- ManglingNumber = 0;
- ContextDecl = 0;
- break;
- }
- // Fall through to assign a mangling number.
-
- case DataMember:
- case DefaultArgument:
- ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
- .getManglingNumber(Method);
- break;
+
+ // Allocate a mangling number for this lambda expression, if the ABI
+ // requires one.
+ Decl *ContextDecl = ExprEvalContexts.back().LambdaContextDecl;
+
+ enum ContextKind {
+ Normal,
+ DefaultArgument,
+ DataMember,
+ StaticDataMember
+ } Kind = Normal;
+
+ // Default arguments of member function parameters that appear in a class
+ // definition, as well as the initializers of data members, receive special
+ // treatment. Identify them.
+ if (ContextDecl) {
+ if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) {
+ if (const DeclContext *LexicalDC
+ = Param->getDeclContext()->getLexicalParent())
+ if (LexicalDC->isRecord())
+ Kind = DefaultArgument;
+ } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) {
+ if (Var->getDeclContext()->isRecord())
+ Kind = StaticDataMember;
+ } else if (isa<FieldDecl>(ContextDecl)) {
+ Kind = DataMember;
}
}
- Class->setLambdaMangling(*ManglingNumber, ContextDecl);
+ // Itanium ABI [5.1.7]:
+ // In the following contexts [...] the one-definition rule requires closure
+ // types in different translation units to "correspond":
+ bool IsInNonspecializedTemplate =
+ !ActiveTemplateInstantiations.empty() || CurContext->isDependentContext();
+ unsigned ManglingNumber;
+ switch (Kind) {
+ case Normal:
+ // -- the bodies of non-exported nonspecialized template functions
+ // -- the bodies of inline functions
+ if ((IsInNonspecializedTemplate &&
+ !(ContextDecl && isa<ParmVarDecl>(ContextDecl))) ||
+ isInInlineFunction(CurContext))
+ ManglingNumber = Context.getLambdaManglingNumber(Method);
+ else
+ ManglingNumber = 0;
+
+ // There is no special context for this lambda.
+ ContextDecl = 0;
+ break;
+
+ case StaticDataMember:
+ // -- the initializers of nonspecialized static members of template classes
+ if (!IsInNonspecializedTemplate) {
+ ManglingNumber = 0;
+ ContextDecl = 0;
+ break;
+ }
+ // Fall through to assign a mangling number.
+
+ case DataMember:
+ // -- the in-class initializers of class members
+ case DefaultArgument:
+ // -- default arguments appearing in class definitions
+ ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
+ .getManglingNumber(Method);
+ break;
+ }
+
+ Class->setLambdaMangling(ManglingNumber, ContextDecl);
+
return Method;
}
@@ -214,6 +224,141 @@ void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
}
}
+static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E,
+ QualType &DeducedType,
+ QualType &AlternateType) {
+ // Handle ReturnStmts with no expressions.
+ if (!E) {
+ if (AlternateType.isNull())
+ AlternateType = Ctx.VoidTy;
+
+ return Ctx.hasSameType(DeducedType, Ctx.VoidTy);
+ }
+
+ QualType StrictType = E->getType();
+ QualType LooseType = StrictType;
+
+ // In C, enum constants have the type of their underlying integer type,
+ // not the enum. When inferring block return types, we should allow
+ // the enum type if an enum constant is used, unless the enum is
+ // anonymous (in which case there can be no variables of its type).
+ if (!Ctx.getLangOpts().CPlusPlus) {
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
+ if (DRE) {
+ const Decl *D = DRE->getDecl();
+ if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
+ const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
+ if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl())
+ LooseType = Ctx.getTypeDeclType(Enum);
+ }
+ }
+ }
+
+ // Special case for the first return statement we find.
+ // The return type has already been tentatively set, but we might still
+ // have an alternate type we should prefer.
+ if (AlternateType.isNull())
+ AlternateType = LooseType;
+
+ if (Ctx.hasSameType(DeducedType, StrictType)) {
+ // FIXME: The loose type is different when there are constants from two
+ // different enums. We could consider warning here.
+ if (AlternateType != Ctx.DependentTy)
+ if (!Ctx.hasSameType(AlternateType, LooseType))
+ AlternateType = Ctx.VoidTy;
+ return true;
+ }
+
+ if (Ctx.hasSameType(DeducedType, LooseType)) {
+ // Use DependentTy to signal that we're using an alternate type and may
+ // need to add casts somewhere.
+ AlternateType = Ctx.DependentTy;
+ return true;
+ }
+
+ if (Ctx.hasSameType(AlternateType, StrictType) ||
+ Ctx.hasSameType(AlternateType, LooseType)) {
+ DeducedType = AlternateType;
+ // Use DependentTy to signal that we're using an alternate type and may
+ // need to add casts somewhere.
+ AlternateType = Ctx.DependentTy;
+ return true;
+ }
+
+ return false;
+}
+
+void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
+ assert(CSI.HasImplicitReturnType);
+
+ // First case: no return statements, implicit void return type.
+ ASTContext &Ctx = getASTContext();
+ if (CSI.Returns.empty()) {
+ // It's possible there were simply no /valid/ return statements.
+ // In this case, the first one we found may have at least given us a type.
+ if (CSI.ReturnType.isNull())
+ CSI.ReturnType = Ctx.VoidTy;
+ return;
+ }
+
+ // Second case: at least one return statement has dependent type.
+ // Delay type checking until instantiation.
+ assert(!CSI.ReturnType.isNull() && "We should have a tentative return type.");
+ if (CSI.ReturnType->isDependentType())
+ return;
+
+ // Third case: only one return statement. Don't bother doing extra work!
+ SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
+ E = CSI.Returns.end();
+ if (I+1 == E)
+ return;
+
+ // General case: many return statements.
+ // Check that they all have compatible return types.
+ // For now, that means "identical", with an exception for enum constants.
+ // (In C, enum constants have the type of their underlying integer type,
+ // not the type of the enum. C++ uses the type of the enum.)
+ QualType AlternateType;
+
+ // We require the return types to strictly match here.
+ for (; I != E; ++I) {
+ const ReturnStmt *RS = *I;
+ const Expr *RetE = RS->getRetValue();
+ if (!checkReturnValueType(Ctx, RetE, CSI.ReturnType, AlternateType)) {
+ // FIXME: This is a poor diagnostic for ReturnStmts without expressions.
+ Diag(RS->getLocStart(),
+ diag::err_typecheck_missing_return_type_incompatible)
+ << (RetE ? RetE->getType() : Ctx.VoidTy) << CSI.ReturnType
+ << isa<LambdaScopeInfo>(CSI);
+ // Don't bother fixing up the return statements in the block if some of
+ // them are unfixable anyway.
+ AlternateType = Ctx.VoidTy;
+ // Continue iterating so that we keep emitting diagnostics.
+ }
+ }
+
+ // If our return statements turned out to be compatible, but we needed to
+ // pick a different return type, go through and fix the ones that need it.
+ if (AlternateType == Ctx.DependentTy) {
+ for (SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
+ E = CSI.Returns.end();
+ I != E; ++I) {
+ ReturnStmt *RS = *I;
+ Expr *RetE = RS->getRetValue();
+ if (RetE->getType() == CSI.ReturnType)
+ continue;
+
+ // Right now we only support integral fixup casts.
+ assert(CSI.ReturnType->isIntegralOrUnscopedEnumerationType());
+ assert(RetE->getType()->isIntegralOrUnscopedEnumerationType());
+ ExprResult Casted = ImpCastExprToType(RetE, CSI.ReturnType,
+ CK_IntegralCast);
+ assert(Casted.isUsable());
+ RS->setRetValue(Casted.take());
+ }
+ }
+}
+
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
Declarator &ParamInfo,
Scope *CurScope) {
@@ -230,6 +375,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
TypeSourceInfo *MethodTyInfo;
bool ExplicitParams = true;
bool ExplicitResultType = true;
+ bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
llvm::ArrayRef<ParmVarDecl *> Params;
if (ParamInfo.getNumTypeObjects() == 0) {
@@ -269,9 +415,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
Params = llvm::ArrayRef<ParmVarDecl *>(Proto.getParmArray(),
Proto.getNumArgs());
+
+ // Check for unexpanded parameter packs in the method type.
+ if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
}
- CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
+ CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
MethodTyInfo, EndLoc, Params);
if (ExplicitParams)
@@ -287,7 +437,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
LambdaScopeInfo *LSI
= enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams,
ExplicitResultType,
- (Method->getTypeQualifiers() & Qualifiers::Const) == 0);
+ !Method->isConst());
// Handle explicit captures.
SourceLocation PrevCaptureLoc
@@ -409,8 +559,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Just ignore the ellipsis.
}
} else if (Var->isParameterPack()) {
- Diag(C->Loc, diag::err_lambda_unexpanded_pack);
- continue;
+ ContainsUnexpandedParameterPack = true;
}
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
@@ -419,6 +568,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
finishLambdaExplicitCaptures(LSI);
+ LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
+
// Add lambda parameters into scope.
addLambdaParameters(Method, CurScope);
@@ -441,7 +592,10 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
LambdaScopeInfo *LSI = getCurLambda();
CXXRecordDecl *Class = LSI->Lambda;
Class->setInvalidDecl();
- SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
+ SmallVector<Decl*, 4> Fields;
+ for (RecordDecl::field_iterator i = Class->field_begin(),
+ e = Class->field_end(); i != e; ++i)
+ Fields.push_back(*i);
ActOnFields(0, Class->getLocation(), Class, Fields,
SourceLocation(), SourceLocation(), 0);
CheckCompletedCXXClass(Class);
@@ -578,6 +732,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
bool ExplicitParams;
bool ExplicitResultType;
bool LambdaExprNeedsCleanups;
+ bool ContainsUnexpandedParameterPack;
llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
{
@@ -588,6 +743,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
ExplicitParams = LSI->ExplicitParams;
ExplicitResultType = !LSI->HasImplicitReturnType;
LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
+ ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
ArrayIndexVars.swap(LSI->ArrayIndexVars);
ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
@@ -639,32 +795,14 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
// denotes the following type:
// FIXME: Assumes current resolution to core issue 975.
if (LSI->HasImplicitReturnType) {
+ deduceClosureReturnType(*LSI);
+
// - if there are no return statements in the
// compound-statement, or all return statements return
// either an expression of type void or no expression or
// braced-init-list, the type void;
if (LSI->ReturnType.isNull()) {
LSI->ReturnType = Context.VoidTy;
- } else {
- // C++11 [expr.prim.lambda]p4:
- // - if the compound-statement is of the form
- //
- // { attribute-specifier-seq[opt] return expression ; }
- //
- // the type of the returned expression after
- // lvalue-to-rvalue conversion (4.1), array-to-pointer
- // conver- sion (4.2), and function-to-pointer conversion
- // (4.3);
- //
- // Since we're accepting the resolution to a post-C++11 core
- // issue with a non-trivial extension, provide a warning (by
- // default).
- CompoundStmt *CompoundBody = cast<CompoundStmt>(Body);
- if (!(CompoundBody->size() == 1 &&
- isa<ReturnStmt>(*CompoundBody->body_begin())) &&
- !Context.hasSameType(LSI->ReturnType, Context.VoidTy))
- Diag(IntroducerRange.getBegin(),
- diag::ext_lambda_implies_void_return);
}
// Create a function type with the inferred return type.
@@ -704,7 +842,10 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
- SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
+ SmallVector<Decl*, 4> Fields;
+ for (RecordDecl::field_iterator i = Class->field_begin(),
+ e = Class->field_end(); i != e; ++i)
+ Fields.push_back(*i);
ActOnFields(0, Class->getLocation(), Class, Fields,
SourceLocation(), SourceLocation(), 0);
CheckCompletedCXXClass(Class);
@@ -717,7 +858,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
CaptureDefault, Captures,
ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars,
- ArrayIndexStarts, Body->getLocEnd());
+ ArrayIndexStarts, Body->getLocEnd(),
+ ContainsUnexpandedParameterPack);
// C++11 [expr.prim.lambda]p2:
// A lambda-expression shall not appear in an unevaluated operand
@@ -807,9 +949,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
// Add a fake function body to the block. IR generation is responsible
// for filling in the actual body, which cannot be expressed as an AST.
- Block->setBody(new (Context) CompoundStmt(Context, 0, 0,
- ConvLocation,
- ConvLocation));
+ Block->setBody(new (Context) CompoundStmt(ConvLocation));
// Create the block literal expression.
Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 9f5138b..dad196b 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -899,7 +899,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
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
+ // found nothing, so look into the contexts between the
// lexical and semantic declaration contexts returned by
// findOuterContext(). This implements the name lookup behavior
// of C++ [temp.local]p8.
@@ -1004,7 +1004,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
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
+ // found nothing, so look into the contexts between the
// lexical and semantic declaration contexts returned by
// findOuterContext(). This implements the name lookup behavior
// of C++ [temp.local]p8.
@@ -1100,15 +1100,12 @@ static NamedDecl *getVisibleDecl(NamedDecl *D) {
/// begin. If the lookup criteria permits, name lookup may also search
/// in the parent scopes.
///
-/// @param Name The name of the entity that we are searching for.
+/// @param [in,out] R Specifies the lookup to perform (e.g., the name to
+/// look up and the lookup kind), and is updated with the results of lookup
+/// including zero or more declarations and possibly additional information
+/// used to diagnose ambiguities.
///
-/// @param Loc If provided, the source location where we're performing
-/// name lookup. At present, this is only used to produce diagnostics when
-/// C library functions (like "malloc") are implicitly declared.
-///
-/// @returns The result of name lookup, which includes zero or more
-/// declarations and possibly additional information used to diagnose
-/// ambiguities.
+/// @returns \c true if lookup succeeded and false otherwise.
bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
DeclarationName Name = R.getLookupName();
if (!Name) return false;
@@ -1231,7 +1228,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
/// using directives by the given context.
///
/// C++98 [namespace.qual]p2:
-/// Given X::m (where X is a user-declared namespace), or given ::m
+/// Given X::m (where X is a user-declared namespace), or given \::m
/// (where X is the global namespace), let S be the set of all
/// declarations of m in X and in the transitive closure of all
/// namespaces nominated by using-directives in X and its used
@@ -1244,6 +1241,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
/// (namespace.udecl), S is the required set of declarations of
/// m. Otherwise if the use of m is not one that allows a unique
/// declaration to be chosen from S, the program is ill-formed.
+///
/// C++98 [namespace.qual]p5:
/// During the lookup of a qualified namespace member name, if the
/// lookup finds more than one declaration of the member, and if one
@@ -1636,22 +1634,12 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
}
-/// @brief Produce a diagnostic describing the ambiguity that resulted
+/// \brief Produce a diagnostic describing the ambiguity that resulted
/// from name lookup.
///
-/// @param Result The ambiguous name lookup result.
-///
-/// @param Name The name of the entity that name lookup was
-/// searching for.
-///
-/// @param NameLoc The location of the name within the source code.
+/// \param Result The result of the ambiguous lookup to be diagnosed.
///
-/// @param LookupRange A source range that provides more
-/// source-location information concerning the lookup itself. For
-/// example, this range might highlight a nested-name-specifier that
-/// precedes the name.
-///
-/// @returns true
+/// \returns true
bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
assert(Result.isAmbiguous() && "Lookup result must be ambiguous");
@@ -2444,10 +2432,11 @@ CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class,
}
/// \brief Look up the moving constructor for the given class.
-CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class) {
+CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class,
+ unsigned Quals) {
SpecialMemberOverloadResult *Result =
- LookupSpecialMember(Class, CXXMoveConstructor, false,
- false, false, false, false);
+ LookupSpecialMember(Class, CXXMoveConstructor, Quals & Qualifiers::Const,
+ Quals & Qualifiers::Volatile, false, false, false);
return cast_or_null<CXXConstructorDecl>(Result->getMethod());
}
@@ -2488,12 +2477,14 @@ CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class,
/// \brief Look up the moving assignment operator for the given class.
CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class,
+ unsigned Quals,
bool RValueThis,
unsigned ThisQuals) {
assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
"non-const, non-volatile qualifiers for copy assignment this");
SpecialMemberOverloadResult *Result =
- LookupSpecialMember(Class, CXXMoveAssignment, false, false, RValueThis,
+ LookupSpecialMember(Class, CXXMoveAssignment, Quals & Qualifiers::Const,
+ Quals & Qualifiers::Volatile, RValueThis,
ThisQuals & Qualifiers::Const,
ThisQuals & Qualifiers::Volatile);
@@ -3147,7 +3138,8 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
namespace {
-typedef llvm::StringMap<TypoCorrection, llvm::BumpPtrAllocator> TypoResultsMap;
+typedef llvm::SmallVector<TypoCorrection, 1> TypoResultList;
+typedef llvm::StringMap<TypoResultList, llvm::BumpPtrAllocator> TypoResultsMap;
typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
static const unsigned MaxTypoDistanceResultSets = 5;
@@ -3161,7 +3153,7 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer {
///
/// The pointer value being set to the current DeclContext indicates
/// whether there is a keyword with this name.
- TypoEditDistanceMap BestResults;
+ TypoEditDistanceMap CorrectionResults;
Sema &SemaRef;
@@ -3180,23 +3172,28 @@ public:
typedef TypoResultsMap::iterator result_iterator;
typedef TypoEditDistanceMap::iterator distance_iterator;
- distance_iterator begin() { return BestResults.begin(); }
- distance_iterator end() { return BestResults.end(); }
- void erase(distance_iterator I) { BestResults.erase(I); }
- unsigned size() const { return BestResults.size(); }
- bool empty() const { return BestResults.empty(); }
-
- TypoCorrection &operator[](StringRef Name) {
- return BestResults.begin()->second[Name];
+ distance_iterator begin() { return CorrectionResults.begin(); }
+ distance_iterator end() { return CorrectionResults.end(); }
+ void erase(distance_iterator I) { CorrectionResults.erase(I); }
+ unsigned size() const { return CorrectionResults.size(); }
+ bool empty() const { return CorrectionResults.empty(); }
+
+ TypoResultList &operator[](StringRef Name) {
+ return CorrectionResults.begin()->second[Name];
}
unsigned getBestEditDistance(bool Normalized) {
- if (BestResults.empty())
+ if (CorrectionResults.empty())
return (std::numeric_limits<unsigned>::max)();
- unsigned BestED = BestResults.begin()->first;
+ unsigned BestED = CorrectionResults.begin()->first;
return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED;
}
+
+ TypoResultsMap &getBestResults() {
+ return CorrectionResults.begin()->second;
+ }
+
};
}
@@ -3251,19 +3248,31 @@ void TypoCorrectionConsumer::addName(StringRef Name,
void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName();
- TypoResultsMap &Map = BestResults[Correction.getEditDistance(false)];
-
- TypoCorrection &CurrentCorrection = Map[Name];
- if (!CurrentCorrection ||
- // FIXME: The following should be rolled up into an operator< on
- // TypoCorrection with a more principled definition.
- CurrentCorrection.isKeyword() < Correction.isKeyword() ||
- Correction.getAsString(SemaRef.getLangOpts()) <
- CurrentCorrection.getAsString(SemaRef.getLangOpts()))
- CurrentCorrection = Correction;
+ TypoResultList &CList =
+ CorrectionResults[Correction.getEditDistance(false)][Name];
+
+ if (!CList.empty() && !CList.back().isResolved())
+ CList.pop_back();
+ if (NamedDecl *NewND = Correction.getCorrectionDecl()) {
+ std::string CorrectionStr = Correction.getAsString(SemaRef.getLangOpts());
+ for (TypoResultList::iterator RI = CList.begin(), RIEnd = CList.end();
+ RI != RIEnd; ++RI) {
+ // If the Correction refers to a decl already in the result list,
+ // replace the existing result if the string representation of Correction
+ // comes before the current result alphabetically, then stop as there is
+ // nothing more to be done to add Correction to the candidate set.
+ if (RI->getCorrectionDecl() == NewND) {
+ if (CorrectionStr < RI->getAsString(SemaRef.getLangOpts()))
+ *RI = Correction;
+ return;
+ }
+ }
+ }
+ if (CList.empty() || Correction.isResolved())
+ CList.push_back(Correction);
- while (BestResults.size() > MaxTypoDistanceResultSets)
- erase(llvm::prior(BestResults.end()));
+ while (CorrectionResults.size() > MaxTypoDistanceResultSets)
+ erase(llvm::prior(CorrectionResults.end()));
}
// Fill the supplied vector with the IdentifierInfo pointers for each piece of
@@ -3348,7 +3357,7 @@ class NamespaceSpecifierSet {
getNestedNameSpecifierIdentifiers(CurScopeSpec->getScopeRep(),
CurNameSpecifierIdentifiers);
// Build the list of identifiers that would be used for an absolute
- // (from the global context) NestedNameSpecifier refering to the current
+ // (from the global context) NestedNameSpecifier referring to the current
// context.
for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(),
CEnd = CurContextChain.rend();
@@ -3515,7 +3524,16 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
/// \brief Add keywords to the consumer as possible typo corrections.
static void AddKeywordsToConsumer(Sema &SemaRef,
TypoCorrectionConsumer &Consumer,
- Scope *S, CorrectionCandidateCallback &CCC) {
+ Scope *S, CorrectionCandidateCallback &CCC,
+ bool AfterNestedNameSpecifier) {
+ if (AfterNestedNameSpecifier) {
+ // For 'X::', we know exactly which keywords can appear next.
+ Consumer.addKeywordResult("template");
+ if (CCC.WantExpressionKeywords)
+ Consumer.addKeywordResult("operator");
+ return;
+ }
+
if (CCC.WantObjCSuper)
Consumer.addKeywordResult("super");
@@ -3589,6 +3607,12 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
Consumer.addKeywordResult("nullptr");
}
}
+
+ if (SemaRef.getLangOpts().C11) {
+ // FIXME: We should not suggest _Alignof if the alignof macro
+ // is present.
+ Consumer.addKeywordResult("_Alignof");
+ }
}
if (CCC.WantRemainingKeywords) {
@@ -3777,6 +3801,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
bool SearchNamespaces
= getLangOpts().CPlusPlus &&
(IsUnqualifiedLookup || (QualifiedDC && QualifiedDC->isNamespace()));
+ // In a few cases we *only* want to search for corrections bases on just
+ // adding or changing the nested name specifier.
+ bool AllowOnlyNNSChanges = Typo->getName().size() < 3;
if (IsUnqualifiedLookup || SearchNamespaces) {
// For unqualified lookup, look through all of the names that we have
@@ -3802,7 +3829,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
}
}
- AddKeywordsToConsumer(*this, Consumer, S, CCC);
+ AddKeywordsToConsumer(*this, Consumer, S, CCC, SS && SS->isNotEmpty());
// If we haven't found anything, we're done.
if (Consumer.empty()) {
@@ -3813,8 +3840,8 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
return TypoCorrection();
}
- // Make sure that the user typed at least 3 characters for each correction
- // made. Otherwise, we don't even both looking at the results.
+ // Make sure the best edit distance (prior to adding any namespace qualifiers)
+ // is not more that about a third of the length of the typo's identifier.
unsigned ED = Consumer.getBestEditDistance(true);
if (ED > 0 && Typo->getName().size() / ED < 3) {
// If this was an unqualified lookup, note that no correction was found.
@@ -3854,19 +3881,43 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
for (TypoCorrectionConsumer::result_iterator I = DI->second.begin(),
IEnd = DI->second.end();
I != IEnd; /* Increment in loop. */) {
+ // If we only want nested name specifier corrections, ignore potential
+ // corrections that have a different base identifier from the typo.
+ if (AllowOnlyNNSChanges &&
+ I->second.front().getCorrectionAsIdentifierInfo() != Typo) {
+ TypoCorrectionConsumer::result_iterator Prev = I;
+ ++I;
+ DI->second.erase(Prev);
+ continue;
+ }
+
// If the item already has been looked up or is a keyword, keep it.
// If a validator callback object was given, drop the correction
// unless it passes validation.
- if (I->second.isResolved()) {
+ bool Viable = false;
+ for (TypoResultList::iterator RI = I->second.begin();
+ RI != I->second.end(); /* Increment in loop. */) {
+ TypoResultList::iterator Prev = RI;
+ ++RI;
+ if (Prev->isResolved()) {
+ if (!isCandidateViable(CCC, *Prev))
+ RI = I->second.erase(Prev);
+ else
+ Viable = true;
+ }
+ }
+ if (Viable || I->second.empty()) {
TypoCorrectionConsumer::result_iterator Prev = I;
++I;
- if (!isCandidateViable(CCC, Prev->second))
+ if (!Viable)
DI->second.erase(Prev);
continue;
}
+ assert(I->second.size() == 1 && "Expected a single unresolved candidate");
// Perform name lookup on this name.
- IdentifierInfo *Name = I->second.getCorrectionAsIdentifierInfo();
+ TypoCorrection &Candidate = I->second.front();
+ IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo();
LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext,
EnteringContext, CCC.IsObjCIvarLookup);
@@ -3874,7 +3925,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::FoundUnresolvedValue:
- QualifiedResults.push_back(I->second);
+ QualifiedResults.push_back(Candidate);
// We didn't find this name in our scope, or didn't like what we found;
// ignore it.
{
@@ -3895,18 +3946,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
for (LookupResult::iterator TRD = TmpRes.begin(),
TRDEnd = TmpRes.end();
TRD != TRDEnd; ++TRD)
- I->second.addCorrectionDecl(*TRD);
+ Candidate.addCorrectionDecl(*TRD);
++I;
- if (!isCandidateViable(CCC, Prev->second))
+ if (!isCandidateViable(CCC, Candidate))
DI->second.erase(Prev);
break;
}
case LookupResult::Found: {
TypoCorrectionConsumer::result_iterator Prev = I;
- I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
+ Candidate.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
++I;
- if (!isCandidateViable(CCC, Prev->second))
+ if (!isCandidateViable(CCC, Candidate))
DI->second.erase(Prev);
break;
}
@@ -3978,10 +4029,10 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// No corrections remain...
if (Consumer.empty()) return TypoCorrection();
- TypoResultsMap &BestResults = Consumer.begin()->second;
- ED = TypoCorrection::NormalizeEditDistance(Consumer.begin()->first);
+ TypoResultsMap &BestResults = Consumer.getBestResults();
+ ED = Consumer.getBestEditDistance(true);
- if (ED > 0 && Typo->getName().size() / ED < 3) {
+ if (!AllowOnlyNNSChanges && ED > 0 && Typo->getName().size() / ED < 3) {
// If this was an unqualified lookup and we believe the callback
// object wouldn't have filtered out possible corrections, note
// that no correction was found.
@@ -3993,8 +4044,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// If only a single name remains, return that result.
if (BestResults.size() == 1) {
- const llvm::StringMapEntry<TypoCorrection> &Correction = *(BestResults.begin());
- const TypoCorrection &Result = Correction.second;
+ const TypoResultList &CorrectionList = BestResults.begin()->second;
+ const TypoCorrection &Result = CorrectionList.front();
+ if (CorrectionList.size() != 1) return TypoCorrection();
// Don't correct to a keyword that's the same as the typo; the keyword
// wasn't actually in scope.
@@ -4012,7 +4064,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// some instances of CTC_Unknown, while WantRemainingKeywords is true
// for CTC_Unknown but not for CTC_ObjCMessageReceiver.
&& CCC.WantObjCSuper && !CCC.WantRemainingKeywords
- && BestResults["super"].isKeyword()) {
+ && BestResults["super"].front().isKeyword()) {
// Prefer 'super' when we're completing in a message-receiver
// context.
@@ -4022,9 +4074,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
- UnqualifiedTyposCorrected[Typo] = BestResults["super"];
+ UnqualifiedTyposCorrected[Typo] = BestResults["super"].front();
- return BestResults["super"];
+ return BestResults["super"].front();
}
// If this was an unqualified lookup and we believe the callback object did
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 5ece8f1..27deab2 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -18,6 +18,8 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
@@ -133,7 +135,6 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
// Proceed with constructing the ObjCPropertDecls.
ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
-
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
if (CDecl->IsClassExtension()) {
Decl *Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
@@ -144,10 +145,11 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
isOverridingProperty, TSI,
MethodImplKind);
if (Res) {
- CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+ CheckObjCPropertyAttributes(Res, AtLoc, Attributes, false);
if (getLangOpts().ObjCAutoRefCount)
checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res));
}
+ ActOnDocumentableDecl(Res);
return Res;
}
@@ -161,11 +163,14 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
Res->setLexicalDeclContext(lexicalDC);
// Validate the attributes on the @property.
- CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+ CheckObjCPropertyAttributes(Res, AtLoc, Attributes,
+ (isa<ObjCInterfaceDecl>(ClassDecl) ||
+ isa<ObjCProtocolDecl>(ClassDecl)));
if (getLangOpts().ObjCAutoRefCount)
checkARCPropertyDecl(*this, Res);
+ ActOnDocumentableDecl(Res);
return Res;
}
@@ -200,6 +205,37 @@ makePropertyAttributesAsWritten(unsigned Attributes) {
return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten;
}
+static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
+ SourceLocation LParenLoc, SourceLocation &Loc) {
+ if (LParenLoc.isMacroID())
+ return false;
+
+ SourceManager &SM = Context.getSourceManager();
+ std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(LParenLoc);
+ // Try to load the file buffer.
+ bool invalidTemp = false;
+ StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
+ if (invalidTemp)
+ return false;
+ const char *tokenBegin = file.data() + locInfo.second;
+
+ // Lex from the start of the given location.
+ Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
+ Context.getLangOpts(),
+ file.begin(), tokenBegin, file.end());
+ Token Tok;
+ do {
+ lexer.LexFromRawLexer(Tok);
+ if (Tok.is(tok::raw_identifier) &&
+ StringRef(Tok.getRawIdentifierData(), Tok.getLength()) == attrName) {
+ Loc = Tok.getLocation();
+ return true;
+ }
+ } while (Tok.isNot(tok::r_paren));
+ return false;
+
+}
+
Decl *
Sema::HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc,
@@ -568,9 +604,70 @@ static void setImpliedPropertyAttributeForReadOnlyProperty(
return;
}
+/// DiagnoseClassAndClassExtPropertyMismatch - diagnose inconsistant property
+/// attribute declared in primary class and attributes overridden in any of its
+/// class extensions.
+static void
+DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl,
+ ObjCPropertyDecl *property) {
+ unsigned Attributes = property->getPropertyAttributesAsWritten();
+ bool warn = (Attributes & ObjCDeclSpec::DQ_PR_readonly);
+ for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension();
+ CDecl; CDecl = CDecl->getNextClassExtension()) {
+ ObjCPropertyDecl *ClassExtProperty = 0;
+ for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(),
+ E = CDecl->prop_end(); P != E; ++P) {
+ if ((*P)->getIdentifier() == property->getIdentifier()) {
+ ClassExtProperty = *P;
+ break;
+ }
+ }
+ if (ClassExtProperty) {
+ warn = false;
+ unsigned classExtPropertyAttr =
+ ClassExtProperty->getPropertyAttributesAsWritten();
+ // We are issuing the warning that we postponed because class extensions
+ // can override readonly->readwrite and 'setter' attributes originally
+ // placed on class's property declaration now make sense in the overridden
+ // property.
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly) {
+ if (!classExtPropertyAttr ||
+ (classExtPropertyAttr & ObjCDeclSpec::DQ_PR_readwrite))
+ continue;
+ warn = true;
+ break;
+ }
+ }
+ }
+ if (warn) {
+ unsigned setterAttrs = (ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
+ ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong);
+ if (Attributes & setterAttrs) {
+ const char * which =
+ (Attributes & ObjCDeclSpec::DQ_PR_assign) ?
+ "assign" :
+ (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) ?
+ "unsafe_unretained" :
+ (Attributes & ObjCDeclSpec::DQ_PR_copy) ?
+ "copy" :
+ (Attributes & ObjCDeclSpec::DQ_PR_retain) ?
+ "retain" : "strong";
+
+ S.Diag(property->getLocation(),
+ diag::warn_objc_property_attr_mutually_exclusive)
+ << "readonly" << which;
+ }
+ }
+
+
+}
+
/// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared
-/// as @synthesize or @dynamic.
+/// as \@synthesize or \@dynamic.
///
Decl *Sema::ActOnPropertyImplDecl(Scope *S,
SourceLocation AtLoc,
@@ -588,6 +685,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
if (PropertyIvarLoc.isInvalid())
PropertyIvarLoc = PropertyLoc;
+ SourceLocation PropertyDiagLoc = PropertyLoc;
+ if (PropertyDiagLoc.isInvalid())
+ PropertyDiagLoc = ClassImpDecl->getLocStart();
ObjCPropertyDecl *property = 0;
ObjCInterfaceDecl* IDecl = 0;
// Find the class or category class where this property must have
@@ -625,6 +725,27 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
return 0;
}
}
+
+ if (Synthesize&&
+ (PIkind & ObjCPropertyDecl::OBJC_PR_readonly) &&
+ property->hasAttr<IBOutletAttr>() &&
+ !AtLoc.isValid()) {
+ Diag(IC->getLocation(), diag::warn_auto_readonly_iboutlet_property);
+ Diag(property->getLocation(), diag::note_property_declare);
+ SourceLocation readonlyLoc;
+ if (LocPropertyAttribute(Context, "readonly",
+ property->getLParenLoc(), readonlyLoc)) {
+ SourceLocation endLoc =
+ readonlyLoc.getLocWithOffset(strlen("readonly")-1);
+ SourceRange ReadonlySourceRange(readonlyLoc, endLoc);
+ Diag(property->getLocation(),
+ diag::note_auto_readonly_iboutlet_fixup_suggest) <<
+ FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");
+ }
+ }
+
+ DiagnoseClassAndClassExtPropertyMismatch(*this, IDecl, property);
+
} else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
if (Synthesize) {
Diag(AtLoc, diag::error_synthesize_category_decl);
@@ -654,6 +775,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
return 0;
}
ObjCIvarDecl *Ivar = 0;
+ bool CompleteTypeErr = false;
+ bool compat = true;
// Check that we have a valid, previously declared ivar for @synthesize
if (Synthesize) {
// @synthesize
@@ -664,7 +787,14 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
QualType PropType = property->getType();
QualType PropertyIvarType = PropType.getNonReferenceType();
-
+
+ if (RequireCompleteType(PropertyDiagLoc, PropertyIvarType,
+ diag::err_incomplete_synthesized_property,
+ property->getDeclName())) {
+ Diag(property->getLocation(), diag::note_property_declare);
+ CompleteTypeErr = true;
+ }
+
if (getLangOpts().ObjCAutoRefCount &&
(property->getPropertyAttributesAsWritten() &
ObjCPropertyDecl::OBJC_PR_readonly) &&
@@ -680,14 +810,32 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
getLangOpts().getGC() != LangOptions::NonGC) {
assert(!getLangOpts().ObjCAutoRefCount);
if (PropertyIvarType.isObjCGCStrong()) {
- Diag(PropertyLoc, diag::err_gc_weak_property_strong_type);
+ Diag(PropertyDiagLoc, diag::err_gc_weak_property_strong_type);
Diag(property->getLocation(), diag::note_property_declare);
} else {
PropertyIvarType =
Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak);
}
}
-
+ if (AtLoc.isInvalid()) {
+ // Check when default synthesizing a property that there is
+ // an ivar matching property name and issue warning; since this
+ // is the most common case of not using an ivar used for backing
+ // property in non-default synthesis case.
+ ObjCInterfaceDecl *ClassDeclared=0;
+ ObjCIvarDecl *originalIvar =
+ IDecl->lookupInstanceVariable(property->getIdentifier(),
+ ClassDeclared);
+ if (originalIvar) {
+ Diag(PropertyDiagLoc,
+ diag::warn_autosynthesis_property_ivar_match)
+ << PropertyId << (Ivar == 0) << PropertyIvar
+ << originalIvar->getIdentifier();
+ Diag(property->getLocation(), diag::note_property_declare);
+ Diag(originalIvar->getLocation(), diag::note_ivar_decl);
+ }
+ }
+
if (!Ivar) {
// In ARC, give the ivar a lifetime qualifier based on the
// property attributes.
@@ -699,7 +847,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// explicitly write an ownership attribute on the property.
if (!property->hasWrittenStorageAttribute() &&
!(kind & ObjCPropertyDecl::OBJC_PR_strong)) {
- Diag(PropertyLoc,
+ Diag(PropertyDiagLoc,
diag::err_arc_objc_property_default_assign_on_object);
Diag(property->getLocation(), diag::note_property_declare);
} else {
@@ -711,12 +859,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (const ObjCObjectPointerType *ObjT =
PropertyIvarType->getAs<ObjCObjectPointerType>())
if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) {
- Diag(PropertyLoc, diag::err_arc_weak_unavailable_property);
+ Diag(PropertyDiagLoc, diag::err_arc_weak_unavailable_property);
Diag(property->getLocation(), diag::note_property_declare);
err = true;
}
if (!err && !getLangOpts().ObjCRuntimeHasWeak) {
- Diag(PropertyLoc, diag::err_arc_weak_no_runtime);
+ Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime);
Diag(property->getLocation(), diag::note_property_declare);
}
}
@@ -730,7 +878,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (kind & ObjCPropertyDecl::OBJC_PR_weak &&
!getLangOpts().ObjCAutoRefCount &&
getLangOpts().getGC() == LangOptions::NonGC) {
- Diag(PropertyLoc, diag::error_synthesize_weak_non_arc_or_gc);
+ Diag(PropertyDiagLoc, diag::error_synthesize_weak_non_arc_or_gc);
Diag(property->getLocation(), diag::note_property_declare);
}
@@ -739,17 +887,20 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
PropertyIvarType, /*Dinfo=*/0,
ObjCIvarDecl::Private,
(Expr *)0, true);
+ if (CompleteTypeErr)
+ Ivar->setInvalidDecl();
ClassImpDecl->addDecl(Ivar);
IDecl->makeDeclVisibleInContext(Ivar);
property->setPropertyIvarDecl(Ivar);
- if (!getLangOpts().ObjCNonFragileABI)
- Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId;
+ if (getLangOpts().ObjCRuntime.isFragile())
+ Diag(PropertyDiagLoc, diag::error_missing_property_ivar_decl)
+ << PropertyId;
// Note! I deliberately want it to fall thru so, we have a
// a property implementation and to avoid future warnings.
- } else if (getLangOpts().ObjCNonFragileABI &&
+ } else if (getLangOpts().ObjCRuntime.isNonFragile() &&
!declaresSameEntity(ClassDeclared, IDecl)) {
- Diag(PropertyLoc, diag::error_ivar_in_superclass_use)
+ Diag(PropertyDiagLoc, diag::error_ivar_in_superclass_use)
<< property->getDeclName() << Ivar->getDeclName()
<< ClassDeclared->getDeclName();
Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
@@ -759,8 +910,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
QualType IvarType = Context.getCanonicalType(Ivar->getType());
// Check that type of property and its ivar are type compatible.
- if (Context.getCanonicalType(PropertyIvarType) != IvarType) {
- bool compat = false;
+ if (!Context.hasSameType(PropertyIvarType, IvarType)) {
+ compat = false;
if (isa<ObjCObjectPointerType>(PropertyIvarType)
&& isa<ObjCObjectPointerType>(IvarType))
compat =
@@ -773,31 +924,32 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
== Compatible);
}
if (!compat) {
- Diag(PropertyLoc, diag::error_property_ivar_type)
+ Diag(PropertyDiagLoc, diag::error_property_ivar_type)
<< property->getDeclName() << PropType
<< Ivar->getDeclName() << IvarType;
Diag(Ivar->getLocation(), diag::note_ivar_decl);
// Note! I deliberately want it to fall thru so, we have a
// a property implementation and to avoid future warnings.
}
-
- // FIXME! Rules for properties are somewhat different that those
- // for assignments. Use a new routine to consolidate all cases;
- // specifically for property redeclarations as well as for ivars.
- QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
- QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
- if (lhsType != rhsType &&
- lhsType->isArithmeticType()) {
- Diag(PropertyLoc, diag::error_property_ivar_type)
- << property->getDeclName() << PropType
- << Ivar->getDeclName() << IvarType;
- Diag(Ivar->getLocation(), diag::note_ivar_decl);
- // Fall thru - see previous comment
+ else {
+ // FIXME! Rules for properties are somewhat different that those
+ // for assignments. Use a new routine to consolidate all cases;
+ // specifically for property redeclarations as well as for ivars.
+ QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
+ QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
+ if (lhsType != rhsType &&
+ lhsType->isArithmeticType()) {
+ Diag(PropertyDiagLoc, diag::error_property_ivar_type)
+ << property->getDeclName() << PropType
+ << Ivar->getDeclName() << IvarType;
+ Diag(Ivar->getLocation(), diag::note_ivar_decl);
+ // Fall thru - see previous comment
+ }
}
// __weak is explicit. So it works on Canonical type.
if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
getLangOpts().getGC() != LangOptions::NonGC)) {
- Diag(PropertyLoc, diag::error_weak_property)
+ Diag(PropertyDiagLoc, diag::error_weak_property)
<< property->getDeclName() << Ivar->getDeclName();
Diag(Ivar->getLocation(), diag::note_ivar_decl);
// Fall thru - see previous comment
@@ -806,7 +958,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if ((property->getType()->isObjCObjectPointerType() ||
PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
getLangOpts().getGC() != LangOptions::NonGC) {
- Diag(PropertyLoc, diag::error_strong_property)
+ Diag(PropertyDiagLoc, diag::error_strong_property)
<< property->getDeclName() << Ivar->getDeclName();
// Fall thru - see previous comment
}
@@ -815,7 +967,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
checkARCPropertyImpl(*this, PropertyLoc, property, Ivar);
} else if (PropertyIvar)
// @dynamic
- Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
+ Diag(PropertyDiagLoc, diag::error_dynamic_property_ivar_decl);
assert (property && "ActOnPropertyImplDecl - property declaration missing");
ObjCPropertyImplDecl *PIDecl =
@@ -825,9 +977,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
ObjCPropertyImplDecl::Synthesize
: ObjCPropertyImplDecl::Dynamic),
Ivar, PropertyIvarLoc);
+
+ if (CompleteTypeErr || !compat)
+ PIDecl->setInvalidDecl();
+
if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
getterMethod->createImplicitParams(Context, IDecl);
- if (getLangOpts().CPlusPlus && Synthesize &&
+ if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
Ivar->getType()->isRecordType()) {
// For Objective-C++, need to synthesize the AST for the IVAR object to be
// returned by the getter as it must conform to C++'s copy-return rules.
@@ -862,8 +1018,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
setterMethod->createImplicitParams(Context, IDecl);
- if (getLangOpts().CPlusPlus && Synthesize
- && Ivar->getType()->isRecordType()) {
+ if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
+ Ivar->getType()->isRecordType()) {
// FIXME. Eventually we want to do this for Objective-C as well.
ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
DeclRefExpr *SelfExpr =
@@ -916,7 +1072,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
IC->addPropertyImplementation(PIDecl);
if (getLangOpts().ObjCDefaultSynthProperties &&
- getLangOpts().ObjCNonFragileABI2 &&
+ getLangOpts().ObjCRuntime.isNonFragile() &&
!IDecl->isObjCRequiresPropertyDefs()) {
// Diagnose if an ivar was lazily synthesdized due to a previous
// use and if 1) property is @dynamic or 2) property is synthesized
@@ -941,7 +1097,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (Synthesize)
if (ObjCPropertyImplDecl *PPIDecl =
CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ Diag(PropertyDiagLoc, diag::error_duplicate_ivar_use)
<< PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
<< PropertyIvar;
Diag(PPIDecl->getLocation(), diag::note_previous_use);
@@ -949,7 +1105,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (ObjCPropertyImplDecl *PPIDecl =
CatImplClass->FindPropertyImplDecl(PropertyId)) {
- Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
+ Diag(PropertyDiagLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
return 0;
}
@@ -1030,21 +1186,42 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
ObjCMethodDecl *GetterMethod,
SourceLocation Loc) {
- if (GetterMethod &&
- !Context.hasSameType(GetterMethod->getResultType().getNonReferenceType(),
- property->getType().getNonReferenceType())) {
- AssignConvertType result = Incompatible;
- if (property->getType()->isObjCObjectPointerType())
- result = CheckAssignmentConstraints(Loc, GetterMethod->getResultType(),
- property->getType());
- if (result != Compatible) {
- Diag(Loc, diag::warn_accessor_property_type_mismatch)
- << property->getDeclName()
- << GetterMethod->getSelector();
- Diag(GetterMethod->getLocation(), diag::note_declared_at);
- return true;
+ if (!GetterMethod)
+ return false;
+ QualType GetterType = GetterMethod->getResultType().getNonReferenceType();
+ QualType PropertyIvarType = property->getType().getNonReferenceType();
+ bool compat = Context.hasSameType(PropertyIvarType, GetterType);
+ if (!compat) {
+ if (isa<ObjCObjectPointerType>(PropertyIvarType) &&
+ isa<ObjCObjectPointerType>(GetterType))
+ compat =
+ Context.canAssignObjCInterfaces(
+ GetterType->getAs<ObjCObjectPointerType>(),
+ PropertyIvarType->getAs<ObjCObjectPointerType>());
+ else if (CheckAssignmentConstraints(Loc, GetterType, PropertyIvarType)
+ != Compatible) {
+ Diag(Loc, diag::error_property_accessor_type)
+ << property->getDeclName() << PropertyIvarType
+ << GetterMethod->getSelector() << GetterType;
+ Diag(GetterMethod->getLocation(), diag::note_declared_at);
+ return true;
+ } else {
+ compat = true;
+ QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
+ QualType rhsType =Context.getCanonicalType(GetterType).getUnqualifiedType();
+ if (lhsType != rhsType && lhsType->isArithmeticType())
+ compat = false;
}
}
+
+ if (!compat) {
+ Diag(Loc, diag::warn_accessor_property_type_mismatch)
+ << property->getDeclName()
+ << GetterMethod->getSelector();
+ Diag(GetterMethod->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
return false;
}
@@ -1059,11 +1236,11 @@ void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
// FIXME: O(N^2)
for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(),
E = SDecl->prop_end(); S != E; ++S) {
- ObjCPropertyDecl *SuperPDecl = (*S);
+ ObjCPropertyDecl *SuperPDecl = *S;
// Does property in super class has declaration in current class?
for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(),
E = IDecl->prop_end(); I != E; ++I) {
- ObjCPropertyDecl *PDecl = (*I);
+ ObjCPropertyDecl *PDecl = *I;
if (SuperPDecl->getIdentifier() == PDecl->getIdentifier())
DiagnosePropertyMismatch(PDecl, SuperPDecl,
SDecl->getIdentifier());
@@ -1085,29 +1262,29 @@ Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
if (!CatDecl->IsClassExtension())
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Pr = (*P);
+ ObjCPropertyDecl *Pr = *P;
ObjCCategoryDecl::prop_iterator CP, CE;
// Is this property already in category's list of properties?
for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP!=CE; ++CP)
- if ((*CP)->getIdentifier() == Pr->getIdentifier())
+ if (CP->getIdentifier() == Pr->getIdentifier())
break;
if (CP != CE)
// Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
+ DiagnosePropertyMismatch(*CP, Pr, PDecl->getIdentifier());
}
return;
}
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Pr = (*P);
+ ObjCPropertyDecl *Pr = *P;
ObjCInterfaceDecl::prop_iterator CP, CE;
// Is this property already in class's list of properties?
for (CP = IDecl->prop_begin(), CE = IDecl->prop_end(); CP != CE; ++CP)
- if ((*CP)->getIdentifier() == Pr->getIdentifier())
+ if (CP->getIdentifier() == Pr->getIdentifier())
break;
if (CP != CE)
// Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
+ DiagnosePropertyMismatch(*CP, Pr, PDecl->getIdentifier());
}
}
@@ -1223,7 +1400,7 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
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);
+ ObjCPropertyDecl *Prop = *P;
PropMap[Prop->getIdentifier()] = Prop;
}
// scan through class's protocols.
@@ -1236,7 +1413,7 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
if (!CATDecl->IsClassExtension())
for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
E = CATDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
+ ObjCPropertyDecl *Prop = *P;
PropMap[Prop->getIdentifier()] = Prop;
}
// scan through class's protocols.
@@ -1247,7 +1424,7 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
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);
+ ObjCPropertyDecl *Prop = *P;
ObjCPropertyDecl *PropertyFromSuper = SuperPropMap[Prop->getIdentifier()];
// Exclude property for protocols which conform to class's super-class,
// as super-class has to implement the property.
@@ -1273,7 +1450,7 @@ static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl,
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);
+ ObjCPropertyDecl *Prop = *P;
PropMap[Prop->getIdentifier()] = Prop;
}
for (ObjCInterfaceDecl::all_protocol_iterator
@@ -1284,7 +1461,7 @@ static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl,
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);
+ ObjCPropertyDecl *Prop = *P;
if (!PropMap.count(Prop->getIdentifier()))
PropMap[Prop->getIdentifier()] = Prop;
}
@@ -1316,7 +1493,7 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
dyn_cast<ObjCInterfaceDecl>(CDecl)) {
for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
E = IDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
+ ObjCPropertyDecl *Prop = *P;
if (Prop->getIdentifier() == II)
return Prop;
}
@@ -1333,7 +1510,7 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
dyn_cast<ObjCProtocolDecl>(CDecl)) {
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
+ ObjCPropertyDecl *Prop = *P;
if (Prop->getIdentifier() == II)
return Prop;
}
@@ -1358,8 +1535,8 @@ static IdentifierInfo * getDefaultSynthIvarName(ObjCPropertyDecl *Prop,
return &Ctx.Idents.get(ivarName.str());
}
-/// DefaultSynthesizeProperties - This routine default synthesizes all
-/// properties which must be synthesized in class's @implementation.
+/// \brief Default synthesizes all properties which must be synthesized
+/// in class's \@implementation.
void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCInterfaceDecl *IDecl) {
@@ -1402,16 +1579,21 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
// aren't really synthesized at a particular location; they just exist.
// Saying that they are located at the @implementation isn't really going
// to help users.
- ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(),
- true,
- /* property = */ Prop->getIdentifier(),
- /* ivar = */ getDefaultSynthIvarName(Prop, Context),
- SourceLocation());
+ ObjCPropertyImplDecl *PIDecl = dyn_cast_or_null<ObjCPropertyImplDecl>(
+ ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(),
+ true,
+ /* property = */ Prop->getIdentifier(),
+ /* ivar = */ getDefaultSynthIvarName(Prop, Context),
+ Prop->getLocation()));
+ if (PIDecl) {
+ Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
+ Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
+ }
}
}
void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
- if (!LangOpts.ObjCDefaultSynthProperties || !LangOpts.ObjCNonFragileABI2)
+ if (!LangOpts.ObjCDefaultSynthProperties || LangOpts.ObjCRuntime.isFragile())
return;
ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D);
if (!IC)
@@ -1423,7 +1605,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
- const llvm::DenseSet<Selector>& InsMap) {
+ const SelectorSet &InsMap) {
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap;
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))
CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
@@ -1437,7 +1619,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
for (ObjCImplDecl::propimpl_iterator
I = IMPDecl->propimpl_begin(),
EI = IMPDecl->propimpl_end(); I != EI; ++I)
- PropImplMap.insert((*I)->getPropertyDecl());
+ PropImplMap.insert(I->getPropertyDecl());
for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
@@ -1455,7 +1637,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
<< Prop->getDeclName() << Prop->getGetterName();
Diag(Prop->getLocation(),
diag::note_property_declare);
- if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2)
+ if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCRuntime.isNonFragile())
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
Diag(RID->getLocation(), diag::note_suppressed_class_declare);
@@ -1470,7 +1652,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
<< Prop->getDeclName() << Prop->getSetterName();
Diag(Prop->getLocation(),
diag::note_property_declare);
- if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2)
+ if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCRuntime.isNonFragile())
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
Diag(RID->getLocation(), diag::note_suppressed_class_declare);
@@ -1487,7 +1669,7 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(),
E = IDecl->prop_end();
I != E; ++I) {
- ObjCPropertyDecl *Property = (*I);
+ ObjCPropertyDecl *Property = *I;
ObjCMethodDecl *GetterMethod = 0;
ObjCMethodDecl *SetterMethod = 0;
bool LookedUpGetterSetter = false;
@@ -1753,11 +1935,24 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
AddInstanceMethodToGlobalPool(GetterMethod);
if (SetterMethod)
AddInstanceMethodToGlobalPool(SetterMethod);
+
+ ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(CD);
+ if (!CurrentClass) {
+ if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CD))
+ CurrentClass = Cat->getClassInterface();
+ else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(CD))
+ CurrentClass = Impl->getClassInterface();
+ }
+ if (GetterMethod)
+ CheckObjCMethodOverrides(GetterMethod, CurrentClass, Sema::RTC_Unknown);
+ if (SetterMethod)
+ CheckObjCMethodOverrides(SetterMethod, CurrentClass, Sema::RTC_Unknown);
}
void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
SourceLocation Loc,
- unsigned &Attributes) {
+ unsigned &Attributes,
+ bool propertyInPrimaryClass) {
// FIXME: Improve the reported location.
if (!PDecl || PDecl->isInvalidDecl())
return;
@@ -1780,9 +1975,18 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
return;
}
+ if (propertyInPrimaryClass) {
+ // we postpone most property diagnosis until class's implementation
+ // because, its readonly attribute may be overridden in its class
+ // extensions making other attributes, which make no sense, to make sense.
+ if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ (Attributes & ObjCDeclSpec::DQ_PR_readwrite))
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "readonly" << "readwrite";
+ }
// readonly and readwrite/assign/retain/copy conflict.
- if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
+ else if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
ObjCDeclSpec::DQ_PR_assign |
ObjCDeclSpec::DQ_PR_unsafe_unretained |
ObjCDeclSpec::DQ_PR_copy |
@@ -1939,8 +2143,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
&& getLangOpts().getGC() == LangOptions::GCOnly
&& PropertyTy->isBlockPointerType())
Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
- else if (getLangOpts().ObjCAutoRefCount &&
- (Attributes & ObjCDeclSpec::DQ_PR_retain) &&
+ else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) &&
!(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
!(Attributes & ObjCDeclSpec::DQ_PR_strong) &&
PropertyTy->isBlockPointerType())
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 50230f0..a874489 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -28,6 +28,7 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
@@ -388,13 +389,22 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
const unsigned ToWidth = Ctx.getIntWidth(ToType);
if (FromWidth > ToWidth ||
- (FromWidth == ToWidth && FromSigned != ToSigned)) {
+ (FromWidth == ToWidth && FromSigned != ToSigned) ||
+ (FromSigned && !ToSigned)) {
// Not all values of FromType can be represented in ToType.
llvm::APSInt InitializerValue;
const Expr *Initializer = IgnoreNarrowingConversion(Converted);
- if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) {
- ConstantValue = APValue(InitializerValue);
-
+ if (!Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) {
+ // Such conversions on variables are always narrowing.
+ return NK_Variable_Narrowing;
+ }
+ bool Narrowing = false;
+ if (FromWidth < ToWidth) {
+ // Negative -> unsigned is narrowing. Otherwise, more bits is never
+ // narrowing.
+ if (InitializerValue.isSigned() && InitializerValue.isNegative())
+ Narrowing = true;
+ } else {
// Add a bit to the InitializerValue so we don't have to worry about
// signed vs. unsigned comparisons.
InitializerValue = InitializerValue.extend(
@@ -406,13 +416,13 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
ConvertedValue.setIsSigned(InitializerValue.isSigned());
// If the result is different, this was a narrowing conversion.
- if (ConvertedValue != InitializerValue) {
- ConstantType = Initializer->getType();
- return NK_Constant_Narrowing;
- }
- } else {
- // Variables are always narrowings.
- return NK_Variable_Narrowing;
+ if (ConvertedValue != InitializerValue)
+ Narrowing = true;
+ }
+ if (Narrowing) {
+ ConstantType = Initializer->getType();
+ ConstantValue = APValue(InitializerValue);
+ return NK_Constant_Narrowing;
}
}
return NK_Not_Narrowing;
@@ -541,6 +551,7 @@ static MakeDeductionFailureInfo(ASTContext &Context,
TemplateDeductionInfo &Info) {
OverloadCandidate::DeductionFailureInfo Result;
Result.Result = static_cast<unsigned>(TDK);
+ Result.HasDiagnostic = false;
Result.Data = 0;
switch (TDK) {
case Sema::TDK_Success:
@@ -567,6 +578,12 @@ static MakeDeductionFailureInfo(ASTContext &Context,
case Sema::TDK_SubstitutionFailure:
Result.Data = Info.take();
+ if (Info.hasSFINAEDiagnostic()) {
+ PartialDiagnosticAt *Diag = new (Result.Diagnostic) PartialDiagnosticAt(
+ SourceLocation(), PartialDiagnostic::NullDiagnostic());
+ Info.takeSFINAEDiagnostic(*Diag);
+ Result.HasDiagnostic = true;
+ }
break;
case Sema::TDK_NonDeducedMismatch:
@@ -594,8 +611,12 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() {
break;
case Sema::TDK_SubstitutionFailure:
- // FIXME: Destroy the template arugment list?
+ // FIXME: Destroy the template argument list?
Data = 0;
+ if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) {
+ Diag->~PartialDiagnosticAt();
+ HasDiagnostic = false;
+ }
break;
// Unhandled
@@ -605,6 +626,13 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() {
}
}
+PartialDiagnosticAt *
+OverloadCandidate::DeductionFailureInfo::getSFINAEDiagnostic() {
+ if (HasDiagnostic)
+ return static_cast<PartialDiagnosticAt*>(static_cast<void*>(Diagnostic));
+ return 0;
+}
+
TemplateParameter
OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
@@ -707,9 +735,12 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() {
}
void OverloadCandidateSet::clear() {
- for (iterator i = begin(), e = end(); i != e; ++i)
+ for (iterator i = begin(), e = end(); i != e; ++i) {
for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
i->Conversions[ii].~ImplicitConversionSequence();
+ if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction)
+ i->DeductionFailure.Destroy();
+ }
NumInlineSequences = 0;
Candidates.clear();
Functions.clear();
@@ -1657,7 +1688,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// We have already pre-calculated the promotion type, so this is trivial.
if (ToType->isIntegerType() &&
- !RequireCompleteType(From->getLocStart(), FromType, PDiag()))
+ !RequireCompleteType(From->getLocStart(), FromType, 0))
return Context.hasSameUnqualifiedType(ToType,
FromEnumType->getDecl()->getPromotionType());
}
@@ -1987,7 +2018,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
if (getLangOpts().CPlusPlus &&
FromPointeeType->isRecordType() && ToPointeeType->isRecordType() &&
!Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType) &&
- !RequireCompleteType(From->getLocStart(), FromPointeeType, PDiag()) &&
+ !RequireCompleteType(From->getLocStart(), FromPointeeType, 0) &&
IsDerivedFrom(FromPointeeType, ToPointeeType)) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
@@ -2469,7 +2500,7 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
/// for equality of their argument types. Caller has already checked that
/// they have same number of arguments. This routine assumes that Objective-C
/// pointer types which only differ in their protocol qualifiers are equal.
-/// If the parameters are different, ArgPos will have the the parameter index
+/// If the parameters are different, ArgPos will have the parameter index
/// of the first different parameter.
bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType,
const FunctionProtoType *NewType,
@@ -2531,13 +2562,17 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
Kind = CK_BitCast;
- if (!IsCStyleOrFunctionalCast &&
- Context.hasSameUnqualifiedType(From->getType(), Context.BoolTy) &&
- From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
- DiagRuntimeBehavior(From->getExprLoc(), From,
- PDiag(diag::warn_impcast_bool_to_null_pointer)
- << ToType << From->getSourceRange());
-
+ if (!IsCStyleOrFunctionalCast && !FromType->isAnyPointerType() &&
+ From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) ==
+ Expr::NPCK_ZeroExpression) {
+ if (Context.hasSameUnqualifiedType(From->getType(), Context.BoolTy))
+ DiagRuntimeBehavior(From->getExprLoc(), From,
+ PDiag(diag::warn_impcast_bool_to_null_pointer)
+ << ToType << From->getSourceRange());
+ else if (!isUnevaluatedContext())
+ Diag(From->getExprLoc(), diag::warn_non_literal_null_pointer)
+ << ToType << From->getSourceRange();
+ }
if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) {
if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) {
QualType FromPointeeType = FromPtrType->getPointeeType(),
@@ -2616,7 +2651,7 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
QualType ToClass(ToTypePtr->getClass(), 0);
if (!Context.hasSameUnqualifiedType(FromClass, ToClass) &&
- !RequireCompleteType(From->getLocStart(), ToClass, PDiag()) &&
+ !RequireCompleteType(From->getLocStart(), ToClass, 0) &&
IsDerivedFrom(ToClass, FromClass)) {
ConvertedType = Context.getMemberPointerType(FromTypePtr->getPointeeType(),
ToClass.getTypePtr());
@@ -2923,7 +2958,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
S.IsDerivedFrom(From->getType(), ToType)))
ConstructorsOnly = true;
- S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag());
+ S.RequireCompleteType(From->getLocStart(), ToType, 0);
// RequireCompleteType may have returned true due to some invalid decl
// during template instantiation, but ToType may be complete enough now
// to try to recover.
@@ -3001,8 +3036,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// Enumerate conversion functions, if we're allowed to.
if (ConstructorsOnly || isa<InitListExpr>(From)) {
- } else if (S.RequireCompleteType(From->getLocStart(), From->getType(),
- S.PDiag(0) << From->getSourceRange())) {
+ } else if (S.RequireCompleteType(From->getLocStart(), From->getType(), 0)) {
// No conversion functions from incomplete types.
} else if (const RecordType *FromRecordType
= From->getType()->getAs<RecordType>()) {
@@ -3848,7 +3882,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
ObjCLifetimeConversion = false;
if (UnqualT1 == UnqualT2) {
// Nothing to do.
- } else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&
+ } else if (!RequireCompleteType(Loc, OrigT2, 0) &&
IsDerivedFrom(UnqualT2, UnqualT1))
DerivedToBase = true;
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
@@ -4135,7 +4169,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// qualifier.
// This is also the point where rvalue references and lvalue inits no longer
// go together.
- if (!isRValRef && !T1.isConstQualified())
+ if (!isRValRef && (!T1.isConstQualified() || T1.isVolatileQualified()))
return ICS;
// -- If the initializer expression
@@ -4313,7 +4347,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
// We need a complete type for what follows. Incomplete types can never be
// initialized from init lists.
- if (S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag()))
+ if (S.RequireCompleteType(From->getLocStart(), ToType, 0))
return Result;
// C++11 [over.ics.list]p2:
@@ -4995,29 +5029,9 @@ static bool isIntegralOrEnumerationType(QualType T, bool AllowScopedEnum) {
/// \param Loc The source location of the construct that requires the
/// conversion.
///
-/// \param FromE The expression we're converting from.
-///
-/// \param NotIntDiag The diagnostic to be emitted if the expression does not
-/// have integral or enumeration type.
-///
-/// \param IncompleteDiag The diagnostic to be emitted if the expression has
-/// incomplete class type.
+/// \param From The expression we're converting from.
///
-/// \param ExplicitConvDiag The diagnostic to be emitted if we're calling an
-/// explicit conversion function (because no implicit conversion functions
-/// were available). This is a recovery mode.
-///
-/// \param ExplicitConvNote The note to be emitted with \p ExplicitConvDiag,
-/// showing which conversion was picked.
-///
-/// \param AmbigDiag The diagnostic to be emitted if there is more than one
-/// conversion function that could convert to integral or enumeration type.
-///
-/// \param AmbigNote The note to be emitted with \p AmbigDiag for each
-/// usable conversion function.
-///
-/// \param ConvDiag The diagnostic to be emitted if we are calling a conversion
-/// function, which may be an extension in this case.
+/// \param Diagnoser Used to output any diagnostics.
///
/// \param AllowScopedEnumerations Specifies whether conversions to scoped
/// enumerations should be considered.
@@ -5026,13 +5040,7 @@ static bool isIntegralOrEnumerationType(QualType T, bool AllowScopedEnum) {
/// successful.
ExprResult
Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
- const PartialDiagnostic &NotIntDiag,
- const PartialDiagnostic &IncompleteDiag,
- const PartialDiagnostic &ExplicitConvDiag,
- const PartialDiagnostic &ExplicitConvNote,
- const PartialDiagnostic &AmbigDiag,
- const PartialDiagnostic &AmbigNote,
- const PartialDiagnostic &ConvDiag,
+ ICEConvertDiagnoser &Diagnoser,
bool AllowScopedEnumerations) {
// We can't perform any more checking for type-dependent expressions.
if (From->isTypeDependent())
@@ -5056,13 +5064,25 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
// expression of integral or enumeration type.
const RecordType *RecordTy = T->getAs<RecordType>();
if (!RecordTy || !getLangOpts().CPlusPlus) {
- if (NotIntDiag.getDiagID())
- Diag(Loc, NotIntDiag) << T << From->getSourceRange();
+ if (!Diagnoser.Suppress)
+ Diagnoser.diagnoseNotInt(*this, Loc, T) << From->getSourceRange();
return Owned(From);
}
// We must have a complete class type.
- if (RequireCompleteType(Loc, T, IncompleteDiag))
+ struct TypeDiagnoserPartialDiag : TypeDiagnoser {
+ ICEConvertDiagnoser &Diagnoser;
+ Expr *From;
+
+ TypeDiagnoserPartialDiag(ICEConvertDiagnoser &Diagnoser, Expr *From)
+ : TypeDiagnoser(Diagnoser.Suppress), Diagnoser(Diagnoser), From(From) {}
+
+ virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) {
+ Diagnoser.diagnoseIncomplete(S, Loc, T) << From->getSourceRange();
+ }
+ } IncompleteDiagnoser(Diagnoser, From);
+
+ if (RequireCompleteType(Loc, T, IncompleteDiagnoser))
return Owned(From);
// Look for a conversion to an integral or enumeration type.
@@ -5092,7 +5112,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
switch (ViableConversions.size()) {
case 0:
- if (ExplicitConversions.size() == 1 && ExplicitConvDiag.getDiagID()) {
+ if (ExplicitConversions.size() == 1 && !Diagnoser.Suppress) {
DeclAccessPair Found = ExplicitConversions[0];
CXXConversionDecl *Conversion
= cast<CXXConversionDecl>(Found->getUnderlyingDecl());
@@ -5104,14 +5124,12 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
std::string TypeStr;
ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy());
- Diag(Loc, ExplicitConvDiag)
- << T << ConvTy
+ Diagnoser.diagnoseExplicitConv(*this, Loc, T, ConvTy)
<< FixItHint::CreateInsertion(From->getLocStart(),
"static_cast<" + TypeStr + ">(")
<< FixItHint::CreateInsertion(PP.getLocForEndOfToken(From->getLocEnd()),
")");
- Diag(Conversion->getLocation(), ExplicitConvNote)
- << ConvTy->isEnumeralType() << ConvTy;
+ Diagnoser.noteExplicitConv(*this, Conversion, ConvTy);
// If we aren't in a SFINAE context, build a call to the
// explicit conversion function.
@@ -5142,12 +5160,12 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
= cast<CXXConversionDecl>(Found->getUnderlyingDecl());
QualType ConvTy
= Conversion->getConversionType().getNonReferenceType();
- if (ConvDiag.getDiagID()) {
+ if (!Diagnoser.SuppressConversion) {
if (isSFINAEContext())
return ExprError();
- Diag(Loc, ConvDiag)
- << T << ConvTy->isEnumeralType() << ConvTy << From->getSourceRange();
+ Diagnoser.diagnoseConversion(*this, Loc, T, ConvTy)
+ << From->getSourceRange();
}
ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion,
@@ -5163,24 +5181,24 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
}
default:
- if (!AmbigDiag.getDiagID())
- return Owned(From);
+ if (Diagnoser.Suppress)
+ return ExprError();
- Diag(Loc, AmbigDiag)
- << T << From->getSourceRange();
+ Diagnoser.diagnoseAmbiguous(*this, Loc, T) << From->getSourceRange();
for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
CXXConversionDecl *Conv
= cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
QualType ConvTy = Conv->getConversionType().getNonReferenceType();
- Diag(Conv->getLocation(), AmbigNote)
- << ConvTy->isEnumeralType() << ConvTy;
+ Diagnoser.noteAmbiguous(*this, Conv, ConvTy);
}
return Owned(From);
}
if (!isIntegralOrEnumerationType(From->getType(), AllowScopedEnumerations) &&
- NotIntDiag.getDiagID())
- Diag(Loc, NotIntDiag) << From->getType() << From->getSourceRange();
+ !Diagnoser.Suppress) {
+ Diagnoser.diagnoseNotInt(*this, Loc, From->getType())
+ << From->getSourceRange();
+ }
return DefaultLvalueConversion(From);
}
@@ -5190,7 +5208,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
/// @p SuppressUserConversions, then don't allow user-defined
/// conversions via constructors or conversion operators.
///
-/// \para PartialOverloading true if we are performing "partial" overloading
+/// \param PartialOverloading true if we are performing "partial" overloading
/// based on an incomplete set of function arguments. This feature is used by
/// code completion.
void
@@ -5906,7 +5924,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
// empty.
if (const RecordType *T1Rec = T1->getAs<RecordType>()) {
// Complete the type if it can be completed. Otherwise, we're done.
- if (RequireCompleteType(OpLoc, T1, PDiag()))
+ if (RequireCompleteType(OpLoc, T1, 0))
return;
LookupResult Operators(*this, OpName, OpLoc, LookupOrdinaryName);
@@ -6098,40 +6116,49 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
const PointerType *PointerTy = Ty->getAs<PointerType>();
bool buildObjCPtr = false;
if (!PointerTy) {
- if (const ObjCObjectPointerType *PTy = Ty->getAs<ObjCObjectPointerType>()) {
- PointeeTy = PTy->getPointeeType();
- buildObjCPtr = true;
- }
- else
- llvm_unreachable("type was not a pointer type!");
- }
- else
+ const ObjCObjectPointerType *PTy = Ty->castAs<ObjCObjectPointerType>();
+ PointeeTy = PTy->getPointeeType();
+ buildObjCPtr = true;
+ } else {
PointeeTy = PointerTy->getPointeeType();
-
+ }
+
// Don't add qualified variants of arrays. For one, they're not allowed
// (the qualifier would sink to the element type), and for another, the
// only overload situation where it matters is subscript or pointer +- int,
// and those shouldn't have qualifier variants anyway.
if (PointeeTy->isArrayType())
return true;
+
unsigned BaseCVR = PointeeTy.getCVRQualifiers();
- if (const ConstantArrayType *Array =Context.getAsConstantArrayType(PointeeTy))
- BaseCVR = Array->getElementType().getCVRQualifiers();
bool hasVolatile = VisibleQuals.hasVolatile();
bool hasRestrict = VisibleQuals.hasRestrict();
// Iterate through all strict supersets of BaseCVR.
for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) {
if ((CVR | BaseCVR) != CVR) continue;
- // Skip over Volatile/Restrict if no Volatile/Restrict found anywhere
- // in the types.
+ // Skip over volatile if no volatile found anywhere in the types.
if ((CVR & Qualifiers::Volatile) && !hasVolatile) continue;
- if ((CVR & Qualifiers::Restrict) && !hasRestrict) continue;
+
+ // Skip over restrict if no restrict found anywhere in the types, or if
+ // the type cannot be restrict-qualified.
+ if ((CVR & Qualifiers::Restrict) &&
+ (!hasRestrict ||
+ (!(PointeeTy->isAnyPointerType() || PointeeTy->isReferenceType()))))
+ continue;
+
+ // Build qualified pointee type.
QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR);
+
+ // Build qualified pointer type.
+ QualType QPointerTy;
if (!buildObjCPtr)
- PointerTypes.insert(Context.getPointerType(QPointeeTy));
+ QPointerTy = Context.getPointerType(QPointeeTy);
else
- PointerTypes.insert(Context.getObjCObjectPointerType(QPointeeTy));
+ QPointerTy = Context.getObjCObjectPointerType(QPointeeTy);
+
+ // Insert qualified pointer type.
+ PointerTypes.insert(QPointerTy);
}
return true;
@@ -6328,6 +6355,8 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
// as see them.
bool done = false;
while (!done) {
+ if (CanTy.isRestrictQualified())
+ VRQuals.addRestrict();
if (const PointerType *ResTypePtr = CanTy->getAs<PointerType>())
CanTy = ResTypePtr->getPointeeType();
else if (const MemberPointerType *ResTypeMPtr =
@@ -6337,8 +6366,6 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
done = true;
if (CanTy.isVolatileQualified())
VRQuals.addVolatile();
- if (CanTy.isRestrictQualified())
- VRQuals.addRestrict();
if (VRQuals.hasRestrict() && VRQuals.hasVolatile())
return VRQuals;
}
@@ -6368,12 +6395,12 @@ class BuiltinOperatorOverloadBuilder {
// The "promoted arithmetic types" are the arithmetic
// types are that preserved by promotion (C++ [over.built]p2).
static const unsigned FirstIntegralType = 3;
- static const unsigned LastIntegralType = 18;
+ static const unsigned LastIntegralType = 20;
static const unsigned FirstPromotedIntegralType = 3,
- LastPromotedIntegralType = 9;
+ LastPromotedIntegralType = 11;
static const unsigned FirstPromotedArithmeticType = 0,
- LastPromotedArithmeticType = 9;
- static const unsigned NumArithmeticTypes = 18;
+ LastPromotedArithmeticType = 11;
+ static const unsigned NumArithmeticTypes = 20;
/// \brief Get the canonical type for a given arithmetic type index.
CanQualType getArithmeticType(unsigned index) {
@@ -6389,9 +6416,11 @@ class BuiltinOperatorOverloadBuilder {
&ASTContext::IntTy,
&ASTContext::LongTy,
&ASTContext::LongLongTy,
+ &ASTContext::Int128Ty,
&ASTContext::UnsignedIntTy,
&ASTContext::UnsignedLongTy,
&ASTContext::UnsignedLongLongTy,
+ &ASTContext::UnsignedInt128Ty,
// End of promoted types.
&ASTContext::BoolTy,
@@ -6404,7 +6433,7 @@ class BuiltinOperatorOverloadBuilder {
&ASTContext::UnsignedCharTy,
&ASTContext::UnsignedShortTy,
// End of integral types.
- // FIXME: What about complex?
+ // FIXME: What about complex? What about half?
};
return S.Context.*ArithmeticTypes[index];
}
@@ -6423,20 +6452,24 @@ class BuiltinOperatorOverloadBuilder {
// *except* when dealing with signed types of higher rank.
// (we could precompute SLL x UI for all known platforms, but it's
// better not to make any assumptions).
+ // We assume that int128 has a higher rank than long long on all platforms.
enum PromotedType {
- Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL, Dep=-1
+ Dep=-1,
+ Flt, Dbl, LDbl, SI, SL, SLL, S128, UI, UL, ULL, U128
};
- static PromotedType ConversionsTable[LastPromotedArithmeticType]
+ static const PromotedType ConversionsTable[LastPromotedArithmeticType]
[LastPromotedArithmeticType] = {
- /* Flt*/ { Flt, Dbl, LDbl, Flt, Flt, Flt, Flt, Flt, Flt },
- /* Dbl*/ { Dbl, Dbl, LDbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl },
- /*LDbl*/ { LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl },
- /* SI*/ { Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL },
- /* SL*/ { Flt, Dbl, LDbl, SL, SL, SLL, Dep, UL, ULL },
- /* SLL*/ { Flt, Dbl, LDbl, SLL, SLL, SLL, Dep, Dep, ULL },
- /* UI*/ { Flt, Dbl, LDbl, UI, Dep, Dep, UI, UL, ULL },
- /* UL*/ { Flt, Dbl, LDbl, UL, UL, Dep, UL, UL, ULL },
- /* ULL*/ { Flt, Dbl, LDbl, ULL, ULL, ULL, ULL, ULL, ULL },
+/* Flt*/ { Flt, Dbl, LDbl, Flt, Flt, Flt, Flt, Flt, Flt, Flt, Flt },
+/* Dbl*/ { Dbl, Dbl, LDbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl },
+/*LDbl*/ { LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl },
+/* SI*/ { Flt, Dbl, LDbl, SI, SL, SLL, S128, UI, UL, ULL, U128 },
+/* SL*/ { Flt, Dbl, LDbl, SL, SL, SLL, S128, Dep, UL, ULL, U128 },
+/* SLL*/ { Flt, Dbl, LDbl, SLL, SLL, SLL, S128, Dep, Dep, ULL, U128 },
+/*S128*/ { Flt, Dbl, LDbl, S128, S128, S128, S128, S128, S128, S128, U128 },
+/* UI*/ { Flt, Dbl, LDbl, UI, Dep, Dep, S128, UI, UL, ULL, U128 },
+/* UL*/ { Flt, Dbl, LDbl, UL, UL, Dep, S128, UL, UL, ULL, U128 },
+/* ULL*/ { Flt, Dbl, LDbl, ULL, ULL, ULL, S128, ULL, ULL, ULL, U128 },
+/*U128*/ { Flt, Dbl, LDbl, U128, U128, U128, U128, U128, U128, U128, U128 },
};
assert(L < LastPromotedArithmeticType);
@@ -6466,7 +6499,8 @@ class BuiltinOperatorOverloadBuilder {
/// \brief Helper method to factor out the common pattern of adding overloads
/// for '++' and '--' builtin operators.
void addPlusPlusMinusMinusStyleOverloads(QualType CandidateTy,
- bool HasVolatile) {
+ bool HasVolatile,
+ bool HasRestrict) {
QualType ParamTypes[2] = {
S.Context.getLValueReferenceType(CandidateTy),
S.Context.IntTy
@@ -6489,6 +6523,33 @@ class BuiltinOperatorOverloadBuilder {
else
S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet);
}
+
+ // Add restrict version only if there are conversions to a restrict type
+ // and our candidate type is a non-restrict-qualified pointer.
+ if (HasRestrict && CandidateTy->isAnyPointerType() &&
+ !CandidateTy.isRestrictQualified()) {
+ ParamTypes[0]
+ = S.Context.getLValueReferenceType(
+ S.Context.getCVRQualifiedType(CandidateTy, Qualifiers::Restrict));
+ if (NumArgs == 1)
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
+ else
+ S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet);
+
+ if (HasVolatile) {
+ ParamTypes[0]
+ = S.Context.getLValueReferenceType(
+ S.Context.getCVRQualifiedType(CandidateTy,
+ (Qualifiers::Volatile |
+ Qualifiers::Restrict)));
+ if (NumArgs == 1)
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1,
+ CandidateSet);
+ else
+ S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet);
+ }
+ }
+
}
public:
@@ -6508,13 +6569,13 @@ public:
assert(getArithmeticType(FirstPromotedIntegralType) == S.Context.IntTy &&
"Invalid first promoted integral type");
assert(getArithmeticType(LastPromotedIntegralType - 1)
- == S.Context.UnsignedLongLongTy &&
+ == S.Context.UnsignedInt128Ty &&
"Invalid last promoted integral type");
assert(getArithmeticType(FirstPromotedArithmeticType)
== S.Context.FloatTy &&
"Invalid first promoted arithmetic type");
assert(getArithmeticType(LastPromotedArithmeticType - 1)
- == S.Context.UnsignedLongLongTy &&
+ == S.Context.UnsignedInt128Ty &&
"Invalid last promoted arithmetic type");
}
@@ -6543,7 +6604,8 @@ public:
Arith < NumArithmeticTypes; ++Arith) {
addPlusPlusMinusMinusStyleOverloads(
getArithmeticType(Arith),
- VisibleTypeConversionsQuals.hasVolatile());
+ VisibleTypeConversionsQuals.hasVolatile(),
+ VisibleTypeConversionsQuals.hasRestrict());
}
}
@@ -6567,8 +6629,10 @@ public:
continue;
addPlusPlusMinusMinusStyleOverloads(*Ptr,
- (!S.Context.getCanonicalType(*Ptr).isVolatileQualified() &&
- VisibleTypeConversionsQuals.hasVolatile()));
+ (!(*Ptr).isVolatileQualified() &&
+ VisibleTypeConversionsQuals.hasVolatile()),
+ (!(*Ptr).isRestrictQualified() &&
+ VisibleTypeConversionsQuals.hasRestrict()));
}
}
@@ -7026,14 +7090,36 @@ public:
S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
/*IsAssigmentOperator=*/ isEqualOp);
- if (!S.Context.getCanonicalType(*Ptr).isVolatileQualified() &&
- VisibleTypeConversionsQuals.hasVolatile()) {
+ bool NeedVolatile = !(*Ptr).isVolatileQualified() &&
+ VisibleTypeConversionsQuals.hasVolatile();
+ if (NeedVolatile) {
// volatile version
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr));
S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
}
+
+ if (!(*Ptr).isRestrictQualified() &&
+ VisibleTypeConversionsQuals.hasRestrict()) {
+ // restrict version
+ ParamTypes[0]
+ = S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr));
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/isEqualOp);
+
+ if (NeedVolatile) {
+ // volatile restrict version
+ ParamTypes[0]
+ = S.Context.getLValueReferenceType(
+ S.Context.getCVRQualifiedType(*Ptr,
+ (Qualifiers::Volatile |
+ Qualifiers::Restrict)));
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2,
+ CandidateSet,
+ /*IsAssigmentOperator=*/isEqualOp);
+ }
+ }
}
if (isEqualOp) {
@@ -7054,14 +7140,36 @@ public:
S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
/*IsAssigmentOperator=*/true);
- if (!S.Context.getCanonicalType(*Ptr).isVolatileQualified() &&
- VisibleTypeConversionsQuals.hasVolatile()) {
+ bool NeedVolatile = !(*Ptr).isVolatileQualified() &&
+ VisibleTypeConversionsQuals.hasVolatile();
+ if (NeedVolatile) {
// volatile version
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr));
S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2,
CandidateSet, /*IsAssigmentOperator=*/true);
}
+
+ if (!(*Ptr).isRestrictQualified() &&
+ VisibleTypeConversionsQuals.hasRestrict()) {
+ // restrict version
+ ParamTypes[0]
+ = S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr));
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2,
+ CandidateSet, /*IsAssigmentOperator=*/true);
+
+ if (NeedVolatile) {
+ // volatile restrict version
+ ParamTypes[0]
+ = S.Context.getLValueReferenceType(
+ S.Context.getCVRQualifiedType(*Ptr,
+ (Qualifiers::Volatile |
+ Qualifiers::Restrict)));
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2,
+ CandidateSet, /*IsAssigmentOperator=*/true);
+
+ }
+ }
}
}
}
@@ -7705,13 +7813,11 @@ isBetterOverloadCandidate(Sema &S,
/// \brief Computes the best viable function (C++ 13.3.3)
/// within an overload candidate set.
///
-/// \param CandidateSet the set of candidate functions.
-///
-/// \param Loc the location of the function name (or operator symbol) for
+/// \param Loc The location of the function name (or operator symbol) for
/// which overload resolution occurs.
///
-/// \param Best f overload resolution was successful or found a deleted
-/// function, Best points to the candidate function found.
+/// \param Best If overload resolution was successful or found a deleted
+/// function, \p Best points to the candidate function found.
///
/// \returns The result of overload resolution.
OverloadingResult
@@ -8035,12 +8141,22 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
FromIface->isSuperClassOf(ToIface))
BaseToDerivedConversion = 2;
} else if (const ReferenceType *ToRefTy = ToTy->getAs<ReferenceType>()) {
- if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy) &&
- !FromTy->isIncompleteType() &&
- !ToRefTy->getPointeeType()->isIncompleteType() &&
- S.IsDerivedFrom(ToRefTy->getPointeeType(), FromTy))
- BaseToDerivedConversion = 3;
+ if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy) &&
+ !FromTy->isIncompleteType() &&
+ !ToRefTy->getPointeeType()->isIncompleteType() &&
+ S.IsDerivedFrom(ToRefTy->getPointeeType(), FromTy)) {
+ BaseToDerivedConversion = 3;
+ } else if (ToTy->isLValueReferenceType() && !FromExpr->isLValue() &&
+ ToTy.getNonReferenceType().getCanonicalType() ==
+ FromTy.getNonReferenceType().getCanonicalType()) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_lvalue)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << (unsigned) isObjectArgument << I + 1;
+ MaybeEmitInheritedConstructorNote(S, Fn);
+ return;
}
+ }
if (BaseToDerivedConversion) {
S.Diag(Fn->getLocation(),
@@ -8127,9 +8243,14 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
std::string Description;
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description);
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
- << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode
- << modeCount << NumFormalArgs;
+ if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName())
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one)
+ << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode
+ << Fn->getParamDecl(0) << NumFormalArgs;
+ else
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
+ << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode
+ << modeCount << NumFormalArgs;
MaybeEmitInheritedConstructorNote(S, Fn);
}
@@ -8232,14 +8353,39 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
return;
case Sema::TDK_SubstitutionFailure: {
- std::string ArgString;
- if (TemplateArgumentList *Args
- = Cand->DeductionFailure.getTemplateArgumentList())
- ArgString = S.getTemplateArgumentBindingsText(
- Fn->getDescribedFunctionTemplate()->getTemplateParameters(),
- *Args);
+ // Format the template argument list into the argument string.
+ llvm::SmallString<128> TemplateArgString;
+ if (TemplateArgumentList *Args =
+ Cand->DeductionFailure.getTemplateArgumentList()) {
+ TemplateArgString = " ";
+ TemplateArgString += S.getTemplateArgumentBindingsText(
+ Fn->getDescribedFunctionTemplate()->getTemplateParameters(), *Args);
+ }
+
+ // If this candidate was disabled by enable_if, say so.
+ PartialDiagnosticAt *PDiag = Cand->DeductionFailure.getSFINAEDiagnostic();
+ if (PDiag && PDiag->second.getDiagID() ==
+ diag::err_typename_nested_not_found_enable_if) {
+ // FIXME: Use the source range of the condition, and the fully-qualified
+ // name of the enable_if template. These are both present in PDiag.
+ S.Diag(PDiag->first, diag::note_ovl_candidate_disabled_by_enable_if)
+ << "'enable_if'" << TemplateArgString;
+ return;
+ }
+
+ // Format the SFINAE diagnostic into the argument string.
+ // FIXME: Add a general mechanism to include a PartialDiagnostic *'s
+ // formatted message in another diagnostic.
+ llvm::SmallString<128> SFINAEArgString;
+ SourceRange R;
+ if (PDiag) {
+ SFINAEArgString = ": ";
+ R = SourceRange(PDiag->first, PDiag->first);
+ PDiag->second.EmitToString(S.getDiagnostics(), SFINAEArgString);
+ }
+
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure)
- << ArgString;
+ << TemplateArgString << SFINAEArgString << R;
MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -9190,7 +9336,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
return true;
}
- // Fix the expresion to refer to 'fn'.
+ // Fix the expression to refer to 'fn'.
SingleFunctionExpression =
Owned(FixOverloadedFunctionReference(SrcExpr.take(), found, fn));
@@ -9692,14 +9838,14 @@ static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
/// \param OpcIn The UnaryOperator::Opcode that describes this
/// operator.
///
-/// \param Functions The set of non-member functions that will be
+/// \param Fns The set of non-member functions that will be
/// considered by overload resolution. The caller needs to build this
/// set based on the context using, e.g.,
/// LookupOverloadedOperatorName() and ArgumentDependentLookup(). This
/// set should not contain any member functions; those will be added
/// by CreateOverloadedUnaryOp().
///
-/// \param input The input argument.
+/// \param Input The input argument.
ExprResult
Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
const UnresolvedSetImpl &Fns,
@@ -9892,7 +10038,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
/// \param OpcIn The BinaryOperator::Opcode that describes this
/// operator.
///
-/// \param Functions The set of non-member functions that will be
+/// \param Fns The set of non-member functions that will be
/// considered by overload resolution. The caller needs to build this
/// set based on the context using, e.g.,
/// LookupOverloadedOperatorName() and ArgumentDependentLookup(). This
@@ -10559,7 +10705,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
- if (CheckFunctionCall(Method, TheCall))
+ if (CheckFunctionCall(Method, TheCall, Proto))
return ExprError();
if ((isa<CXXConstructorDecl>(CurContext) ||
@@ -10610,8 +10756,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
if (RequireCompleteType(LParenLoc, Object.get()->getType(),
- PDiag(diag::err_incomplete_object_call)
- << Object.get()->getSourceRange()))
+ diag::err_incomplete_object_call, Object.get()))
return true;
LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName);
@@ -10857,7 +11002,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// If this is a variadic call, handle args passed through "...".
if (Proto->isVariadic()) {
// Promote the arguments (C99 6.5.2.2p7).
- for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
+ for (unsigned i = NumArgsInProto; i < NumArgs; i++) {
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0);
IsError |= Arg.isInvalid();
TheCall->setArg(i + 1, Arg.take());
@@ -10868,7 +11013,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
- if (CheckFunctionCall(Method, TheCall))
+ if (CheckFunctionCall(Method, TheCall, Proto))
return true;
return MaybeBindToTemporary(TheCall);
@@ -10899,8 +11044,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
if (RequireCompleteType(Loc, Base->getType(),
- PDiag(diag::err_typecheck_incomplete_tag)
- << Base->getSourceRange()))
+ diag::err_typecheck_incomplete_tag, Base))
return ExprError();
LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
@@ -11049,7 +11193,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD))
return ExprError();
- if (CheckFunctionCall(FD, UDL))
+ if (CheckFunctionCall(FD, UDL, NULL))
return ExprError();
return MaybeBindToTemporary(UDL);
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index 0e66329..722ac19 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -34,6 +34,7 @@
#include "clang/Sema/Initialization.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace sema;
@@ -232,7 +233,7 @@ namespace {
Expr *op);
bool tryBuildGetOfReference(Expr *op, ExprResult &result);
- bool findSetter();
+ bool findSetter(bool warn=true);
bool findGetter();
Expr *rebuildAndCaptureObject(Expr *syntacticBase);
@@ -505,7 +506,7 @@ bool ObjCPropertyOpBuilder::findGetter() {
/// reference.
///
/// \return true if a setter was found, in which case Setter
-bool ObjCPropertyOpBuilder::findSetter() {
+bool ObjCPropertyOpBuilder::findSetter(bool warn) {
// For implicit properties, just trust the lookup we already did.
if (RefExpr->isImplicitProperty()) {
if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) {
@@ -531,6 +532,23 @@ bool ObjCPropertyOpBuilder::findSetter() {
// Do a normal method lookup first.
if (ObjCMethodDecl *setter =
LookupMethodInReceiverType(S, SetterSelector, RefExpr)) {
+ if (setter->isSynthesized() && warn)
+ if (const ObjCInterfaceDecl *IFace =
+ dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) {
+ const StringRef thisPropertyName(prop->getName());
+ char front = thisPropertyName.front();
+ front = islower(front) ? toupper(front) : tolower(front);
+ SmallString<100> PropertyName = thisPropertyName;
+ PropertyName[0] = front;
+ IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName);
+ if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration(AltMember))
+ if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) {
+ S.Diag(RefExpr->getExprLoc(), diag::error_property_setter_ambiguous_use)
+ << prop->getName() << prop1->getName() << setter->getSelector();
+ S.Diag(prop->getLocation(), diag::note_property_declare);
+ S.Diag(prop1->getLocation(), diag::note_property_declare);
+ }
+ }
Setter = setter;
return true;
}
@@ -603,7 +621,7 @@ ExprResult ObjCPropertyOpBuilder::buildGet() {
/// value being set as the value of the property operation.
ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
bool captureSetValueAsResult) {
- bool hasSetter = findSetter();
+ bool hasSetter = findSetter(false);
assert(hasSetter); (void) hasSetter;
if (SyntacticRefExpr)
@@ -889,8 +907,7 @@ Sema::ObjCSubscriptKind
// We must have a complete class type.
if (RequireCompleteType(FromE->getExprLoc(), T,
- PDiag(diag::err_objc_index_incomplete_class_type)
- << FromE->getSourceRange()))
+ diag::err_objc_index_incomplete_class_type, FromE))
return OS_Error;
// Look for a conversion to an integral, enumeration type, or
@@ -938,6 +955,27 @@ Sema::ObjCSubscriptKind
return OS_Error;
}
+/// CheckKeyForObjCARCConversion - This routine suggests bridge casting of CF
+/// objects used as dictionary subscript key objects.
+static void CheckKeyForObjCARCConversion(Sema &S, QualType ContainerT,
+ Expr *Key) {
+ if (ContainerT.isNull())
+ return;
+ // dictionary subscripting.
+ // - (id)objectForKeyedSubscript:(id)key;
+ IdentifierInfo *KeyIdents[] = {
+ &S.Context.Idents.get("objectForKeyedSubscript")
+ };
+ Selector GetterSelector = S.Context.Selectors.getSelector(1, KeyIdents);
+ ObjCMethodDecl *Getter = S.LookupMethodInObjectType(GetterSelector, ContainerT,
+ true /*instance*/);
+ if (!Getter)
+ return;
+ QualType T = Getter->param_begin()[0]->getType();
+ S.CheckObjCARCConversion(Key->getSourceRange(),
+ T, Key, Sema::CCK_ImplicitConversion);
+}
+
bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
if (AtIndexGetter)
return true;
@@ -955,8 +993,12 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
}
Sema::ObjCSubscriptKind Res =
S.CheckSubscriptingKind(RefExpr->getKeyExpr());
- if (Res == Sema::OS_Error)
+ if (Res == Sema::OS_Error) {
+ if (S.getLangOpts().ObjCAutoRefCount)
+ CheckKeyForObjCARCConversion(S, ResultType,
+ RefExpr->getKeyExpr());
return false;
+ }
bool arrayRef = (Res == Sema::OS_Array);
if (ResultType.isNull()) {
@@ -1063,8 +1105,12 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
Sema::ObjCSubscriptKind Res =
S.CheckSubscriptingKind(RefExpr->getKeyExpr());
- if (Res == Sema::OS_Error)
+ if (Res == Sema::OS_Error) {
+ if (S.getLangOpts().ObjCAutoRefCount)
+ CheckKeyForObjCARCConversion(S, ResultType,
+ RefExpr->getKeyExpr());
return false;
+ }
bool arrayRef = (Res == Sema::OS_Array);
if (ResultType.isNull()) {
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 9052278..d22deb2 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtObjC.h"
@@ -28,7 +29,21 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
using namespace clang;
using namespace sema;
@@ -150,10 +165,11 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (!E)
return;
+ const Expr *WarnExpr;
SourceLocation Loc;
SourceRange R1, R2;
if (SourceMgr.isInSystemMacro(E->getExprLoc()) ||
- !E->isUnusedResultAWarning(Loc, R1, R2, Context))
+ !E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context))
return;
// Okay, we have an unused result. Depending on what the base expression is,
@@ -168,7 +184,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (DiagnoseUnusedComparison(*this, E))
return;
- E = E->IgnoreParenImpCasts();
+ E = WarnExpr;
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
if (E->getType()->isVoidType())
return;
@@ -226,6 +242,11 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
}
+ if (E->isGLValue() && E->getType().isVolatileQualified()) {
+ Diag(Loc, diag::warn_unused_volatile) << R1 << R2;
+ return;
+ }
+
DiagRuntimeBehavior(Loc, 0, PDiag(DiagID) << R1 << R2);
}
@@ -361,12 +382,10 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
}
StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc,
- const AttrVec &Attrs,
+ ArrayRef<const Attr*> Attrs,
Stmt *SubStmt) {
- // Fill in the declaration and return it. Variable length will require to
- // change this to AttributedStmt::Create(Context, ....);
- // and probably using ArrayRef
- AttributedStmt *LS = new (Context) AttributedStmt(AttrLoc, Attrs, SubStmt);
+ // Fill in the declaration and return it.
+ AttributedStmt *LS = AttributedStmt::Create(Context, AttrLoc, Attrs, SubStmt);
return Owned(LS);
}
@@ -519,16 +538,56 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
if (!Cond)
return StmtError();
+ class SwitchConvertDiagnoser : public ICEConvertDiagnoser {
+ Expr *Cond;
+
+ public:
+ SwitchConvertDiagnoser(Expr *Cond)
+ : ICEConvertDiagnoser(false, true), Cond(Cond) { }
+
+ virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T;
+ }
+
+ virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_switch_incomplete_class_type)
+ << T << Cond->getSourceRange();
+ }
+
+ virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
+ QualType T,
+ QualType ConvTy) {
+ return S.Diag(Loc, diag::err_switch_explicit_conversion) << T << ConvTy;
+ }
+
+ virtual DiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv,
+ QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_switch_conversion)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+
+ virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
+ QualType T) {
+ return S.Diag(Loc, diag::err_switch_multiple_conversions) << T;
+ }
+
+ virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
+ QualType ConvTy) {
+ return S.Diag(Conv->getLocation(), diag::note_switch_conversion)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+
+ virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
+ QualType T,
+ QualType ConvTy) {
+ return DiagnosticBuilder::getEmpty();
+ }
+ } SwitchDiagnoser(Cond);
+
CondResult
- = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond,
- PDiag(diag::err_typecheck_statement_requires_integer),
- PDiag(diag::err_switch_incomplete_class_type)
- << Cond->getSourceRange(),
- PDiag(diag::err_switch_explicit_conversion),
- PDiag(diag::note_switch_conversion),
- PDiag(diag::err_switch_multiple_conversions),
- PDiag(diag::note_switch_conversion),
- PDiag(0),
+ = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, SwitchDiagnoser,
/*AllowScopedEnumerations*/ true);
if (CondResult.isInvalid()) return StmtError();
Cond = CondResult.take();
@@ -609,7 +668,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
unsigned CondWidth
= HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion);
- bool CondIsSigned
+ bool CondIsSigned
= CondTypeBeforePromotion->isSignedIntegerOrEnumerationType();
// Accumulate all of the case values in a vector so that we can sort them
@@ -726,8 +785,30 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
if (i != 0 && CaseVals[i].first == CaseVals[i-1].first) {
// If we have a duplicate, report it.
- Diag(CaseVals[i].second->getLHS()->getLocStart(),
- diag::err_duplicate_case) << CaseVals[i].first.toString(10);
+ // First, determine if either case value has a name
+ StringRef PrevString, CurrString;
+ Expr *PrevCase = CaseVals[i-1].second->getLHS()->IgnoreParenCasts();
+ Expr *CurrCase = CaseVals[i].second->getLHS()->IgnoreParenCasts();
+ if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(PrevCase)) {
+ PrevString = DeclRef->getDecl()->getName();
+ }
+ if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(CurrCase)) {
+ CurrString = DeclRef->getDecl()->getName();
+ }
+ llvm::SmallString<16> CaseValStr;
+ CaseVals[i-1].first.toString(CaseValStr);
+
+ if (PrevString == CurrString)
+ Diag(CaseVals[i].second->getLHS()->getLocStart(),
+ diag::err_duplicate_case) <<
+ (PrevString.empty() ? CaseValStr.str() : PrevString);
+ else
+ Diag(CaseVals[i].second->getLHS()->getLocStart(),
+ diag::err_duplicate_case_differing_expr) <<
+ (PrevString.empty() ? CaseValStr.str() : PrevString) <<
+ (CurrString.empty() ? CaseValStr.str() : CurrString) <<
+ CaseValStr;
+
Diag(CaseVals[i-1].second->getLHS()->getLocStart(),
diag::note_duplicate_case_prev);
// FIXME: We really want to remove the bogus case stmt from the
@@ -904,7 +985,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
<< CondTypeBeforePromotion;
}
- llvm::APSInt Hi =
+ llvm::APSInt Hi =
RI->second->getRHS()->EvaluateKnownConstInt(Context);
AdjustAPSInt(Hi, CondWidth, CondIsSigned);
while (EI != EIend && EI->first < Hi)
@@ -952,12 +1033,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
switch (UnhandledNames.size()) {
case 0: break;
case 1:
- Diag(CondExpr->getExprLoc(), TheDefaultStmt
+ Diag(CondExpr->getExprLoc(), TheDefaultStmt
? diag::warn_def_missing_case1 : diag::warn_missing_case1)
<< UnhandledNames[0];
break;
case 2:
- Diag(CondExpr->getExprLoc(), TheDefaultStmt
+ Diag(CondExpr->getExprLoc(), TheDefaultStmt
? diag::warn_def_missing_case2 : diag::warn_missing_case2)
<< UnhandledNames[0] << UnhandledNames[1];
break;
@@ -990,6 +1071,55 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
return Owned(SS);
}
+void
+Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
+ Expr *SrcExpr) {
+ unsigned DIAG = diag::warn_not_in_enum_assignement;
+ if (Diags.getDiagnosticLevel(DIAG, SrcExpr->getExprLoc())
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ if (const EnumType *ET = DstType->getAs<EnumType>())
+ if (!Context.hasSameType(SrcType, DstType) &&
+ SrcType->isIntegerType()) {
+ if (!SrcExpr->isTypeDependent() && !SrcExpr->isValueDependent() &&
+ SrcExpr->isIntegerConstantExpr(Context)) {
+ // Get the bitwidth of the enum value before promotions.
+ unsigned DstWith = Context.getIntWidth(DstType);
+ bool DstIsSigned = DstType->isSignedIntegerOrEnumerationType();
+
+ llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context);
+ const EnumDecl *ED = ET->getDecl();
+ typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64>
+ EnumValsTy;
+ EnumValsTy EnumVals;
+
+ // Gather all enum values, set their type and sort them,
+ // allowing easier comparison with rhs constant.
+ for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
+ EDI != ED->enumerator_end(); ++EDI) {
+ llvm::APSInt Val = EDI->getInitVal();
+ AdjustAPSInt(Val, DstWith, DstIsSigned);
+ EnumVals.push_back(std::make_pair(Val, *EDI));
+ }
+ if (EnumVals.empty())
+ return;
+ std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
+ EnumValsTy::iterator EIend =
+ std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
+
+ // See which case values aren't in enum.
+ EnumValsTy::const_iterator EI = EnumVals.begin();
+ while (EI != EIend && EI->first < RhsVal)
+ EI++;
+ if (EI == EIend || EI->first != RhsVal) {
+ Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignement)
+ << DstType;
+ }
+ }
+ }
+}
+
StmtResult
Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
Decl *CondVar, Stmt *Body) {
@@ -1037,6 +1167,215 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
return Owned(new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen));
}
+namespace {
+ // This visitor will traverse a conditional statement and store all
+ // the evaluated decls into a vector. Simple is set to true if none
+ // of the excluded constructs are used.
+ class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> {
+ llvm::SmallPtrSet<VarDecl*, 8> &Decls;
+ llvm::SmallVector<SourceRange, 10> &Ranges;
+ bool Simple;
+public:
+ typedef EvaluatedExprVisitor<DeclExtractor> Inherited;
+
+ DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls,
+ llvm::SmallVector<SourceRange, 10> &Ranges) :
+ Inherited(S.Context),
+ Decls(Decls),
+ Ranges(Ranges),
+ Simple(true) {}
+
+ bool isSimple() { return Simple; }
+
+ // Replaces the method in EvaluatedExprVisitor.
+ void VisitMemberExpr(MemberExpr* E) {
+ Simple = false;
+ }
+
+ // Any Stmt not whitelisted will cause the condition to be marked complex.
+ void VisitStmt(Stmt *S) {
+ Simple = false;
+ }
+
+ void VisitBinaryOperator(BinaryOperator *E) {
+ Visit(E->getLHS());
+ Visit(E->getRHS());
+ }
+
+ void VisitCastExpr(CastExpr *E) {
+ Visit(E->getSubExpr());
+ }
+
+ void VisitUnaryOperator(UnaryOperator *E) {
+ // Skip checking conditionals with derefernces.
+ if (E->getOpcode() == UO_Deref)
+ Simple = false;
+ else
+ Visit(E->getSubExpr());
+ }
+
+ void VisitConditionalOperator(ConditionalOperator *E) {
+ Visit(E->getCond());
+ Visit(E->getTrueExpr());
+ Visit(E->getFalseExpr());
+ }
+
+ void VisitParenExpr(ParenExpr *E) {
+ Visit(E->getSubExpr());
+ }
+
+ void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
+ Visit(E->getOpaqueValue()->getSourceExpr());
+ Visit(E->getFalseExpr());
+ }
+
+ void VisitIntegerLiteral(IntegerLiteral *E) { }
+ void VisitFloatingLiteral(FloatingLiteral *E) { }
+ void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { }
+ void VisitCharacterLiteral(CharacterLiteral *E) { }
+ void VisitGNUNullExpr(GNUNullExpr *E) { }
+ void VisitImaginaryLiteral(ImaginaryLiteral *E) { }
+
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
+ if (!VD) return;
+
+ Ranges.push_back(E->getSourceRange());
+
+ Decls.insert(VD);
+ }
+
+ }; // end class DeclExtractor
+
+ // DeclMatcher checks to see if the decls are used in a non-evauluated
+ // context.
+ class DeclMatcher : public EvaluatedExprVisitor<DeclMatcher> {
+ llvm::SmallPtrSet<VarDecl*, 8> &Decls;
+ bool FoundDecl;
+
+public:
+ typedef EvaluatedExprVisitor<DeclMatcher> Inherited;
+
+ DeclMatcher(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, Stmt *Statement) :
+ Inherited(S.Context), Decls(Decls), FoundDecl(false) {
+ if (!Statement) return;
+
+ Visit(Statement);
+ }
+
+ void VisitReturnStmt(ReturnStmt *S) {
+ FoundDecl = true;
+ }
+
+ void VisitBreakStmt(BreakStmt *S) {
+ FoundDecl = true;
+ }
+
+ void VisitGotoStmt(GotoStmt *S) {
+ FoundDecl = true;
+ }
+
+ void VisitCastExpr(CastExpr *E) {
+ if (E->getCastKind() == CK_LValueToRValue)
+ CheckLValueToRValueCast(E->getSubExpr());
+ else
+ Visit(E->getSubExpr());
+ }
+
+ void CheckLValueToRValueCast(Expr *E) {
+ E = E->IgnoreParenImpCasts();
+
+ if (isa<DeclRefExpr>(E)) {
+ return;
+ }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ Visit(CO->getCond());
+ CheckLValueToRValueCast(CO->getTrueExpr());
+ CheckLValueToRValueCast(CO->getFalseExpr());
+ return;
+ }
+
+ if (BinaryConditionalOperator *BCO =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ CheckLValueToRValueCast(BCO->getOpaqueValue()->getSourceExpr());
+ CheckLValueToRValueCast(BCO->getFalseExpr());
+ return;
+ }
+
+ Visit(E);
+ }
+
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
+ if (Decls.count(VD))
+ FoundDecl = true;
+ }
+
+ bool FoundDeclInUse() { return FoundDecl; }
+
+ }; // end class DeclMatcher
+
+ void CheckForLoopConditionalStatement(Sema &S, Expr *Second,
+ Expr *Third, Stmt *Body) {
+ // Condition is empty
+ if (!Second) return;
+
+ if (S.Diags.getDiagnosticLevel(diag::warn_variables_not_in_loop_body,
+ Second->getLocStart())
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ PartialDiagnostic PDiag = S.PDiag(diag::warn_variables_not_in_loop_body);
+ llvm::SmallPtrSet<VarDecl*, 8> Decls;
+ llvm::SmallVector<SourceRange, 10> Ranges;
+ DeclExtractor DE(S, Decls, Ranges);
+ DE.Visit(Second);
+
+ // Don't analyze complex conditionals.
+ if (!DE.isSimple()) return;
+
+ // No decls found.
+ if (Decls.size() == 0) return;
+
+ // Don't warn on volatile, static, or global variables.
+ for (llvm::SmallPtrSet<VarDecl*, 8>::iterator I = Decls.begin(),
+ E = Decls.end();
+ I != E; ++I)
+ if ((*I)->getType().isVolatileQualified() ||
+ (*I)->hasGlobalStorage()) return;
+
+ if (DeclMatcher(S, Decls, Second).FoundDeclInUse() ||
+ DeclMatcher(S, Decls, Third).FoundDeclInUse() ||
+ DeclMatcher(S, Decls, Body).FoundDeclInUse())
+ return;
+
+ // Load decl names into diagnostic.
+ if (Decls.size() > 4)
+ PDiag << 0;
+ else {
+ PDiag << Decls.size();
+ for (llvm::SmallPtrSet<VarDecl*, 8>::iterator I = Decls.begin(),
+ E = Decls.end();
+ I != E; ++I)
+ PDiag << (*I)->getDeclName();
+ }
+
+ // Load SourceRanges into diagnostic if there is room.
+ // Otherwise, load the SourceRange of the conditional expression.
+ if (Ranges.size() <= PartialDiagnostic::MaxArguments)
+ for (llvm::SmallVector<SourceRange, 10>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ PDiag << *I;
+ else
+ PDiag << Second->getSourceRange();
+
+ S.Diag(Ranges.begin()->getBegin(), PDiag);
+ }
+
+} // end namespace
+
StmtResult
Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
Stmt *First, FullExprArg second, Decl *secondVar,
@@ -1059,6 +1398,8 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
}
}
+ CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body);
+
ExprResult SecondResult(second.release());
VarDecl *ConditionVar = 0;
if (secondVar) {
@@ -1103,8 +1444,9 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) {
}
ExprResult
-Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
- assert(collection);
+Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
+ if (!collection)
+ return ExprError();
// Bail out early if we've got a type-dependent expression.
if (collection->isTypeDependent()) return Owned(collection);
@@ -1130,12 +1472,12 @@ Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
// If we have a forward-declared type, we can't do this check.
// Under ARC, it is an error not to have a forward-declared class.
- if (iface &&
+ if (iface &&
RequireCompleteType(forLoc, QualType(objectType, 0),
getLangOpts().ObjCAutoRefCount
- ? PDiag(diag::err_arc_collection_forward)
- << collection->getSourceRange()
- : PDiag(0))) {
+ ? diag::err_arc_collection_forward
+ : 0,
+ collection)) {
// Otherwise, if we have any useful type information, check that
// the type declares the appropriate method.
} else if (iface || !objectType->qual_empty()) {
@@ -1151,7 +1493,7 @@ Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
// If there's an interface, look in both the public and private APIs.
if (iface) {
method = iface->lookupInstanceMethod(selector);
- if (!method) method = LookupPrivateInstanceMethod(selector, iface);
+ if (!method) method = iface->lookupPrivateMethod(selector);
}
// Also check protocol qualifiers.
@@ -1175,8 +1517,12 @@ Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
StmtResult
Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
SourceLocation LParenLoc,
- Stmt *First, Expr *Second,
- SourceLocation RParenLoc, Stmt *Body) {
+ Stmt *First, Expr *collection,
+ SourceLocation RParenLoc) {
+
+ ExprResult CollectionExprResult =
+ CheckObjCForCollectionOperand(ForLoc, collection);
+
if (First) {
QualType FirstType;
if (DeclStmt *DS = dyn_cast<DeclStmt>(First)) {
@@ -1204,11 +1550,15 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
if (!FirstType->isDependentType() &&
!FirstType->isObjCObjectPointerType() &&
!FirstType->isBlockPointerType())
- Diag(ForLoc, diag::err_selector_element_type)
- << FirstType << First->getSourceRange();
+ return StmtError(Diag(ForLoc, diag::err_selector_element_type)
+ << FirstType << First->getSourceRange());
}
- return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body,
+ if (CollectionExprResult.isInvalid())
+ return StmtError();
+
+ return Owned(new (Context) ObjCForCollectionStmt(First,
+ CollectionExprResult.take(), 0,
ForLoc, RParenLoc));
}
@@ -1252,7 +1602,7 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
// In ARC, infer lifetime.
// FIXME: ARC may want to turn this into 'const __unsafe_unretained' if
// we're doing the equivalent of fast iteration.
- if (SemaRef.getLangOpts().ObjCAutoRefCount &&
+ if (SemaRef.getLangOpts().ObjCAutoRefCount &&
SemaRef.inferObjCARCLifetime(Decl))
Decl->setInvalidDecl();
@@ -1343,6 +1693,11 @@ static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S,
}
+static bool ObjCEnumerationCollection(Expr *Collection) {
+ return !Collection->isTypeDependent()
+ && Collection->getType()->getAs<ObjCObjectPointerType>() != 0;
+}
+
/// ActOnCXXForRangeStmt - Check and build a C++0x for-range statement.
///
/// C++0x [stmt.ranged]:
@@ -1368,6 +1723,10 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
if (!First || !Range)
return StmtError();
+ if (ObjCEnumerationCollection(Range))
+ return ActOnObjCForCollectionStmt(ForLoc, LParenLoc, First, Range,
+ RParenLoc);
+
DeclStmt *DS = dyn_cast<DeclStmt>(First);
assert(DS && "first part of for range not a decl stmt");
@@ -1442,7 +1801,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
QualType RangeType = Range->getType();
if (RequireCompleteType(RangeLoc, RangeType,
- PDiag(diag::err_for_range_incomplete_type)))
+ diag::err_for_range_incomplete_type))
return StmtError();
// Build auto __begin = begin-expr, __end = end-expr.
@@ -1618,6 +1977,17 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
ColonLoc, RParenLoc));
}
+/// FinishObjCForCollectionStmt - Attach the body to a objective-C foreach
+/// statement.
+StmtResult Sema::FinishObjCForCollectionStmt(Stmt *S, Stmt *B) {
+ if (!S || !B)
+ return StmtError();
+ ObjCForCollectionStmt * ForStmt = cast<ObjCForCollectionStmt>(S);
+
+ ForStmt->setBody(B);
+ return S;
+}
+
/// FinishCXXForRangeStmt - Attach the body to a C++0x for-range statement.
/// This is a separate step from ActOnCXXForRangeStmt because analysis of the
/// body cannot be performed until after the type of the range variable is
@@ -1626,6 +1996,9 @@ StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B) {
if (!S || !B)
return StmtError();
+ if (isa<ObjCForCollectionStmt>(S))
+ return FinishObjCForCollectionStmt(S, B);
+
CXXForRangeStmt *ForStmt = cast<CXXForRangeStmt>(S);
ForStmt->setBody(B);
@@ -1723,7 +2096,7 @@ const VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType,
// ... the expression is the name of a non-volatile automatic object
// (other than a function or catch-clause parameter)) ...
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens());
- if (!DR)
+ if (!DR || DR->refersToEnclosingLocal())
return 0;
const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
if (!VD)
@@ -1776,8 +2149,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
if (AllowNRVO &&
(NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true))) {
ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack,
- Value->getType(), CK_LValueToRValue,
- Value, VK_XValue);
+ Value->getType(), CK_NoOp, Value, VK_XValue);
Expr *InitExpr = &AsRvalue;
InitializationKind Kind
@@ -1812,8 +2184,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
// Promote "AsRvalue" to the heap, since we now need this
// expression node to persist.
Value = ImplicitCastExpr::Create(Context, Value->getType(),
- CK_LValueToRValue, Value, 0,
- VK_XValue);
+ CK_NoOp, Value, 0, VK_XValue);
// Complete type-checking the initialization of the return type
// using the constructor we found.
@@ -1840,8 +2211,12 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// [expr.prim.lambda]p4 in C++11; block literals follow a superset of those
// rules which allows multiple return statements.
CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction());
+ QualType FnRetType = CurCap->ReturnType;
+
+ // For blocks/lambdas with implicit return types, we check each return
+ // statement individually, and deduce the common return type when the block
+ // or lambda is completed.
if (CurCap->HasImplicitReturnType) {
- QualType ReturnT;
if (RetValExp && !isa<InitListExpr>(RetValExp)) {
ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
if (Result.isInvalid())
@@ -1849,10 +2224,10 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
RetValExp = Result.take();
if (!RetValExp->isTypeDependent())
- ReturnT = RetValExp->getType();
+ FnRetType = RetValExp->getType();
else
- ReturnT = Context.DependentTy;
- } else {
+ FnRetType = CurCap->ReturnType = Context.DependentTy;
+ } else {
if (RetValExp) {
// C++11 [expr.lambda.prim]p4 bans inferring the result from an
// initializer list, because it is not an expression (even
@@ -1861,21 +2236,14 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
<< RetValExp->getSourceRange();
}
- ReturnT = Context.VoidTy;
- }
- // We require the return types to strictly match here.
- if (!CurCap->ReturnType.isNull() &&
- !CurCap->ReturnType->isDependentType() &&
- !ReturnT->isDependentType() &&
- !Context.hasSameType(ReturnT, CurCap->ReturnType)) {
- Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
- << ReturnT << CurCap->ReturnType
- << (getCurLambda() != 0);
- return StmtError();
+ FnRetType = Context.VoidTy;
}
- CurCap->ReturnType = ReturnT;
+
+ // Although we'll properly infer the type of the block once it's completed,
+ // make sure we provide a return type now for better error recovery.
+ if (CurCap->ReturnType.isNull())
+ CurCap->ReturnType = FnRetType;
}
- QualType FnRetType = CurCap->ReturnType;
assert(!FnRetType.isNull());
if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) {
@@ -1943,10 +2311,12 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp,
NRVOCandidate);
- // If we need to check for the named return value optimization, save the
- // return statement in our scope for later processing.
- if (getLangOpts().CPlusPlus && FnRetType->isRecordType() &&
- !CurContext->isDependentContext())
+ // If we need to check for the named return value optimization,
+ // or if we need to infer the return type,
+ // save the return statement in our scope for later processing.
+ if (CurCap->HasImplicitReturnType ||
+ (getLangOpts().CPlusPlus && FnRetType->isRecordType() &&
+ !CurContext->isDependentContext()))
FunctionScopes.back()->Returns.push_back(Result);
return Owned(Result);
@@ -1957,7 +2327,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// Check for unexpanded parameter packs.
if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
return StmtError();
-
+
if (isa<CapturingScopeInfo>(getCurFunction()))
return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp);
@@ -1973,7 +2343,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
FnRetType = MD->getResultType();
if (MD->hasRelatedResultType() && MD->getClassInterface()) {
// In the implementation of a method with a related return type, the
- // type used to type-check the validity of return statements within the
+ // type used to type-check the validity of return statements within the
// method body is a pointer to the type of the class being implemented.
RelatedRetType = Context.getObjCInterfaceType(MD->getClassInterface());
RelatedRetType = Context.getObjCObjectPointerType(RelatedRetType);
@@ -2064,7 +2434,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// FIXME: The diagnostics here don't really describe what is happening.
InitializedEntity Entity =
InitializedEntity::InitializeTemporary(RelatedRetType);
-
+
ExprResult Res = PerformCopyInitialization(Entity, SourceLocation(),
RetValExp);
if (Res.isInvalid()) {
@@ -2108,7 +2478,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (getLangOpts().CPlusPlus && FnRetType->isRecordType() &&
!CurContext->isDependentContext())
FunctionScopes.back()->Returns.push_back(Result);
-
+
return Owned(Result);
}
@@ -2147,18 +2517,17 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) {
/// isOperandMentioned - Return true if the specified operand # is mentioned
/// anywhere in the decomposed asm string.
-static bool isOperandMentioned(unsigned OpNo,
+static bool isOperandMentioned(unsigned OpNo,
ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) {
for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
if (!Piece.isOperand()) continue;
-
+
// If this is a reference to the input and if the input was the smaller
// one, then we have to reject this asm.
if (Piece.getOperandNo() == OpNo)
return true;
}
-
return false;
}
@@ -2343,7 +2712,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// then we can promote the smaller one to a larger input and the asm string
// won't notice.
bool SmallerValueMentioned = false;
-
+
// If this is a reference to the input and if the input was the smaller
// one, then we have to reject this asm.
if (isOperandMentioned(InputOpNo, Pieces)) {
@@ -2364,7 +2733,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (!SmallerValueMentioned && InputDomain != AD_Other &&
OutputConstraintInfos[TiedTo].allowsRegister())
continue;
-
+
// Either both of the operands were mentioned or the smaller one was
// mentioned. One more special case that we'll allow: if the tied input is
// integer, unmentioned, and is a constant, then we'll allow truncating it
@@ -2379,7 +2748,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
NS->setInputExpr(i, InputExpr);
continue;
}
-
+
Diag(InputExpr->getLocStart(),
diag::err_asm_tying_incompatible_types)
<< InTy << OutTy << OutputExpr->getSourceRange()
@@ -2390,6 +2759,213 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return Owned(NS);
}
+// needSpaceAsmToken - This function handles whitespace around asm punctuation.
+// Returns true if a space should be emitted.
+static inline bool needSpaceAsmToken(Token currTok) {
+ static Token prevTok;
+
+ // No need for space after prevToken.
+ switch(prevTok.getKind()) {
+ default:
+ break;
+ case tok::l_square:
+ case tok::r_square:
+ case tok::l_brace:
+ case tok::r_brace:
+ case tok::colon:
+ prevTok = currTok;
+ return false;
+ }
+
+ // No need for a space before currToken.
+ switch(currTok.getKind()) {
+ default:
+ break;
+ case tok::l_square:
+ case tok::r_square:
+ case tok::l_brace:
+ case tok::r_brace:
+ case tok::comma:
+ case tok::colon:
+ prevTok = currTok;
+ return false;
+ }
+ prevTok = currTok;
+ return true;
+}
+
+static void patchMSAsmStrings(Sema &SemaRef, bool &IsSimple,
+ SourceLocation AsmLoc,
+ ArrayRef<Token> AsmToks,
+ ArrayRef<unsigned> LineEnds,
+ const TargetInfo &TI,
+ std::vector<std::string> &AsmStrings) {
+ assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
+
+ // Assume simple asm stmt until we parse a non-register identifer.
+ IsSimple = true;
+
+ for (unsigned i = 0, e = LineEnds.size(); i != e; ++i) {
+ SmallString<512> Asm;
+
+ // Check the operands.
+ for (unsigned j = (i == 0) ? 0 : LineEnds[i-1], e = LineEnds[i]; j != e; ++j) {
+
+ IdentifierInfo *II;
+ if (j == 0 || (i > 0 && j == LineEnds[i-1])) {
+ II = AsmToks[j].getIdentifierInfo();
+ Asm = II->getName().str();
+ continue;
+ }
+
+ if (needSpaceAsmToken(AsmToks[j]))
+ Asm += " ";
+
+ switch (AsmToks[j].getKind()) {
+ default:
+ //llvm_unreachable("Unknown token.");
+ break;
+ case tok::comma: Asm += ","; break;
+ case tok::colon: Asm += ":"; break;
+ case tok::l_square: Asm += "["; break;
+ case tok::r_square: Asm += "]"; break;
+ case tok::l_brace: Asm += "{"; break;
+ case tok::r_brace: Asm += "}"; break;
+ case tok::numeric_constant: {
+ SmallString<32> TokenBuf;
+ TokenBuf.resize(32);
+ bool StringInvalid = false;
+ Asm += SemaRef.PP.getSpelling(AsmToks[j], TokenBuf, &StringInvalid);
+ assert (!StringInvalid && "Expected valid string!");
+ break;
+ }
+ case tok::identifier: {
+ II = AsmToks[j].getIdentifierInfo();
+ StringRef Name = II->getName();
+
+ // Valid registers don't need modification.
+ if (TI.isValidGCCRegisterName(Name)) {
+ Asm += Name;
+ break;
+ }
+
+ // TODO: Lookup the identifier.
+ IsSimple = false;
+ }
+ } // AsmToks[i].getKind()
+ }
+ AsmStrings[i] = Asm.c_str();
+ }
+}
+
+// Build the unmodified MSAsmString.
+static std::string buildMSAsmString(Sema &SemaRef,
+ ArrayRef<Token> AsmToks,
+ ArrayRef<unsigned> LineEnds) {
+ assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
+ SmallString<512> Asm;
+ SmallString<512> TokenBuf;
+ TokenBuf.resize(512);
+ unsigned AsmLineNum = 0;
+ for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
+ const char *ThisTokBuf = &TokenBuf[0];
+ bool StringInvalid = false;
+ unsigned ThisTokLen =
+ Lexer::getSpelling(AsmToks[i], ThisTokBuf, SemaRef.getSourceManager(),
+ SemaRef.getLangOpts(), &StringInvalid);
+ if (i && (!AsmLineNum || i != LineEnds[AsmLineNum-1]) &&
+ needSpaceAsmToken(AsmToks[i]))
+ Asm += ' ';
+ Asm += StringRef(ThisTokBuf, ThisTokLen);
+ if (i + 1 == LineEnds[AsmLineNum] && i + 1 != AsmToks.size()) {
+ Asm += '\n';
+ ++AsmLineNum;
+ }
+ }
+ return Asm.c_str();
+}
+
+StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc,
+ ArrayRef<Token> AsmToks,
+ ArrayRef<unsigned> LineEnds,
+ SourceLocation EndLoc) {
+ // MS-style inline assembly is not fully supported, so emit a warning.
+ Diag(AsmLoc, diag::warn_unsupported_msasm);
+ SmallVector<StringRef,4> Clobbers;
+
+ // Empty asm statements don't need to instantiate the AsmParser, etc.
+ if (AsmToks.empty()) {
+ StringRef AsmString;
+ MSAsmStmt *NS =
+ new (Context) MSAsmStmt(Context, AsmLoc, /* IsSimple */ true,
+ /* IsVolatile */ true, AsmToks, LineEnds,
+ AsmString, Clobbers, EndLoc);
+ return Owned(NS);
+ }
+
+ std::string AsmString = buildMSAsmString(*this, AsmToks, LineEnds);
+
+ bool IsSimple;
+ std::vector<std::string> PatchedAsmStrings;
+ PatchedAsmStrings.resize(LineEnds.size());
+
+ // Rewrite operands to appease the AsmParser.
+ patchMSAsmStrings(*this, IsSimple, AsmLoc, AsmToks, LineEnds,
+ Context.getTargetInfo(), PatchedAsmStrings);
+
+ // patchMSAsmStrings doesn't correctly patch non-simple asm statements.
+ if (!IsSimple) {
+ MSAsmStmt *NS =
+ new (Context) MSAsmStmt(Context, AsmLoc, /* IsSimple */ true,
+ /* IsVolatile */ true, AsmToks, LineEnds,
+ AsmString, Clobbers, EndLoc);
+ return Owned(NS);
+ }
+
+ // Initialize targets and assembly printers/parsers.
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+
+ // Get the target specific parser.
+ std::string Error;
+ const std::string &TT = Context.getTargetInfo().getTriple().getTriple();
+ const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error));
+
+ OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT));
+ OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
+ OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
+ OwningPtr<llvm::MCSubtargetInfo>
+ STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
+
+ for (unsigned i = 0, e = PatchedAsmStrings.size(); i != e; ++i) {
+ llvm::SourceMgr SrcMgr;
+ llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
+ llvm::MemoryBuffer *Buffer =
+ llvm::MemoryBuffer::getMemBuffer(PatchedAsmStrings[i], "<inline asm>");
+
+ // Tell SrcMgr about this buffer, which is what the parser will pick up.
+ SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
+
+ OwningPtr<llvm::MCStreamer> Str;
+ OwningPtr<llvm::MCAsmParser>
+ Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
+ OwningPtr<llvm::MCTargetAsmParser>
+ TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
+ // Change to the Intel dialect.
+ Parser->setAssemblerDialect(1);
+ Parser->setTargetParser(*TargetParser.get());
+
+ // TODO: Start parsing.
+ }
+
+ MSAsmStmt *NS =
+ new (Context) MSAsmStmt(Context, AsmLoc, IsSimple, /* IsVolatile */ true,
+ AsmToks, LineEnds, AsmString, Clobbers, EndLoc);
+
+ return Owned(NS);
+}
+
StmtResult
Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen, Decl *Parm,
@@ -2420,15 +2996,13 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try,
Finally));
}
-StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc,
- Expr *Throw) {
+StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) {
if (Throw) {
- Throw = MaybeCreateExprWithCleanups(Throw);
ExprResult Result = DefaultLvalueConversion(Throw);
if (Result.isInvalid())
return StmtError();
- Throw = Result.take();
+ Throw = MaybeCreateExprWithCleanups(Result.take());
QualType ThrowType = Throw->getType();
// Make sure the expression type is an ObjC pointer or "void *".
if (!ThrowType->isDependentType() &&
@@ -2458,7 +3032,6 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw,
if (!AtCatchParent)
return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch));
}
-
return BuildObjCAtThrowStmt(AtLoc, Throw);
}
@@ -2646,17 +3219,17 @@ StmtResult Sema::BuildMSDependentExistsStmt(SourceLocation KeywordLoc,
Stmt *Nested)
{
return new (Context) MSDependentExistsStmt(KeywordLoc, IsIfExists,
- QualifierLoc, NameInfo,
+ QualifierLoc, NameInfo,
cast<CompoundStmt>(Nested));
}
-StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc,
+StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc,
bool IsIfExists,
- CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
Stmt *Nested) {
- return BuildMSDependentExistsStmt(KeywordLoc, IsIfExists,
+ return BuildMSDependentExistsStmt(KeywordLoc, IsIfExists,
SS.getWithLocInContext(Context),
GetNameFromUnqualifiedId(Name),
Nested);
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index 21c3297..3c15b7a 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -15,29 +15,55 @@
#include "TargetAttributesSema.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/StringExtras.h"
+
using namespace clang;
using namespace sema;
+static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
+ SourceRange Range) {
+ if (!isa<NullStmt>(St)) {
+ S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
+ << St->getLocStart();
+ if (isa<SwitchCase>(St)) {
+ SourceLocation L = Lexer::getLocForEndOfToken(Range.getEnd(), 0,
+ S.getSourceManager(), S.getLangOpts());
+ S.Diag(L, diag::note_fallthrough_insert_semi_fixit)
+ << FixItHint::CreateInsertion(L, ";");
+ }
+ return 0;
+ }
+ if (S.getCurFunction()->SwitchStack.empty()) {
+ S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
+ return 0;
+ }
+ return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context);
+}
+
-static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A) {
+static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
+ SourceRange Range) {
switch (A.getKind()) {
+ case AttributeList::AT_FallThrough:
+ return handleFallThroughAttr(S, St, A, Range);
default:
// if we're here, then we parsed an attribute, but didn't recognize it as a
// statement attribute => it is declaration attribute
- S.Diag(A.getRange().getBegin(), diag::warn_attribute_invalid_on_stmt) <<
- A.getName()->getName();
+ S.Diag(A.getRange().getBegin(), diag::warn_attribute_invalid_on_stmt)
+ << A.getName()->getName() << St->getLocStart();
return 0;
}
}
StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList,
SourceRange Range) {
- AttrVec Attrs;
+ SmallVector<const Attr*, 8> Attrs;
for (const AttributeList* l = AttrList; l; l = l->getNext()) {
- if (Attr *a = ProcessStmtAttribute(*this, S, *l))
+ if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
Attrs.push_back(a);
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 51ce2a1..c8e4501 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -354,12 +354,14 @@ void Sema::LookupTemplateName(LookupResult &Found,
return;
}
- if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope) {
- // C++ [basic.lookup.classref]p1:
+ if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope &&
+ !(getLangOpts().CPlusPlus0x && !Found.empty())) {
+ // C++03 [basic.lookup.classref]p1:
// [...] If the lookup in the class of the object expression finds a
// template, the name is also looked up in the context of the entire
// postfix-expression and [...]
//
+ // Note: C++11 does not perform this second lookup.
LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(),
LookupOrdinaryName);
LookupName(FoundOuter, S);
@@ -743,7 +745,7 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
}
/// ActOnTemplateTemplateParameter - Called when a C++ template template
-/// parameter (e.g. T in template <template <typename> class T> class array)
+/// parameter (e.g. T in template <template \<typename> class T> class array)
/// has been parsed. S is the current scope.
Decl *Sema::ActOnTemplateTemplateParameter(Scope* S,
SourceLocation TmpLoc,
@@ -865,9 +867,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
return true;
}
- // Find any previous declaration with this name.
+ // Find any previous declaration with this name. For a friend with no
+ // scope explicitly specified, we only look for tag declarations (per
+ // C++11 [basic.lookup.elab]p2).
DeclContext *SemanticContext;
- LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName,
+ LookupResult Previous(*this, Name, NameLoc,
+ (SS.isEmpty() && TUK == TUK_Friend)
+ ? LookupTagName : LookupOrdinaryName,
ForRedeclaration);
if (SS.isNotEmpty() && !SS.isInvalid()) {
SemanticContext = computeDeclContext(SS, true);
@@ -893,7 +899,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
Invalid = true;
} else if (TUK != TUK_Friend && TUK != TUK_Reference)
diagnoseQualifiedDeclaration(SS, SemanticContext, Name, NameLoc);
-
+
LookupQualifiedName(Previous, SemanticContext);
} else {
SemanticContext = CurContext;
@@ -948,22 +954,32 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// declaration.
PrevDecl = PrevClassTemplate = 0;
SemanticContext = OutermostContext;
- }
- }
- if (CurContext->isDependentContext()) {
- // If this is a dependent context, we don't want to link the friend
- // class template to the template in scope, because that would perform
- // checking of the template parameter lists that can't be performed
- // until the outer context is instantiated.
- PrevDecl = PrevClassTemplate = 0;
+ // Check that the chosen semantic context doesn't already contain a
+ // declaration of this name as a non-tag type.
+ LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName,
+ ForRedeclaration);
+ DeclContext *LookupContext = SemanticContext;
+ while (LookupContext->isTransparentContext())
+ LookupContext = LookupContext->getLookupParent();
+ LookupQualifiedName(Previous, LookupContext);
+
+ if (Previous.isAmbiguous())
+ return true;
+
+ if (Previous.begin() != Previous.end())
+ PrevDecl = (*Previous.begin())->getUnderlyingDecl();
+ }
}
} else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
PrevDecl = PrevClassTemplate = 0;
if (PrevClassTemplate) {
- // Ensure that the template parameter lists are compatible.
- if (!TemplateParameterListsAreEqual(TemplateParams,
+ // Ensure that the template parameter lists are compatible. Skip this check
+ // for a friend in a dependent context: the template parameter list itself
+ // could be dependent.
+ if (!(TUK == TUK_Friend && CurContext->isDependentContext()) &&
+ !TemplateParameterListsAreEqual(TemplateParams,
PrevClassTemplate->getTemplateParameters(),
/*Complain=*/true,
TPL_TemplateMatch))
@@ -1012,8 +1028,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Check the template parameter list of this declaration, possibly
// merging in the template parameter list from the previous class
- // template declaration.
- if (CheckTemplateParameterList(TemplateParams,
+ // template declaration. Skip this check for a friend in a dependent
+ // context, because the template parameter list might be dependent.
+ if (!(TUK == TUK_Friend && CurContext->isDependentContext()) &&
+ CheckTemplateParameterList(TemplateParams,
PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0,
(SS.isSet() && SemanticContext &&
SemanticContext->isRecord() &&
@@ -1025,9 +1043,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (SS.isSet()) {
// If the name of the template was qualified, we must be defining the
// template out-of-line.
- if (!SS.isInvalid() && !Invalid && !PrevClassTemplate &&
- !(TUK == TUK_Friend && CurContext->isDependentContext())) {
- Diag(NameLoc, diag::err_member_def_does_not_match)
+ if (!SS.isInvalid() && !Invalid && !PrevClassTemplate) {
+ Diag(NameLoc, TUK == TUK_Friend ? diag::err_friend_decl_does_not_match
+ : diag::err_member_def_does_not_match)
<< Name << SemanticContext << SS.getRange();
Invalid = true;
}
@@ -1046,8 +1064,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
- AddAlignmentAttributesForRecord(NewClass);
- AddMsStructLayoutForRecord(NewClass);
+ if (TUK == TUK_Definition) {
+ AddAlignmentAttributesForRecord(NewClass);
+ AddMsStructLayoutForRecord(NewClass);
+ }
ClassTemplateDecl *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
@@ -1084,6 +1104,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Attr)
ProcessDeclAttributeList(S, NewClass, Attr);
+ AddPushedVisibilityAttribute(NewClass);
+
if (TUK != TUK_Friend)
PushOnScopeChains(NewTemplate, S);
else {
@@ -1116,6 +1138,11 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
NewTemplate->setInvalidDecl();
NewClass->setInvalidDecl();
}
+ if (PrevClassTemplate)
+ mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
+
+ ActOnDocumentableDecl(NewTemplate);
+
return NewTemplate;
}
@@ -1972,6 +1999,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
TemplateArgLists.addOuterTemplateArguments(0, 0);
InstantiatingTemplate Inst(*this, TemplateLoc, Template);
+ if (Inst)
+ return QualType();
CanonType = SubstType(Pattern->getUnderlyingType(),
TemplateArgLists, AliasTemplate->getLocation(),
AliasTemplate->getDeclName());
@@ -2420,6 +2449,43 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
return true;
}
+ case TemplateArgument::Expression: {
+ // We have a template type parameter but the template argument is an
+ // expression; see if maybe it is missing the "typename" keyword.
+ CXXScopeSpec SS;
+ DeclarationNameInfo NameInfo;
+
+ if (DeclRefExpr *ArgExpr = dyn_cast<DeclRefExpr>(Arg.getAsExpr())) {
+ SS.Adopt(ArgExpr->getQualifierLoc());
+ NameInfo = ArgExpr->getNameInfo();
+ } else if (DependentScopeDeclRefExpr *ArgExpr =
+ dyn_cast<DependentScopeDeclRefExpr>(Arg.getAsExpr())) {
+ SS.Adopt(ArgExpr->getQualifierLoc());
+ NameInfo = ArgExpr->getNameInfo();
+ } else if (CXXDependentScopeMemberExpr *ArgExpr =
+ dyn_cast<CXXDependentScopeMemberExpr>(Arg.getAsExpr())) {
+ if (ArgExpr->isImplicitAccess()) {
+ SS.Adopt(ArgExpr->getQualifierLoc());
+ NameInfo = ArgExpr->getMemberNameInfo();
+ }
+ }
+
+ if (NameInfo.getName().isIdentifier()) {
+ LookupResult Result(*this, NameInfo, LookupOrdinaryName);
+ LookupParsedName(Result, CurScope, &SS);
+
+ if (Result.getAsSingle<TypeDecl>() ||
+ Result.getResultKind() ==
+ LookupResult::NotFoundInCurrentInstantiation) {
+ // FIXME: Add a FixIt and fix up the template argument for recovery.
+ SourceLocation Loc = AL.getSourceRange().getBegin();
+ Diag(Loc, diag::err_template_arg_must_be_type_suggest);
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+ }
+ // fallthrough
+ }
default: {
// We have a template type parameter but the template argument
// is not a type.
@@ -2492,9 +2558,10 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
= SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Template, Converted.data(),
- Converted.size(),
+ Template, Converted,
SourceRange(TemplateLoc, RAngleLoc));
+ if (Inst)
+ return 0;
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs,
@@ -2541,9 +2608,10 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
= SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Template, Converted.data(),
- Converted.size(),
+ Template, Converted,
SourceRange(TemplateLoc, RAngleLoc));
+ if (Inst)
+ return ExprError();
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
@@ -2590,9 +2658,10 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
= SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Template, Converted.data(),
- Converted.size(),
+ Template, Converted,
SourceRange(TemplateLoc, RAngleLoc));
+ if (Inst)
+ return TemplateName();
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
// Substitute into the nested-name-specifier first,
@@ -2724,8 +2793,10 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
!Template->getDeclContext()->isDependentContext()) {
// Do substitution on the type of the non-type template parameter.
InstantiatingTemplate Inst(*this, TemplateLoc, Template,
- NTTP, Converted.data(), Converted.size(),
+ NTTP, Converted,
SourceRange(TemplateLoc, RAngleLoc));
+ if (Inst)
+ return true;
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Converted.data(), Converted.size());
@@ -2856,8 +2927,10 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
// Set up a template instantiation context.
LocalInstantiationScope Scope(*this);
InstantiatingTemplate Inst(*this, TemplateLoc, Template,
- TempParm, Converted.data(), Converted.size(),
+ TempParm, Converted,
SourceRange(TemplateLoc, RAngleLoc));
+ if (Inst)
+ return true;
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Converted.data(), Converted.size());
@@ -3086,9 +3159,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// Introduce an instantiation record that describes where we are using
// the default template argument.
- InstantiatingTemplate Instantiating(*this, RAngleLoc, Template, *Param,
- Converted.data(), Converted.size(),
+ InstantiatingTemplate Instantiating(*this, RAngleLoc, Template,
+ *Param, Converted,
SourceRange(TemplateLoc, RAngleLoc));
+ if (Instantiating)
+ return true;
// Check the default template argument.
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc,
@@ -3574,6 +3649,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
if (ParamType->isPointerType() || ParamType->isNullPtrType()) {
switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) {
case NPV_NullPointer:
+ S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
Converted = TemplateArgument((Decl *)0);
return false;
@@ -3870,6 +3946,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
case NPV_Error:
return true;
case NPV_NullPointer:
+ S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
Converted = TemplateArgument((Decl *)0);
return false;
case NPV_NotNullPointer:
@@ -4066,7 +4143,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
IntegerType = Enum->getDecl()->getIntegerType();
Value = Value.extOrTrunc(Context.getTypeSize(IntegerType));
- Converted = TemplateArgument(Value, Context.getCanonicalType(ParamType));
+ Converted = TemplateArgument(Context, Value,
+ Context.getCanonicalType(ParamType));
return ArgResult;
}
@@ -4093,8 +4171,20 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Diag(Param->getLocation(), diag::note_template_param_here);
return ExprError();
} else if (!Arg->isValueDependent()) {
- Arg = VerifyIntegerConstantExpression(Arg, &Value,
- PDiag(diag::err_template_arg_not_ice) << ArgType, false).take();
+ class TmplArgICEDiagnoser : public VerifyICEDiagnoser {
+ QualType T;
+
+ public:
+ TmplArgICEDiagnoser(QualType T) : T(T) { }
+
+ virtual void diagnoseNotICE(Sema &S, SourceLocation Loc,
+ SourceRange SR) {
+ S.Diag(Loc, diag::err_template_arg_not_ice) << T << SR;
+ }
+ } Diagnoser(ArgType);
+
+ Arg = VerifyIntegerConstantExpression(Arg, &Value, Diagnoser,
+ false).take();
if (!Arg)
return ExprError();
}
@@ -4180,7 +4270,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
}
- Converted = TemplateArgument(Value,
+ Converted = TemplateArgument(Context, Value,
ParamType->isEnumeralType()
? Context.getCanonicalType(ParamType)
: IntegerType);
@@ -4305,6 +4395,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
case NPV_NullPointer:
+ Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
Converted = TemplateArgument((Decl *)0);
return Owned(Arg);;
}
@@ -4497,13 +4588,13 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
Kind = CharacterLiteral::Ascii;
return Owned(new (Context) CharacterLiteral(
- Arg.getAsIntegral()->getZExtValue(),
+ Arg.getAsIntegral().getZExtValue(),
Kind, T, Loc));
}
if (T->isBooleanType())
return Owned(new (Context) CXXBoolLiteralExpr(
- Arg.getAsIntegral()->getBoolValue(),
+ Arg.getAsIntegral().getBoolValue(),
T, Loc));
if (T->isNullPtrType())
@@ -4518,7 +4609,7 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
else
BT = T;
- Expr *E = IntegerLiteral::Create(Context, *Arg.getAsIntegral(), BT, Loc);
+ Expr *E = IntegerLiteral::Create(Context, Arg.getAsIntegral(), BT, Loc);
if (T->isEnumeralType()) {
// FIXME: This is a hack. We need a better way to handle substituted
// non-type template parameters.
@@ -5041,7 +5132,7 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S,
/// \param TemplateParams the template parameters of the primary class
/// template.
///
-/// \param TemplateArg the template arguments of the class template
+/// \param TemplateArgs the template arguments of the class template
/// partial specialization.
///
/// \returns true if there was an error, false otherwise.
@@ -5481,7 +5572,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Decl *Sema::ActOnTemplateDeclarator(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
- return HandleDeclarator(S, D, move(TemplateParameterLists));
+ Decl *NewDecl = HandleDeclarator(S, D, move(TemplateParameterLists));
+ ActOnDocumentableDecl(NewDecl);
+ return NewDecl;
}
Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
@@ -5719,14 +5812,17 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
}
/// \brief Perform semantic analysis for the given dependent function
-/// template specialization. The only possible way to get a dependent
-/// function template specialization is with a friend declaration,
-/// like so:
+/// template specialization.
+///
+/// The only possible way to get a dependent function template specialization
+/// is with a friend declaration, like so:
///
-/// template <class T> void foo(T);
-/// template <class T> class A {
+/// \code
+/// template \<class T> void foo(T);
+/// template \<class T> class A {
/// friend void foo<>(T);
/// };
+/// \endcode
///
/// There really isn't any useful analysis we can do here, so we
/// just store the information.
@@ -6890,6 +6986,42 @@ Sema::ActOnTypenameType(Scope *S,
}
+/// Determine whether this failed name lookup should be treated as being
+/// disabled by a usage of std::enable_if.
+static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
+ SourceRange &CondRange) {
+ // We must be looking for a ::type...
+ if (!II.isStr("type"))
+ return false;
+
+ // ... within an explicitly-written template specialization...
+ if (!NNS || !NNS.getNestedNameSpecifier()->getAsType())
+ return false;
+ TypeLoc EnableIfTy = NNS.getTypeLoc();
+ TemplateSpecializationTypeLoc *EnableIfTSTLoc =
+ dyn_cast<TemplateSpecializationTypeLoc>(&EnableIfTy);
+ if (!EnableIfTSTLoc || EnableIfTSTLoc->getNumArgs() == 0)
+ return false;
+ const TemplateSpecializationType *EnableIfTST =
+ cast<TemplateSpecializationType>(EnableIfTSTLoc->getTypePtr());
+
+ // ... which names a complete class template declaration...
+ const TemplateDecl *EnableIfDecl =
+ EnableIfTST->getTemplateName().getAsTemplateDecl();
+ if (!EnableIfDecl || EnableIfTST->isIncompleteType())
+ return false;
+
+ // ... called "enable_if".
+ const IdentifierInfo *EnableIfII =
+ EnableIfDecl->getDeclName().getAsIdentifierInfo();
+ if (!EnableIfII || !EnableIfII->isStr("enable_if"))
+ return false;
+
+ // Assume the first template argument is the condition.
+ CondRange = EnableIfTSTLoc->getArgLoc(0).getSourceRange();
+ return true;
+}
+
/// \brief Build the type that describes a C++ typename specifier,
/// e.g., "typename T::type".
QualType
@@ -6926,9 +7058,19 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
unsigned DiagID = 0;
Decl *Referenced = 0;
switch (Result.getResultKind()) {
- case LookupResult::NotFound:
+ case LookupResult::NotFound: {
+ // If we're looking up 'type' within a template named 'enable_if', produce
+ // a more specific diagnostic.
+ SourceRange CondRange;
+ if (isEnableIf(QualifierLoc, II, CondRange)) {
+ Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if)
+ << Ctx << CondRange;
+ return QualType();
+ }
+
DiagID = diag::err_typename_nested_not_found;
break;
+ }
case LookupResult::FoundUnresolvedValue: {
// We found a using declaration that is a value. Most likely, the using
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index d68e464..9500ec3 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -137,8 +137,17 @@ DeduceTemplateArguments(Sema &S,
/// of a non-type template parameter, return the declaration of that
/// non-type template parameter.
static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
- if (ImplicitCastExpr *IC = dyn_cast<ImplicitCastExpr>(E))
- E = IC->getSubExpr();
+ // If we are within an alias template, the expression may have undergone
+ // any number of parameter substitutions already.
+ while (1) {
+ if (ImplicitCastExpr *IC = dyn_cast<ImplicitCastExpr>(E))
+ E = IC->getSubExpr();
+ else if (SubstNonTypeTemplateParmExpr *Subst =
+ dyn_cast<SubstNonTypeTemplateParmExpr>(E))
+ E = Subst->getReplacement();
+ else
+ break;
+ }
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());
@@ -193,7 +202,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
if (Y.getKind() == TemplateArgument::Expression ||
Y.getKind() == TemplateArgument::Declaration ||
(Y.getKind() == TemplateArgument::Integral &&
- hasSameExtendedValue(*X.getAsIntegral(), *Y.getAsIntegral())))
+ hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral())))
return DeducedTemplateArgument(X,
X.wasDeducedFromArrayBound() &&
Y.wasDeducedFromArrayBound());
@@ -293,7 +302,8 @@ DeduceNonTypeTemplateArgument(Sema &S,
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
- DeducedTemplateArgument NewDeduced(Value, ValueType, DeducedFromArrayBound);
+ DeducedTemplateArgument NewDeduced(S.Context, Value, ValueType,
+ DeducedFromArrayBound);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[NTTP->getIndex()],
NewDeduced);
@@ -1595,7 +1605,7 @@ DeduceTemplateArguments(Sema &S,
case TemplateArgument::Integral:
if (Arg.getKind() == TemplateArgument::Integral) {
- if (hasSameExtendedValue(*Param.getAsIntegral(), *Arg.getAsIntegral()))
+ if (hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral()))
return Sema::TDK_Success;
Info.FirstArg = Param;
@@ -1618,7 +1628,7 @@ DeduceTemplateArguments(Sema &S,
= getDeducedParameterFromExpr(Param.getAsExpr())) {
if (Arg.getKind() == TemplateArgument::Integral)
return DeduceNonTypeTemplateArgument(S, NTTP,
- *Arg.getAsIntegral(),
+ Arg.getAsIntegral(),
Arg.getIntegralType(),
/*ArrayBound=*/false,
Info, Deduced);
@@ -1867,7 +1877,7 @@ static bool isSameTemplateArg(ASTContext &Context,
Y.getAsTemplateOrTemplatePattern()).getAsVoidPointer();
case TemplateArgument::Integral:
- return *X.getAsIntegral() == *Y.getAsIntegral();
+ return X.getAsIntegral() == Y.getAsIntegral();
case TemplateArgument::Expression: {
llvm::FoldingSetNodeID XID, YID;
@@ -1898,7 +1908,7 @@ static bool isSameTemplateArg(ASTContext &Context,
///
/// \param S The semantic analysis object.
///
-/// \param The template argument we are producing template argument
+/// \param Arg The template argument we are producing template argument
/// location information for.
///
/// \param NTTPType For a declaration template argument, the type of
@@ -2171,8 +2181,9 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
TemplateArgs, Info, Deduced))
return Result;
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
- Deduced.data(), Deduced.size(), Info);
+ DeducedArgs, Info);
if (Inst)
return TDK_InstantiationDepth;
@@ -2198,7 +2209,7 @@ static bool isSimpleTemplateIdType(QualType T) {
/// \param FunctionTemplate the function template into which the explicit
/// template arguments will be substituted.
///
-/// \param ExplicitTemplateArguments the explicitly-specified template
+/// \param ExplicitTemplateArgs the explicitly-specified template
/// arguments.
///
/// \param Deduced the deduced template arguments, which will be populated
@@ -2256,8 +2267,9 @@ Sema::SubstituteExplicitTemplateArguments(
// Enter a new template instantiation context where we check the
// explicitly-specified template arguments against this function template,
// and then substitute them into the function parameter types.
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
- FunctionTemplate, Deduced.data(), Deduced.size(),
+ FunctionTemplate, DeducedArgs,
ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution,
Info);
if (Inst)
@@ -2424,6 +2436,16 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
Qualifiers AQuals = A.getQualifiers();
Qualifiers DeducedAQuals = DeducedA.getQualifiers();
+
+ // Under Objective-C++ ARC, the deduced type may have implicitly been
+ // given strong lifetime. If so, update the original qualifiers to
+ // include this strong lifetime.
+ if (S.getLangOpts().ObjCAutoRefCount &&
+ DeducedAQuals.getObjCLifetime() == Qualifiers::OCL_Strong &&
+ AQuals.getObjCLifetime() == Qualifiers::OCL_None) {
+ AQuals.setObjCLifetime(Qualifiers::OCL_Strong);
+ }
+
if (AQuals == DeducedAQuals) {
// Qualifiers match; there's nothing to do.
} else if (!DeducedAQuals.compatiblyIncludes(AQuals)) {
@@ -2502,8 +2524,9 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// Enter a new template instantiation context while we instantiate the
// actual function declaration.
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
- FunctionTemplate, Deduced.data(), Deduced.size(),
+ FunctionTemplate, DeducedArgs,
ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
Info);
if (Inst)
@@ -2825,9 +2848,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
QualType PointeeType = ParamRefType->getPointeeType();
// If the argument has incomplete array type, try to complete it's type.
- if (ArgType->isIncompleteArrayType() &&
- !S.RequireCompleteExprType(Arg, S.PDiag(),
- std::make_pair(SourceLocation(), S.PDiag())))
+ if (ArgType->isIncompleteArrayType() && !S.RequireCompleteExprType(Arg, 0))
ArgType = Arg->getType();
// [C++0x] If P is an rvalue reference to a cv-unqualified
@@ -2966,7 +2987,7 @@ DeduceTemplateArgumentByListElement(Sema &S,
/// \param FunctionTemplate the function template for which we are performing
/// template argument deduction.
///
-/// \param ExplicitTemplateArguments the explicit template arguments provided
+/// \param ExplicitTemplateArgs the explicit template arguments provided
/// for this call.
///
/// \param Args the function call arguments
@@ -3226,7 +3247,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
/// \param FunctionTemplate the function template for which we are performing
/// template argument deduction.
///
-/// \param ExplicitTemplateArguments the explicitly-specified template
+/// \param ExplicitTemplateArgs the explicitly-specified template
/// arguments.
///
/// \param ArgFunctionType the function type that will be used as the
@@ -3409,7 +3430,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
/// \param FunctionTemplate the function template for which we are performing
/// template argument deduction.
///
-/// \param ExplicitTemplateArguments the explicitly-specified template
+/// \param ExplicitTemplateArgs the explicitly-specified template
/// arguments.
///
/// \param Specialization if template argument deduction was successful,
@@ -3465,6 +3486,41 @@ namespace {
return E;
}
};
+
+ /// Determine whether the specified type (which contains an 'auto' type
+ /// specifier) is dependent. This is not trivial, because the 'auto' specifier
+ /// itself claims to be type-dependent.
+ bool isDependentAutoType(QualType Ty) {
+ while (1) {
+ QualType Pointee = Ty->getPointeeType();
+ if (!Pointee.isNull()) {
+ Ty = Pointee;
+ } else if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()){
+ if (MPT->getClass()->isDependentType())
+ return true;
+ Ty = MPT->getPointeeType();
+ } else if (const FunctionProtoType *FPT = Ty->getAs<FunctionProtoType>()){
+ for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(),
+ E = FPT->arg_type_end();
+ I != E; ++I)
+ if ((*I)->isDependentType())
+ return true;
+ Ty = FPT->getResultType();
+ } else if (Ty->isDependentSizedArrayType()) {
+ return true;
+ } else if (const ArrayType *AT = Ty->getAsArrayTypeUnsafe()) {
+ Ty = AT->getElementType();
+ } else if (Ty->getAs<DependentSizedExtVectorType>()) {
+ return true;
+ } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ Ty = VT->getElementType();
+ } else {
+ break;
+ }
+ }
+ assert(Ty->getAs<AutoType>() && "didn't find 'auto' in auto type");
+ return false;
+ }
}
/// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6)
@@ -3487,7 +3543,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
Init = result.take();
}
- if (Init->isTypeDependent()) {
+ if (Init->isTypeDependent() || isDependentAutoType(Type->getType())) {
Result = Type;
return DAR_Succeeded;
}
@@ -3518,10 +3574,10 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
TemplateDeductionInfo Info(Context, Loc);
- InitListExpr * InitList = dyn_cast<InitListExpr>(Init);
+ InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
if (InitList) {
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
- if (DeduceTemplateArgumentByListElement(*this, &TemplateParams,
+ if (DeduceTemplateArgumentByListElement(*this, &TemplateParams,
TemplArg,
InitList->getInit(i),
Info, Deduced, TDF))
@@ -3532,7 +3588,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
FuncParam, InitType, Init,
TDF))
return DAR_Failed;
-
+
if (DeduceTemplateArgumentsByTypeMatch(*this, &TemplateParams, FuncParam,
InitType, Info, Deduced, TDF))
return DAR_Failed;
@@ -4075,8 +4131,9 @@ Sema::getMoreSpecializedPartialSpecialization(
/*PartialOrdering=*/true,
/*RefParamComparisons=*/0);
if (Better1) {
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end());
InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2,
- Deduced.data(), Deduced.size(), Info);
+ DeducedArgs, Info);
Better1 = !::FinishTemplateArgumentDeduction(*this, PS2,
PS1->getTemplateArgs(),
Deduced, Info);
@@ -4091,8 +4148,9 @@ Sema::getMoreSpecializedPartialSpecialization(
/*PartialOrdering=*/true,
/*RefParamComparisons=*/0);
if (Better2) {
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end());
InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1,
- Deduced.data(), Deduced.size(), Info);
+ DeducedArgs, Info);
Better2 = !::FinishTemplateArgumentDeduction(*this, PS1,
PS2->getTemplateArgs(),
Deduced, Info);
@@ -4123,9 +4181,17 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E))
E = Expansion->getPattern();
- // Skip through any implicit casts we added while type-checking.
- while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
- E = ICE->getSubExpr();
+ // Skip through any implicit casts we added while type-checking, and any
+ // substitutions performed by template alias expansion.
+ while (1) {
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ E = ICE->getSubExpr();
+ else if (const SubstNonTypeTemplateParmExpr *Subst =
+ dyn_cast<SubstNonTypeTemplateParmExpr>(E))
+ E = Subst->getReplacement();
+ else
+ break;
+ }
// FIXME: if !OnlyDeduced, we have to walk the whole subexpression to
// find other occurrences of template parameters.
@@ -4456,13 +4522,13 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
}
}
-/// \brief Mark the template parameters can be deduced by the given
+/// \brief Mark which template parameters can be deduced from a given
/// template argument list.
///
/// \param TemplateArgs the template argument list from which template
/// parameters will be deduced.
///
-/// \param Deduced a bit vector whose elements will be set to \c true
+/// \param Used a bit vector whose elements will be set to \c true
/// to indicate when the corresponding template parameter will be
/// deduced.
void
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 128dc2f..c7cbc41 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -156,11 +156,11 @@ bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
case ExceptionSpecInstantiation:
case DefaultTemplateArgumentInstantiation:
case DefaultFunctionArgumentInstantiation:
- return true;
-
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
case PriorTemplateArgumentSubstitution:
+ return true;
+
case DefaultTemplateArgumentChecking:
return false;
}
@@ -214,12 +214,11 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
}
}
-Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
- SourceLocation PointOfInstantiation,
- TemplateDecl *Template,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceRange InstantiationRange)
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
: SemaRef(SemaRef),
SavedInNonInstantiationSFINAEContext(
SemaRef.InNonInstantiationSFINAEContext)
@@ -232,35 +231,33 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
= ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = reinterpret_cast<uintptr_t>(Template);
- Inst.TemplateArgs = TemplateArgs;
- Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.TemplateArgs = TemplateArgs.data();
+ Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
}
}
-Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
- SourceLocation PointOfInstantiation,
- FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- ActiveTemplateInstantiation::InstantiationKind Kind,
- sema::TemplateDeductionInfo &DeductionInfo,
- SourceRange InstantiationRange)
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ FunctionTemplateDecl *FunctionTemplate,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ ActiveTemplateInstantiation::InstantiationKind Kind,
+ sema::TemplateDeductionInfo &DeductionInfo,
+ SourceRange InstantiationRange)
: SemaRef(SemaRef),
SavedInNonInstantiationSFINAEContext(
SemaRef.InNonInstantiationSFINAEContext)
{
- Invalid = CheckInstantiationDepth(PointOfInstantiation,
- InstantiationRange);
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
if (!Invalid) {
ActiveTemplateInstantiation Inst;
Inst.Kind = Kind;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = reinterpret_cast<uintptr_t>(FunctionTemplate);
- Inst.TemplateArgs = TemplateArgs;
- Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.TemplateArgs = TemplateArgs.data();
+ Inst.NumTemplateArgs = TemplateArgs.size();
Inst.DeductionInfo = &DeductionInfo;
Inst.InstantiationRange = InstantiationRange;
SemaRef.InNonInstantiationSFINAEContext = false;
@@ -271,54 +268,49 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
}
}
-Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
- SourceLocation PointOfInstantiation,
- ClassTemplatePartialSpecializationDecl *PartialSpec,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- sema::TemplateDeductionInfo &DeductionInfo,
- SourceRange InstantiationRange)
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ClassTemplatePartialSpecializationDecl *PartialSpec,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ sema::TemplateDeductionInfo &DeductionInfo,
+ SourceRange InstantiationRange)
: SemaRef(SemaRef),
SavedInNonInstantiationSFINAEContext(
SemaRef.InNonInstantiationSFINAEContext)
{
- Invalid = false;
-
- ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
- Inst.TemplateArgs = TemplateArgs;
- Inst.NumTemplateArgs = NumTemplateArgs;
- Inst.DeductionInfo = &DeductionInfo;
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-
- assert(!Inst.isInstantiationRecord());
- ++SemaRef.NonInstantiationEntries;
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
+ Inst.TemplateArgs = TemplateArgs.data();
+ Inst.NumTemplateArgs = TemplateArgs.size();
+ Inst.DeductionInfo = &DeductionInfo;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ }
}
-Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
- SourceLocation PointOfInstantiation,
- ParmVarDecl *Param,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceRange InstantiationRange)
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ParmVarDecl *Param,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
: SemaRef(SemaRef),
SavedInNonInstantiationSFINAEContext(
SemaRef.InNonInstantiationSFINAEContext)
{
Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
-
if (!Invalid) {
ActiveTemplateInstantiation Inst;
Inst.Kind
= ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = reinterpret_cast<uintptr_t>(Param);
- Inst.TemplateArgs = TemplateArgs;
- Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.TemplateArgs = TemplateArgs.data();
+ Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
@@ -327,66 +319,57 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- NamedDecl *Template,
- NonTypeTemplateParmDecl *Param,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceRange InstantiationRange)
+ NamedDecl *Template, NonTypeTemplateParmDecl *Param,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
: SemaRef(SemaRef),
SavedInNonInstantiationSFINAEContext(
SemaRef.InNonInstantiationSFINAEContext)
{
- Invalid = false;
-
- ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Template = Template;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
- Inst.TemplateArgs = TemplateArgs;
- Inst.NumTemplateArgs = NumTemplateArgs;
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-
- assert(!Inst.isInstantiationRecord());
- ++SemaRef.NonInstantiationEntries;
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Template = Template;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs.data();
+ Inst.NumTemplateArgs = TemplateArgs.size();
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ }
}
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- NamedDecl *Template,
- TemplateTemplateParmDecl *Param,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceRange InstantiationRange)
+ NamedDecl *Template, TemplateTemplateParmDecl *Param,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
: SemaRef(SemaRef),
SavedInNonInstantiationSFINAEContext(
SemaRef.InNonInstantiationSFINAEContext)
{
- Invalid = false;
- ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Template = Template;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
- Inst.TemplateArgs = TemplateArgs;
- Inst.NumTemplateArgs = NumTemplateArgs;
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-
- assert(!Inst.isInstantiationRecord());
- ++SemaRef.NonInstantiationEntries;
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Template = Template;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs.data();
+ Inst.NumTemplateArgs = TemplateArgs.size();
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ }
}
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- TemplateDecl *Template,
- NamedDecl *Param,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceRange InstantiationRange)
+ TemplateDecl *Template, NamedDecl *Param,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
: SemaRef(SemaRef),
SavedInNonInstantiationSFINAEContext(
SemaRef.InNonInstantiationSFINAEContext)
@@ -398,8 +381,8 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Template = Template;
Inst.Entity = reinterpret_cast<uintptr_t>(Param);
- Inst.TemplateArgs = TemplateArgs;
- Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.TemplateArgs = TemplateArgs.data();
+ Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
@@ -638,8 +621,13 @@ llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
++Active)
{
switch(Active->Kind) {
- case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
case ActiveTemplateInstantiation::TemplateInstantiation:
+ // An instantiation of an alias template may or may not be a SFINAE
+ // context, depending on what else is on the stack.
+ if (isa<TypeAliasTemplateDecl>(reinterpret_cast<Decl *>(Active->Entity)))
+ break;
+ // Fall through.
+ case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
// This is a template instantiation, so there is no SFINAE.
return llvm::Optional<TemplateDeductionInfo *>();
@@ -850,10 +838,23 @@ namespace {
return move(Result);
}
+ ExprResult TransformLambdaExpr(LambdaExpr *E) {
+ LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+ return TreeTransform<TemplateInstantiator>::TransformLambdaExpr(E);
+ }
+
+ ExprResult TransformLambdaScope(LambdaExpr *E,
+ CXXMethodDecl *CallOperator) {
+ CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
+ TSK_ImplicitInstantiation);
+ return TreeTransform<TemplateInstantiator>::
+ TransformLambdaScope(E, CallOperator);
+ }
+
private:
ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
SourceLocation loc,
- const TemplateArgument &arg);
+ TemplateArgument arg);
};
}
@@ -1088,7 +1089,11 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
llvm::APInt LengthI(32, Length + 1);
- QualType ResTy = getSema().Context.CharTy.withConst();
+ QualType ResTy;
+ if (IT == PredefinedExpr::LFunction)
+ ResTy = getSema().Context.WCharTy.withConst();
+ else
+ ResTy = getSema().Context.CharTy.withConst();
ResTy = getSema().Context.getConstantArrayType(ResTy, LengthI,
ArrayType::Normal, 0);
PredefinedExpr *PE =
@@ -1138,10 +1143,18 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
NonTypeTemplateParmDecl *parm,
SourceLocation loc,
- const TemplateArgument &arg) {
+ TemplateArgument arg) {
ExprResult result;
QualType type;
+ // If the argument is a pack expansion, the parameter must actually be a
+ // parameter pack, and we should substitute the pattern itself, producing
+ // an expression which contains an unexpanded parameter pack.
+ if (arg.isPackExpansion()) {
+ assert(parm->isParameterPack() && "pack expansion for non-pack");
+ arg = arg.getPackExpansionPattern();
+ }
+
// The template argument itself might be an expression, in which
// case we just return that expression.
if (arg.getKind() == TemplateArgument::Expression) {
@@ -1378,7 +1391,7 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
/// substituted. If this type is not dependent, it will be returned
/// immediately.
///
-/// \param TemplateArgs the template arguments that will be
+/// \param Args the template arguments that will be
/// substituted for the top-level template parameters within T.
///
/// \param Loc the location in the source code where this substitution
@@ -1590,6 +1603,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
NewParm->setUnparsedDefaultArg();
UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm);
} else if (Expr *Arg = OldParm->getDefaultArg())
+ // FIXME: if we non-lazily instantiated non-dependent default args for
+ // non-dependent parameter types we could remove a bunch of duplicate
+ // conversion warnings for such arguments.
NewParm->setUninstantiatedDefaultArg(Arg);
NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
@@ -1820,8 +1836,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateSpecializationKind TSK,
bool Complain) {
- bool Invalid = false;
-
CXXRecordDecl *PatternDef
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation,
@@ -1867,7 +1881,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Do substitution on the base class specifiers.
if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
- Invalid = true;
+ Instantiation->setInvalidDecl();
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
SmallVector<Decl*, 4> Fields;
@@ -1893,7 +1907,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
continue;
if ((*Member)->isInvalidDecl()) {
- Invalid = true;
+ Instantiation->setInvalidDecl();
continue;
}
@@ -1917,14 +1931,22 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
MSInfo->setTemplateSpecializationKind(TSK_ImplicitInstantiation);
MSInfo->setPointOfInstantiation(PointOfInstantiation);
}
+ } else if (StaticAssertDecl *SA = dyn_cast<StaticAssertDecl>(NewMember)) {
+ if (SA->isFailed()) {
+ // A static_assert failed. Bail out; instantiating this
+ // class is probably not meaningful.
+ Instantiation->setInvalidDecl();
+ break;
+ }
}
if (NewMember->isInvalidDecl())
- Invalid = true;
+ Instantiation->setInvalidDecl();
} else {
// FIXME: Eventually, a NULL return will mean that one of the
- // instantiations was a semantic disaster, and we'll want to set Invalid =
- // true. For now, we expect to skip some members that we can't yet handle.
+ // instantiations was a semantic disaster, and we'll want to mark the
+ // declaration invalid.
+ // For now, we expect to skip some members that we can't yet handle.
}
}
@@ -1934,7 +1956,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CheckCompletedCXXClass(Instantiation);
// Attach any in-class member initializers now the class is complete.
- {
+ if (!FieldsWithMemberInitializers.empty()) {
// C++11 [expr.prim.general]p4:
// Otherwise, if a member-declarator declares a non-static data member
// (9.2) of a class X, the expression this is a prvalue of type "pointer
@@ -1955,9 +1977,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Expr *Init = NewInit.take();
assert(Init && "no-argument initializer in class");
assert(!isa<ParenListExpr>(Init) && "call-style init in class");
- ActOnCXXInClassMemberInitializer(NewField,
- Init->getSourceRange().getBegin(),
- Init);
+ ActOnCXXInClassMemberInitializer(NewField, Init->getLocStart(), Init);
}
}
}
@@ -1976,8 +1996,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Instantiator.disableLateAttributeInstantiation();
LateAttrs.clear();
- if (!FieldsWithMemberInitializers.empty())
- ActOnFinishDelayedMemberInitializers(Instantiation);
+ ActOnFinishDelayedMemberInitializers(Instantiation);
if (TSK == TSK_ImplicitInstantiation) {
Instantiation->setLocation(Pattern->getLocation());
@@ -1985,9 +2004,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Instantiation->setRBraceLoc(Pattern->getRBraceLoc());
}
- if (Instantiation->isInvalidDecl())
- Invalid = true;
- else {
+ if (!Instantiation->isInvalidDecl()) {
+ // Perform any dependent diagnostics from the pattern.
+ PerformDependentDiagnostics(Pattern, TemplateArgs);
+
// Instantiate any out-of-line class template partial
// specializations now.
for (TemplateDeclInstantiator::delayed_partial_spec_iterator
@@ -1997,7 +2017,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
if (!Instantiator.InstantiateClassTemplatePartialSpecialization(
P->first,
P->second)) {
- Invalid = true;
+ Instantiation->setInvalidDecl();
break;
}
}
@@ -2006,7 +2026,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Exit the scope of this instantiation.
SavedContext.pop();
- if (!Invalid) {
+ if (!Instantiation->isInvalidDecl()) {
Consumer.HandleTagDeclDefinition(Instantiation);
// Always emit the vtable for an explicit instantiation definition
@@ -2015,7 +2035,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
MarkVTableUsed(PointOfInstantiation, Instantiation, true);
}
- return Invalid;
+ return Instantiation->isInvalidDecl();
}
/// \brief Instantiate the definition of an enum from a given pattern.
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index c7bd99c..bdbe71d 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -79,14 +79,16 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
ExprResult Result = SubstExpr(Aligned->getAlignmentExpr(),
TemplateArgs);
if (!Result.isInvalid())
- AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>());
+ AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>(),
+ Aligned->getIsMSDeclSpec());
} else {
TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(),
TemplateArgs,
Aligned->getLocation(),
DeclarationName());
if (Result)
- AddAlignedAttr(Aligned->getLocation(), New, Result);
+ AddAlignedAttr(Aligned->getLocation(), New, Result,
+ Aligned->getIsMSDeclSpec());
}
continue;
}
@@ -102,7 +104,8 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
} else {
Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
*this, TemplateArgs);
- New->addAttr(NewAttr);
+ if (NewAttr)
+ New->addAttr(NewAttr);
}
}
}
@@ -338,9 +341,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// We already have an initializer in the class.
} else if (D->getInit()) {
if (Var->isStaticDataMember() && !D->isOutOfLine())
- SemaRef.PushExpressionEvaluationContext(Sema::ConstantEvaluated);
+ SemaRef.PushExpressionEvaluationContext(Sema::ConstantEvaluated, D);
else
- SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, D);
// Instantiate the initializer.
ExprResult Init = SemaRef.SubstInitializer(D->getInit(), TemplateArgs,
@@ -429,8 +432,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
D->getLocation(),
D->isMutable(),
BitWidth,
- D->hasInClassInitializer(),
- D->getTypeSpecStartLoc(),
+ D->getInClassInitStyle(),
+ D->getInnerLocStart(),
D->getAccess(),
0);
if (!Field) {
@@ -549,12 +552,11 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
if (InstantiatedAssertExpr.isInvalid())
return 0;
- ExprResult Message(D->getMessage());
- D->getMessage();
- return SemaRef.ActOnStaticAssertDeclaration(D->getLocation(),
+ return SemaRef.BuildStaticAssertDeclaration(D->getLocation(),
InstantiatedAssertExpr.get(),
- Message.get(),
- D->getRParenLoc());
+ D->getMessage(),
+ D->getRParenLoc(),
+ D->isFailed());
}
Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
@@ -933,8 +935,6 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (!Instantiated)
return 0;
- Instantiated->setAccess(D->getAccess());
-
// Link the instantiated function template declaration to the function
// template from which it was instantiated.
FunctionTemplateDecl *InstTemplate
@@ -952,8 +952,12 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
InstTemplate->setInstantiatedFromMemberTemplate(D);
// Make declarations visible in the appropriate context.
- if (!isFriend)
+ if (!isFriend) {
Owner->addDecl(InstTemplate);
+ } else if (InstTemplate->getDeclContext()->isRecord() &&
+ !D->getPreviousDecl()) {
+ SemaRef.CheckFriendAccess(InstTemplate);
+ }
return InstTemplate;
}
@@ -1524,7 +1528,15 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
if (D->isPure())
SemaRef.CheckPureMethod(Method, SourceRange());
- Method->setAccess(D->getAccess());
+ // Propagate access. For a non-friend declaration, the access is
+ // whatever we're propagating from. For a friend, it should be the
+ // previous declaration we just found.
+ if (isFriend && Method->getPreviousDecl())
+ Method->setAccess(Method->getPreviousDecl()->getAccess());
+ else
+ Method->setAccess(D->getAccess());
+ if (FunctionTemplate)
+ FunctionTemplate->setAccess(Method->getAccess());
SemaRef.CheckOverrideControl(Method);
@@ -1534,18 +1546,28 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
if (D->isDeletedAsWritten())
Method->setDeletedAsWritten();
+ // If there's a function template, let our caller handle it.
if (FunctionTemplate) {
- // If there's a function template, let our caller handle it.
+ // do nothing
+
+ // Don't hide a (potentially) valid declaration with an invalid one.
} else if (Method->isInvalidDecl() && !Previous.empty()) {
- // Don't hide a (potentially) valid declaration with an invalid one.
- } else {
- NamedDecl *DeclToAdd = (TemplateParams
- ? cast<NamedDecl>(FunctionTemplate)
- : Method);
- if (isFriend)
- Record->makeDeclVisibleInContext(DeclToAdd);
- else if (!IsClassScopeSpecialization)
- Owner->addDecl(DeclToAdd);
+ // do nothing
+
+ // Otherwise, check access to friends and make them visible.
+ } else if (isFriend) {
+ // We only need to re-check access for methods which we didn't
+ // manage to match during parsing.
+ if (!D->getPreviousDecl())
+ SemaRef.CheckFriendAccess(Method);
+
+ Record->makeDeclVisibleInContext(Method);
+
+ // Otherwise, add the declaration. We don't need to do this for
+ // class-scope specializations because we'll have matched them with
+ // the appropriate template.
+ } else if (!IsClassScopeSpecialization) {
+ Owner->addDecl(Method);
}
if (D->isExplicitlyDefaulted()) {
@@ -1949,13 +1971,22 @@ Decl * TemplateDeclInstantiator
Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *Decl) {
CXXMethodDecl *OldFD = Decl->getSpecialization();
- CXXMethodDecl *NewFD = cast<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, 0, true));
+ CXXMethodDecl *NewFD = cast<CXXMethodDecl>(VisitCXXMethodDecl(OldFD,
+ 0, true));
LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName,
Sema::ForRedeclaration);
+ TemplateArgumentListInfo TemplateArgs;
+ TemplateArgumentListInfo* TemplateArgsPtr = 0;
+ if (Decl->hasExplicitTemplateArgs()) {
+ TemplateArgs = Decl->templateArgs();
+ TemplateArgsPtr = &TemplateArgs;
+ }
+
SemaRef.LookupQualifiedName(Previous, SemaRef.CurContext);
- if (SemaRef.CheckFunctionTemplateSpecialization(NewFD, 0, Previous)) {
+ if (SemaRef.CheckFunctionTemplateSpecialization(NewFD, TemplateArgsPtr,
+ Previous)) {
NewFD->setInvalidDecl();
return NewFD;
}
@@ -2165,35 +2196,31 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens();
FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
assert(NewProtoLoc && "Missing prototype?");
- unsigned NewIdx = 0, NumNewParams = NewProtoLoc->getNumArgs();
+ unsigned NewIdx = 0;
for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc->getNumArgs();
OldIdx != NumOldParams; ++OldIdx) {
ParmVarDecl *OldParam = OldProtoLoc->getArg(OldIdx);
- if (!OldParam->isParameterPack() ||
- // FIXME: Is this right? OldParam could expand to an empty parameter
- // pack and the next parameter could be an unexpanded parameter pack
- (NewIdx < NumNewParams &&
- NewProtoLoc->getArg(NewIdx)->isParameterPack())) {
+ LocalInstantiationScope *Scope = SemaRef.CurrentInstantiationScope;
+
+ llvm::Optional<unsigned> NumArgumentsInExpansion;
+ if (OldParam->isParameterPack())
+ NumArgumentsInExpansion =
+ SemaRef.getNumArgumentsInExpansion(OldParam->getType(),
+ TemplateArgs);
+ if (!NumArgumentsInExpansion) {
// Simple case: normal parameter, or a parameter pack that's
// instantiated to a (still-dependent) parameter pack.
ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++);
Params.push_back(NewParam);
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParam,
- NewParam);
- continue;
- }
-
- // Parameter pack: make the instantiation an argument pack.
- SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(
- OldParam);
- unsigned NumArgumentsInExpansion
- = SemaRef.getNumArgumentsInExpansion(OldParam->getType(),
- TemplateArgs);
- while (NumArgumentsInExpansion--) {
- ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++);
- Params.push_back(NewParam);
- SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg(OldParam,
- NewParam);
+ Scope->InstantiatedLocal(OldParam, NewParam);
+ } else {
+ // Parameter pack expansion: make the instantiation an argument pack.
+ Scope->MakeInstantiatedLocalArgPack(OldParam);
+ for (unsigned I = 0; I != *NumArgumentsInExpansion; ++I) {
+ ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++);
+ Params.push_back(NewParam);
+ Scope->InstantiatedLocalPackArg(OldParam, NewParam);
+ }
}
}
}
@@ -2237,9 +2264,11 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
// Expand the parameter pack.
Scope.MakeInstantiatedLocalArgPack(PatternParam);
- unsigned NumArgumentsInExpansion
+ llvm::Optional<unsigned> NumArgumentsInExpansion
= S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
- for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) {
+ assert(NumArgumentsInExpansion &&
+ "should only be called when all template arguments are known");
+ for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
FunctionParam->setDeclName(PatternParam->getDeclName());
Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
@@ -2354,9 +2383,10 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
NoexceptExpr = E.take();
if (!NoexceptExpr->isTypeDependent() &&
!NoexceptExpr->isValueDependent())
- NoexceptExpr = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
- 0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression),
- /*AllowFold*/ false).take();
+ NoexceptExpr
+ = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
+ 0, diag::err_noexcept_needs_constant_expression,
+ /*AllowFold*/ false).take();
}
}
@@ -2385,8 +2415,17 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
InstantiatingTemplate::ExceptionSpecification());
- if (Inst)
+ if (Inst) {
+ // We hit the instantiation depth limit. Clear the exception specification
+ // so that our callers don't have to cope with EST_Uninstantiated.
+ FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
+ EPI.ExceptionSpecType = EST_None;
+ Decl->setType(Context.getFunctionType(Proto->getResultType(),
+ Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ EPI));
return;
+ }
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
@@ -2411,7 +2450,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
bool
TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *Tmpl) {
- if (Tmpl->isDeletedAsWritten())
+ if (Tmpl->isDeleted())
New->setDeletedAsWritten();
// If we are performing substituting explicitly-specified template arguments
@@ -2433,7 +2472,6 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
(void) FunTmpl;
ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
ActiveInst.Entity = reinterpret_cast<uintptr_t>(New);
- --SemaRef.NonInstantiationEntries;
}
}
@@ -2452,6 +2490,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *ExceptionSpecTemplate = Tmpl;
if (EPI.ExceptionSpecType == EST_Uninstantiated)
ExceptionSpecTemplate = EPI.ExceptionSpecTemplate;
+ assert(EPI.ExceptionSpecType != EST_Unevaluated &&
+ "instantiating implicitly-declared special member");
// Mark the function has having an uninstantiated exception specification.
const FunctionProtoType *NewProto
@@ -3238,8 +3278,8 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
///
/// In the instantiation of X<int>::getKind(), we need to map the
/// EnumConstantDecl for KnownValue (which refers to
-/// X<T>::<Kind>::KnownValue) to its instantiation
-/// (X<int>::<Kind>::KnownValue). InstantiateCurrentDeclRef() performs
+/// X<T>::\<Kind>\::KnownValue) to its instantiation
+/// (X<int>::\<Kind>\::KnownValue). InstantiateCurrentDeclRef() performs
/// this mapping from within the instantiation of X<int>.
NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs) {
@@ -3422,7 +3462,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
void Sema::PerformPendingInstantiations(bool LocalOnly) {
// Load pending instantiations from the external source.
if (!LocalOnly && ExternalSource) {
- SmallVector<std::pair<ValueDecl *, SourceLocation>, 4> Pending;
+ SmallVector<PendingImplicitInstantiation, 4> Pending;
ExternalSource->ReadPendingInstantiations(Pending);
PendingInstantiations.insert(PendingInstantiations.begin(),
Pending.begin(), Pending.end());
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index a40100c..aece90b 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -12,6 +12,7 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/AST/Expr.h"
@@ -34,10 +35,12 @@ namespace {
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;
+ bool InLambda;
+
public:
explicit CollectUnexpandedParameterPacksVisitor(
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
- : Unexpanded(Unexpanded) { }
+ : Unexpanded(Unexpanded), InLambda(false) { }
bool shouldWalkTypesOfTypeLocs() const { return false; }
@@ -107,17 +110,17 @@ namespace {
/// \brief Suppress traversal into statements and expressions that
/// do not contain unexpanded parameter packs.
bool TraverseStmt(Stmt *S) {
- if (Expr *E = dyn_cast_or_null<Expr>(S))
- if (E->containsUnexpandedParameterPack())
- return inherited::TraverseStmt(E);
+ Expr *E = dyn_cast_or_null<Expr>(S);
+ if ((E && E->containsUnexpandedParameterPack()) || InLambda)
+ return inherited::TraverseStmt(S);
- return true;
+ return true;
}
/// \brief Suppress traversal into types that do not contain
/// unexpanded parameter packs.
bool TraverseType(QualType T) {
- if (!T.isNull() && T->containsUnexpandedParameterPack())
+ if ((!T.isNull() && T->containsUnexpandedParameterPack()) || InLambda)
return inherited::TraverseType(T);
return true;
@@ -126,8 +129,9 @@ namespace {
/// \brief Suppress traversel into types with location information
/// that do not contain unexpanded parameter packs.
bool TraverseTypeLoc(TypeLoc TL) {
- if (!TL.getType().isNull() &&
- TL.getType()->containsUnexpandedParameterPack())
+ if ((!TL.getType().isNull() &&
+ TL.getType()->containsUnexpandedParameterPack()) ||
+ InLambda)
return inherited::TraverseTypeLoc(TL);
return true;
@@ -136,10 +140,10 @@ namespace {
/// \brief Suppress traversal of non-parameter declarations, since
/// they cannot contain unexpanded parameter packs.
bool TraverseDecl(Decl *D) {
- if (D && isa<ParmVarDecl>(D))
+ if ((D && isa<ParmVarDecl>(D)) || InLambda)
return inherited::TraverseDecl(D);
- return true;
+ return true;
}
/// \brief Suppress traversal of template argument pack expansions.
@@ -157,17 +161,57 @@ namespace {
return inherited::TraverseTemplateArgumentLoc(ArgLoc);
}
+
+ /// \brief Note whether we're traversing a lambda containing an unexpanded
+ /// parameter pack. In this case, the unexpanded pack can occur anywhere,
+ /// including all the places where we normally wouldn't look. Within a
+ /// lambda, we don't propagate the 'contains unexpanded parameter pack' bit
+ /// outside an expression.
+ bool TraverseLambdaExpr(LambdaExpr *Lambda) {
+ // The ContainsUnexpandedParameterPack bit on a lambda is always correct,
+ // even if it's contained within another lambda.
+ if (!Lambda->containsUnexpandedParameterPack())
+ return true;
+
+ bool WasInLambda = InLambda;
+ InLambda = true;
+
+ // If any capture names a function parameter pack, that pack is expanded
+ // when the lambda is expanded.
+ for (LambdaExpr::capture_iterator I = Lambda->capture_begin(),
+ E = Lambda->capture_end(); I != E; ++I)
+ if (VarDecl *VD = I->getCapturedVar())
+ if (VD->isParameterPack())
+ Unexpanded.push_back(std::make_pair(VD, I->getLocation()));
+
+ inherited::TraverseLambdaExpr(Lambda);
+
+ InLambda = WasInLambda;
+ return true;
+ }
};
}
/// \brief Diagnose all of the unexpanded parameter packs in the given
/// vector.
-void
+bool
Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
UnexpandedParameterPackContext UPPC,
ArrayRef<UnexpandedParameterPack> Unexpanded) {
if (Unexpanded.empty())
- return;
+ return false;
+
+ // If we are within a lambda expression, that lambda contains an unexpanded
+ // parameter pack, and we are done.
+ // FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
+ // later.
+ for (unsigned N = FunctionScopes.size(); N; --N) {
+ if (sema::LambdaScopeInfo *LSI =
+ dyn_cast<sema::LambdaScopeInfo>(FunctionScopes[N-1])) {
+ LSI->ContainsUnexpandedParameterPack = true;
+ return false;
+ }
+ }
SmallVector<SourceLocation, 4> Locations;
SmallVector<IdentifierInfo *, 4> Names;
@@ -200,6 +244,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
for (unsigned I = 0, N = Locations.size(); I != N; ++I)
DB << SourceRange(Locations[I]);
+ return true;
}
bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
@@ -215,8 +260,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(
T->getTypeLoc());
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
- return true;
+ return DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
}
bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
@@ -230,8 +274,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(E->getLocStart(), UPPC, Unexpanded);
- return true;
+ return DiagnoseUnexpandedParameterPacks(E->getLocStart(), UPPC, Unexpanded);
}
bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
@@ -247,9 +290,8 @@ bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseNestedNameSpecifier(SS.getScopeRep());
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(),
- UPPC, Unexpanded);
- return true;
+ return DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(),
+ UPPC, Unexpanded);
}
bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
@@ -284,8 +326,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseType(NameInfo.getName().getCXXNameType());
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(NameInfo.getLoc(), UPPC, Unexpanded);
- return true;
+ return DiagnoseUnexpandedParameterPacks(NameInfo.getLoc(), UPPC, Unexpanded);
}
bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
@@ -299,8 +340,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseTemplateName(Template);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
- return true;
+ return DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
}
bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
@@ -313,8 +353,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseTemplateArgumentLoc(Arg);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(Arg.getLocation(), UPPC, Unexpanded);
- return true;
+ return DiagnoseUnexpandedParameterPacks(Arg.getLocation(), UPPC, Unexpanded);
}
void Sema::collectUnexpandedParameterPacks(TemplateArgument Arg,
@@ -597,12 +636,13 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
return false;
}
-unsigned Sema::getNumArgumentsInExpansion(QualType T,
+llvm::Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs) {
QualType Pattern = cast<PackExpansionType>(T)->getPattern();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern);
+ llvm::Optional<unsigned> Result;
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
// Compute the depth and index for this parameter pack.
unsigned Depth;
@@ -621,9 +661,14 @@ unsigned Sema::getNumArgumentsInExpansion(QualType T,
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
= CurrentInstantiationScope->findInstantiationOf(
Unexpanded[I].first.get<NamedDecl *>());
- if (Instantiation->is<DeclArgumentPack *>())
- return Instantiation->get<DeclArgumentPack *>()->size();
-
+ if (Instantiation->is<Decl*>())
+ // The pattern refers to an unexpanded pack. We're not ready to expand
+ // this pack yet.
+ return llvm::Optional<unsigned>();
+
+ unsigned Size = Instantiation->get<DeclArgumentPack *>()->size();
+ assert((!Result || *Result == Size) && "inconsistent pack sizes");
+ Result = Size;
continue;
}
@@ -631,13 +676,17 @@ unsigned Sema::getNumArgumentsInExpansion(QualType T,
}
if (Depth >= TemplateArgs.getNumLevels() ||
!TemplateArgs.hasTemplateArgument(Depth, Index))
- continue;
+ // The pattern refers to an unknown template argument. We're not ready to
+ // expand this pack yet.
+ return llvm::Optional<unsigned>();
// Determine the size of the argument pack.
- return TemplateArgs(Depth, Index).pack_size();
+ unsigned Size = TemplateArgs(Depth, Index).pack_size();
+ assert((!Result || *Result == Size) && "inconsistent pack sizes");
+ Result = Size;
}
- llvm_unreachable("No unexpanded parameter packs in type expansion.");
+ return Result;
}
bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 1400e7e..20fe036 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -35,19 +35,19 @@
using namespace clang;
/// isOmittedBlockReturnType - Return true if this declarator is missing a
-/// return type because this is a omitted return type on a block literal.
+/// return type because this is a omitted return type on a block literal.
static bool isOmittedBlockReturnType(const Declarator &D) {
if (D.getContext() != Declarator::BlockLiteralContext ||
D.getDeclSpec().hasTypeSpecifier())
return false;
-
+
if (D.getNumTypeObjects() == 0)
return true; // ^{ ... }
-
+
if (D.getNumTypeObjects() == 1 &&
D.getTypeObject(0).Kind == DeclaratorChunk::Function)
return true; // ^(int X, float Y) { ... }
-
+
return false;
}
@@ -59,12 +59,12 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
unsigned diagID = 0;
switch (attr.getKind()) {
- case AttributeList::AT_objc_gc:
+ case AttributeList::AT_ObjCGC:
diagID = diag::warn_pointer_attribute_wrong_type;
useExpansionLoc = true;
break;
- case AttributeList::AT_objc_ownership:
+ case AttributeList::AT_ObjCOwnership:
diagID = diag::warn_objc_object_attribute_wrong_type;
useExpansionLoc = true;
break;
@@ -93,19 +93,19 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
// objc_gc applies to Objective-C pointers or, otherwise, to the
// smallest available pointer type (i.e. 'void*' in 'void**').
#define OBJC_POINTER_TYPE_ATTRS_CASELIST \
- case AttributeList::AT_objc_gc: \
- case AttributeList::AT_objc_ownership
+ case AttributeList::AT_ObjCGC: \
+ case AttributeList::AT_ObjCOwnership
// Function type attributes.
#define FUNCTION_TYPE_ATTRS_CASELIST \
- case AttributeList::AT_noreturn: \
- case AttributeList::AT_cdecl: \
- case AttributeList::AT_fastcall: \
- case AttributeList::AT_stdcall: \
- case AttributeList::AT_thiscall: \
- case AttributeList::AT_pascal: \
- case AttributeList::AT_regparm: \
- case AttributeList::AT_pcs \
+ case AttributeList::AT_NoReturn: \
+ case AttributeList::AT_CDecl: \
+ case AttributeList::AT_FastCall: \
+ case AttributeList::AT_StdCall: \
+ case AttributeList::AT_ThisCall: \
+ case AttributeList::AT_Pascal: \
+ case AttributeList::AT_Regparm: \
+ case AttributeList::AT_Pcs \
namespace {
/// An object which stores processing state for the entire
@@ -284,9 +284,9 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
static bool handleObjCPointerTypeAttr(TypeProcessingState &state,
AttributeList &attr, QualType &type) {
- if (attr.getKind() == AttributeList::AT_objc_gc)
+ if (attr.getKind() == AttributeList::AT_ObjCGC)
return handleObjCGCTypeAttr(state, attr, type);
- assert(attr.getKind() == AttributeList::AT_objc_ownership);
+ assert(attr.getKind() == AttributeList::AT_ObjCOwnership);
return handleObjCOwnershipTypeAttr(state, attr, type);
}
@@ -412,7 +412,7 @@ static void distributeFunctionTypeAttr(TypeProcessingState &state,
continue;
}
}
-
+
diagnoseBadTypeAttribute(state.getSema(), attr, type);
}
@@ -505,7 +505,7 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
- case AttributeList::AT_ns_returns_retained:
+ case AttributeList::AT_NSReturnsRetained:
if (!state.getSema().getLangOpts().ObjCAutoRefCount)
break;
// fallthrough
@@ -554,7 +554,8 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
// ...and *prepend* it to the declarator.
declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction(
/*proto*/ true,
- /*variadic*/ false, SourceLocation(),
+ /*variadic*/ false,
+ /*ambiguous*/ false, SourceLocation(),
/*args*/ 0, 0,
/*type quals*/ 0,
/*ref-qualifier*/true, SourceLocation(),
@@ -573,7 +574,8 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/// \brief Convert the specified declspec to the appropriate type
/// object.
-/// \param D the declarator containing the declaration specifier.
+/// \param state Specifies the declarator containing the declaration specifier
+/// to be converted, along with other associated processing state.
/// \returns The type described by the declaration specifiers. This function
/// never returns null.
static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
@@ -586,7 +588,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
SourceLocation DeclLoc = declarator.getIdentifierLoc();
if (DeclLoc.isInvalid())
DeclLoc = DS.getLocStart();
-
+
ASTContext &Context = S.Context;
QualType Result;
@@ -639,7 +641,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.getObjCObjectPointerType(Result);
break;
}
-
+
// If this is a missing declspec in a block literal return context, then it
// is inferred from the return statements inside the block.
// The declspec is always missing in a lambda expr context; it is either
@@ -695,7 +697,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TSW_long: Result = Context.LongTy; break;
case DeclSpec::TSW_longlong:
Result = Context.LongLongTy;
-
+
// long long is a C99 feature.
if (!S.getLangOpts().C99)
S.Diag(DS.getTypeSpecWidthLoc(),
@@ -710,7 +712,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break;
case DeclSpec::TSW_longlong:
Result = Context.UnsignedLongLongTy;
-
+
// long long is a C99 feature.
if (!S.getLangOpts().C99)
S.Diag(DS.getTypeSpecWidthLoc(),
@@ -762,10 +764,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// If the type is deprecated or unavailable, diagnose it.
S.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeNameLoc());
-
+
assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
DS.getTypeSpecSign() == 0 && "No qualifiers on tag names!");
-
+
// TypeQuals handled by caller.
Result = Context.getTypeDeclType(D);
@@ -858,7 +860,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.IntTy;
declarator.setInvalidType(true);
}
- break;
+ break;
case DeclSpec::TST_auto: {
// TypeQuals handled by caller.
@@ -878,7 +880,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.IntTy;
declarator.setInvalidType(true);
}
- break;
+ break;
case DeclSpec::TST_error:
Result = Context.IntTy;
@@ -983,15 +985,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// C90 6.5.3 constraints: "The same type qualifier shall not appear more
// than once in the same specifier-list or qualifier-list, either directly
// or via one or more typedefs."
- if (!S.getLangOpts().C99 && !S.getLangOpts().CPlusPlus
+ if (!S.getLangOpts().C99 && !S.getLangOpts().CPlusPlus
&& TypeQuals & Result.getCVRQualifiers()) {
if (TypeQuals & DeclSpec::TQ_const && Result.isConstQualified()) {
- S.Diag(DS.getConstSpecLoc(), diag::ext_duplicate_declspec)
+ S.Diag(DS.getConstSpecLoc(), diag::ext_duplicate_declspec)
<< "const";
}
if (TypeQuals & DeclSpec::TQ_volatile && Result.isVolatileQualified()) {
- S.Diag(DS.getVolatileSpecLoc(), diag::ext_duplicate_declspec)
+ S.Diag(DS.getVolatileSpecLoc(), diag::ext_duplicate_declspec)
<< "volatile";
}
@@ -1036,7 +1038,7 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
if (!PTy->getPointeeType()->isIncompleteOrObjectType()) {
DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
ProblemTy = T->getAs<PointerType>()->getPointeeType();
- }
+ }
} else if (!Ty->isDependentType()) {
// FIXME: this deserves a proper diagnostic
DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
@@ -1083,7 +1085,7 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type,
// If we are in an unevaluated context, like sizeof, skip adding a
// qualification.
- } else if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) {
+ } else if (S.isUnevaluatedContext()) {
return type;
// If that failed, give an error and recover using __strong. __strong
@@ -1157,14 +1159,14 @@ QualType Sema::BuildPointerType(QualType T,
QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
SourceLocation Loc,
DeclarationName Entity) {
- assert(Context.getCanonicalType(T) != Context.OverloadTy &&
+ assert(Context.getCanonicalType(T) != Context.OverloadTy &&
"Unresolved overloaded function type");
-
+
// C++0x [dcl.ref]p6:
- // If a typedef (7.1.3), a type template-parameter (14.3.1), or a
- // decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a
- // type T, an attempt to create the type "lvalue reference to cv TR" creates
- // the type "lvalue reference to T", while an attempt to create the type
+ // If a typedef (7.1.3), a type template-parameter (14.3.1), or a
+ // decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a
+ // type T, an attempt to create the type "lvalue reference to cv TR" creates
+ // the type "lvalue reference to T", while an attempt to create the type
// "rvalue reference to cv TR" creates the type TR.
bool LValueRef = SpelledAsLValue || T->getAs<LValueReferenceType>();
@@ -1205,9 +1207,20 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) {
// If the size is an ICE, it certainly isn't a VLA. If we're in a GNU mode
// (like gnu99, but not c99) accept any evaluatable value as an extension.
- return S.VerifyIntegerConstantExpression(
- ArraySize, &SizeVal, S.PDiag(), S.LangOpts.GNUMode,
- S.PDiag(diag::ext_vla_folded_to_constant)).isInvalid();
+ class VLADiagnoser : public Sema::VerifyICEDiagnoser {
+ public:
+ VLADiagnoser() : Sema::VerifyICEDiagnoser(true) {}
+
+ virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) {
+ }
+
+ virtual void diagnoseFold(Sema &S, SourceLocation Loc, SourceRange SR) {
+ S.Diag(Loc, diag::ext_vla_folded_to_constant) << SR;
+ }
+ } Diagnoser;
+
+ return S.VerifyIntegerConstantExpression(ArraySize, &SizeVal, Diagnoser,
+ S.LangOpts.GNUMode).isInvalid();
}
@@ -1219,9 +1232,7 @@ static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) {
///
/// \param ArraySize Expression describing the size of the array.
///
-/// \param Loc The location of the entity whose type involves this
-/// array type or, if there is no such entity, the location of the
-/// type that will have array type.
+/// \param Brackets The range from the opening '[' to the closing ']'.
///
/// \param Entity The name of the entity that involves the array
/// type, if known.
@@ -1236,25 +1247,30 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
if (getLangOpts().CPlusPlus) {
// C++ [dcl.array]p1:
// T is called the array element type; this type shall not be a reference
- // type, the (possibly cv-qualified) type void, a function type or an
+ // type, the (possibly cv-qualified) type void, a function type or an
// abstract class type.
//
+ // C++ [dcl.array]p3:
+ // When several "array of" specifications are adjacent, [...] only the
+ // first of the constant expressions that specify the bounds of the arrays
+ // may be omitted.
+ //
// Note: function types are handled in the common path with C.
if (T->isReferenceType()) {
Diag(Loc, diag::err_illegal_decl_array_of_references)
<< getPrintableNameForEntity(Entity) << T;
return QualType();
}
-
- if (T->isVoidType()) {
+
+ if (T->isVoidType() || T->isIncompleteArrayType()) {
Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T;
return QualType();
}
-
- if (RequireNonAbstractType(Brackets.getBegin(), T,
+
+ if (RequireNonAbstractType(Brackets.getBegin(), T,
diag::err_array_of_abstract_type))
return QualType();
-
+
} else {
// C99 6.7.5.2p1: If the element type is an incomplete or function type,
// reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
@@ -1350,7 +1366,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
if (ConstVal == 0) {
// GCC accepts zero sized static arrays. We allow them when
// we're not in a SFINAE context.
- Diag(ArraySize->getLocStart(),
+ Diag(ArraySize->getLocStart(),
isSFINAEContext()? diag::err_typecheck_zero_array_size
: diag::ext_typecheck_zero_array_size)
<< ArraySize->getSourceRange();
@@ -1361,9 +1377,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
<< ArraySize->getSourceRange();
ASM = ArrayType::Normal;
}
- } else if (!T->isDependentType() && !T->isVariablyModifiedType() &&
+ } else if (!T->isDependentType() && !T->isVariablyModifiedType() &&
!T->isIncompleteType()) {
- // Is the array too large?
+ // Is the array too large?
unsigned ActiveSizeBits
= ConstantArrayType::getNumAddressingBits(Context, T, ConstVal);
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context))
@@ -1371,7 +1387,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
<< ConstVal.toString(10)
<< ArraySize->getSourceRange();
}
-
+
T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
}
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
@@ -1379,13 +1395,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
if (T->isVariableArrayType()) {
// Prohibit the use of non-POD types in VLAs.
QualType BaseT = Context.getBaseElementType(T);
- if (!T->isDependentType() &&
+ if (!T->isDependentType() &&
!BaseT.isPODType(Context) &&
!BaseT->isObjCLifetimeType()) {
Diag(Loc, diag::err_vla_non_pod)
<< BaseT;
return QualType();
- }
+ }
// Prohibit the use of VLAs during template argument deduction.
else if (isSFINAEContext()) {
Diag(Loc, diag::err_vla_in_sfinae);
@@ -1480,7 +1496,7 @@ QualType Sema::BuildFunctionType(QualType T,
SourceLocation Loc, DeclarationName Entity,
FunctionType::ExtInfo Info) {
if (T->isArrayType() || T->isFunctionType()) {
- Diag(Loc, diag::err_func_returning_array_function)
+ Diag(Loc, diag::err_func_returning_array_function)
<< T->isFunctionType() << T;
return QualType();
}
@@ -1581,18 +1597,14 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
///
/// \param T The type to which we'll be building a block pointer.
///
-/// \param CVR The cvr-qualifiers to be applied to the block pointer type.
-///
-/// \param Loc The location of the entity whose type involves this
-/// block pointer type or, if there is no such entity, the location of the
-/// type that will have block pointer type.
+/// \param Loc The source location, used for diagnostics.
///
/// \param Entity The name of the entity that involves the block pointer
/// type, if known.
///
/// \returns A suitable block pointer type, if there are no
/// errors. Otherwise, returns a NULL type.
-QualType Sema::BuildBlockPointerType(QualType T,
+QualType Sema::BuildBlockPointerType(QualType T,
SourceLocation Loc,
DeclarationName Entity) {
if (!T->isFunctionType()) {
@@ -1688,7 +1700,7 @@ static void inferARCWriteback(TypeProcessingState &state,
// Otherwise, modify the type in-place.
Qualifiers qs;
-
+
if (declSpecType->isObjCARCImplicitlyUnretainedType())
qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone);
else
@@ -1711,7 +1723,7 @@ static void inferARCWriteback(TypeProcessingState &state,
return;
for (const AttributeList *attr = chunk.getAttrs(); attr;
attr = attr->getNext())
- if (attr->getKind() == AttributeList::AT_objc_ownership)
+ if (attr->getKind() == AttributeList::AT_ObjCOwnership)
return;
transferARCOwnershipToDeclaratorChunk(state, Qualifiers::OCL_Autoreleasing,
@@ -1786,7 +1798,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
T = ConvertDeclSpecToType(state);
-
+
if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) {
OwnedTagDecl = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
// Owned declaration is embedded in declarator.
@@ -1798,14 +1810,16 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case UnqualifiedId::IK_ConstructorTemplateId:
case UnqualifiedId::IK_DestructorName:
// Constructors and destructors don't have return types. Use
- // "void" instead.
+ // "void" instead.
T = SemaRef.Context.VoidTy;
+ if (AttributeList *attrs = D.getDeclSpec().getAttributes().getList())
+ processTypeAttrs(state, T, true, attrs);
break;
case UnqualifiedId::IK_ConversionFunctionId:
// The result type of a conversion function is the type that it
// converts to.
- T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId,
+ T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId,
&ReturnTypeInfo);
break;
}
@@ -1890,7 +1904,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
if (DeclType.Kind == DeclaratorChunk::Function) {
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
- if (FTI.TrailingReturnType) {
+ if (FTI.hasTrailingReturnType()) {
Error = -1;
break;
}
@@ -2029,6 +2043,102 @@ static void checkQualifiedFunction(Sema &S, QualType T,
<< getFunctionQualifiersAsString(T->castAs<FunctionProtoType>());
}
+/// Produce an approprioate diagnostic for an ambiguity between a function
+/// declarator and a C++ direct-initializer.
+static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
+ DeclaratorChunk &DeclType, QualType RT) {
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ assert(FTI.isAmbiguous && "no direct-initializer / function ambiguity");
+
+ // If the return type is void there is no ambiguity.
+ if (RT->isVoidType())
+ return;
+
+ // An initializer for a non-class type can have at most one argument.
+ if (!RT->isRecordType() && FTI.NumArgs > 1)
+ return;
+
+ // An initializer for a reference must have exactly one argument.
+ if (RT->isReferenceType() && FTI.NumArgs != 1)
+ return;
+
+ // Only warn if this declarator is declaring a function at block scope, and
+ // doesn't have a storage class (such as 'extern') specified.
+ if (!D.isFunctionDeclarator() ||
+ D.getFunctionDefinitionKind() != FDK_Declaration ||
+ !S.CurContext->isFunctionOrMethod() ||
+ D.getDeclSpec().getStorageClassSpecAsWritten()
+ != DeclSpec::SCS_unspecified)
+ return;
+
+ // Inside a condition, a direct initializer is not permitted. We allow one to
+ // be parsed in order to give better diagnostics in condition parsing.
+ if (D.getContext() == Declarator::ConditionContext)
+ return;
+
+ SourceRange ParenRange(DeclType.Loc, DeclType.EndLoc);
+
+ S.Diag(DeclType.Loc,
+ FTI.NumArgs ? diag::warn_parens_disambiguated_as_function_declaration
+ : diag::warn_empty_parens_are_function_decl)
+ << ParenRange;
+
+ // If the declaration looks like:
+ // T var1,
+ // f();
+ // and name lookup finds a function named 'f', then the ',' was
+ // probably intended to be a ';'.
+ if (!D.isFirstDeclarator() && D.getIdentifier()) {
+ FullSourceLoc Comma(D.getCommaLoc(), S.SourceMgr);
+ FullSourceLoc Name(D.getIdentifierLoc(), S.SourceMgr);
+ if (Comma.getFileID() != Name.getFileID() ||
+ Comma.getSpellingLineNumber() != Name.getSpellingLineNumber()) {
+ LookupResult Result(S, D.getIdentifier(), SourceLocation(),
+ Sema::LookupOrdinaryName);
+ if (S.LookupName(Result, S.getCurScope()))
+ S.Diag(D.getCommaLoc(), diag::note_empty_parens_function_call)
+ << FixItHint::CreateReplacement(D.getCommaLoc(), ";")
+ << D.getIdentifier();
+ }
+ }
+
+ if (FTI.NumArgs > 0) {
+ // For a declaration with parameters, eg. "T var(T());", suggest adding parens
+ // around the first parameter to turn the declaration into a variable
+ // declaration.
+ SourceRange Range = FTI.ArgInfo[0].Param->getSourceRange();
+ SourceLocation B = Range.getBegin();
+ SourceLocation E = S.PP.getLocForEndOfToken(Range.getEnd());
+ // FIXME: Maybe we should suggest adding braces instead of parens
+ // in C++11 for classes that don't have an initializer_list constructor.
+ S.Diag(B, diag::note_additional_parens_for_variable_declaration)
+ << FixItHint::CreateInsertion(B, "(")
+ << FixItHint::CreateInsertion(E, ")");
+ } else {
+ // For a declaration without parameters, eg. "T var();", suggest replacing the
+ // parens with an initializer to turn the declaration into a variable
+ // declaration.
+ const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
+
+ // Empty parens mean value-initialization, and no parens mean
+ // default initialization. These are equivalent if the default
+ // constructor is user-provided or if zero-initialization is a
+ // no-op.
+ if (RD && RD->hasDefinition() &&
+ (RD->isEmpty() || RD->hasUserProvidedDefaultConstructor()))
+ S.Diag(DeclType.Loc, diag::note_empty_parens_default_ctor)
+ << FixItHint::CreateRemoval(ParenRange);
+ else {
+ std::string Init = S.getFixItZeroInitializerForType(RT);
+ if (Init.empty() && S.LangOpts.CPlusPlus0x)
+ Init = "{}";
+ if (!Init.empty())
+ S.Diag(DeclType.Loc, diag::note_empty_parens_zero_initialize)
+ << FixItHint::CreateReplacement(ParenRange, Init);
+ }
+ }
+}
+
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
@@ -2165,12 +2275,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// trailing-return-type is only required if we're declaring a function,
// and not, for instance, a pointer to a function.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
- !FTI.TrailingReturnType && chunkIndex == 0) {
+ !FTI.hasTrailingReturnType() && chunkIndex == 0) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_auto_missing_trailing_return);
T = Context.IntTy;
D.setInvalidType(true);
- } else if (FTI.TrailingReturnType) {
+ } else if (FTI.hasTrailingReturnType()) {
// T must be exactly 'auto' at this point. See CWG issue 681.
if (isa<ParenType>(T)) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
@@ -2184,10 +2294,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
}
-
- T = S.GetTypeFromParser(
- ParsedType::getFromOpaquePtr(FTI.TrailingReturnType),
- &TInfo);
+ T = S.GetTypeFromParser(FTI.getTrailingReturnType(), &TInfo);
+ if (T.isNull()) {
+ // An error occurred parsing the trailing return type.
+ T = Context.IntTy;
+ D.setInvalidType(true);
+ }
}
}
@@ -2259,6 +2371,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< (D.getContext() == Declarator::AliasDeclContext ||
D.getContext() == Declarator::AliasTemplateContext);
+ // If we see "T var();" or "T var(T());" at block scope, it is probably
+ // an attempt to initialize a variable, not a function declaration.
+ if (FTI.isAmbiguous)
+ warnAboutAmbiguousFunction(S, D, DeclType, T);
+
if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T);
@@ -2270,7 +2387,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
bool Overloadable = false;
for (const AttributeList *Attrs = D.getAttributes();
Attrs; Attrs = Attrs->getNext()) {
- if (Attrs->getKind() == AttributeList::AT_overloadable) {
+ if (Attrs->getKind() == AttributeList::AT_Overloadable) {
Overloadable = true;
break;
}
@@ -2290,12 +2407,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = FTI.isVariadic;
- EPI.HasTrailingReturn = FTI.TrailingReturnType;
+ EPI.HasTrailingReturn = FTI.hasTrailingReturnType();
EPI.TypeQuals = FTI.TypeQuals;
EPI.RefQualifier = !FTI.hasRefQualifier()? RQ_None
: FTI.RefQualifierIsLValueRef? RQ_LValue
: RQ_RValue;
-
+
// Otherwise, we have a function with an argument list that is
// potentially variadic.
SmallVector<QualType, 16> ArgTys;
@@ -2311,7 +2428,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
assert(!ArgTy.isNull() && "Couldn't parse type?");
// Adjust the parameter type.
- assert((ArgTy == Context.getAdjustedParameterType(ArgTy)) &&
+ assert((ArgTy == Context.getAdjustedParameterType(ArgTy)) &&
"Unadjusted type?");
// Look for 'void'. void is allowed only as a single argument to a
@@ -2374,7 +2491,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
SmallVector<ParsedType, 2> DynamicExceptions;
SmallVector<SourceRange, 2> DynamicExceptionRanges;
Expr *NoexceptExpr = 0;
-
+
if (FTI.getExceptionSpecType() == EST_Dynamic) {
// FIXME: It's rather inefficient to have to split into two vectors
// here.
@@ -2388,14 +2505,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
} else if (FTI.getExceptionSpecType() == EST_ComputedNoexcept) {
NoexceptExpr = FTI.NoexceptExpr;
}
-
+
S.checkExceptionSpecification(FTI.getExceptionSpecType(),
DynamicExceptions,
DynamicExceptionRanges,
NoexceptExpr,
Exceptions,
EPI);
-
+
if (FTI.getExceptionSpecType() == EST_None &&
ImplicitlyNoexcept && chunkIndex == 0) {
// Only the outermost chunk is marked noexcept, of course.
@@ -2475,7 +2592,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>();
assert(FnTy && "Why oh why is there not a FunctionProtoType here?");
- // C++ 8.3.5p4:
+ // C++ 8.3.5p4:
// A cv-qualifier-seq shall only be part of the function type
// for a nonstatic member function, the function type to which a pointer
// to member refers, or the top-level function type of a function typedef
@@ -2503,7 +2620,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Rebuild function type adding a 'const' qualifier.
FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
EPI.TypeQuals |= DeclSpec::TQ_const;
- T = Context.getFunctionType(FnTy->getResultType(),
+ T = Context.getFunctionType(FnTy->getResultType(),
FnTy->arg_type_begin(),
FnTy->getNumArgs(), EPI);
}
@@ -2540,7 +2657,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc());
if (!RemovalLocs.empty()) {
std::sort(RemovalLocs.begin(), RemovalLocs.end(),
- SourceManager::LocBeforeThanCompare(S.getSourceManager()));
+ BeforeThanCompare<SourceLocation>(S.getSourceManager()));
RemovalRange = SourceRange(RemovalLocs.front(), RemovalLocs.back());
Loc = RemovalLocs.front();
}
@@ -2556,7 +2673,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
- T = Context.getFunctionType(FnTy->getResultType(),
+ T = Context.getFunctionType(FnTy->getResultType(),
FnTy->arg_type_begin(),
FnTy->getNumArgs(), EPI);
}
@@ -2572,31 +2689,31 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C++0x [dcl.constexpr]p9:
// A constexpr specifier used in an object declaration declares the object
- // as const.
+ // as const.
if (D.getDeclSpec().isConstexprSpecified() && T->isObjectType()) {
T.addConst();
}
- // If there was an ellipsis in the declarator, the declaration declares a
+ // If there was an ellipsis in the declarator, the declaration declares a
// parameter pack whose type may be a pack expansion type.
if (D.hasEllipsis() && !T.isNull()) {
// C++0x [dcl.fct]p13:
- // A declarator-id or abstract-declarator containing an ellipsis shall
+ // A declarator-id or abstract-declarator containing an ellipsis shall
// only be used in a parameter-declaration. Such a parameter-declaration
// is a parameter pack (14.5.3). [...]
switch (D.getContext()) {
case Declarator::PrototypeContext:
// C++0x [dcl.fct]p13:
- // [...] When it is part of a parameter-declaration-clause, the
- // parameter pack is a function parameter pack (14.5.3). The type T
+ // [...] When it is part of a parameter-declaration-clause, the
+ // parameter pack is a function parameter pack (14.5.3). The type T
// of the declarator-id of the function parameter pack shall contain
- // a template parameter pack; each template parameter pack in T is
+ // a template parameter pack; each template parameter pack in T is
// expanded by the function parameter pack.
//
// We represent function parameter packs as function parameters whose
// type is a pack expansion.
if (!T->containsUnexpandedParameterPack()) {
- S.Diag(D.getEllipsisLoc(),
+ S.Diag(D.getEllipsisLoc(),
diag::err_function_parameter_pack_without_parameter_packs)
<< T << D.getSourceRange();
D.setEllipsisLoc(SourceLocation());
@@ -2604,10 +2721,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
T = Context.getPackExpansionType(T, llvm::Optional<unsigned>());
}
break;
-
+
case Declarator::TemplateParamContext:
// C++0x [temp.param]p15:
- // If a template-parameter is a [...] is a parameter-declaration that
+ // If a template-parameter is a [...] is a parameter-declaration that
// declares a parameter pack (8.3.5), then the template-parameter is a
// template parameter pack (14.5.3).
//
@@ -2622,7 +2739,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
break;
-
+
case Declarator::FileContext:
case Declarator::KNRTypeListContext:
case Declarator::ObjCParameterContext: // FIXME: special diagnostic here?
@@ -2675,7 +2792,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
if (D.isPrototypeContext() && getLangOpts().ObjCAutoRefCount)
inferARCWriteback(state, T);
-
+
return GetFullTypeForDeclarator(state, T, ReturnTypeInfo);
}
@@ -2700,7 +2817,7 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
DeclaratorChunk &chunk = D.getTypeObject(chunkIndex);
for (const AttributeList *attr = chunk.getAttrs(); attr;
attr = attr->getNext())
- if (attr->getKind() == AttributeList::AT_objc_ownership)
+ if (attr->getKind() == AttributeList::AT_ObjCOwnership)
return;
const char *attrStr = 0;
@@ -2718,14 +2835,13 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
.create(&S.Context.Idents.get("objc_ownership"), SourceLocation(),
/*scope*/ 0, SourceLocation(),
&S.Context.Idents.get(attrStr), SourceLocation(),
- /*args*/ 0, 0,
- /*declspec*/ false, /*C++0x*/ false);
+ /*args*/ 0, 0, AttributeList::AS_GNU);
spliceAttrIntoList(*attr, chunk.getAttrListRef());
// TODO: mark whether we did this inference?
}
-/// \brief Used for transfering ownership in casts resulting in l-values.
+/// \brief Used for transferring ownership in casts resulting in l-values.
static void transferARCOwnership(TypeProcessingState &state,
QualType &declSpecTy,
Qualifiers::ObjCLifetime ownership) {
@@ -2763,7 +2879,7 @@ static void transferARCOwnership(TypeProcessingState &state,
if (inner == -1)
return;
- DeclaratorChunk &chunk = D.getTypeObject(inner);
+ DeclaratorChunk &chunk = D.getTypeObject(inner);
if (chunk.Kind == DeclaratorChunk::Pointer) {
if (declSpecTy->isObjCRetainableType())
return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
@@ -2797,33 +2913,33 @@ TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) {
static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
switch (kind) {
case AttributedType::attr_address_space:
- return AttributeList::AT_address_space;
+ return AttributeList::AT_AddressSpace;
case AttributedType::attr_regparm:
- return AttributeList::AT_regparm;
+ return AttributeList::AT_Regparm;
case AttributedType::attr_vector_size:
- return AttributeList::AT_vector_size;
+ return AttributeList::AT_VectorSize;
case AttributedType::attr_neon_vector_type:
- return AttributeList::AT_neon_vector_type;
+ return AttributeList::AT_NeonVectorType;
case AttributedType::attr_neon_polyvector_type:
- return AttributeList::AT_neon_polyvector_type;
+ return AttributeList::AT_NeonPolyVectorType;
case AttributedType::attr_objc_gc:
- return AttributeList::AT_objc_gc;
+ return AttributeList::AT_ObjCGC;
case AttributedType::attr_objc_ownership:
- return AttributeList::AT_objc_ownership;
+ return AttributeList::AT_ObjCOwnership;
case AttributedType::attr_noreturn:
- return AttributeList::AT_noreturn;
+ return AttributeList::AT_NoReturn;
case AttributedType::attr_cdecl:
- return AttributeList::AT_cdecl;
+ return AttributeList::AT_CDecl;
case AttributedType::attr_fastcall:
- return AttributeList::AT_fastcall;
+ return AttributeList::AT_FastCall;
case AttributedType::attr_stdcall:
- return AttributeList::AT_stdcall;
+ return AttributeList::AT_StdCall;
case AttributedType::attr_thiscall:
- return AttributeList::AT_thiscall;
+ return AttributeList::AT_ThisCall;
case AttributedType::attr_pascal:
- return AttributeList::AT_pascal;
+ return AttributeList::AT_Pascal;
case AttributedType::attr_pcs:
- return AttributeList::AT_pcs;
+ return AttributeList::AT_Pcs;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -2856,7 +2972,7 @@ namespace {
const DeclSpec &DS;
public:
- TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS)
+ TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS)
: Context(Context), DS(DS) {}
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
@@ -2871,6 +2987,10 @@ namespace {
}
void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ // FIXME. We should have DS.getTypeSpecTypeEndLoc(). But, it requires
+ // addition field. What we have is good enough for dispay of location
+ // of 'fixit' on interface name.
+ TL.setNameEndLoc(DS.getLocEnd());
}
void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
// Handle the base type, which might not have been written explicitly.
@@ -3000,7 +3120,7 @@ namespace {
void VisitAtomicTypeLoc(AtomicTypeLoc TL) {
TL.setKWLoc(DS.getTypeSpecTypeLoc());
TL.setParensRange(DS.getTypeofParensRange());
-
+
TypeSourceInfo *TInfo = 0;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
@@ -3104,7 +3224,7 @@ namespace {
assert(Chunk.Kind == DeclaratorChunk::Function);
TL.setLocalRangeBegin(Chunk.Loc);
TL.setLocalRangeEnd(Chunk.EndLoc);
- TL.setTrailingReturn(!!Chunk.Fun.TrailingReturnType);
+ TL.setTrailingReturn(Chunk.Fun.hasTrailingReturnType());
const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun;
for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) {
@@ -3142,9 +3262,9 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
// Handle parameter packs whose type is a pack expansion.
if (isa<PackExpansionType>(T)) {
cast<PackExpansionTypeLoc>(CurrTL).setEllipsisLoc(D.getEllipsisLoc());
- CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
+ CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
}
-
+
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
while (isa<AttributedTypeLoc>(CurrTL)) {
AttributedTypeLoc TL = cast<AttributedTypeLoc>(CurrTL);
@@ -3155,7 +3275,7 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL);
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
}
-
+
// If we have different source information for the return type, use
// that. This really only applies to C++ conversion functions.
if (ReturnTypeInfo) {
@@ -3165,7 +3285,7 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
} else {
TypeSpecLocFiller(Context, D.getDeclSpec()).Visit(CurrTL);
}
-
+
return TInfo;
}
@@ -3174,7 +3294,7 @@ ParsedType Sema::CreateParsedType(QualType T, TypeSourceInfo *TInfo) {
// FIXME: LocInfoTypes are "transient", only needed for passing to/from Parser
// and Sema during declaration parsing. Try deallocating/caching them when
// it's appropriate, instead of allocating them and keeping them around.
- LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType),
+ LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType),
TypeAlignment);
new (LocT) LocInfoType(T, TInfo);
assert(LocT->getTypeClass() != T->getTypeClass() &&
@@ -3304,13 +3424,13 @@ static bool hasDirectOwnershipQualifier(QualType type) {
// X *__strong (...)
} else if (const ParenType *paren = dyn_cast<ParenType>(type)) {
type = paren->getInnerType();
-
+
// That's it for things we want to complain about. In particular,
// we do not want to look through typedefs, typeof(expr),
// typeof(type), or any other way that the type is somehow
// abstracted.
} else {
-
+
return false;
}
}
@@ -3439,8 +3559,8 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
attr.setInvalid();
return true;
}
-
- // Forbid __weak for class objects marked as
+
+ // Forbid __weak for class objects marked as
// objc_arc_weak_reference_unavailable
if (lifetime == Qualifiers::OCL_Weak) {
QualType T = type;
@@ -3450,12 +3570,12 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
if (Class->isArcWeakrefUnavailable()) {
S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
- S.Diag(ObjT->getInterfaceDecl()->getLocation(),
+ S.Diag(ObjT->getInterfaceDecl()->getLocation(),
diag::note_class_declared);
}
}
}
-
+
return true;
}
@@ -3654,7 +3774,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
FunctionTypeUnwrapper unwrapped(S, type);
- if (attr.getKind() == AttributeList::AT_noreturn) {
+ if (attr.getKind() == AttributeList::AT_NoReturn) {
if (S.CheckNoReturnAttr(attr))
return true;
@@ -3670,7 +3790,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
// ns_returns_retained is not always a type attribute, but if we got
// here, we're treating it as one right now.
- if (attr.getKind() == AttributeList::AT_ns_returns_retained) {
+ if (attr.getKind() == AttributeList::AT_NSReturnsRetained) {
assert(S.getLangOpts().ObjCAutoRefCount &&
"ns_returns_retained treated as type attribute in non-ARC");
if (attr.getNumArgs()) return true;
@@ -3685,7 +3805,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
return true;
}
- if (attr.getKind() == AttributeList::AT_regparm) {
+ if (attr.getKind() == AttributeList::AT_Regparm) {
unsigned value;
if (S.CheckRegparmAttr(attr, value))
return true;
@@ -3705,7 +3825,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
return true;
}
- FunctionType::ExtInfo EI =
+ FunctionType::ExtInfo EI =
unwrapped.get()->getExtInfo().withRegParm(value);
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
return true;
@@ -3860,11 +3980,11 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr,
/// \brief Process the OpenCL-like ext_vector_type attribute when it occurs on
/// a type.
-static void HandleExtVectorTypeAttr(QualType &CurType,
- const AttributeList &Attr,
+static void HandleExtVectorTypeAttr(QualType &CurType,
+ const AttributeList &Attr,
Sema &S) {
Expr *sizeExpr;
-
+
// Special case where the argument is a template id.
if (Attr.getParameterName()) {
CXXScopeSpec SS;
@@ -3876,7 +3996,7 @@ static void HandleExtVectorTypeAttr(QualType &CurType,
id, false, false);
if (Size.isInvalid())
return;
-
+
sizeExpr = Size.get();
} else {
// check the attribute arguments.
@@ -3886,7 +4006,7 @@ static void HandleExtVectorTypeAttr(QualType &CurType,
}
sizeExpr = Attr.getArg(0);
}
-
+
// Create the vector type.
QualType T = S.BuildExtVectorType(CurType, sizeExpr, Attr.getLoc());
if (!T.isNull())
@@ -3973,12 +4093,12 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
switch (attr.getKind()) {
default: break;
- case AttributeList::AT_may_alias:
+ case AttributeList::AT_MayAlias:
// FIXME: This attribute needs to actually be handled, but if we ignore
// it it breaks large amounts of Linux software.
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_address_space:
+ case AttributeList::AT_AddressSpace:
HandleAddressSpaceTypeAttribute(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
break;
@@ -3987,35 +4107,42 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
distributeObjCPointerTypeAttr(state, attr, type);
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_vector_size:
+ case AttributeList::AT_VectorSize:
HandleVectorSizeAttr(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_ext_vector_type:
+ case AttributeList::AT_ExtVectorType:
if (state.getDeclarator().getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_typedef)
HandleExtVectorTypeAttr(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_neon_vector_type:
+ case AttributeList::AT_NeonVectorType:
HandleNeonVectorTypeAttr(type, attr, state.getSema(),
VectorType::NeonVector, "neon_vector_type");
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_neon_polyvector_type:
+ case AttributeList::AT_NeonPolyVectorType:
HandleNeonVectorTypeAttr(type, attr, state.getSema(),
VectorType::NeonPolyVector,
"neon_polyvector_type");
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_opencl_image_access:
+ case AttributeList::AT_OpenCLImageAccess:
HandleOpenCLImageAccessAttribute(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_ns_returns_retained:
+ case AttributeList::AT_Win64:
+ case AttributeList::AT_Ptr32:
+ case AttributeList::AT_Ptr64:
+ // FIXME: don't ignore these
+ attr.setUsedAsTypeAttr();
+ break;
+
+ case AttributeList::AT_NSReturnsRetained:
if (!state.getSema().getLangOpts().ObjCAutoRefCount)
- break;
+ break;
// fallthrough into the function attrs
FUNCTION_TYPE_ATTRS_CASELIST:
@@ -4043,14 +4170,12 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
/// case of a reference type, the referred-to type).
///
/// \param E The expression whose type is required to be complete.
-/// \param PD The partial diagnostic that will be printed out if the type cannot
-/// be completed.
+/// \param Diagnoser The object that will emit a diagnostic if the type is
+/// incomplete.
///
/// \returns \c true if the type of \p E is incomplete and diagnosed, \c false
/// otherwise.
-bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
- std::pair<SourceLocation,
- PartialDiagnostic> Note) {
+bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser){
QualType T = E->getType();
// Fast path the case where the type is already complete.
@@ -4065,7 +4190,7 @@ bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
if (Var->isStaticDataMember() &&
Var->getInstantiatedFromStaticDataMember()) {
-
+
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
assert(MSInfo && "Missing member specialization information?");
if (MSInfo->getTemplateSpecializationKind()
@@ -4073,15 +4198,15 @@ bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
// If we don't already have a point of instantiation, this is it.
if (MSInfo->getPointOfInstantiation().isInvalid()) {
MSInfo->setPointOfInstantiation(E->getLocStart());
-
- // This is a modification of an existing AST node. Notify
+
+ // This is a modification of an existing AST node. Notify
// listeners.
if (ASTMutationListener *L = getASTMutationListener())
L->StaticDataMemberInstantiated(Var);
}
-
+
InstantiateStaticDataMemberDefinition(E->getExprLoc(), Var);
-
+
// Update the type to the newly instantiated definition's type both
// here and within the expression.
if (VarDecl *Def = Var->getDefinition()) {
@@ -4091,7 +4216,7 @@ bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
E->setType(T);
}
}
-
+
// We still go on to try to complete the type independently, as it
// may also require instantiations or diagnostics if it remains
// incomplete.
@@ -4107,7 +4232,26 @@ bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
if (const ReferenceType *Ref = T->getAs<ReferenceType>())
T = Ref->getPointeeType();
- return RequireCompleteType(E->getExprLoc(), T, PD, Note);
+ return RequireCompleteType(E->getExprLoc(), T, Diagnoser);
+}
+
+namespace {
+ struct TypeDiagnoserDiag : Sema::TypeDiagnoser {
+ unsigned DiagID;
+
+ TypeDiagnoserDiag(unsigned DiagID)
+ : Sema::TypeDiagnoser(DiagID == 0), DiagID(DiagID) {}
+
+ virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) {
+ if (Suppressed) return;
+ S.Diag(Loc, DiagID) << T;
+ }
+ };
+}
+
+bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) {
+ TypeDiagnoserDiag Diagnoser(DiagID);
+ return RequireCompleteExprType(E, Diagnoser);
}
/// @brief Ensure that the type T is a complete type.
@@ -4125,17 +4269,10 @@ bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
///
/// @param T The type that this routine is examining for completeness.
///
-/// @param PD The partial diagnostic that will be printed out if T is not a
-/// complete type.
-///
/// @returns @c true if @p T is incomplete and a diagnostic was emitted,
/// @c false otherwise.
bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
- const PartialDiagnostic &PD,
- std::pair<SourceLocation,
- PartialDiagnostic> Note) {
- unsigned diag = PD.getDiagID();
-
+ TypeDiagnoser &Diagnoser) {
// FIXME: Add this assertion to make sure we always get instantiation points.
// assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType");
// FIXME: Add this assertion to help us flush out problems with
@@ -4148,9 +4285,9 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
NamedDecl *Def = 0;
if (!T->isIncompleteType(&Def)) {
// If we know about the definition but it is not visible, complain.
- if (diag != 0 && Def && !LookupResult::isVisible(Def)) {
+ if (!Diagnoser.Suppressed && Def && !LookupResult::isVisible(Def)) {
// Suppress this error outside of a SFINAE context if we've already
- // emitted the error once for this type. There's no usefulness in
+ // emitted the error once for this type. There's no usefulness in
// repeating the diagnostic.
// FIXME: Add a Fix-It that imports the corresponding module or includes
// the header.
@@ -4159,13 +4296,13 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
Diag(Def->getLocation(), diag::note_previous_definition);
}
}
-
+
return false;
}
const TagType *Tag = T->getAs<TagType>();
const ObjCInterfaceType *IFace = 0;
-
+
if (Tag) {
// Avoid diagnosing invalid decls as incomplete.
if (Tag->getDecl()->isInvalidDecl())
@@ -4182,7 +4319,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
// Avoid diagnosing invalid decls as incomplete.
if (IFace->getDecl()->isInvalidDecl())
return true;
-
+
// Give the external AST source a chance to complete the type.
if (IFace->getDecl()->hasExternalLexicalStorage()) {
Context.getExternalSource()->CompleteType(IFace->getDecl());
@@ -4190,7 +4327,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return false;
}
}
-
+
// If we have a class template specialization or a class member of a
// class template specialization, or an array with known size of such,
// try to instantiate it.
@@ -4204,7 +4341,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared)
return InstantiateClassTemplateSpecialization(Loc, ClassTemplateSpec,
TSK_ImplicitInstantiation,
- /*Complain=*/diag != 0);
+ /*Complain=*/!Diagnoser.Suppressed);
} else if (CXXRecordDecl *Rec
= dyn_cast<CXXRecordDecl>(Record->getDecl())) {
CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass();
@@ -4216,21 +4353,17 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return InstantiateClass(Loc, Rec, Pattern,
getTemplateInstantiationArgs(Rec),
TSK_ImplicitInstantiation,
- /*Complain=*/diag != 0);
+ /*Complain=*/!Diagnoser.Suppressed);
}
}
}
- if (diag == 0)
+ if (Diagnoser.Suppressed)
return true;
-
+
// We have an incomplete type. Produce a diagnostic.
- Diag(Loc, PD) << T;
-
- // If we have a note, produce it.
- if (!Note.first.isInvalid())
- Diag(Note.first, Note.second);
-
+ Diagnoser.diagnose(*this, Loc, T);
+
// If the type was a forward declaration of a class/struct/union
// type, produce a note.
if (Tag && !Tag->getDecl()->isInvalidDecl())
@@ -4238,7 +4371,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
Tag->isBeingDefined() ? diag::note_type_being_defined
: diag::note_forward_declaration)
<< QualType(Tag, 0);
-
+
// If the Objective-C class was a forward declaration, produce a note.
if (IFace && !IFace->getDecl()->isInvalidDecl())
Diag(IFace->getDecl()->getLocation(), diag::note_forward_class);
@@ -4247,15 +4380,9 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
}
bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
- const PartialDiagnostic &PD) {
- return RequireCompleteType(Loc, T, PD,
- std::make_pair(SourceLocation(), PDiag(0)));
-}
-
-bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
unsigned DiagID) {
- return RequireCompleteType(Loc, T, PDiag(DiagID),
- std::make_pair(SourceLocation(), PDiag(0)));
+ TypeDiagnoserDiag Diagnoser(DiagID);
+ return RequireCompleteType(Loc, T, Diagnoser);
}
/// @brief Ensure that the type T is a literal type.
@@ -4272,13 +4399,12 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
///
/// @param T The type that this routine is examining for literalness.
///
-/// @param PD The partial diagnostic that will be printed out if T is not a
-/// literal type.
+/// @param Diagnoser Emits a diagnostic if T is not a literal type.
///
/// @returns @c true if @p T is not a literal type and a diagnostic was emitted,
/// @c false otherwise.
bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
- const PartialDiagnostic &PD) {
+ TypeDiagnoser &Diagnoser) {
assert(!T->isDependentType() && "type should not be dependent");
QualType ElemType = Context.getBaseElementType(T);
@@ -4287,10 +4413,10 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
if (T->isLiteralType())
return false;
- if (PD.getDiagID() == 0)
+ if (Diagnoser.Suppressed)
return true;
- Diag(Loc, PD) << T;
+ Diagnoser.diagnose(*this, Loc, T);
if (T->isVariableArrayType())
return true;
@@ -4301,9 +4427,13 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- // FIXME: Better diagnostic for incomplete class?
- if (!RD->isCompleteDefinition())
+ // A partially-defined class type can't be a literal type, because a literal
+ // class type must have a trivial destructor (which can't be checked until
+ // the class definition is complete).
+ if (!RD->isCompleteDefinition()) {
+ RequireCompleteType(Loc, ElemType, diag::note_non_literal_incomplete, T);
return true;
+ }
// If the class has virtual base classes, then it's not an aggregate, and
// cannot have any constexpr constructors or a trivial default constructor,
@@ -4331,11 +4461,11 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
}
for (CXXRecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I) {
- if (!(*I)->getType()->isLiteralType() ||
- (*I)->getType().isVolatileQualified()) {
- Diag((*I)->getLocation(), diag::note_non_literal_field)
- << RD << (*I) << (*I)->getType()
- << (*I)->getType().isVolatileQualified();
+ if (!I->getType()->isLiteralType() ||
+ I->getType().isVolatileQualified()) {
+ Diag(I->getLocation(), diag::note_non_literal_field)
+ << RD << *I << I->getType()
+ << I->getType().isVolatileQualified();
return true;
}
}
@@ -4355,6 +4485,11 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
return true;
}
+bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID) {
+ TypeDiagnoserDiag Diagnoser(DiagID);
+ return RequireLiteralType(Loc, T, Diagnoser);
+}
+
/// \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,
@@ -4396,8 +4531,8 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
// The type denoted by decltype(e) is defined as follows:
//
// - if e is an unparenthesized id-expression or an unparenthesized class
- // member access (5.2.5), decltype(e) is the type of the entity named
- // by e. If there is no such entity, or if e names a set of overloaded
+ // member access (5.2.5), decltype(e) is the type of the entity named
+ // by e. If there is no such entity, or if e names a set of overloaded
// functions, the program is ill-formed;
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
@@ -4407,7 +4542,7 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
return FD->getType();
}
-
+
// C++11 [expr.lambda.prim]p18:
// Every occurrence of decltype((x)) where x is a possibly
// parenthesized id-expression that names an entity of automatic
@@ -4433,16 +4568,16 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
// [...]
QualType T = E->getType();
switch (E->getValueKind()) {
- // - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the
+ // - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the
// type of e;
case VK_XValue: T = S.Context.getRValueReferenceType(T); break;
- // - otherwise, if e is an lvalue, decltype(e) is T&, where T is the
+ // - otherwise, if e is an lvalue, decltype(e) is T&, where T is the
// type of e;
case VK_LValue: T = S.Context.getLValueReferenceType(T); break;
// - otherwise, decltype(e) is the type of e.
case VK_RValue: break;
}
-
+
return T;
}
@@ -4450,7 +4585,7 @@ QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) {
ExprResult ER = CheckPlaceholderExpr(E);
if (ER.isInvalid()) return QualType();
E = ER.take();
-
+
return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
}
@@ -4482,8 +4617,7 @@ QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
if (!T->isDependentType()) {
// FIXME: It isn't entirely clear whether incomplete atomic types
// are allowed or not; for simplicity, ban them for the moment.
- if (RequireCompleteType(Loc, T,
- PDiag(diag::err_atomic_specifier_bad_type) << 0))
+ if (RequireCompleteType(Loc, T, diag::err_atomic_specifier_bad_type, 0))
return QualType();
int DisallowedKind = -1;
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
index 8b19be7..25ace95 100644
--- a/lib/Sema/TargetAttributesSema.cpp
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -151,6 +151,18 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D,
S.Context));
}
+DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range) {
+ if (D->hasAttr<DLLExportAttr>()) {
+ Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport";
+ return NULL;
+ }
+
+ if (D->hasAttr<DLLImportAttr>())
+ return NULL;
+
+ return ::new (Context) DLLImportAttr(Range, Context);
+}
+
static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
@@ -159,13 +171,8 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
// Attribute can be applied only to functions or variables.
- if (isa<VarDecl>(D)) {
- D->addAttr(::new (S.Context) DLLImportAttr(Attr.getLoc(), S.Context));
- return;
- }
-
FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD) {
+ if (!FD && !isa<VarDecl>(D)) {
// Apparently Visual C++ thinks it is okay to not emit a warning
// in this case, so only emit a warning when -fms-extensions is not
// specified.
@@ -177,27 +184,26 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Currently, the dllimport attribute is ignored for inlined functions.
// Warning is emitted.
- if (FD->isInlineSpecified()) {
+ if (FD && FD->isInlineSpecified()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
return;
}
- // The attribute is also overridden by a subsequent declaration as dllexport.
- // Warning is emitted.
- for (AttributeList *nextAttr = Attr.getNext(); nextAttr;
- nextAttr = nextAttr->getNext()) {
- if (nextAttr->getKind() == AttributeList::AT_dllexport) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
- return;
- }
- }
+ DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange());
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
- if (D->getAttr<DLLExportAttr>()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
- return;
+DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range) {
+ if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
+ Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport";
+ D->dropAttr<DLLImportAttr>();
}
- D->addAttr(::new (S.Context) DLLImportAttr(Attr.getLoc(), S.Context));
+ if (D->hasAttr<DLLExportAttr>())
+ return NULL;
+
+ return ::new (Context) DLLExportAttr(Range, Context);
}
static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
@@ -208,13 +214,8 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
// Attribute can be applied only to functions or variables.
- if (isa<VarDecl>(D)) {
- D->addAttr(::new (S.Context) DLLExportAttr(Attr.getLoc(), S.Context));
- return;
- }
-
FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD) {
+ if (!FD && !isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
@@ -222,13 +223,15 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Currently, the dllexport attribute is ignored for inlined functions, unless
// the -fkeep-inline-functions flag has been used. Warning is emitted;
- if (FD->isInlineSpecified()) {
+ if (FD && FD->isInlineSpecified()) {
// FIXME: ... unless the -fkeep-inline-functions flag has been used.
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
return;
}
- D->addAttr(::new (S.Context) DLLExportAttr(Attr.getLoc(), S.Context));
+ DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange());
+ if (NewAttr)
+ D->addAttr(NewAttr);
}
namespace {
@@ -241,9 +244,9 @@ namespace {
if (Triple.getOS() == llvm::Triple::Win32 ||
Triple.getOS() == llvm::Triple::MinGW32) {
switch (Attr.getKind()) {
- case AttributeList::AT_dllimport: HandleDLLImportAttr(D, Attr, S);
+ case AttributeList::AT_DLLImport: HandleDLLImportAttr(D, Attr, S);
return true;
- case AttributeList::AT_dllexport: HandleDLLExportAttr(D, Attr, S);
+ case AttributeList::AT_DLLExport: HandleDLLExportAttr(D, Attr, S);
return true;
default: break;
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index a66378e..90d5840 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -98,25 +98,25 @@ class TreeTransform {
class ForgetPartiallySubstitutedPackRAII {
Derived &Self;
TemplateArgument Old;
-
+
public:
ForgetPartiallySubstitutedPackRAII(Derived &Self) : Self(Self) {
Old = Self.ForgetPartiallySubstitutedPack();
}
-
+
~ForgetPartiallySubstitutedPackRAII() {
Self.RememberPartiallySubstitutedPack(Old);
}
};
-
+
protected:
Sema &SemaRef;
-
+
/// \brief The set of local declarations that have been transformed, for
/// cases where we are forced to build new declarations within the transformer
/// rather than in the subclass (e.g., lambda closure types).
llvm::DenseMap<Decl *, Decl *> TransformedLocalDecls;
-
+
public:
/// \brief Initializes a new tree transformer.
TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { }
@@ -177,7 +177,7 @@ public:
DeclarationName Entity) : Self(Self) {
OldLocation = Self.getDerived().getBaseLocation();
OldEntity = Self.getDerived().getBaseEntity();
-
+
if (Location.isValid())
Self.getDerived().setBase(Location, Entity);
}
@@ -207,7 +207,7 @@ public:
bool DropCallArgument(Expr *E) {
return E->isDefaultArgument();
}
-
+
/// \brief Determine whether we should expand a pack expansion with the
/// given set of parameter packs into separate arguments by repeatedly
/// transforming the pattern.
@@ -221,12 +221,9 @@ public:
/// \param PatternRange The source range that covers the entire pattern of
/// the pack expansion.
///
- /// \param Unexpanded The set of unexpanded parameter packs within the
+ /// \param Unexpanded The set of unexpanded parameter packs within the
/// pattern.
///
- /// \param NumUnexpanded The number of unexpanded parameter packs in
- /// \p Unexpanded.
- ///
/// \param ShouldExpand Will be set to \c true if the transformer should
/// expand the corresponding pack expansions into separate arguments. When
/// set, \c NumExpansions must also be set.
@@ -244,9 +241,9 @@ public:
/// The callee must set this value when \c ShouldExpand is \c true; it may
/// set this value in other cases.
///
- /// \returns true if an error occurred (e.g., because the parameter packs
- /// are to be instantiated with arguments of different lengths), false
- /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions)
+ /// \returns true if an error occurred (e.g., because the parameter packs
+ /// are to be instantiated with arguments of different lengths), false
+ /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions)
/// must be set.
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
@@ -257,7 +254,7 @@ public:
ShouldExpand = false;
return false;
}
-
+
/// \brief "Forget" about the partially-substituted pack template argument,
/// when performing an instantiation that must preserve the parameter pack
/// use.
@@ -266,18 +263,18 @@ public:
TemplateArgument ForgetPartiallySubstitutedPack() {
return TemplateArgument();
}
-
+
/// \brief "Remember" the partially-substituted pack template argument
/// after performing an instantiation that must preserve the parameter pack
/// use.
///
/// This routine is meant to be overridden by the template instantiator.
void RememberPartiallySubstitutedPack(TemplateArgument Arg) { }
-
+
/// \brief Note to the derived class when a function parameter pack is
/// being expanded.
void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { }
-
+
/// \brief Transforms the given type into another type.
///
/// By default, this routine transforms a type by creating a
@@ -328,8 +325,8 @@ public:
/// \brief Transform the given list of expressions.
///
- /// This routine transforms a list of expressions by invoking
- /// \c TransformExpr() for each subexpression. However, it also provides
+ /// This routine transforms a list of expressions by invoking
+ /// \c TransformExpr() for each subexpression. However, it also provides
/// support for variadic templates by expanding any pack expansions (if the
/// derived class permits such expansion) along the way. When pack expansions
/// are present, the number of outputs may not equal the number of inputs.
@@ -339,7 +336,7 @@ public:
/// \param NumInputs The number of expressions in \c Inputs.
///
/// \param IsCall If \c true, then this transform is being performed on
- /// function-call arguments, and any arguments that should be dropped, will
+ /// function-call arguments, and any arguments that should be dropped, will
/// be.
///
/// \param Outputs The transformed input expressions will be added to this
@@ -352,61 +349,61 @@ public:
bool TransformExprs(Expr **Inputs, unsigned NumInputs, bool IsCall,
SmallVectorImpl<Expr *> &Outputs,
bool *ArgChanged = 0);
-
+
/// \brief Transform the given declaration, which is referenced from a type
/// or expression.
///
/// By default, acts as the identity function on declarations, unless the
/// transformer has had to transform the declaration itself. Subclasses
/// may override this function to provide alternate behavior.
- Decl *TransformDecl(SourceLocation Loc, Decl *D) {
+ Decl *TransformDecl(SourceLocation Loc, Decl *D) {
llvm::DenseMap<Decl *, Decl *>::iterator Known
= TransformedLocalDecls.find(D);
if (Known != TransformedLocalDecls.end())
return Known->second;
-
- return D;
+
+ return D;
}
- /// \brief Transform the attributes associated with the given declaration and
+ /// \brief Transform the attributes associated with the given declaration and
/// place them on the new declaration.
///
/// By default, this operation does nothing. Subclasses may override this
/// behavior to transform attributes.
void transformAttrs(Decl *Old, Decl *New) { }
-
+
/// \brief Note that a local declaration has been transformed by this
/// transformer.
///
- /// Local declarations are typically transformed via a call to
+ /// Local declarations are typically transformed via a call to
/// TransformDefinition. However, in some cases (e.g., lambda expressions),
/// the transformer itself has to transform the declarations. This routine
/// can be overridden by a subclass that keeps track of such mappings.
void transformedLocalDecl(Decl *Old, Decl *New) {
TransformedLocalDecls[Old] = New;
}
-
+
/// \brief Transform the definition of the given declaration.
///
/// By default, invokes TransformDecl() to transform the declaration.
/// Subclasses may override this function to provide alternate behavior.
- Decl *TransformDefinition(SourceLocation Loc, Decl *D) {
- return getDerived().TransformDecl(Loc, D);
+ Decl *TransformDefinition(SourceLocation Loc, Decl *D) {
+ return getDerived().TransformDecl(Loc, D);
}
/// \brief Transform the given declaration, which was the first part of a
/// nested-name-specifier in a member access expression.
///
- /// This specific declaration transformation only applies to the first
+ /// This specific declaration transformation only applies to the first
/// identifier in a nested-name-specifier of a member access expression, e.g.,
/// the \c T in \c x->T::member
///
/// By default, invokes TransformDecl() to transform the declaration.
/// Subclasses may override this function to provide alternate behavior.
- NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc) {
- return cast_or_null<NamedDecl>(getDerived().TransformDecl(Loc, D));
+ NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc) {
+ return cast_or_null<NamedDecl>(getDerived().TransformDecl(Loc, D));
}
-
+
/// \brief Transform the given nested-name-specifier with source-location
/// information.
///
@@ -436,7 +433,7 @@ public:
///
/// \param NameLoc The source location of the template name.
///
- /// \param ObjectType If we're translating a template name within a member
+ /// \param ObjectType If we're translating a template name within a member
/// access expression, this is the type of the object whose member template
/// is being referenced.
///
@@ -466,7 +463,7 @@ public:
/// \brief Transform the given set of template arguments.
///
- /// By default, this operation transforms all of the template arguments
+ /// By default, this operation transforms all of the template arguments
/// in the input set using \c TransformTemplateArgument(), and appends
/// the transformed arguments to the output list.
///
@@ -490,9 +487,9 @@ public:
/// \brief Transform the given set of template arguments.
///
- /// By default, this operation transforms all of the template arguments
+ /// By default, this operation transforms all of the template arguments
/// in the input set using \c TransformTemplateArgument(), and appends
- /// the transformed arguments to the output list.
+ /// the transformed arguments to the output list.
///
/// \param First An iterator to the first template argument.
///
@@ -530,18 +527,18 @@ public:
StmtResult
TransformSEHHandler(Stmt *Handler);
- QualType
+ QualType
TransformTemplateSpecializationType(TypeLocBuilder &TLB,
TemplateSpecializationTypeLoc TL,
TemplateName Template);
- QualType
+ QualType
TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
DependentTemplateSpecializationTypeLoc TL,
TemplateName Template,
CXXScopeSpec &SS);
- QualType
+ QualType
TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
DependentTemplateSpecializationTypeLoc TL,
NestedNameSpecifierLoc QualifierLoc);
@@ -574,6 +571,9 @@ public:
StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
+ /// \brief Transform the captures and body of a lambda expression.
+ ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
+
#define STMT(Node, Parent) \
StmtResult Transform##Node(Node *S);
#define EXPR(Node, Parent) \
@@ -784,8 +784,8 @@ public:
ElaboratedTypeKeyword Keyword,
NestedNameSpecifierLoc QualifierLoc,
QualType Named) {
- return SemaRef.Context.getElaboratedType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
+ return SemaRef.Context.getElaboratedType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
Named);
}
@@ -804,30 +804,30 @@ public:
// TODO: avoid TemplateName abstraction
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- TemplateName InstName
+ TemplateName InstName
= getDerived().RebuildTemplateName(SS, *Name, NameLoc, QualType(), 0);
-
+
if (InstName.isNull())
return QualType();
-
+
// If it's still dependent, make a dependent specialization.
if (InstName.getAsDependentTemplateName())
- return SemaRef.Context.getDependentTemplateSpecializationType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
- Name,
+ return SemaRef.Context.getDependentTemplateSpecializationType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
+ Name,
Args);
-
+
// Otherwise, make an elaborated type wrapping a non-dependent
// specialization.
QualType T =
getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args);
if (T.isNull()) return QualType();
-
+
if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == 0)
return T;
-
- return SemaRef.Context.getElaboratedType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
+
+ return SemaRef.Context.getElaboratedType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
T);
}
@@ -847,8 +847,8 @@ public:
if (QualifierLoc.getNestedNameSpecifier()->isDependent()) {
// If the name is still dependent, just build a new dependent name type.
if (!SemaRef.computeDeclContext(SS))
- return SemaRef.Context.getDependentNameType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
+ return SemaRef.Context.getDependentNameType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
Id);
}
@@ -875,15 +875,15 @@ public:
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
break;
-
+
case LookupResult::Found:
Tag = Result.getAsSingle<TagDecl>();
break;
-
+
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
llvm_unreachable("Tag lookup cannot find non-tags");
-
+
case LookupResult::Ambiguous:
// Let the LookupResult structure handle ambiguities.
return QualType();
@@ -925,8 +925,8 @@ public:
// Build the elaborated-type-specifier type.
QualType T = SemaRef.Context.getTypeDeclType(Tag);
- return SemaRef.Context.getElaboratedType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
+ return SemaRef.Context.getElaboratedType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
T);
}
@@ -934,7 +934,7 @@ public:
///
/// By default, builds a new PackExpansionType type from the given pattern.
/// Subclasses may override this routine to provide different behavior.
- QualType RebuildPackExpansionType(QualType Pattern,
+ QualType RebuildPackExpansionType(QualType Pattern,
SourceRange PatternRange,
SourceLocation EllipsisLoc,
llvm::Optional<unsigned> NumExpansions) {
@@ -984,7 +984,7 @@ public:
QualType ObjectType);
/// \brief Build a new template name given a template template parameter pack
- /// and the
+ /// and the
///
/// By default, performs semantic analysis to determine whether the name can
/// be resolved to a specific template, then builds the appropriate kind of
@@ -1053,7 +1053,8 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildAttributedStmt(SourceLocation AttrLoc, const AttrVec &Attrs,
+ StmtResult RebuildAttributedStmt(SourceLocation AttrLoc,
+ ArrayRef<const Attr*> Attrs,
Stmt *SubStmt) {
return SemaRef.ActOnAttributedStmt(AttrLoc, Attrs, SubStmt);
}
@@ -1063,7 +1064,7 @@ public:
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond,
- VarDecl *CondVar, Stmt *Then,
+ VarDecl *CondVar, Stmt *Then,
SourceLocation ElseLoc, Stmt *Else) {
return getSema().ActOnIfStmt(IfLoc, Cond, CondVar, Then, ElseLoc, Else);
}
@@ -1074,7 +1075,7 @@ public:
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc,
Expr *Cond, VarDecl *CondVar) {
- return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Cond,
+ return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Cond,
CondVar);
}
@@ -1112,10 +1113,10 @@ public:
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
- Stmt *Init, Sema::FullExprArg Cond,
+ Stmt *Init, Sema::FullExprArg Cond,
VarDecl *CondVar, Sema::FullExprArg Inc,
SourceLocation RParenLoc, Stmt *Body) {
- return getSema().ActOnForStmt(ForLoc, LParenLoc, Init, Cond,
+ return getSema().ActOnForStmt(ForLoc, LParenLoc, Init, Cond,
CondVar, Inc, RParenLoc, Body);
}
@@ -1173,13 +1174,24 @@ public:
MultiExprArg Clobbers,
SourceLocation RParenLoc,
bool MSAsm) {
- return getSema().ActOnAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ return getSema().ActOnAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, move(Constraints),
Exprs, AsmString, Clobbers,
RParenLoc, MSAsm);
}
- /// \brief Build a new Objective-C @try statement.
+ /// \brief Build a new MS style inline asm statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc,
+ ArrayRef<Token> AsmToks,
+ ArrayRef<unsigned> LineEnds,
+ SourceLocation EndLoc) {
+ return getSema().ActOnMSAsmStmt(AsmLoc, AsmToks, LineEnds, EndLoc);
+ }
+
+ /// \brief Build a new Objective-C \@try statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
@@ -1202,8 +1214,8 @@ public:
ExceptionDecl->getLocation(),
ExceptionDecl->getIdentifier());
}
-
- /// \brief Build a new Objective-C @catch statement.
+
+ /// \brief Build a new Objective-C \@catch statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
@@ -1214,8 +1226,8 @@ public:
return getSema().ActOnObjCAtCatchStmt(AtLoc, RParenLoc,
Var, Body);
}
-
- /// \brief Build a new Objective-C @finally statement.
+
+ /// \brief Build a new Objective-C \@finally statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
@@ -1223,8 +1235,8 @@ public:
Stmt *Body) {
return getSema().ActOnObjCAtFinallyStmt(AtLoc, Body);
}
-
- /// \brief Build a new Objective-C @throw statement.
+
+ /// \brief Build a new Objective-C \@throw statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
@@ -1232,8 +1244,8 @@ public:
Expr *Operand) {
return getSema().BuildObjCAtThrowStmt(AtLoc, Operand);
}
-
- /// \brief Rebuild the operand to an Objective-C @synchronized statement.
+
+ /// \brief Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
@@ -1242,7 +1254,7 @@ public:
return getSema().ActOnObjCAtSynchronizedOperand(atLoc, object);
}
- /// \brief Build a new Objective-C @synchronized statement.
+ /// \brief Build a new Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
@@ -1251,7 +1263,7 @@ public:
return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object, Body);
}
- /// \brief Build a new Objective-C @autoreleasepool statement.
+ /// \brief Build a new Objective-C \@autoreleasepool statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
@@ -1260,16 +1272,6 @@ public:
return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body);
}
- /// \brief Build the collection operand to a new Objective-C fast
- /// enumeration statement.
- ///
- /// By default, performs semantic analysis to build the new statement.
- /// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildObjCForCollectionOperand(SourceLocation forLoc,
- Expr *collection) {
- return getSema().ActOnObjCForCollectionOperand(forLoc, collection);
- }
-
/// \brief Build a new Objective-C fast enumeration statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -1280,13 +1282,16 @@ public:
Expr *Collection,
SourceLocation RParenLoc,
Stmt *Body) {
- return getSema().ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
- Element,
+ StmtResult ForEachStmt = getSema().ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
+ Element,
Collection,
- RParenLoc,
- Body);
+ RParenLoc);
+ if (ForEachStmt.isInvalid())
+ return StmtError();
+
+ return getSema().FinishObjCForCollectionStmt(ForEachStmt.take(), Body);
}
-
+
/// \brief Build a new C++ exception declaration.
///
/// By default, performs semantic analysis to build the new decaration.
@@ -1342,7 +1347,7 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildMSDependentExistsStmt(SourceLocation KeywordLoc,
+ StmtResult RebuildMSDependentExistsStmt(SourceLocation KeywordLoc,
bool IsIfExists,
NestedNameSpecifierLoc QualifierLoc,
DeclarationNameInfo NameInfo,
@@ -1358,7 +1363,7 @@ public:
StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body) {
return getSema().FinishCXXForRangeStmt(ForRange, Body);
}
-
+
StmtResult RebuildSEHTryStmt(bool IsCXXTry,
SourceLocation TryLoc,
Stmt *TryBlock,
@@ -1448,8 +1453,8 @@ public:
return getSema().BuildBuiltinOffsetOf(OperatorLoc, Type, Components,
NumComponents, RParenLoc);
}
-
- /// \brief Build a new sizeof, alignof or vec_step expression with a
+
+ /// \brief Build a new sizeof, alignof or vec_step expression with a
/// type argument.
///
/// By default, performs semantic analysis to build the new expression.
@@ -1637,7 +1642,7 @@ public:
= SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc);
if (Result.isInvalid() || ResultTy->isDependentType())
return move(Result);
-
+
// Patch in the result type we were given, which may have been computed
// when the initial InitListExpr was built.
InitListExpr *ILE = cast<InitListExpr>((Expr *)Result.get());
@@ -1887,7 +1892,7 @@ public:
SourceLocation TypeidLoc,
TypeSourceInfo *Operand,
SourceLocation RParenLoc) {
- return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, Operand,
+ return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, Operand,
RParenLoc);
}
@@ -1912,7 +1917,7 @@ public:
SourceLocation TypeidLoc,
TypeSourceInfo *Operand,
SourceLocation RParenLoc) {
- return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand,
+ return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand,
RParenLoc);
}
@@ -1956,7 +1961,7 @@ public:
/// By default, builds a new default-argument expression, which does not
/// require any semantic analysis. Subclasses may override this routine to
/// provide different behavior.
- ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc,
+ ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc,
ParmVarDecl *Param) {
return getSema().Owned(CXXDefaultArgExpr::Create(getSema().Context, Loc,
Param));
@@ -2046,7 +2051,7 @@ public:
SourceLocation RParenLoc) {
return getSema().BuildTypeTrait(Trait, StartLoc, Args, RParenLoc);
}
-
+
/// \brief Build a new array type trait expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2117,10 +2122,10 @@ public:
CXXConstructExpr::ConstructionKind ConstructKind,
SourceRange ParenRange) {
ASTOwningVector<Expr*> ConvertedArgs(SemaRef);
- if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc,
+ if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc,
ConvertedArgs))
return ExprError();
-
+
return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable,
move_arg(ConvertedArgs),
HadMultipleCandidates,
@@ -2211,31 +2216,39 @@ public:
}
/// \brief Build a new expression to compute the length of a parameter pack.
- ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack,
- SourceLocation PackLoc,
+ ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack,
+ SourceLocation PackLoc,
SourceLocation RParenLoc,
llvm::Optional<unsigned> Length) {
if (Length)
- return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
- OperatorLoc, Pack, PackLoc,
+ return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
+ OperatorLoc, Pack, PackLoc,
RParenLoc, *Length);
-
- return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
- OperatorLoc, Pack, PackLoc,
+
+ return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
+ OperatorLoc, Pack, PackLoc,
RParenLoc);
}
+ /// \brief Build a new Objective-C boxed expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
+ return getSema().BuildObjCBoxedExpr(SR, ValueExpr);
+ }
+
/// \brief Build a new Objective-C array literal.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildObjCArrayLiteral(SourceRange Range,
Expr **Elements, unsigned NumElements) {
- return getSema().BuildObjCArrayLiteral(Range,
+ return getSema().BuildObjCArrayLiteral(Range,
MultiExprArg(Elements, NumElements));
}
-
- ExprResult RebuildObjCSubscriptRefExpr(SourceLocation RB,
+
+ ExprResult RebuildObjCSubscriptRefExpr(SourceLocation RB,
Expr *Base, Expr *Key,
ObjCMethodDecl *getterMethod,
ObjCMethodDecl *setterMethod) {
@@ -2252,8 +2265,8 @@ public:
unsigned NumElements) {
return getSema().BuildObjCDictionaryLiteral(Range, Elements, NumElements);
}
-
- /// \brief Build a new Objective-C @encode expression.
+
+ /// \brief Build a new Objective-C \@encode expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
@@ -2269,7 +2282,7 @@ public:
Selector Sel,
ArrayRef<SourceLocation> SelectorLocs,
ObjCMethodDecl *Method,
- SourceLocation LBracLoc,
+ SourceLocation LBracLoc,
MultiExprArg Args,
SourceLocation RBracLoc) {
return SemaRef.BuildClassMessage(ReceiverTypeInfo,
@@ -2284,7 +2297,7 @@ public:
Selector Sel,
ArrayRef<SourceLocation> SelectorLocs,
ObjCMethodDecl *Method,
- SourceLocation LBracLoc,
+ SourceLocation LBracLoc,
MultiExprArg Args,
SourceLocation RBracLoc) {
return SemaRef.BuildInstanceMessage(Receiver,
@@ -2312,15 +2325,15 @@ public:
false);
if (Result.isInvalid() || Base.isInvalid())
return ExprError();
-
+
if (Result.get())
return move(Result);
-
+
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/IvarLoc, IsArrow,
SS, SourceLocation(),
/*FirstQualifierInScope=*/0,
- R,
+ R,
/*TemplateArgs=*/0);
}
@@ -2328,7 +2341,7 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildObjCPropertyRefExpr(Expr *BaseArg,
+ ExprResult RebuildObjCPropertyRefExpr(Expr *BaseArg,
ObjCPropertyDecl *Property,
SourceLocation PropertyLoc) {
CXXScopeSpec SS;
@@ -2341,18 +2354,18 @@ public:
SS, 0, false);
if (Result.isInvalid() || Base.isInvalid())
return ExprError();
-
+
if (Result.get())
return move(Result);
-
+
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
- /*FIXME:*/PropertyLoc, IsArrow,
+ /*FIXME:*/PropertyLoc, IsArrow,
SS, SourceLocation(),
/*FirstQualifierInScope=*/0,
- R,
+ R,
/*TemplateArgs=*/0);
}
-
+
/// \brief Build a new Objective-C property reference expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2384,18 +2397,18 @@ public:
SS, 0, false);
if (Result.isInvalid() || Base.isInvalid())
return ExprError();
-
+
if (Result.get())
return move(Result);
-
+
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/IsaLoc, IsArrow,
SS, SourceLocation(),
/*FirstQualifierInScope=*/0,
- R,
+ R,
/*TemplateArgs=*/0);
}
-
+
/// \brief Build a new shuffle vector expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2437,7 +2450,7 @@ public:
/// \brief Build a new template argument pack expansion.
///
/// By default, performs semantic analysis to build a new pack expansion
- /// for a template argument. Subclasses may override this routine to provide
+ /// for a template argument. Subclasses may override this routine to provide
/// different behavior.
TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
SourceLocation EllipsisLoc,
@@ -2449,10 +2462,10 @@ public:
EllipsisLoc, NumExpansions);
if (Result.isInvalid())
return TemplateArgumentLoc();
-
+
return TemplateArgumentLoc(Result.get(), Result.get());
}
-
+
case TemplateArgument::Template:
return TemplateArgumentLoc(TemplateArgument(
Pattern.getArgument().getAsTemplate(),
@@ -2460,16 +2473,16 @@ public:
Pattern.getTemplateQualifierLoc(),
Pattern.getTemplateNameLoc(),
EllipsisLoc);
-
+
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
case TemplateArgument::Pack:
case TemplateArgument::TemplateExpansion:
llvm_unreachable("Pack expansion pattern has no parameter packs");
-
+
case TemplateArgument::Type:
- if (TypeSourceInfo *Expansion
+ if (TypeSourceInfo *Expansion
= getSema().CheckPackExpansion(Pattern.getTypeSourceInfo(),
EllipsisLoc,
NumExpansions))
@@ -2477,14 +2490,14 @@ public:
Expansion);
break;
}
-
+
return TemplateArgumentLoc();
}
-
+
/// \brief Build a new expression pack expansion.
///
/// By default, performs semantic analysis to build a new pack expansion
- /// for an expression. Subclasses may override this routine to provide
+ /// for an expression. Subclasses may override this routine to provide
/// different behavior.
ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
llvm::Optional<unsigned> NumExpansions) {
@@ -2573,8 +2586,8 @@ ExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
}
template<typename Derived>
-bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
- unsigned NumInputs,
+bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
+ unsigned NumInputs,
bool IsCall,
SmallVectorImpl<Expr *> &Outputs,
bool *ArgChanged) {
@@ -2583,17 +2596,17 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
if (IsCall && getDerived().DropCallArgument(Inputs[I])) {
if (ArgChanged)
*ArgChanged = true;
-
+
break;
}
-
+
if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(Inputs[I])) {
Expr *Pattern = Expansion->getPattern();
-
+
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
-
+
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
@@ -2607,22 +2620,22 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
Expand, RetainExpansion,
NumExpansions))
return true;
-
+
if (!Expand) {
// The transform has determined that we should perform a simple
- // transformation on the pack expansion, producing another pack
+ // transformation on the pack expansion, producing another pack
// expansion.
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
ExprResult OutPattern = getDerived().TransformExpr(Pattern);
if (OutPattern.isInvalid())
return true;
-
- ExprResult Out = getDerived().RebuildPackExpansion(OutPattern.get(),
+
+ ExprResult Out = getDerived().RebuildPackExpansion(OutPattern.get(),
Expansion->getEllipsisLoc(),
NumExpansions);
if (Out.isInvalid())
return true;
-
+
if (ArgChanged)
*ArgChanged = true;
Outputs.push_back(Out.get());
@@ -2632,7 +2645,7 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
// Record right away that the argument was changed. This needs
// to happen even if the array expands to nothing.
if (ArgChanged) *ArgChanged = true;
-
+
// The transform has determined that we should perform an elementwise
// expansion of the pattern. Do so.
for (unsigned I = 0; I != *NumExpansions; ++I) {
@@ -2647,23 +2660,23 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
if (Out.isInvalid())
return true;
}
-
+
Outputs.push_back(Out.get());
}
-
+
continue;
}
-
+
ExprResult Result = getDerived().TransformExpr(Inputs[I]);
if (Result.isInvalid())
return true;
-
+
if (Result.get() != Inputs[I] && ArgChanged)
*ArgChanged = true;
-
- Outputs.push_back(Result.get());
+
+ Outputs.push_back(Result.get());
}
-
+
return false;
}
@@ -2674,7 +2687,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
QualType ObjectType,
NamedDecl *FirstQualifierInScope) {
SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
- for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier;
+ for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier;
Qualifier = Qualifier.getPrefix())
Qualifiers.push_back(Qualifier);
@@ -2682,19 +2695,19 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
while (!Qualifiers.empty()) {
NestedNameSpecifierLoc Q = Qualifiers.pop_back_val();
NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier();
-
+
switch (QNNS->getKind()) {
case NestedNameSpecifier::Identifier:
- if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/0,
+ if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/0,
*QNNS->getAsIdentifier(),
- Q.getLocalBeginLoc(),
+ Q.getLocalBeginLoc(),
Q.getLocalEndLoc(),
- ObjectType, false, SS,
+ ObjectType, false, SS,
FirstQualifierInScope, false))
return NestedNameSpecifierLoc();
-
+
break;
-
+
case NestedNameSpecifier::Namespace: {
NamespaceDecl *NS
= cast_or_null<NamespaceDecl>(
@@ -2704,35 +2717,35 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
SS.Extend(SemaRef.Context, NS, Q.getLocalBeginLoc(), Q.getLocalEndLoc());
break;
}
-
+
case NestedNameSpecifier::NamespaceAlias: {
NamespaceAliasDecl *Alias
= cast_or_null<NamespaceAliasDecl>(
getDerived().TransformDecl(Q.getLocalBeginLoc(),
QNNS->getAsNamespaceAlias()));
- SS.Extend(SemaRef.Context, Alias, Q.getLocalBeginLoc(),
+ SS.Extend(SemaRef.Context, Alias, Q.getLocalBeginLoc(),
Q.getLocalEndLoc());
break;
}
-
+
case NestedNameSpecifier::Global:
// There is no meaningful transformation that one could perform on the
// global scope.
SS.MakeGlobal(SemaRef.Context, Q.getBeginLoc());
break;
-
+
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec: {
TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType,
FirstQualifierInScope, SS);
-
+
if (!TL)
return NestedNameSpecifierLoc();
-
+
if (TL.getType()->isDependentType() || TL.getType()->isRecordType() ||
- (SemaRef.getLangOpts().CPlusPlus0x &&
+ (SemaRef.getLangOpts().CPlusPlus0x &&
TL.getType()->isEnumeralType())) {
- assert(!TL.getType().hasLocalQualifiers() &&
+ assert(!TL.getType().hasLocalQualifiers() &&
"Can't get cv-qualifiers here");
if (TL.getType()->isEnumeralType())
SemaRef.Diag(TL.getBeginLoc(),
@@ -2745,24 +2758,24 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
// error because a previous error should have already been emitted.
TypedefTypeLoc* TTL = dyn_cast<TypedefTypeLoc>(&TL);
if (!TTL || !TTL->getTypedefNameDecl()->isInvalidDecl()) {
- SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
+ SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
<< TL.getType() << SS.getRange();
}
return NestedNameSpecifierLoc();
}
}
-
+
// The qualifier-in-scope and object type only apply to the leftmost entity.
FirstQualifierInScope = 0;
ObjectType = QualType();
}
-
+
// Don't rebuild the nested-name-specifier if we don't have to.
- if (SS.getScopeRep() == NNS.getNestedNameSpecifier() &&
+ if (SS.getScopeRep() == NNS.getNestedNameSpecifier() &&
!getDerived().AlwaysRebuild())
return NNS;
-
- // If we can re-use the source-location data from the original
+
+ // If we can re-use the source-location data from the original
// nested-name-specifier, do so.
if (SS.location_size() == NNS.getDataLength() &&
memcmp(SS.location_data(), NNS.getOpaqueData(), SS.location_size()) == 0)
@@ -2833,60 +2846,60 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
TemplateDecl *Template = QTN->getTemplateDecl();
assert(Template && "qualified template name must refer to a template");
-
+
TemplateDecl *TransTemplate
- = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc,
+ = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc,
Template));
if (!TransTemplate)
return TemplateName();
-
+
if (!getDerived().AlwaysRebuild() &&
SS.getScopeRep() == QTN->getQualifier() &&
TransTemplate == Template)
return Name;
-
+
return getDerived().RebuildTemplateName(SS, QTN->hasTemplateKeyword(),
TransTemplate);
}
-
+
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
if (SS.getScopeRep()) {
// These apply to the scope specifier, not the template.
ObjectType = QualType();
FirstQualifierInScope = 0;
- }
-
+ }
+
if (!getDerived().AlwaysRebuild() &&
SS.getScopeRep() == DTN->getQualifier() &&
ObjectType.isNull())
return Name;
-
+
if (DTN->isIdentifier()) {
return getDerived().RebuildTemplateName(SS,
- *DTN->getIdentifier(),
+ *DTN->getIdentifier(),
NameLoc,
ObjectType,
FirstQualifierInScope);
}
-
+
return getDerived().RebuildTemplateName(SS, DTN->getOperator(), NameLoc,
ObjectType);
}
-
+
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
TemplateDecl *TransTemplate
- = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc,
+ = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc,
Template));
if (!TransTemplate)
return TemplateName();
-
+
if (!getDerived().AlwaysRebuild() &&
TransTemplate == Template)
return Name;
-
+
return TemplateName(TransTemplate);
}
-
+
if (SubstTemplateTemplateParmPackStorage *SubstPack
= Name.getAsSubstTemplateTemplateParmPack()) {
TemplateTemplateParmDecl *TransParam
@@ -2894,15 +2907,15 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
getDerived().TransformDecl(NameLoc, SubstPack->getParameterPack()));
if (!TransParam)
return TemplateName();
-
+
if (!getDerived().AlwaysRebuild() &&
TransParam == SubstPack->getParameterPack())
return Name;
-
- return getDerived().RebuildTemplateName(TransParam,
+
+ return getDerived().RebuildTemplateName(TransParam,
SubstPack->getArgumentPack());
}
-
+
// These should be getting filtered out before they reach the AST.
llvm_unreachable("overloaded function decl survived to here");
}
@@ -2920,7 +2933,7 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc(
case TemplateArgument::Type:
Output = TemplateArgumentLoc(Arg,
SemaRef.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
-
+
break;
case TemplateArgument::Template:
@@ -2931,16 +2944,16 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc(
Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc);
else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Builder.MakeTrivial(SemaRef.Context, QTN->getQualifier(), Loc);
-
+
if (Arg.getKind() == TemplateArgument::Template)
- Output = TemplateArgumentLoc(Arg,
+ Output = TemplateArgumentLoc(Arg,
Builder.getWithLocInContext(SemaRef.Context),
Loc);
else
- Output = TemplateArgumentLoc(Arg,
+ Output = TemplateArgumentLoc(Arg,
Builder.getWithLocInContext(SemaRef.Context),
Loc, Loc);
-
+
break;
}
@@ -3008,7 +3021,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
if (!QualifierLoc)
return true;
}
-
+
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
TemplateName Template
@@ -3016,7 +3029,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
Input.getTemplateNameLoc());
if (Template.isNull())
return true;
-
+
Output = TemplateArgumentLoc(TemplateArgument(Template), QualifierLoc,
Input.getTemplateNameLoc());
return false;
@@ -3063,8 +3076,8 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
= new (getSema().Context) TemplateArgument[TransformedArgs.size()];
std::copy(TransformedArgs.begin(), TransformedArgs.end(),
TransformedArgsPtr);
- Output = TemplateArgumentLoc(TemplateArgument(TransformedArgsPtr,
- TransformedArgs.size()),
+ Output = TemplateArgumentLoc(TemplateArgument(TransformedArgsPtr,
+ TransformedArgs.size()),
Input.getLocInfo());
return false;
}
@@ -3080,48 +3093,48 @@ template<typename Derived, typename InputIterator>
class TemplateArgumentLocInventIterator {
TreeTransform<Derived> &Self;
InputIterator Iter;
-
+
public:
typedef TemplateArgumentLoc value_type;
typedef TemplateArgumentLoc reference;
typedef typename std::iterator_traits<InputIterator>::difference_type
difference_type;
typedef std::input_iterator_tag iterator_category;
-
+
class pointer {
TemplateArgumentLoc Arg;
-
+
public:
explicit pointer(TemplateArgumentLoc Arg) : Arg(Arg) { }
-
+
const TemplateArgumentLoc *operator->() const { return &Arg; }
};
-
+
TemplateArgumentLocInventIterator() { }
-
+
explicit TemplateArgumentLocInventIterator(TreeTransform<Derived> &Self,
InputIterator Iter)
: Self(Self), Iter(Iter) { }
-
+
TemplateArgumentLocInventIterator &operator++() {
++Iter;
return *this;
}
-
+
TemplateArgumentLocInventIterator operator++(int) {
TemplateArgumentLocInventIterator Old(*this);
++(*this);
return Old;
}
-
+
reference operator*() const {
TemplateArgumentLoc Result;
Self.InventTemplateArgumentLoc(*Iter, Result);
return Result;
}
-
+
pointer operator->() const { return pointer(**this); }
-
+
friend bool operator==(const TemplateArgumentLocInventIterator &X,
const TemplateArgumentLocInventIterator &Y) {
return X.Iter == Y.Iter;
@@ -3132,7 +3145,7 @@ public:
return X.Iter != Y.Iter;
}
};
-
+
template<typename Derived>
template<typename InputIterator>
bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
@@ -3141,39 +3154,39 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
for (; First != Last; ++First) {
TemplateArgumentLoc Out;
TemplateArgumentLoc In = *First;
-
+
if (In.getArgument().getKind() == TemplateArgument::Pack) {
// Unpack argument packs, which we translate them into separate
// arguments.
// FIXME: We could do much better if we could guarantee that the
// TemplateArgumentLocInfo for the pack expansion would be usable for
// all of the template arguments in the argument pack.
- typedef TemplateArgumentLocInventIterator<Derived,
+ typedef TemplateArgumentLocInventIterator<Derived,
TemplateArgument::pack_iterator>
PackLocIterator;
- if (TransformTemplateArguments(PackLocIterator(*this,
+ if (TransformTemplateArguments(PackLocIterator(*this,
In.getArgument().pack_begin()),
PackLocIterator(*this,
In.getArgument().pack_end()),
Outputs))
return true;
-
+
continue;
}
-
+
if (In.getArgument().isPackExpansion()) {
// We have a pack expansion, for which we will be substituting into
// the pattern.
SourceLocation Ellipsis;
llvm::Optional<unsigned> OrigNumExpansions;
TemplateArgumentLoc Pattern
- = In.getPackExpansionPattern(Ellipsis, OrigNumExpansions,
+ = In.getPackExpansionPattern(Ellipsis, OrigNumExpansions,
getSema().Context);
-
+
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
-
+
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
@@ -3182,29 +3195,29 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
if (getDerived().TryExpandParameterPacks(Ellipsis,
Pattern.getSourceRange(),
Unexpanded,
- Expand,
+ Expand,
RetainExpansion,
NumExpansions))
return true;
-
+
if (!Expand) {
// The transform has determined that we should perform a simple
- // transformation on the pack expansion, producing another pack
+ // transformation on the pack expansion, producing another pack
// expansion.
TemplateArgumentLoc OutPattern;
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
if (getDerived().TransformTemplateArgument(Pattern, OutPattern))
return true;
-
+
Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis,
NumExpansions);
if (Out.getArgument().isNull())
return true;
-
+
Outputs.addArgument(Out);
continue;
}
-
+
// The transform has determined that we should perform an elementwise
// expansion of the pattern. Do so.
for (unsigned I = 0; I != *NumExpansions; ++I) {
@@ -3212,43 +3225,43 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
if (getDerived().TransformTemplateArgument(Pattern, Out))
return true;
-
+
if (Out.getArgument().containsUnexpandedParameterPack()) {
Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
OrigNumExpansions);
if (Out.getArgument().isNull())
return true;
}
-
+
Outputs.addArgument(Out);
}
-
+
// If we're supposed to retain a pack expansion, do so by temporarily
// forgetting the partially-substituted parameter pack.
if (RetainExpansion) {
ForgetPartiallySubstitutedPackRAII Forget(getDerived());
-
+
if (getDerived().TransformTemplateArgument(Pattern, Out))
return true;
-
+
Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
OrigNumExpansions);
if (Out.getArgument().isNull())
return true;
-
+
Outputs.addArgument(Out);
}
-
+
continue;
}
-
- // The simple case:
+
+ // The simple case:
if (getDerived().TransformTemplateArgument(In, Out))
return true;
-
+
Outputs.addArgument(Out);
}
-
+
return false;
}
@@ -3266,7 +3279,7 @@ QualType TreeTransform<Derived>::TransformType(QualType T) {
// eventually turn into transformations on TypeLocs.
TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo(T,
getDerived().getBaseLocation());
-
+
TypeSourceInfo *NewDI = getDerived().TransformType(DI);
if (!NewDI)
@@ -3336,19 +3349,19 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
if (!Result->isObjCLifetimeType() && !Result->isDependentType())
Quals.removeObjCLifetime();
else if (Result.getObjCLifetime()) {
- // Objective-C ARC:
+ // Objective-C ARC:
// A lifetime qualifier applied to a substituted template parameter
// overrides the lifetime qualifier from the template argument.
- if (const SubstTemplateTypeParmType *SubstTypeParam
+ if (const SubstTemplateTypeParmType *SubstTypeParam
= dyn_cast<SubstTemplateTypeParmType>(Result)) {
QualType Replacement = SubstTypeParam->getReplacementType();
Qualifiers Qs = Replacement.getQualifiers();
Qs.removeObjCLifetime();
- Replacement
+ Replacement
= SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(),
Qs);
Result = SemaRef.Context.getSubstTemplateTypeParmType(
- SubstTypeParam->getReplacedParameter(),
+ SubstTypeParam->getReplacedParameter(),
Replacement);
TLB.TypeWasModifiedSafely(Result);
} else {
@@ -3357,7 +3370,7 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
SourceRange R = TLB.getTemporaryTypeLoc(Result).getSourceRange();
SemaRef.Diag(R.getBegin(), diag::err_attr_objc_ownership_redundant)
<< Result << R;
-
+
Quals.removeObjCLifetime();
}
}
@@ -3380,37 +3393,37 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
QualType T = TL.getType();
if (getDerived().AlreadyTransformed(T))
return TL;
-
+
TypeLocBuilder TLB;
QualType Result;
-
+
if (isa<TemplateSpecializationType>(T)) {
TemplateSpecializationTypeLoc SpecTL
= cast<TemplateSpecializationTypeLoc>(TL);
-
+
TemplateName Template =
getDerived().TransformTemplateName(SS,
SpecTL.getTypePtr()->getTemplateName(),
SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup);
- if (Template.isNull())
+ if (Template.isNull())
return TypeLoc();
-
- Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
+
+ Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
Template);
} else if (isa<DependentTemplateSpecializationType>(T)) {
DependentTemplateSpecializationTypeLoc SpecTL
= cast<DependentTemplateSpecializationTypeLoc>(TL);
-
+
TemplateName Template
- = getDerived().RebuildTemplateName(SS,
- *SpecTL.getTypePtr()->getIdentifier(),
+ = getDerived().RebuildTemplateName(SS,
+ *SpecTL.getTypePtr()->getIdentifier(),
SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup);
if (Template.isNull())
return TypeLoc();
-
- Result = getDerived().TransformDependentTemplateSpecializationType(TLB,
+
+ Result = getDerived().TransformDependentTemplateSpecializationType(TLB,
SpecTL,
Template,
SS);
@@ -3418,10 +3431,10 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
// Nothing special needs to be done for these.
Result = getDerived().TransformType(TLB, TL);
}
-
- if (Result.isNull())
+
+ if (Result.isNull())
return TypeLoc();
-
+
return TLB.getTypeSourceInfo(SemaRef.Context, Result)->getTypeLoc();
}
@@ -3432,42 +3445,42 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
NamedDecl *UnqualLookup,
CXXScopeSpec &SS) {
// FIXME: Painfully copy-paste from the above!
-
+
QualType T = TSInfo->getType();
if (getDerived().AlreadyTransformed(T))
return TSInfo;
-
+
TypeLocBuilder TLB;
QualType Result;
-
+
TypeLoc TL = TSInfo->getTypeLoc();
if (isa<TemplateSpecializationType>(T)) {
TemplateSpecializationTypeLoc SpecTL
= cast<TemplateSpecializationTypeLoc>(TL);
-
+
TemplateName Template
= getDerived().TransformTemplateName(SS,
SpecTL.getTypePtr()->getTemplateName(),
SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup);
- if (Template.isNull())
+ if (Template.isNull())
return 0;
-
- Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
+
+ Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
Template);
} else if (isa<DependentTemplateSpecializationType>(T)) {
DependentTemplateSpecializationTypeLoc SpecTL
= cast<DependentTemplateSpecializationTypeLoc>(TL);
-
+
TemplateName Template
- = getDerived().RebuildTemplateName(SS,
- *SpecTL.getTypePtr()->getIdentifier(),
+ = getDerived().RebuildTemplateName(SS,
+ *SpecTL.getTypePtr()->getIdentifier(),
SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup);
if (Template.isNull())
return 0;
-
- Result = getDerived().TransformDependentTemplateSpecializationType(TLB,
+
+ Result = getDerived().TransformDependentTemplateSpecializationType(TLB,
SpecTL,
Template,
SS);
@@ -3475,10 +3488,10 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
// Nothing special needs to be done for these.
Result = getDerived().TransformType(TLB, TL);
}
-
- if (Result.isNull())
+
+ if (Result.isNull())
return 0;
-
+
return TLB.getTypeSourceInfo(SemaRef.Context, Result);
}
@@ -3509,8 +3522,8 @@ QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
PointerTypeLoc TL) {
- QualType PointeeType
- = getDerived().TransformType(TLB, TL.getPointeeLoc());
+ QualType PointeeType
+ = getDerived().TransformType(TLB, TL.getPointeeLoc());
if (PointeeType.isNull())
return QualType();
@@ -3521,7 +3534,7 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
// resulting pointer type is an ObjCObjectPointerType, not a
// PointerType.
Result = SemaRef.Context.getObjCObjectPointerType(PointeeType);
-
+
ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
NewT.setStarLoc(TL.getStarLoc());
return Result;
@@ -3533,14 +3546,14 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
if (Result.isNull())
return QualType();
}
-
+
// Objective-C ARC can add lifetime qualifiers to the type that we're
// pointing to.
TLB.TypeWasModifiedSafely(Result->getPointeeType());
-
+
PointerTypeLoc NewT = TLB.push<PointerTypeLoc>(Result);
NewT.setSigilLoc(TL.getSigilLoc());
- return Result;
+ return Result;
}
template<typename Derived>
@@ -3548,14 +3561,14 @@ QualType
TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB,
BlockPointerTypeLoc TL) {
QualType PointeeType
- = getDerived().TransformType(TLB, TL.getPointeeLoc());
- if (PointeeType.isNull())
- return QualType();
-
- QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() ||
- PointeeType != TL.getPointeeLoc().getType()) {
- Result = getDerived().RebuildBlockPointerType(PointeeType,
+ = getDerived().TransformType(TLB, TL.getPointeeLoc());
+ if (PointeeType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() ||
+ PointeeType != TL.getPointeeLoc().getType()) {
+ Result = getDerived().RebuildBlockPointerType(PointeeType,
TL.getSigilLoc());
if (Result.isNull())
return QualType();
@@ -3725,7 +3738,7 @@ QualType TreeTransform<Derived>::TransformIncompleteArrayType(
if (Result.isNull())
return QualType();
}
-
+
IncompleteArrayTypeLoc NewTL = TLB.push<IncompleteArrayTypeLoc>(Result);
NewTL.setLBracketLoc(TL.getLBracketLoc());
NewTL.setRBracketLoc(TL.getRBracketLoc());
@@ -3762,7 +3775,7 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB,
if (Result.isNull())
return QualType();
}
-
+
VariableArrayTypeLoc NewTL = TLB.push<VariableArrayTypeLoc>(Result);
NewTL.setLBracketLoc(TL.getLBracketLoc());
NewTL.setRBracketLoc(TL.getRBracketLoc());
@@ -3879,7 +3892,7 @@ QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB,
if (Result.isNull())
return QualType();
}
-
+
VectorTypeLoc NewTL = TLB.push<VectorTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
@@ -3903,7 +3916,7 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB,
if (Result.isNull())
return QualType();
}
-
+
ExtVectorTypeLoc NewTL = TLB.push<ExtVectorTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
@@ -3918,29 +3931,29 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm,
bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = 0;
-
+
if (NumExpansions && isa<PackExpansionType>(OldDI->getType())) {
- // If we're substituting into a pack expansion type and we know the
+ // If we're substituting into a pack expansion type and we know the
// length we want to expand to, just substitute for the pattern.
TypeLoc OldTL = OldDI->getTypeLoc();
PackExpansionTypeLoc OldExpansionTL = cast<PackExpansionTypeLoc>(OldTL);
-
+
TypeLocBuilder TLB;
TypeLoc NewTL = OldDI->getTypeLoc();
TLB.reserve(NewTL.getFullDataSize());
-
- QualType Result = getDerived().TransformType(TLB,
+
+ QualType Result = getDerived().TransformType(TLB,
OldExpansionTL.getPatternLoc());
if (Result.isNull())
return 0;
-
- Result = RebuildPackExpansionType(Result,
- OldExpansionTL.getPatternLoc().getSourceRange(),
+
+ Result = RebuildPackExpansionType(Result,
+ OldExpansionTL.getPatternLoc().getSourceRange(),
OldExpansionTL.getEllipsisLoc(),
NumExpansions);
if (Result.isNull())
return 0;
-
+
PackExpansionTypeLoc NewExpansionTL
= TLB.push<PackExpansionTypeLoc>(Result);
NewExpansionTL.setEllipsisLoc(OldExpansionTL.getEllipsisLoc());
@@ -4002,27 +4015,27 @@ bool TreeTransform<Derived>::
NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
Pattern.getSourceRange(),
- Unexpanded,
- ShouldExpand,
+ Unexpanded,
+ ShouldExpand,
RetainExpansion,
NumExpansions)) {
return true;
}
-
+
if (ShouldExpand) {
// Expand the function parameter pack into multiple, separate
// parameters.
getDerived().ExpandingFunctionParameterPack(OldParm);
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
- ParmVarDecl *NewParm
+ ParmVarDecl *NewParm
= getDerived().TransformFunctionTypeParam(OldParm,
indexAdjustment++,
OrigNumExpansions,
/*ExpectParameterPack=*/false);
if (!NewParm)
return true;
-
+
OutParamTypes.push_back(NewParm->getType());
if (PVars)
PVars->push_back(NewParm);
@@ -4032,14 +4045,14 @@ bool TreeTransform<Derived>::
// forgetting the partially-substituted parameter pack.
if (RetainExpansion) {
ForgetPartiallySubstitutedPackRAII Forget(getDerived());
- ParmVarDecl *NewParm
+ ParmVarDecl *NewParm
= getDerived().TransformFunctionTypeParam(OldParm,
indexAdjustment++,
OrigNumExpansions,
/*ExpectParameterPack=*/false);
if (!NewParm)
return true;
-
+
OutParamTypes.push_back(NewParm->getType());
if (PVars)
PVars->push_back(NewParm);
@@ -4054,8 +4067,8 @@ bool TreeTransform<Derived>::
// We're done with the pack expansion.
continue;
}
-
- // We'll substitute the parameter now without expanding the pack
+
+ // We'll substitute the parameter now without expanding the pack
// expansion.
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
NewParm = getDerived().TransformFunctionTypeParam(OldParm,
@@ -4071,7 +4084,7 @@ bool TreeTransform<Derived>::
if (!NewParm)
return true;
-
+
OutParamTypes.push_back(NewParm->getType());
if (PVars)
PVars->push_back(NewParm);
@@ -4084,26 +4097,26 @@ bool TreeTransform<Derived>::
bool IsPackExpansion = false;
llvm::Optional<unsigned> NumExpansions;
QualType NewType;
- if (const PackExpansionType *Expansion
+ if (const PackExpansionType *Expansion
= dyn_cast<PackExpansionType>(OldType)) {
// We have a function parameter pack that may need to be expanded.
QualType Pattern = Expansion->getPattern();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
-
+
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
bool RetainExpansion = false;
if (getDerived().TryExpandParameterPacks(Loc, SourceRange(),
- Unexpanded,
- ShouldExpand,
+ Unexpanded,
+ ShouldExpand,
RetainExpansion,
NumExpansions)) {
return true;
}
-
+
if (ShouldExpand) {
- // Expand the function parameter pack into multiple, separate
+ // Expand the function parameter pack into multiple, separate
// parameters.
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
@@ -4115,11 +4128,11 @@ bool TreeTransform<Derived>::
if (PVars)
PVars->push_back(0);
}
-
+
// We're done with the pack expansion.
continue;
}
-
+
// If we're supposed to retain a pack expansion, do so by temporarily
// forgetting the partially-substituted parameter pack.
if (RetainExpansion) {
@@ -4127,13 +4140,13 @@ bool TreeTransform<Derived>::
QualType NewType = getDerived().TransformType(Pattern);
if (NewType.isNull())
return true;
-
+
OutParamTypes.push_back(NewType);
if (PVars)
PVars->push_back(0);
}
- // We'll substitute the parameter now without expanding the pack
+ // We'll substitute the parameter now without expanding the pack
// expansion.
OldType = Expansion->getPattern();
IsPackExpansion = true;
@@ -4142,14 +4155,14 @@ bool TreeTransform<Derived>::
} else {
NewType = getDerived().TransformType(OldType);
}
-
+
if (NewType.isNull())
return true;
if (IsPackExpansion)
NewType = getSema().Context.getPackExpansionType(NewType,
NumExpansions);
-
+
OutParamTypes.push_back(NewType);
if (PVars)
PVars->push_back(0);
@@ -4193,22 +4206,22 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
QualType ResultType;
if (TL.getTrailingReturn()) {
- if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(),
+ if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(),
TL.getParmArray(),
TL.getNumArgs(),
- TL.getTypePtr()->arg_type_begin(),
+ TL.getTypePtr()->arg_type_begin(),
ParamTypes, &ParamDecls))
return QualType();
{
// C++11 [expr.prim.general]p3:
- // If a declaration declares a member function or member function
- // template of a class X, the expression this is a prvalue of type
+ // If a declaration declares a member function or member function
+ // template of a class X, the expression this is a prvalue of type
// "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
- // and the end of the function-definition, member-declarator, or
+ // and the end of the function-definition, member-declarator, or
// declarator.
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals);
-
+
ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
if (ResultType.isNull())
return QualType();
@@ -4219,10 +4232,10 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
if (ResultType.isNull())
return QualType();
- if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(),
+ if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(),
TL.getParmArray(),
TL.getNumArgs(),
- TL.getTypePtr()->arg_type_begin(),
+ TL.getTypePtr()->arg_type_begin(),
ParamTypes, &ParamDecls))
return QualType();
}
@@ -4533,7 +4546,7 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
TypeLocBuilder &TLB,
SubstTemplateTypeParmTypeLoc TL) {
const SubstTemplateTypeParmType *T = TL.getTypePtr();
-
+
// Substitute into the replacement type, which itself might involve something
// that needs to be transformed. This only tends to occur with default
// template arguments of template template parameters.
@@ -4541,13 +4554,13 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
QualType Replacement = getDerived().TransformType(T->getReplacementType());
if (Replacement.isNull())
return QualType();
-
+
// Always canonicalize the replacement type.
Replacement = SemaRef.Context.getCanonicalType(Replacement);
QualType Result
- = SemaRef.Context.getSubstTemplateTypeParmType(T->getReplacedParameter(),
+ = SemaRef.Context.getSubstTemplateTypeParmType(T->getReplacedParameter(),
Replacement);
-
+
// Propagate type-source information.
SubstTemplateTypeParmTypeLoc NewTL
= TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
@@ -4605,7 +4618,7 @@ QualType TreeTransform<Derived>::TransformAtomicType(TypeLocBuilder &TLB,
}
namespace {
- /// \brief Simple iterator that traverses the template arguments in a
+ /// \brief Simple iterator that traverses the template arguments in a
/// container that provides a \c getArgLoc() member function.
///
/// This iterator is intended to be used with the iterator form of
@@ -4614,63 +4627,63 @@ namespace {
class TemplateArgumentLocContainerIterator {
ArgLocContainer *Container;
unsigned Index;
-
+
public:
typedef TemplateArgumentLoc value_type;
typedef TemplateArgumentLoc reference;
typedef int difference_type;
typedef std::input_iterator_tag iterator_category;
-
+
class pointer {
TemplateArgumentLoc Arg;
-
+
public:
explicit pointer(TemplateArgumentLoc Arg) : Arg(Arg) { }
-
+
const TemplateArgumentLoc *operator->() const {
return &Arg;
}
};
-
-
+
+
TemplateArgumentLocContainerIterator() {}
-
+
TemplateArgumentLocContainerIterator(ArgLocContainer &Container,
unsigned Index)
: Container(&Container), Index(Index) { }
-
+
TemplateArgumentLocContainerIterator &operator++() {
++Index;
return *this;
}
-
+
TemplateArgumentLocContainerIterator operator++(int) {
TemplateArgumentLocContainerIterator Old(*this);
++(*this);
return Old;
}
-
+
TemplateArgumentLoc operator*() const {
return Container->getArgLoc(Index);
}
-
+
pointer operator->() const {
return pointer(Container->getArgLoc(Index));
}
-
+
friend bool operator==(const TemplateArgumentLocContainerIterator &X,
const TemplateArgumentLocContainerIterator &Y) {
return X.Container == Y.Container && X.Index == Y.Index;
}
-
+
friend bool operator!=(const TemplateArgumentLocContainerIterator &X,
const TemplateArgumentLocContainerIterator &Y) {
return !(X == Y);
}
};
}
-
-
+
+
template <typename Derived>
QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
TypeLocBuilder &TLB,
@@ -4681,7 +4694,7 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
typedef TemplateArgumentLocContainerIterator<TemplateSpecializationTypeLoc>
ArgIterator;
- if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
+ if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
ArgIterator(TL, TL.getNumArgs()),
NewTemplateArgs))
return QualType();
@@ -4736,13 +4749,13 @@ QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
typedef TemplateArgumentLocContainerIterator<
DependentTemplateSpecializationTypeLoc> ArgIterator;
- if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
+ if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
ArgIterator(TL, TL.getNumArgs()),
NewTemplateArgs))
return QualType();
-
+
// FIXME: maybe don't rebuild if all the template arguments are the same.
-
+
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
QualType Result
= getSema().Context.getDependentTemplateSpecializationType(
@@ -4750,7 +4763,7 @@ QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
DTN->getQualifier(),
DTN->getIdentifier(),
NewTemplateArgs);
-
+
DependentTemplateSpecializationTypeLoc NewTL
= TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc());
@@ -4763,12 +4776,12 @@ QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo());
return Result;
}
-
- QualType Result
+
+ QualType Result
= getDerived().RebuildTemplateSpecializationType(Template,
TL.getTemplateNameLoc(),
NewTemplateArgs);
-
+
if (!Result.isNull()) {
/// FIXME: Wrap this in an elaborated-type-specifier?
TemplateSpecializationTypeLoc NewTL
@@ -4780,7 +4793,7 @@ QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i)
NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo());
}
-
+
return Result;
}
@@ -4793,7 +4806,7 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
NestedNameSpecifierLoc QualifierLoc;
// NOTE: the qualifier in an ElaboratedType is optional.
if (TL.getQualifierLoc()) {
- QualifierLoc
+ QualifierLoc
= getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc());
if (!QualifierLoc)
return QualType();
@@ -4825,7 +4838,7 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
QualifierLoc != TL.getQualifierLoc() ||
NamedT != T->getNamedType()) {
Result = getDerived().RebuildElaboratedType(TL.getElaboratedKeywordLoc(),
- T->getKeyword(),
+ T->getKeyword(),
QualifierLoc, NamedT);
if (Result.isNull())
return QualType();
@@ -4942,7 +4955,7 @@ QualType TreeTransform<Derived>::
if (!QualifierLoc)
return QualType();
}
-
+
return getDerived()
.TransformDependentTemplateSpecializationType(TLB, TL, QualifierLoc);
}
@@ -4953,18 +4966,18 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
DependentTemplateSpecializationTypeLoc TL,
NestedNameSpecifierLoc QualifierLoc) {
const DependentTemplateSpecializationType *T = TL.getTypePtr();
-
+
TemplateArgumentListInfo NewTemplateArgs;
NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
-
+
typedef TemplateArgumentLocContainerIterator<
DependentTemplateSpecializationTypeLoc> ArgIterator;
if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
ArgIterator(TL, TL.getNumArgs()),
NewTemplateArgs))
return QualType();
-
+
QualType Result
= getDerived().RebuildDependentTemplateSpecializationType(T->getKeyword(),
QualifierLoc,
@@ -4973,10 +4986,10 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
NewTemplateArgs);
if (Result.isNull())
return QualType();
-
+
if (const ElaboratedType *ElabT = dyn_cast<ElaboratedType>(Result)) {
QualType NamedT = ElabT->getNamedType();
-
+
// Copy information relevant to the template specialization.
TemplateSpecializationTypeLoc NamedTL
= TLB.push<TemplateSpecializationTypeLoc>(NamedT);
@@ -4986,7 +4999,7 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
NamedTL.setRAngleLoc(TL.getRAngleLoc());
for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I)
NamedTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo());
-
+
// Copy information relevant to the elaborated type.
ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc());
@@ -5018,22 +5031,22 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformPackExpansionType(TypeLocBuilder &TLB,
PackExpansionTypeLoc TL) {
- QualType Pattern
- = getDerived().TransformType(TLB, TL.getPatternLoc());
+ QualType Pattern
+ = getDerived().TransformType(TLB, TL.getPatternLoc());
if (Pattern.isNull())
return QualType();
-
- QualType Result = TL.getType();
+
+ QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
Pattern != TL.getPatternLoc().getType()) {
- Result = getDerived().RebuildPackExpansionType(Pattern,
+ Result = getDerived().RebuildPackExpansionType(Pattern,
TL.getPatternLoc().getSourceRange(),
TL.getEllipsisLoc(),
TL.getTypePtr()->getNumExpansions());
if (Result.isNull())
return QualType();
}
-
+
PackExpansionTypeLoc NewT = TLB.push<PackExpansionTypeLoc>(Result);
NewT.setEllipsisLoc(TL.getEllipsisLoc());
return Result;
@@ -5217,7 +5230,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
ExprResult Cond;
VarDecl *ConditionVar = 0;
if (S->getConditionVariable()) {
- ConditionVar
+ ConditionVar
= cast_or_null<VarDecl>(
getDerived().TransformDefinition(
S->getConditionVariable()->getLocation(),
@@ -5226,25 +5239,25 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
return StmtError();
} else {
Cond = getDerived().TransformExpr(S->getCond());
-
+
if (Cond.isInvalid())
return StmtError();
-
+
// Convert the condition to a boolean value.
if (S->getCond()) {
- ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getIfLoc(),
+ ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getIfLoc(),
Cond.get());
if (CondE.isInvalid())
return StmtError();
-
+
Cond = CondE.get();
}
}
-
+
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.take()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
-
+
// Transform the "then" branch.
StmtResult Then = getDerived().TransformStmt(S->getThen());
if (Then.isInvalid())
@@ -5274,7 +5287,7 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
ExprResult Cond;
VarDecl *ConditionVar = 0;
if (S->getConditionVariable()) {
- ConditionVar
+ ConditionVar
= cast_or_null<VarDecl>(
getDerived().TransformDefinition(
S->getConditionVariable()->getLocation(),
@@ -5283,7 +5296,7 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
return StmtError();
} else {
Cond = getDerived().TransformExpr(S->getCond());
-
+
if (Cond.isInvalid())
return StmtError();
}
@@ -5312,7 +5325,7 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
ExprResult Cond;
VarDecl *ConditionVar = 0;
if (S->getConditionVariable()) {
- ConditionVar
+ ConditionVar
= cast_or_null<VarDecl>(
getDerived().TransformDefinition(
S->getConditionVariable()->getLocation(),
@@ -5321,13 +5334,13 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
return StmtError();
} else {
Cond = getDerived().TransformExpr(S->getCond());
-
+
if (Cond.isInvalid())
return StmtError();
if (S->getCond()) {
// Convert the condition to a boolean value.
- ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getWhileLoc(),
+ ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getWhileLoc(),
Cond.get());
if (CondE.isInvalid())
return StmtError();
@@ -5366,7 +5379,7 @@ TreeTransform<Derived>::TransformDoStmt(DoStmt *S) {
ExprResult Cond = getDerived().TransformExpr(S->getCond());
if (Cond.isInvalid())
return StmtError();
-
+
if (!getDerived().AlwaysRebuild() &&
Cond.get() == S->getCond() &&
Body.get() == S->getBody())
@@ -5389,7 +5402,7 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
ExprResult Cond;
VarDecl *ConditionVar = 0;
if (S->getConditionVariable()) {
- ConditionVar
+ ConditionVar
= cast_or_null<VarDecl>(
getDerived().TransformDefinition(
S->getConditionVariable()->getLocation(),
@@ -5398,13 +5411,13 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
return StmtError();
} else {
Cond = getDerived().TransformExpr(S->getCond());
-
+
if (Cond.isInvalid())
return StmtError();
if (S->getCond()) {
// Convert the condition to a boolean value.
- ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getForLoc(),
+ ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getForLoc(),
Cond.get());
if (CondE.isInvalid())
return StmtError();
@@ -5413,7 +5426,7 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
}
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.take()));
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.take()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
@@ -5450,7 +5463,7 @@ TreeTransform<Derived>::TransformGotoStmt(GotoStmt *S) {
S->getLabel());
if (!LD)
return StmtError();
-
+
// Goto statements must always be rebuilt, to resolve the label.
return getDerived().RebuildGotoStmt(S->getGotoLoc(), S->getLabelLoc(),
cast<LabelDecl>(LD));
@@ -5524,7 +5537,7 @@ TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
-
+
ASTOwningVector<Expr*> Constraints(getSema());
ASTOwningVector<Expr*> Exprs(getSema());
SmallVector<IdentifierInfo *, 4> Names;
@@ -5533,43 +5546,43 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
ASTOwningVector<Expr*> Clobbers(getSema());
bool ExprsChanged = false;
-
+
// Go through the outputs.
for (unsigned I = 0, E = S->getNumOutputs(); I != E; ++I) {
Names.push_back(S->getOutputIdentifier(I));
-
+
// No need to transform the constraint literal.
Constraints.push_back(S->getOutputConstraintLiteral(I));
-
+
// Transform the output expr.
Expr *OutputExpr = S->getOutputExpr(I);
ExprResult Result = getDerived().TransformExpr(OutputExpr);
if (Result.isInvalid())
return StmtError();
-
+
ExprsChanged |= Result.get() != OutputExpr;
-
+
Exprs.push_back(Result.get());
}
-
+
// Go through the inputs.
for (unsigned I = 0, E = S->getNumInputs(); I != E; ++I) {
Names.push_back(S->getInputIdentifier(I));
-
+
// No need to transform the constraint literal.
Constraints.push_back(S->getInputConstraintLiteral(I));
-
+
// Transform the input expr.
Expr *InputExpr = S->getInputExpr(I);
ExprResult Result = getDerived().TransformExpr(InputExpr);
if (Result.isInvalid())
return StmtError();
-
+
ExprsChanged |= Result.get() != InputExpr;
-
+
Exprs.push_back(Result.get());
}
-
+
if (!getDerived().AlwaysRebuild() && !ExprsChanged)
return SemaRef.Owned(S);
@@ -5594,6 +5607,18 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
S->isMSAsm());
}
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) {
+ ArrayRef<Token> AsmToks =
+ llvm::makeArrayRef(S->getAsmToks(), S->getNumAsmToks());
+ ArrayRef<unsigned> LineEnds =
+ llvm::makeArrayRef(S->getLineEnds(), S->getNumLineEnds());
+
+ // No need to transform the asm string literal.
+ return getDerived().RebuildMSAsmStmt(S->getAsmLoc(), AsmToks, LineEnds,
+ S->getEndLoc());
+}
template<typename Derived>
StmtResult
@@ -5602,7 +5627,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
StmtResult TryBody = getDerived().TransformStmt(S->getTryBody());
if (TryBody.isInvalid())
return StmtError();
-
+
// Transform the @catch statements (if present).
bool AnyCatchChanged = false;
ASTOwningVector<Stmt*> CatchStmts(SemaRef);
@@ -5614,7 +5639,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
AnyCatchChanged = true;
CatchStmts.push_back(Catch.release());
}
-
+
// Transform the @finally statement (if present).
StmtResult Finally;
if (S->getFinallyStmt()) {
@@ -5629,7 +5654,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
!AnyCatchChanged &&
Finally.get() == S->getFinallyStmt())
return SemaRef.Owned(S);
-
+
// Build a new statement.
return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), TryBody.get(),
move_arg(CatchStmts), Finally.get());
@@ -5647,26 +5672,26 @@ TreeTransform<Derived>::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) {
if (!TSInfo)
return StmtError();
}
-
+
QualType T;
if (TSInfo)
T = TSInfo->getType();
else {
T = getDerived().TransformType(FromVar->getType());
if (T.isNull())
- return StmtError();
+ return StmtError();
}
-
+
Var = getDerived().RebuildObjCExceptionDecl(FromVar, TSInfo, T);
if (!Var)
return StmtError();
}
-
+
StmtResult Body = getDerived().TransformStmt(S->getCatchBody());
if (Body.isInvalid())
return StmtError();
-
- return getDerived().RebuildObjCAtCatchStmt(S->getAtCatchLoc(),
+
+ return getDerived().RebuildObjCAtCatchStmt(S->getAtCatchLoc(),
S->getRParenLoc(),
Var, Body.get());
}
@@ -5678,7 +5703,7 @@ TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
StmtResult Body = getDerived().TransformStmt(S->getFinallyBody());
if (Body.isInvalid())
return StmtError();
-
+
// If nothing changed, just retain this statement.
if (!getDerived().AlwaysRebuild() &&
Body.get() == S->getFinallyBody())
@@ -5698,11 +5723,11 @@ TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) {
if (Operand.isInvalid())
return StmtError();
}
-
+
if (!getDerived().AlwaysRebuild() &&
Operand.get() == S->getThrowExpr())
return getSema().Owned(S);
-
+
return getDerived().RebuildObjCAtThrowStmt(S->getThrowLoc(), Operand.get());
}
@@ -5719,12 +5744,12 @@ TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
Object.get());
if (Object.isInvalid())
return StmtError();
-
+
// Transform the body.
StmtResult Body = getDerived().TransformStmt(S->getSynchBody());
if (Body.isInvalid())
return StmtError();
-
+
// If nothing change, just retain the current statement.
if (!getDerived().AlwaysRebuild() &&
Object.get() == S->getSynchExpr() &&
@@ -5744,7 +5769,7 @@ TreeTransform<Derived>::TransformObjCAutoreleasePoolStmt(
StmtResult Body = getDerived().TransformStmt(S->getSubStmt());
if (Body.isInvalid())
return StmtError();
-
+
// If nothing changed, just retain this statement.
if (!getDerived().AlwaysRebuild() &&
Body.get() == S->getSubStmt())
@@ -5763,28 +5788,24 @@ TreeTransform<Derived>::TransformObjCForCollectionStmt(
StmtResult Element = getDerived().TransformStmt(S->getElement());
if (Element.isInvalid())
return StmtError();
-
+
// Transform the collection expression.
ExprResult Collection = getDerived().TransformExpr(S->getCollection());
if (Collection.isInvalid())
return StmtError();
- Collection = getDerived().RebuildObjCForCollectionOperand(S->getForLoc(),
- Collection.take());
- if (Collection.isInvalid())
- return StmtError();
-
+
// Transform the body.
StmtResult Body = getDerived().TransformStmt(S->getBody());
if (Body.isInvalid())
return StmtError();
-
+
// If nothing changed, just retain this statement.
if (!getDerived().AlwaysRebuild() &&
Element.get() == S->getElement() &&
Collection.get() == S->getCollection() &&
Body.get() == S->getBody())
return SemaRef.Owned(S);
-
+
// Build a new statement.
return getDerived().RebuildObjCForCollectionStmt(S->getForLoc(),
/*FIXME:*/S->getForLoc(),
@@ -5931,7 +5952,7 @@ TreeTransform<Derived>::TransformMSDependentExistsStmt(
// Transform the nested-name-specifier, if any.
NestedNameSpecifierLoc QualifierLoc;
if (S->getQualifierLoc()) {
- QualifierLoc
+ QualifierLoc
= getDerived().TransformNestedNameSpecifierLoc(S->getQualifierLoc());
if (!QualifierLoc)
return StmtError();
@@ -5950,7 +5971,7 @@ TreeTransform<Derived>::TransformMSDependentExistsStmt(
QualifierLoc == S->getQualifierLoc() &&
NameInfo.getName() == S->getNameInfo().getName())
return S;
-
+
// Determine whether this name exists, if we can.
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
@@ -5959,32 +5980,32 @@ TreeTransform<Derived>::TransformMSDependentExistsStmt(
case Sema::IER_Exists:
if (S->isIfExists())
break;
-
+
return new (getSema().Context) NullStmt(S->getKeywordLoc());
case Sema::IER_DoesNotExist:
if (S->isIfNotExists())
break;
-
+
return new (getSema().Context) NullStmt(S->getKeywordLoc());
-
+
case Sema::IER_Dependent:
Dependent = true;
break;
-
+
case Sema::IER_Error:
return StmtError();
}
-
+
// We need to continue with the instantiation, so do so now.
StmtResult SubStmt = getDerived().TransformCompoundStmt(S->getSubStmt());
if (SubStmt.isInvalid())
return StmtError();
-
+
// If we have resolved the name, just transform to the substatement.
if (!Dependent)
return SubStmt;
-
+
// The name is still dependent, so build a dependent expression again.
return getDerived().RebuildMSDependentExistsStmt(S->getKeywordLoc(),
S->isIfExists(),
@@ -6101,7 +6122,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
return ExprError();
}
- return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo,
+ return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo,
TemplateArgs);
}
@@ -6213,12 +6234,12 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) {
TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo());
if (!Type)
return ExprError();
-
+
// Transform all of the components into components similar to what the
// parser uses.
- // FIXME: It would be slightly more efficient in the non-dependent case to
- // just map FieldDecls, rather than requiring the rebuilder to look for
- // the fields again. However, __builtin_offsetof is rare enough in
+ // FIXME: It would be slightly more efficient in the non-dependent case to
+ // just map FieldDecls, rather than requiring the rebuilder to look for
+ // the fields again. However, __builtin_offsetof is rare enough in
// template code that we don't care.
bool ExprChanged = false;
typedef Sema::OffsetOfComponent Component;
@@ -6236,36 +6257,36 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) {
ExprResult Index = getDerived().TransformExpr(FromIndex);
if (Index.isInvalid())
return ExprError();
-
+
ExprChanged = ExprChanged || Index.get() != FromIndex;
Comp.isBrackets = true;
Comp.U.E = Index.get();
break;
}
-
+
case Node::Field:
case Node::Identifier:
Comp.isBrackets = false;
Comp.U.IdentInfo = ON.getFieldName();
if (!Comp.U.IdentInfo)
continue;
-
+
break;
-
+
case Node::Base:
// Will be recomputed during the rebuild.
continue;
}
-
+
Components.push_back(Comp);
}
-
+
// If nothing changed, retain the existing expression.
if (!getDerived().AlwaysRebuild() &&
Type == E->getTypeSourceInfo() &&
!ExprChanged)
return SemaRef.Owned(E);
-
+
// Build a new offsetof expression.
return getDerived().RebuildOffsetOfExpr(E->getOperatorLoc(), Type,
Components.data(), Components.size(),
@@ -6373,10 +6394,10 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {
// Transform arguments.
bool ArgChanged = false;
ASTOwningVector<Expr*> Args(SemaRef);
- if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
+ if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgChanged))
return ExprError();
-
+
if (!getDerived().AlwaysRebuild() &&
Callee.get() == E->getCallee() &&
!ArgChanged)
@@ -6401,7 +6422,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
if (E->hasQualifier()) {
QualifierLoc
= getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
-
+
if (!QualifierLoc)
return ExprError();
}
@@ -6429,7 +6450,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
Member == E->getMemberDecl() &&
FoundDecl == E->getFoundDecl() &&
!E->hasExplicitTemplateArgs()) {
-
+
// Mark it referenced in the new context regardless.
// FIXME: this is a bit instantiation-specific.
SemaRef.MarkMemberReferenced(E);
@@ -6446,7 +6467,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
TransArgs))
return ExprError();
}
-
+
// FIXME: Bogus source location for the operator
SourceLocation FakeOperatorLoc
= SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
@@ -6564,7 +6585,7 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
TypeSourceInfo *Type = getDerived().TransformType(E->getTypeInfoAsWritten());
if (!Type)
return ExprError();
-
+
ExprResult SubExpr
= getDerived().TransformExpr(E->getSubExprAsWritten());
if (SubExpr.isInvalid())
@@ -6632,10 +6653,10 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) {
bool InitChanged = false;
ASTOwningVector<Expr*, 4> Inits(SemaRef);
- if (getDerived().TransformExprs(E->getInits(), E->getNumInits(), false,
+ if (getDerived().TransformExprs(E->getInits(), E->getNumInits(), false,
Inits, &InitChanged))
return ExprError();
-
+
if (!getDerived().AlwaysRebuild() && !InitChanged)
return SemaRef.Owned(E);
@@ -6716,7 +6737,7 @@ ExprResult
TreeTransform<Derived>::TransformImplicitValueInitExpr(
ImplicitValueInitExpr *E) {
TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
-
+
// FIXME: Will we ever have proper type location here? Will we actually
// need to transform the type?
QualType T = getDerived().TransformType(E->getType());
@@ -6758,7 +6779,7 @@ TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) {
if (TransformExprs(E->getExprs(), E->getNumExprs(), true, Inits,
&ArgumentChanged))
return ExprError();
-
+
return getDerived().RebuildParenListExpr(E->getLParenLoc(),
move_arg(Inits),
E->getRParenLoc());
@@ -6776,13 +6797,13 @@ TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) {
E->getLabel());
if (!LD)
return ExprError();
-
+
return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(),
cast<LabelDecl>(LD));
}
template<typename Derived>
-ExprResult
+ExprResult
TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) {
SemaRef.ActOnStartStmtExpr();
StmtResult SubStmt
@@ -6845,7 +6866,7 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
case OO_Array_New:
case OO_Array_Delete:
llvm_unreachable("new and delete operators cannot use CXXOperatorCallExpr");
-
+
case OO_Call: {
// This is a call to an object's operator().
assert(E->getNumArgs() >= 1 && "Object call is missing arguments");
@@ -6862,7 +6883,7 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
// Transform the call arguments.
ASTOwningVector<Expr*> Args(SemaRef);
- if (getDerived().TransformExprs(E->getArgs() + 1, E->getNumArgs() - 1, true,
+ if (getDerived().TransformExprs(E->getArgs() + 1, E->getNumArgs() - 1, true,
Args))
return ExprError();
@@ -6937,7 +6958,7 @@ TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
// Transform arguments.
bool ArgChanged = false;
ASTOwningVector<Expr*> Args(SemaRef);
- if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
+ if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgChanged))
return ExprError();
@@ -6960,7 +6981,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
TypeSourceInfo *Type = getDerived().TransformType(E->getTypeInfoAsWritten());
if (!Type)
return ExprError();
-
+
ExprResult SubExpr
= getDerived().TransformExpr(E->getSubExprAsWritten());
if (SubExpr.isInvalid())
@@ -7140,7 +7161,7 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
getSema().CheckCXXThisCapture(E->getLocStart());
return SemaRef.Owned(E);
}
-
+
return getDerived().RebuildCXXThisExpr(E->getLocStart(), T, E->isImplicit());
}
@@ -7182,12 +7203,12 @@ TreeTransform<Derived>::TransformCXXScalarValueInitExpr(
TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo());
if (!T)
return ExprError();
-
+
if (!getDerived().AlwaysRebuild() &&
T == E->getTypeSourceInfo())
return SemaRef.Owned(E);
- return getDerived().RebuildCXXScalarValueInitExpr(T,
+ return getDerived().RebuildCXXScalarValueInitExpr(T,
/*FIXME:*/T->getTypeLoc().getEndLoc(),
E->getRParenLoc());
}
@@ -7209,7 +7230,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// Transform the placement arguments (if any).
bool ArgumentChanged = false;
ASTOwningVector<Expr*> PlacementArgs(SemaRef);
- if (getDerived().TransformExprs(E->getPlacementArgs(),
+ if (getDerived().TransformExprs(E->getPlacementArgs(),
E->getNumPlacementArgs(), true,
PlacementArgs, &ArgumentChanged))
return ExprError();
@@ -7240,7 +7261,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
if (!OperatorDelete)
return ExprError();
}
-
+
if (!getDerived().AlwaysRebuild() &&
AllocTypeInfo == E->getAllocatedTypeSourceInfo() &&
ArraySize.get() == E->getArraySize() &&
@@ -7254,7 +7275,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorNew);
if (OperatorDelete)
SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorDelete);
-
+
if (E->isArray() && !E->getAllocatedType()->isDependentType()) {
QualType ElementType
= SemaRef.Context.getBaseElementType(E->getAllocatedType());
@@ -7281,9 +7302,9 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// Do nothing
} else if (const ConstantArrayType *ConsArrayT
= dyn_cast<ConstantArrayType>(ArrayT)) {
- ArraySize
+ ArraySize
= SemaRef.Owned(IntegerLiteral::Create(SemaRef.Context,
- ConsArrayT->getSize(),
+ ConsArrayT->getSize(),
SemaRef.Context.getSizeType(),
/*FIXME:*/E->getLocStart()));
AllocType = ConsArrayT->getElementType();
@@ -7325,7 +7346,7 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
if (!OperatorDelete)
return ExprError();
}
-
+
if (!getDerived().AlwaysRebuild() &&
Operand.get() == E->getArgument() &&
OperatorDelete == E->getOperatorDelete()) {
@@ -7333,17 +7354,17 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
// FIXME: instantiation-specific.
if (OperatorDelete)
SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorDelete);
-
+
if (!E->getArgument()->isTypeDependent()) {
QualType Destroyed = SemaRef.Context.getBaseElementType(
E->getDestroyedType());
if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl());
- SemaRef.MarkFunctionReferenced(E->getLocStart(),
+ SemaRef.MarkFunctionReferenced(E->getLocStart(),
SemaRef.LookupDestructor(Record));
}
}
-
+
return SemaRef.Owned(E);
}
@@ -7363,14 +7384,14 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
ParsedType ObjectTypePtr;
bool MayBePseudoDestructor = false;
- Base = SemaRef.ActOnStartCXXMemberReference(0, Base.get(),
+ Base = SemaRef.ActOnStartCXXMemberReference(0, Base.get(),
E->getOperatorLoc(),
E->isArrow()? tok::arrow : tok::period,
ObjectTypePtr,
MayBePseudoDestructor);
if (Base.isInvalid())
return ExprError();
-
+
QualType ObjectType = ObjectTypePtr.get();
NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc();
if (QualifierLoc) {
@@ -7405,7 +7426,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
false);
if (!T)
return ExprError();
-
+
Destroyed
= SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.GetTypeFromParser(T),
E->getDestroyedTypeLoc());
@@ -7417,7 +7438,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
if (!ScopeTypeInfo)
return ExprError();
}
-
+
return getDerived().RebuildCXXPseudoDestructorExpr(Base.get(),
E->getOperatorLoc(),
E->isArrow(),
@@ -7473,10 +7494,10 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
= getDerived().TransformNestedNameSpecifierLoc(Old->getQualifierLoc());
if (!QualifierLoc)
return ExprError();
-
+
SS.Adopt(QualifierLoc);
- }
-
+ }
+
if (Old->getNamingClass()) {
CXXRecordDecl *NamingClass
= cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
@@ -7484,7 +7505,7 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
Old->getNamingClass()));
if (!NamingClass)
return ExprError();
-
+
R.setNamingClass(NamingClass);
}
@@ -7559,7 +7580,7 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
QualType To = getDerived().TransformType(TLB, FromTL);
if (To.isNull())
return ExprError();
-
+
if (To == From->getType())
Args.push_back(From);
else {
@@ -7568,15 +7589,15 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
}
continue;
}
-
+
ArgChanged = true;
-
+
// We have a pack expansion. Instantiate it.
- PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(FromTL);
+ PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(FromTL);
TypeLoc PatternTL = ExpansionTL.getPatternLoc();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(PatternTL, Unexpanded);
-
+
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
@@ -7590,13 +7611,13 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
Expand, RetainExpansion,
NumExpansions))
return ExprError();
-
+
if (!Expand) {
// The transform has determined that we should perform a simple
- // transformation on the pack expansion, producing another pack
+ // transformation on the pack expansion, producing another pack
// expansion.
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
-
+
TypeLocBuilder TLB;
TLB.reserve(From->getTypeLoc().getFullDataSize());
@@ -7604,13 +7625,13 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
if (To.isNull())
return ExprError();
- To = getDerived().RebuildPackExpansionType(To,
+ To = getDerived().RebuildPackExpansionType(To,
PatternTL.getSourceRange(),
ExpansionTL.getEllipsisLoc(),
NumExpansions);
if (To.isNull())
return ExprError();
-
+
PackExpansionTypeLoc ToExpansionTL
= TLB.push<PackExpansionTypeLoc>(To);
ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc());
@@ -7630,34 +7651,34 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To));
}
-
+
if (!RetainExpansion)
continue;
-
+
// If we're supposed to retain a pack expansion, do so by temporarily
// forgetting the partially-substituted parameter pack.
ForgetPartiallySubstitutedPackRAII Forget(getDerived());
TypeLocBuilder TLB;
TLB.reserve(From->getTypeLoc().getFullDataSize());
-
+
QualType To = getDerived().TransformType(TLB, PatternTL);
if (To.isNull())
return ExprError();
-
- To = getDerived().RebuildPackExpansionType(To,
+
+ To = getDerived().RebuildPackExpansionType(To,
PatternTL.getSourceRange(),
ExpansionTL.getEllipsisLoc(),
NumExpansions);
if (To.isNull())
return ExprError();
-
+
PackExpansionTypeLoc ToExpansionTL
= TLB.push<PackExpansionTypeLoc>(To);
ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc());
Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To));
}
-
+
if (!getDerived().AlwaysRebuild() && !ArgChanged)
return SemaRef.Owned(E);
@@ -7783,10 +7804,10 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
bool ArgumentChanged = false;
ASTOwningVector<Expr*> Args(SemaRef);
- if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
+ if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgumentChanged))
return ExprError();
-
+
if (!getDerived().AlwaysRebuild() &&
T == E->getType() &&
Constructor == E->getConstructor() &&
@@ -7837,7 +7858,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
CXXConstructorDecl *Constructor
= cast_or_null<CXXConstructorDecl>(
- getDerived().TransformDecl(E->getLocStart(),
+ getDerived().TransformDecl(E->getLocStart(),
E->getConstructor()));
if (!Constructor)
return ExprError();
@@ -7845,7 +7866,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
bool ArgumentChanged = false;
ASTOwningVector<Expr*> Args(SemaRef);
Args.reserve(E->getNumArgs());
- if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
+ if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgumentChanged))
return ExprError();
@@ -7857,7 +7878,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
return SemaRef.MaybeBindToTemporary(E);
}
-
+
return getDerived().RebuildCXXTemporaryObjectExpr(T,
/*FIXME:*/T->getTypeLoc().getEndLoc(),
move_arg(Args),
@@ -7872,40 +7893,38 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
= getSema().createLambdaClosureType(E->getIntroducerRange(),
/*KnownDependent=*/false);
getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
-
+
// Transform the type of the lambda parameters and start the definition of
// the lambda itself.
TypeSourceInfo *MethodTy
- = TransformType(E->getCallOperator()->getTypeSourceInfo());
+ = TransformType(E->getCallOperator()->getTypeSourceInfo());
if (!MethodTy)
return ExprError();
// Transform lambda parameters.
- bool Invalid = false;
llvm::SmallVector<QualType, 4> ParamTypes;
llvm::SmallVector<ParmVarDecl *, 4> Params;
if (getDerived().TransformFunctionTypeParams(E->getLocStart(),
E->getCallOperator()->param_begin(),
E->getCallOperator()->param_size(),
0, ParamTypes, &Params))
- Invalid = true;
+ return ExprError();
// Build the call operator.
- // Note: Once a lambda mangling number and context declaration have been
- // assigned, they never change.
- unsigned ManglingNumber = E->getLambdaClass()->getLambdaManglingNumber();
- Decl *ContextDecl = E->getLambdaClass()->getLambdaContextDecl();
CXXMethodDecl *CallOperator
= getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
- MethodTy,
+ MethodTy,
E->getCallOperator()->getLocEnd(),
- Params, ManglingNumber, ContextDecl);
+ Params);
getDerived().transformAttrs(E->getCallOperator(), CallOperator);
-
- // FIXME: Instantiation-specific.
- CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
- TSK_ImplicitInstantiation);
+ return getDerived().TransformLambdaScope(E, CallOperator);
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
+ CXXMethodDecl *CallOperator) {
// Introduce the context of the call operator.
Sema::ContextRAII SavedContext(getSema(), CallOperator);
@@ -7916,10 +7935,11 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->hasExplicitParameters(),
E->hasExplicitResultType(),
E->isMutable());
-
+
// Transform captures.
+ bool Invalid = false;
bool FinishedExplicitCaptures = false;
- for (LambdaExpr::capture_iterator C = E->capture_begin(),
+ for (LambdaExpr::capture_iterator C = E->capture_begin(),
CEnd = E->capture_end();
C != CEnd; ++C) {
// When we hit the first implicit capture, tell Sema that we've finished
@@ -7928,13 +7948,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getSema().finishLambdaExplicitCaptures(LSI);
FinishedExplicitCaptures = true;
}
-
+
// Capturing 'this' is trivial.
if (C->capturesThis()) {
getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit());
continue;
}
-
+
// Determine the capture kind for Sema.
Sema::TryCaptureKind Kind
= C->isImplicit()? Sema::TryCapture_Implicit
@@ -7947,13 +7967,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
bool ShouldExpand = false;
bool RetainExpansion = false;
llvm::Optional<unsigned> NumExpansions;
- if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(),
- C->getLocation(),
+ if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(),
+ C->getLocation(),
Unexpanded,
ShouldExpand, RetainExpansion,
NumExpansions))
return ExprError();
-
+
if (ShouldExpand) {
// The transform has determined that we should perform an expansion;
// transform and capture each of the arguments.
@@ -7962,31 +7982,31 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
VarDecl *CapturedVar
- = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
+ = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
Pack));
if (!CapturedVar) {
Invalid = true;
continue;
}
-
+
// Capture the transformed variable.
- getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind);
- }
+ getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind);
+ }
continue;
}
-
+
EllipsisLoc = C->getEllipsisLoc();
}
-
+
// Transform the captured variable.
VarDecl *CapturedVar
- = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
+ = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
C->getCapturedVar()));
if (!CapturedVar) {
Invalid = true;
continue;
}
-
+
// Capture the transformed variable.
getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind);
}
@@ -7996,10 +8016,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// Enter a new evaluation context to insulate the lambda from any
// cleanups from the enclosing full-expression.
- getSema().PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ getSema().PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
if (Invalid) {
- getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0,
+ getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0,
/*IsInstantiation=*/true);
return ExprError();
}
@@ -8007,12 +8027,12 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// Instantiate the body of the lambda expression.
StmtResult Body = getDerived().TransformStmt(E->getBody());
if (Body.isInvalid()) {
- getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0,
+ getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0,
/*IsInstantiation=*/true);
- return ExprError();
+ return ExprError();
}
- return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(),
+ return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(),
/*CurScope=*/0, /*IsInstantiation=*/true);
}
@@ -8027,10 +8047,10 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
bool ArgumentChanged = false;
ASTOwningVector<Expr*> Args(SemaRef);
Args.reserve(E->arg_size());
- if (getDerived().TransformExprs(E->arg_begin(), E->arg_size(), true, Args,
+ if (getDerived().TransformExprs(E->arg_begin(), E->arg_size(), true, Args,
&ArgumentChanged))
return ExprError();
-
+
if (!getDerived().AlwaysRebuild() &&
T == E->getTypeSourceInfo() &&
!ArgumentChanged)
@@ -8209,16 +8229,16 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
// Determine the naming class.
if (Old->getNamingClass()) {
- CXXRecordDecl *NamingClass
+ CXXRecordDecl *NamingClass
= cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
Old->getMemberLoc(),
Old->getNamingClass()));
if (!NamingClass)
return ExprError();
-
+
R.setNamingClass(NamingClass);
}
-
+
TemplateArgumentListInfo TransArgs;
if (Old->hasExplicitTemplateArgs()) {
TransArgs.setLAngleLoc(Old->getLAngleLoc());
@@ -8234,7 +8254,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
// base (and therefore couldn't do the check) and a
// nested-name-qualifier (and therefore could do the lookup).
NamedDecl *FirstQualifierInScope = 0;
-
+
return getDerived().RebuildUnresolvedMemberExpr(Base.get(),
BaseType,
Old->getOperatorLoc(),
@@ -8267,7 +8287,7 @@ TreeTransform<Derived>::TransformPackExpansionExpr(PackExpansionExpr *E) {
ExprResult Pattern = getDerived().TransformExpr(E->getPattern());
if (Pattern.isInvalid())
return ExprError();
-
+
if (!getDerived().AlwaysRebuild() && Pattern.get() == E->getPattern())
return SemaRef.Owned(E);
@@ -8285,33 +8305,33 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
// Note: None of the implementations of TryExpandParameterPacks can ever
// produce a diagnostic when given only a single unexpanded parameter pack,
- // so
+ // so
UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
bool ShouldExpand = false;
bool RetainExpansion = false;
llvm::Optional<unsigned> NumExpansions;
- if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
+ if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
Unexpanded,
ShouldExpand, RetainExpansion,
NumExpansions))
return ExprError();
-
+
if (RetainExpansion)
return SemaRef.Owned(E);
-
+
NamedDecl *Pack = E->getPack();
if (!ShouldExpand) {
- Pack = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getPackLoc(),
+ Pack = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getPackLoc(),
Pack));
if (!Pack)
return ExprError();
}
-
+
// We now know the length of the parameter pack, so build a new expression
// that stores that length.
- return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack,
- E->getPackLoc(), E->getRParenLoc(),
+ return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack,
+ E->getPackLoc(), E->getRParenLoc(),
NumExpansions);
}
@@ -8337,7 +8357,7 @@ TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
MaterializeTemporaryExpr *E) {
return getDerived().TransformExpr(E->GetTemporaryExpr());
}
-
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
@@ -8352,8 +8372,16 @@ TreeTransform<Derived>::TransformObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
template<typename Derived>
ExprResult
-TreeTransform<Derived>::TransformObjCNumericLiteral(ObjCNumericLiteral *E) {
- return SemaRef.MaybeBindToTemporary(E);
+TreeTransform<Derived>::TransformObjCBoxedExpr(ObjCBoxedExpr *E) {
+ ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ SubExpr.get() == E->getSubExpr())
+ return SemaRef.Owned(E);
+
+ return getDerived().RebuildObjCBoxedExpr(E->getSourceRange(), SubExpr.get());
}
template<typename Derived>
@@ -8362,13 +8390,13 @@ TreeTransform<Derived>::TransformObjCArrayLiteral(ObjCArrayLiteral *E) {
// Transform each of the elements.
llvm::SmallVector<Expr *, 8> Elements;
bool ArgChanged = false;
- if (getDerived().TransformExprs(E->getElements(), E->getNumElements(),
+ if (getDerived().TransformExprs(E->getElements(), E->getNumElements(),
/*IsCall=*/false, Elements, &ArgChanged))
return ExprError();
-
+
if (!getDerived().AlwaysRebuild() && !ArgChanged)
return SemaRef.MaybeBindToTemporary(E);
-
+
return getDerived().RebuildObjCArrayLiteral(E->getSourceRange(),
Elements.data(),
Elements.size());
@@ -8377,13 +8405,13 @@ TreeTransform<Derived>::TransformObjCArrayLiteral(ObjCArrayLiteral *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCDictionaryLiteral(
- ObjCDictionaryLiteral *E) {
+ ObjCDictionaryLiteral *E) {
// Transform each of the elements.
llvm::SmallVector<ObjCDictionaryElement, 8> Elements;
bool ArgChanged = false;
for (unsigned I = 0, N = E->getNumElements(); I != N; ++I) {
ObjCDictionaryElement OrigElement = E->getKeyValueElement(I);
-
+
if (OrigElement.isPackExpansion()) {
// This key/value element is a pack expansion.
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
@@ -8408,7 +8436,7 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
if (!Expand) {
// The transform has determined that we should perform a simple
- // transformation on the pack expansion, producing another pack
+ // transformation on the pack expansion, producing another pack
// expansion.
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
ExprResult Key = getDerived().TransformExpr(OrigElement.Key);
@@ -8421,11 +8449,11 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
ExprResult Value = getDerived().TransformExpr(OrigElement.Value);
if (Value.isInvalid())
return ExprError();
-
+
if (Value.get() != OrigElement.Value)
ArgChanged = true;
- ObjCDictionaryElement Expansion = {
+ ObjCDictionaryElement Expansion = {
Key.get(), Value.get(), OrigElement.EllipsisLoc, NumExpansions
};
Elements.push_back(Expansion);
@@ -8435,7 +8463,7 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
// Record right away that the argument was changed. This needs
// to happen even if the array expands to nothing.
ArgChanged = true;
-
+
// The transform has determined that we should perform an elementwise
// expansion of the pattern. Do so.
for (unsigned I = 0; I != *NumExpansions; ++I) {
@@ -8448,7 +8476,7 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
if (Value.isInvalid())
return ExprError();
- ObjCDictionaryElement Element = {
+ ObjCDictionaryElement Element = {
Key.get(), Value.get(), SourceLocation(), NumExpansions
};
@@ -8457,7 +8485,7 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
if (Key.get()->containsUnexpandedParameterPack() ||
Value.get()->containsUnexpandedParameterPack())
Element.EllipsisLoc = OrigElement.EllipsisLoc;
-
+
Elements.push_back(Element);
}
@@ -8469,25 +8497,25 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
ExprResult Key = getDerived().TransformExpr(OrigElement.Key);
if (Key.isInvalid())
return ExprError();
-
+
if (Key.get() != OrigElement.Key)
ArgChanged = true;
-
+
// Transform and check value.
ExprResult Value
= getDerived().TransformExpr(OrigElement.Value);
if (Value.isInvalid())
return ExprError();
-
+
if (Value.get() != OrigElement.Value)
ArgChanged = true;
-
- ObjCDictionaryElement Element = {
+
+ ObjCDictionaryElement Element = {
Key.get(), Value.get(), SourceLocation(), llvm::Optional<unsigned>()
};
Elements.push_back(Element);
}
-
+
if (!getDerived().AlwaysRebuild() && !ArgChanged)
return SemaRef.MaybeBindToTemporary(E);
@@ -8531,22 +8559,22 @@ TransformObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
template<typename Derived>
ExprResult TreeTransform<Derived>::
TransformObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
- TypeSourceInfo *TSInfo
+ TypeSourceInfo *TSInfo
= getDerived().TransformType(E->getTypeInfoAsWritten());
if (!TSInfo)
return ExprError();
-
+
ExprResult Result = getDerived().TransformExpr(E->getSubExpr());
- if (Result.isInvalid())
+ if (Result.isInvalid())
return ExprError();
-
+
if (!getDerived().AlwaysRebuild() &&
TSInfo == E->getTypeInfoAsWritten() &&
Result.get() == E->getSubExpr())
return SemaRef.Owned(E);
-
+
return SemaRef.BuildObjCBridgedCast(E->getLParenLoc(), E->getBridgeKind(),
- E->getBridgeKeywordLoc(), TSInfo,
+ E->getBridgeKeywordLoc(), TSInfo,
Result.get());
}
@@ -8557,17 +8585,17 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
bool ArgChanged = false;
ASTOwningVector<Expr*> Args(SemaRef);
Args.reserve(E->getNumArgs());
- if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), false, Args,
+ if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), false, Args,
&ArgChanged))
return ExprError();
-
+
if (E->getReceiverKind() == ObjCMessageExpr::Class) {
// Class message: transform the receiver type.
TypeSourceInfo *ReceiverTypeInfo
= getDerived().TransformType(E->getClassReceiverTypeInfo());
if (!ReceiverTypeInfo)
return ExprError();
-
+
// If nothing changed, just retain the existing message send.
if (!getDerived().AlwaysRebuild() &&
ReceiverTypeInfo == E->getClassReceiverTypeInfo() && !ArgChanged)
@@ -8597,7 +8625,7 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Receiver.get() == E->getInstanceReceiver() && !ArgChanged)
return SemaRef.MaybeBindToTemporary(E);
-
+
// Build a new instance message send.
SmallVector<SourceLocation, 16> SelLocs;
E->getSelectorLocs(SelLocs);
@@ -8631,12 +8659,12 @@ TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) {
return ExprError();
// We don't need to transform the ivar; it will never change.
-
+
// If nothing changed, just retain the existing expression.
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase())
return SemaRef.Owned(E);
-
+
return getDerived().RebuildObjCIvarRefExpr(Base.get(), E->getDecl(),
E->getLocation(),
E->isArrow(), E->isFreeIvar());
@@ -8649,14 +8677,14 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
// retain the existing expression.
if (!E->isObjectReceiver())
return SemaRef.Owned(E);
-
+
// Transform the base expression.
ExprResult Base = getDerived().TransformExpr(E->getBase());
if (Base.isInvalid())
return ExprError();
-
+
// We don't need to transform the property; it will never change.
-
+
// If nothing changed, just retain the existing expression.
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase())
@@ -8692,7 +8720,7 @@ TreeTransform<Derived>::TransformObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) {
Key.get() == E->getKeyExpr() && Base.get() == E->getBaseExpr())
return SemaRef.Owned(E);
- return getDerived().RebuildObjCSubscriptRefExpr(E->getRBracket(),
+ return getDerived().RebuildObjCSubscriptRefExpr(E->getRBracket(),
Base.get(), Key.get(),
E->getAtIndexMethodDecl(),
E->setAtIndexMethodDecl());
@@ -8705,12 +8733,12 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
ExprResult Base = getDerived().TransformExpr(E->getBase());
if (Base.isInvalid())
return ExprError();
-
+
// If nothing changed, just retain the existing expression.
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase())
return SemaRef.Owned(E);
-
+
return getDerived().RebuildObjCIsaExpr(Base.get(), E->getIsaMemberLoc(),
E->isArrow());
}
@@ -8721,7 +8749,7 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
bool ArgumentChanged = false;
ASTOwningVector<Expr*> SubExprs(SemaRef);
SubExprs.reserve(E->getNumSubExprs());
- if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false,
+ if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false,
SubExprs, &ArgumentChanged))
return ExprError();
@@ -8738,17 +8766,17 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
BlockDecl *oldBlock = E->getBlockDecl();
-
+
SemaRef.ActOnBlockStart(E->getCaretLocation(), /*Scope=*/0);
BlockScopeInfo *blockScope = SemaRef.getCurBlock();
blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic());
blockScope->TheDecl->setBlockMissingReturnType(
oldBlock->blockMissingReturnType());
-
+
SmallVector<ParmVarDecl*, 4> params;
SmallVector<QualType, 4> paramTypes;
-
+
// Parameter substitution.
if (getDerived().TransformFunctionTypeParams(E->getCaretLocation(),
oldBlock->param_begin(),
@@ -8764,8 +8792,8 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
// Don't allow returning a objc interface by value.
if (exprResultType->isObjCObjectType()) {
- getSema().Diag(E->getCaretLocation(),
- diag::err_object_cannot_be_passed_returned_by_value)
+ getSema().Diag(E->getCaretLocation(),
+ diag::err_object_cannot_be_passed_returned_by_value)
<< 0 << exprResultType;
getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/0);
return ExprError();
@@ -8788,7 +8816,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
blockScope->HasImplicitReturnType = false;
blockScope->ReturnType = exprResultType;
}
-
+
// Transform the body
StmtResult body = getDerived().TransformStmt(E->getBody());
if (body.isInvalid()) {
@@ -8846,7 +8874,7 @@ TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), move_arg(SubExprs),
RetTy, E->getOp(), E->getRParenLoc());
}
-
+
//===----------------------------------------------------------------------===//
// Type reconstruction
//===----------------------------------------------------------------------===//
@@ -9028,7 +9056,7 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) {
// A valid resolved using typename decl points to exactly one type decl.
assert(++Using->shadow_begin() == Using->shadow_end());
Ty = cast<TypeDecl>((*Using->shadow_begin())->getTargetDecl());
-
+
} else {
assert(isa<UnresolvedUsingTypenameDecl>(D) &&
"UnresolvedUsingTypenameDecl transformed to non-using decl");
@@ -9123,7 +9151,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
Template);
return Template.template getAsVal<TemplateName>();
}
-
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
@@ -9223,7 +9251,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
}
template<typename Derived>
-ExprResult
+ExprResult
TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
SourceLocation OperatorLoc,
bool isArrow,
@@ -9235,7 +9263,7 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
QualType BaseType = Base->getType();
if (Base->isTypeDependent() || Destroyed.getIdentifier() ||
(!isArrow && !BaseType->getAs<RecordType>()) ||
- (isArrow && BaseType->getAs<PointerType>() &&
+ (isArrow && BaseType->getAs<PointerType>() &&
!BaseType->getAs<PointerType>()->getPointeeType()
->template getAs<RecordType>())){
// This pseudo-destructor expression is still a pseudo-destructor.
@@ -9252,7 +9280,11 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
DeclarationNameInfo NameInfo(Name, Destroyed.getLocation());
NameInfo.setNamedTypeInfo(DestroyedType);
- // FIXME: the ScopeType should be tacked onto SS.
+ // The scope type is now known to be a valid nested name specifier
+ // component. Tack it on to the end of the nested name specifier.
+ if (ScopeType)
+ SS.Extend(SemaRef.Context, SourceLocation(),
+ ScopeType->getTypeLoc(), CCLoc);
SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
return getSema().BuildMemberReferenceExpr(Base, BaseType,
OpenPOWER on IntegriCloud