summaryrefslogtreecommitdiffstats
path: root/lib/Sema
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2010-04-02 08:55:10 +0000
committerrdivacky <rdivacky@FreeBSD.org>2010-04-02 08:55:10 +0000
commit07b2cfcdb817cc0790420f159a313d61e7241cb9 (patch)
treed374cdca417e76f1bf101f139dba2db1d10ee8f7 /lib/Sema
parent1e255aab650a7fa2047fd953cae65b12215280af (diff)
downloadFreeBSD-src-07b2cfcdb817cc0790420f159a313d61e7241cb9.zip
FreeBSD-src-07b2cfcdb817cc0790420f159a313d61e7241cb9.tar.gz
Update clang to r100181.
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp110
-rw-r--r--lib/Sema/AnalysisBasedWarnings.h42
-rw-r--r--lib/Sema/Lookup.h6
-rw-r--r--lib/Sema/Sema.cpp27
-rw-r--r--lib/Sema/Sema.h162
-rw-r--r--lib/Sema/SemaAccess.cpp760
-rw-r--r--lib/Sema/SemaCXXCast.cpp58
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp8
-rw-r--r--lib/Sema/SemaChecking.cpp64
-rw-r--r--lib/Sema/SemaDecl.cpp391
-rw-r--r--lib/Sema/SemaDeclAttr.cpp31
-rw-r--r--lib/Sema/SemaDeclCXX.cpp704
-rw-r--r--lib/Sema/SemaDeclObjC.cpp48
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp154
-rw-r--r--lib/Sema/SemaExpr.cpp243
-rw-r--r--lib/Sema/SemaExprCXX.cpp249
-rw-r--r--lib/Sema/SemaExprObjC.cpp5
-rw-r--r--lib/Sema/SemaInit.cpp86
-rw-r--r--lib/Sema/SemaInit.h10
-rw-r--r--lib/Sema/SemaLookup.cpp21
-rw-r--r--lib/Sema/SemaObjCProperty.cpp29
-rw-r--r--lib/Sema/SemaOverload.cpp130
-rw-r--r--lib/Sema/SemaStmt.cpp57
-rw-r--r--lib/Sema/SemaTemplate.cpp672
-rw-r--r--lib/Sema/SemaTemplate.h34
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp273
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp131
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp316
-rw-r--r--lib/Sema/SemaType.cpp84
-rw-r--r--lib/Sema/TreeTransform.h126
30 files changed, 3292 insertions, 1739 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index c4ceec0..d1f00ca 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -154,7 +154,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
continue;
}
Expr *CEE = C->getCallee()->IgnoreParenCasts();
- if (CEE->getType().getNoReturnAttr()) {
+ if (getFunctionExtInfo(CEE->getType()).getNoReturn()) {
NoReturnEdge = true;
HasFakeEdge = true;
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
@@ -189,7 +189,7 @@ struct CheckFallThroughDiagnostics {
unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
unsigned diag_NeverFallThroughOrReturn;
bool funMode;
-
+
static CheckFallThroughDiagnostics MakeForFunction() {
CheckFallThroughDiagnostics D;
D.diag_MaybeFallThrough_HasNoReturn =
@@ -205,7 +205,7 @@ struct CheckFallThroughDiagnostics {
D.funMode = true;
return D;
}
-
+
static CheckFallThroughDiagnostics MakeForBlock() {
CheckFallThroughDiagnostics D;
D.diag_MaybeFallThrough_HasNoReturn =
@@ -221,7 +221,7 @@ struct CheckFallThroughDiagnostics {
D.funMode = false;
return D;
}
-
+
bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid,
bool HasNoReturn) const {
if (funMode) {
@@ -232,7 +232,7 @@ struct CheckFallThroughDiagnostics {
&& (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
== Diagnostic::Ignored || !ReturnsVoid);
}
-
+
// For blocks.
return ReturnsVoid && !HasNoReturn
&& (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
@@ -255,14 +255,14 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
ReturnsVoid = FD->getResultType()->isVoidType();
HasNoReturn = FD->hasAttr<NoReturnAttr>() ||
- FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
}
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
ReturnsVoid = MD->getResultType()->isVoidType();
HasNoReturn = MD->hasAttr<NoReturnAttr>();
}
else if (isa<BlockDecl>(D)) {
- if (const FunctionType *FT =
+ if (const FunctionType *FT =
BlockTy->getPointeeType()->getAs<FunctionType>()) {
if (FT->getResultType()->isVoidType())
ReturnsVoid = true;
@@ -276,7 +276,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
// Short circuit for compilation speed.
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
return;
-
+
// FIXME: Function try block
if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
switch (CheckFallThrough(AC)) {
@@ -312,25 +312,23 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
// warnings on a function, method, or block.
//===----------------------------------------------------------------------===//
-clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
- Diagnostic &D = S.getDiagnostics();
-
+clang::sema::AnalysisBasedWarnings::Policy::Policy() {
enableCheckFallThrough = 1;
+ enableCheckUnreachable = 0;
+}
- enableCheckUnreachable = (unsigned)
+clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
+ Diagnostic &D = S.getDiagnostics();
+ DefaultPolicy.enableCheckUnreachable = (unsigned)
(D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored);
}
-void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D,
- QualType BlockTy) {
-
+void clang::sema::
+AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
+ const Decl *D, QualType BlockTy,
+ const bool analyzeStaticInline) {
+
assert(BlockTy.isNull() || isa<BlockDecl>(D));
-
- // Do not do any analysis for declarations in system headers if we are
- // going to just ignore them.
- if (S.getDiagnostics().getSuppressSystemWarnings() &&
- S.SourceMgr.isInSystemHeader(D->getLocation()))
- return;
// We avoid doing analysis-based warnings when there are errors for
// two reasons:
@@ -339,13 +337,30 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D,
// (2) The code already has problems; running the analysis just takes more
// time.
if (S.getDiagnostics().hasErrorOccurred())
- return;
-
+ return;
+
+ // Do not do any analysis for declarations in system headers if we are
+ // going to just ignore them.
+ if (S.getDiagnostics().getSuppressSystemWarnings() &&
+ S.SourceMgr.isInSystemHeader(D->getLocation()))
+ return;
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// For function templates, class templates and member function templates
// we'll do the analysis at instantiation time.
if (FD->isDependentContext())
return;
+
+ // Only analyze 'static inline' functions when explicitly asked.
+ if (!analyzeStaticInline && FD->isInlineSpecified() &&
+ FD->getStorageClass() == FunctionDecl::Static) {
+ FD = FD->getCanonicalDecl();
+ VisitFlag &visitFlag = VisitedFD[FD];
+ if (visitFlag == Pending)
+ visitFlag = Visited;
+ else
+ return;
+ }
}
const Stmt *Body = D->getBody();
@@ -354,16 +369,61 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *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.
AnalysisContext AC(D, false);
+ bool performedCheck = false;
// Warning: check missing 'return'
- if (enableCheckFallThrough) {
+ if (P.enableCheckFallThrough) {
const CheckFallThroughDiagnostics &CD =
(isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
: CheckFallThroughDiagnostics::MakeForFunction());
CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC);
+ performedCheck = true;
}
// Warning: check for unreachable code
- if (enableCheckUnreachable)
+ if (P.enableCheckUnreachable) {
CheckUnreachable(S, AC);
+ performedCheck = true;
+ }
+
+ // If this block or function calls a 'static inline' function,
+ // we should analyze those functions as well.
+ if (performedCheck) {
+ // The CFG should already be constructed, so this should not
+ // incur any extra cost. We might not have a CFG, however, for
+ // invalid code.
+ if (const CFG *cfg = AC.getCFG()) {
+ // All CallExprs are block-level expressions in the CFG. This means
+ // that walking the basic blocks in the CFG is more efficient
+ // than walking the entire AST to find all calls.
+ for (CFG::const_iterator I=cfg->begin(), E=cfg->end(); I!=E; ++I) {
+ const CFGBlock *B = *I;
+ for (CFGBlock::const_iterator BI=B->begin(), BE=B->end(); BI!=BE; ++BI)
+ if (const CallExpr *CE = dyn_cast<CallExpr>(*BI))
+ if (const DeclRefExpr *DR =
+ dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenCasts()))
+ if (const FunctionDecl *calleeD =
+ dyn_cast<FunctionDecl>(DR->getDecl())) {
+ calleeD = calleeD->getCanonicalDecl();
+ if (calleeD->isInlineSpecified() &&
+ calleeD->getStorageClass() == FunctionDecl::Static) {
+ // Have we analyzed this static inline function before?
+ VisitFlag &visitFlag = VisitedFD[calleeD];
+ if (visitFlag == NotVisited) {
+ // Mark the callee visited prior to analyzing it
+ // so we terminate in case of recursion.
+ if (calleeD->getBody()) {
+ visitFlag = Visited;
+ IssueWarnings(DefaultPolicy, calleeD, QualType(), true);
+ }
+ else {
+ // Delay warnings until we encounter the definition.
+ visitFlag = Pending;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h
index 39da1b1..b5db8af 100644
--- a/lib/Sema/AnalysisBasedWarnings.h
+++ b/lib/Sema/AnalysisBasedWarnings.h
@@ -14,22 +14,44 @@
#ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
#define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
-namespace clang { namespace sema {
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+class Sema;
+
+namespace sema {
class AnalysisBasedWarnings {
- Sema &S;
- // The warnings to run.
- unsigned enableCheckFallThrough : 1;
- unsigned enableCheckUnreachable : 1;
-
public:
+ class Policy {
+ friend class AnalysisBasedWarnings;
+ // The warnings to run.
+ unsigned enableCheckFallThrough : 1;
+ unsigned enableCheckUnreachable : 1;
+ public:
+ Policy();
+ void disableCheckFallThrough() { enableCheckFallThrough = 0; }
+ };
+
+private:
+ Sema &S;
+ Policy DefaultPolicy;
+ enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 };
+ llvm::DenseMap<const FunctionDecl*, VisitFlag> VisitedFD;
+
+public:
AnalysisBasedWarnings(Sema &s);
- void IssueWarnings(const Decl *D, QualType BlockTy = QualType());
-
- void disableCheckFallThrough() { enableCheckFallThrough = 0; }
+
+ Policy getDefaultPolicy() { return DefaultPolicy; }
+
+ void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType(),
+ const bool analyzeStaticInline = false);
+
};
-
+
}} // end namespace clang::sema
#endif
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index 6b26945..f310c25 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -397,6 +397,12 @@ public:
configure();
}
+ /// \brief Change this lookup's redeclaration kind.
+ void setRedeclarationKind(Sema::RedeclarationKind RK) {
+ Redecl = RK;
+ configure();
+ }
+
void print(llvm::raw_ostream &);
/// Suppress the diagnostics that would normally fire because of this
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 7112687..ccfbe1e 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -132,7 +132,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), NonInstantiationEntries(0),
- CurrentInstantiationScope(0), TyposCorrected(0)
+ CurrentInstantiationScope(0), TyposCorrected(0),
+ AnalysisWarnings(*this)
{
TUScope = 0;
if (getLangOptions().CPlusPlus)
@@ -347,6 +348,30 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
}
}
+Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID) {
+ if (isSFINAEContext()) {
+ switch (Diagnostic::getDiagnosticSFINAEResponse(DiagID)) {
+ case Diagnostic::SFINAE_Report:
+ // Fall through; we'll report the diagnostic below.
+ break;
+
+ case Diagnostic::SFINAE_SubstitutionFailure:
+ // Count this failure so that we know that template argument deduction
+ // has failed.
+ ++NumSFINAEErrors;
+ // Fall through
+
+ case Diagnostic::SFINAE_Suppress:
+ // Suppress this diagnostic.
+ Diags.setLastDiagnosticIgnored();
+ return SemaDiagnosticBuilder(*this);
+ }
+ }
+
+ DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
+ return SemaDiagnosticBuilder(DB, *this, DiagID);
+}
+
Sema::SemaDiagnosticBuilder
Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID()));
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b529e5b..0766b1e 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -19,6 +19,7 @@
#include "CXXFieldCollector.h"
#include "SemaOverload.h"
#include "SemaTemplate.h"
+#include "AnalysisBasedWarnings.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Decl.h"
@@ -298,7 +299,7 @@ public:
/// \brief The set of static functions seen so far that have not been used.
std::vector<FunctionDecl*> UnusedStaticFuncs;
-
+
class AccessedEntity {
public:
/// A member declaration found through lookup. The target is the
@@ -311,30 +312,33 @@ public:
bool isMemberAccess() const { return IsMember; }
- AccessedEntity(MemberNonce _,
+ AccessedEntity(ASTContext &Context,
+ MemberNonce _,
CXXRecordDecl *NamingClass,
AccessSpecifier Access,
NamedDecl *Target)
: Access(Access), IsMember(true),
Target(Target), NamingClass(NamingClass),
- Diag(0) {
+ Diag(0, Context.getDiagAllocator()) {
}
- AccessedEntity(MemberNonce _,
+ AccessedEntity(ASTContext &Context,
+ MemberNonce _,
CXXRecordDecl *NamingClass,
DeclAccessPair FoundDecl)
: Access(FoundDecl.getAccess()), IsMember(true),
Target(FoundDecl.getDecl()), NamingClass(NamingClass),
- Diag(0) {
+ Diag(0, Context.getDiagAllocator()) {
}
- AccessedEntity(BaseNonce _,
+ AccessedEntity(ASTContext &Context,
+ BaseNonce _,
CXXRecordDecl *BaseClass,
CXXRecordDecl *DerivedClass,
AccessSpecifier Access)
: Access(Access), IsMember(false),
Target(BaseClass), NamingClass(DerivedClass),
- Diag(0) {
+ Diag(0, Context.getDiagAllocator()) {
}
bool isQuiet() const { return Diag.getDiagID() == 0; }
@@ -362,7 +366,7 @@ public:
PartialDiagnostic &setDiag(unsigned DiagID) {
assert(isQuiet() && "partial diagnostic already defined");
assert(DiagID && "creating null diagnostic");
- Diag = PartialDiagnostic(DiagID);
+ Diag.Reset(DiagID);
return Diag;
}
const PartialDiagnostic &getDiag() const {
@@ -609,23 +613,16 @@ public:
};
/// \brief Emit a diagnostic.
- SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
- if (isSFINAEContext() && Diagnostic::isBuiltinSFINAEDiag(DiagID)) {
- // If we encountered an error during template argument
- // deduction, and that error is one of the SFINAE errors,
- // suppress the diagnostic.
- ++NumSFINAEErrors;
- Diags.setLastDiagnosticIgnored();
- return SemaDiagnosticBuilder(*this);
- }
-
- DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
- return SemaDiagnosticBuilder(DB, *this, DiagID);
- }
+ SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
/// \brief Emit a partial diagnostic.
SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD);
+ /// \brief Build a partial diagnostic.
+ PartialDiagnostic PDiag(unsigned DiagID = 0) {
+ return PartialDiagnostic(DiagID, Context.getDiagAllocator());
+ }
+
virtual void DeleteExpr(ExprTy *E);
virtual void DeleteStmt(StmtTy *S);
@@ -727,6 +724,7 @@ public:
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc,
+ bool *MissingExceptionSpecification = 0,
bool *MissingEmptyExceptionSpecification = 0);
bool CheckExceptionSpecSubset(
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
@@ -742,10 +740,12 @@ public:
bool RequireCompleteType(SourceLocation Loc, QualType T,
const PartialDiagnostic &PD,
- std::pair<SourceLocation,
- PartialDiagnostic> Note =
- std::make_pair(SourceLocation(), PDiag()));
-
+ std::pair<SourceLocation, PartialDiagnostic> Note);
+ bool RequireCompleteType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD);
+ bool RequireCompleteType(SourceLocation Loc, QualType T,
+ unsigned DiagID);
+
QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T);
QualType BuildTypeofExprType(Expr *E);
@@ -783,7 +783,8 @@ public:
const LookupResult &Previous,
Scope *S);
void DiagnoseFunctionSpecifiers(Declarator& D);
- void DiagnoseShadow(Scope *S, Declarator &D, const LookupResult& R);
+ void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
+ void CheckShadow(Scope *S, VarDecl *D);
NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous, bool &Redeclaration);
@@ -827,6 +828,7 @@ public:
virtual void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init);
void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit);
void ActOnUninitializedDecl(DeclPtrTy dcl, bool TypeContainsUndeducedAuto);
+ virtual void ActOnInitializerError(DeclPtrTy Dcl);
virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc);
virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
DeclPtrTy *Group,
@@ -1110,9 +1112,6 @@ public:
bool SuppressUserConversions, bool ForceRValue,
bool InOverloadResolution);
- bool PerformCopyInitialization(Expr *&From, QualType ToType,
- AssignmentAction Action, bool Elidable = false);
-
OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
OwningExprResult Init);
@@ -1121,6 +1120,7 @@ public:
CXXRecordDecl *ActingContext);
bool PerformObjectArgumentInitialization(Expr *&From,
NestedNameSpecifier *Qualifier,
+ NamedDecl *FoundDecl,
CXXMethodDecl *Method);
ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
@@ -1128,6 +1128,7 @@ public:
bool PerformObjectMemberConversion(Expr *&From,
NestedNameSpecifier *Qualifier,
+ NamedDecl *FoundDecl,
NamedDecl *Member);
// Members have to be NamespaceDecl* or TranslationUnitDecl*.
@@ -1248,11 +1249,15 @@ public:
const PartialDiagnostic &PDiag);
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
- bool Complain);
+ bool Complain,
+ DeclAccessPair &Found);
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
- Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
+ Expr *FixOverloadedFunctionReference(Expr *E,
+ NamedDecl *FoundDecl,
+ FunctionDecl *Fn);
OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
+ NamedDecl *FoundDecl,
FunctionDecl *Fn);
void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
@@ -1448,7 +1453,7 @@ public:
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList);
void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
- bool &IncompleteImpl);
+ bool &IncompleteImpl, unsigned DiagID);
void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
ObjCMethodDecl *IntfMethod);
@@ -1464,7 +1469,7 @@ public:
bool& IncompleteImpl,
const llvm::DenseSet<Selector> &InsMap,
const llvm::DenseSet<Selector> &ClsMap,
- ObjCInterfaceDecl *IDecl);
+ ObjCContainerDecl *CDecl);
/// CheckImplementationIvars - This routine checks if the instance variables
/// listed in the implelementation match those listed in the interface.
@@ -2397,7 +2402,9 @@ public:
Expr *BuildObjCEncodeExpression(SourceLocation AtLoc,
QualType EncodedType,
SourceLocation RParenLoc);
- CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method);
+ CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp,
+ NamedDecl *FoundDecl,
+ CXXMethodDecl *Method);
virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc,
SourceLocation EncodeLoc,
@@ -2471,9 +2478,7 @@ public:
bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers,
- bool IsImplicitConstructor,
- bool AnyErrors);
+ unsigned NumInitializers, bool AnyErrors);
/// MarkBaseAndMemberDestructorsReferenced - Given a record decl,
/// mark all the non-trivial destructors of its members and bases as
@@ -2495,7 +2500,8 @@ public:
/// MarkVirtualMembersReferenced - Will mark all virtual members of the given
/// CXXRecordDecl referenced.
- void MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD);
+ void MarkVirtualMembersReferenced(SourceLocation Loc,
+ const CXXRecordDecl *RD);
/// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes
/// that might need to have their virtual members marked as referenced.
@@ -2513,7 +2519,8 @@ public:
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
- SourceLocation RBrac);
+ SourceLocation RBrac,
+ AttributeList *AttrList);
virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template);
virtual void ActOnStartDelayedMemberDeclarations(Scope *S,
@@ -2640,15 +2647,21 @@ public:
Expr *ObjectExpr,
Expr *ArgExpr,
DeclAccessPair FoundDecl);
+ AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr,
+ DeclAccessPair FoundDecl);
AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
QualType Base, QualType Derived,
const CXXBasePath &Path,
unsigned DiagID,
bool ForceCheck = false,
bool ForceUnprivileged = false);
-
void CheckLookupAccess(const LookupResult &R);
+ void HandleDependentAccessCheck(const DependentDiagnostic &DD,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+ void PerformDependentDiagnostics(const DeclContext *Pattern,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+
void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx);
enum AbstractDiagSelID {
@@ -2869,12 +2882,29 @@ public:
Decl *Param,
TemplateArgumentListBuilder &Converted);
+ /// \brief Specifies the context in which a particular template
+ /// argument is being checked.
+ enum CheckTemplateArgumentKind {
+ /// \brief The template argument was specified in the code or was
+ /// instantiated with some deduced template arguments.
+ CTAK_Specified,
+
+ /// \brief The template argument was deduced via template argument
+ /// deduction.
+ CTAK_Deduced,
+
+ /// \brief The template argument was deduced from an array bound
+ /// via template argument deduction.
+ CTAK_DeducedFromArrayBound
+ };
+
bool CheckTemplateArgument(NamedDecl *Param,
const TemplateArgumentLoc &Arg,
TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
- TemplateArgumentListBuilder &Converted);
+ TemplateArgumentListBuilder &Converted,
+ CheckTemplateArgumentKind CTAK = CTAK_Specified);
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
@@ -2888,15 +2918,22 @@ public:
bool CheckTemplateArgument(TemplateTypeParmDecl *Param,
TypeSourceInfo *Arg);
- bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
- NamedDecl *&Entity);
bool CheckTemplateArgumentPointerToMember(Expr *Arg,
TemplateArgument &Converted);
bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
- TemplateArgument &Converted);
+ TemplateArgument &Converted,
+ CheckTemplateArgumentKind CTAK = CTAK_Specified);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
const TemplateArgumentLoc &Arg);
+
+ OwningExprResult
+ BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
+ QualType ParamType,
+ SourceLocation Loc);
+ OwningExprResult
+ BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
+ SourceLocation Loc);
/// \brief Enumeration describing how template parameter lists are compared
/// for equality.
@@ -3119,14 +3156,15 @@ public:
TemplateDeductionResult
SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
const TemplateArgumentListInfo &ExplicitTemplateArgs,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
llvm::SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
TemplateDeductionInfo &Info);
TemplateDeductionResult
FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ unsigned NumExplicitlySpecified,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info);
@@ -3480,15 +3518,27 @@ public:
/// \brief Whether we have already exited this scope.
bool Exited;
+ /// \brief Whether this scope is temporary, meaning that we should
+ /// remove any additions we make once we exit this
+ /// scope. Temporary scopes are always combined with their outer
+ /// scopes.
+ bool Temporary;
+
+ /// \brief List of the declarations that we have added into this
+ /// temporary scope. They will be removed when we exit the
+ /// temporary scope.
+ llvm::SmallVector<const Decl *, 4> AddedTemporaryDecls;
+
// This class is non-copyable
LocalInstantiationScope(const LocalInstantiationScope &);
LocalInstantiationScope &operator=(const LocalInstantiationScope &);
public:
- LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
+ LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false,
+ bool Temporary = false)
: SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
- Exited(false) {
- if (!CombineWithOuterScope)
+ Exited(false), Temporary(Temporary) {
+ if (!CombineWithOuterScope && !Temporary)
SemaRef.CurrentInstantiationScope = this;
else
assert(SemaRef.CurrentInstantiationScope &&
@@ -3496,8 +3546,11 @@ public:
}
~LocalInstantiationScope() {
- if (!Exited)
+ if (!Exited) {
SemaRef.CurrentInstantiationScope = Outer;
+ for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I)
+ LocalDecls.erase(AddedTemporaryDecls[I]);
+ }
}
/// \brief Exit this local instantiation scope early.
@@ -3530,6 +3583,10 @@ public:
void InstantiatedLocal(const Decl *D, Decl *Inst) {
Decl *&Stored = LocalDecls[D];
assert((!Stored || Stored == Inst) && "Already instantiated this local");
+
+ if (Temporary && !Stored)
+ AddedTemporaryDecls.push_back(D);
+
Stored = Inst;
}
};
@@ -3541,6 +3598,9 @@ public:
/// \brief The number of typos corrected by CorrectTypo.
unsigned TyposCorrected;
+ /// \brief Worker object for performing CFG-based warnings.
+ sema::AnalysisBasedWarnings AnalysisWarnings;
+
/// \brief An entity for which implicit template instantiation is required.
///
/// The source location associated with the declaration is the first place in
@@ -3714,7 +3774,7 @@ public:
/// Ensure attributes are consistent with type.
/// \param [in, out] Attributes The attributes to check; they will
/// be modified to be consistent with \arg PropertyTy.
- void CheckObjCPropertyAttributes(QualType PropertyTy,
+ void CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy,
SourceLocation Loc,
unsigned &Attributes);
void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC);
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 40b320c..f628884 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExprCXX.h"
using namespace clang;
@@ -52,136 +53,323 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
namespace {
struct EffectiveContext {
- EffectiveContext() : Function(0) {}
+ EffectiveContext() : Inner(0), Dependent(false) {}
- explicit EffectiveContext(DeclContext *DC) {
- if (isa<FunctionDecl>(DC)) {
- Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
- DC = Function->getDeclContext();
- } else
- Function = 0;
+ explicit EffectiveContext(DeclContext *DC)
+ : Inner(DC),
+ Dependent(DC->isDependentContext()) {
// C++ [class.access.nest]p1:
// A nested class is a member and as such has the same access
// rights as any other member.
// C++ [class.access]p2:
// A member of a class can also access all the names to which
- // the class has access.
- // This implies that the privileges of nesting are transitive.
- while (isa<CXXRecordDecl>(DC)) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
- Records.push_back(Record);
- DC = Record->getDeclContext();
+ // the class has access. A local class of a member function
+ // may access the same names that the member function itself
+ // may access.
+ // This almost implies that the privileges of nesting are transitive.
+ // Technically it says nothing about the local classes of non-member
+ // functions (which can gain privileges through friendship), but we
+ // take that as an oversight.
+ while (true) {
+ if (isa<CXXRecordDecl>(DC)) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ Records.push_back(Record);
+ DC = Record->getDeclContext();
+ } else if (isa<FunctionDecl>(DC)) {
+ FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
+ Functions.push_back(Function);
+ DC = Function->getDeclContext();
+ } else if (DC->isFileContext()) {
+ break;
+ } else {
+ DC = DC->getParent();
+ }
}
}
+ bool isDependent() const { return Dependent; }
+
bool includesClass(const CXXRecordDecl *R) const {
R = R->getCanonicalDecl();
return std::find(Records.begin(), Records.end(), R)
!= Records.end();
}
+ /// Retrieves the innermost "useful" context. Can be null if we're
+ /// doing access-control without privileges.
+ DeclContext *getInnerContext() const {
+ return Inner;
+ }
+
+ typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
+
+ DeclContext *Inner;
+ llvm::SmallVector<FunctionDecl*, 4> Functions;
llvm::SmallVector<CXXRecordDecl*, 4> Records;
- FunctionDecl *Function;
+ bool Dependent;
};
}
static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
- CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+ DeclContext *DC = D->getDeclContext();
+
+ // This can only happen at top: enum decls only "publish" their
+ // immediate members.
+ if (isa<EnumDecl>(DC))
+ DC = cast<EnumDecl>(DC)->getDeclContext();
+
+ CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
while (DeclaringClass->isAnonymousStructOrUnion())
DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
return DeclaringClass;
}
+static bool MightInstantiateTo(Sema &S, DeclContext *Context,
+ DeclContext *Friend) {
+ if (Friend == Context)
+ return true;
+
+ assert(!Friend->isDependentContext() &&
+ "can't handle friends with dependent contexts here");
+
+ if (!Context->isDependentContext())
+ return false;
+
+ if (Friend->isFileContext())
+ return false;
+
+ // TODO: this is very conservative
+ return true;
+}
+
+// Asks whether the type in 'context' can ever instantiate to the type
+// in 'friend'.
+static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
+ if (Friend == Context)
+ return true;
+
+ if (!Friend->isDependentType() && !Context->isDependentType())
+ return false;
+
+ // TODO: this is very conservative.
+ return true;
+}
+
+static bool MightInstantiateTo(Sema &S,
+ FunctionDecl *Context,
+ FunctionDecl *Friend) {
+ if (Context->getDeclName() != Friend->getDeclName())
+ return false;
+
+ if (!MightInstantiateTo(S,
+ Context->getDeclContext(),
+ Friend->getDeclContext()))
+ return false;
+
+ CanQual<FunctionProtoType> FriendTy
+ = S.Context.getCanonicalType(Friend->getType())
+ ->getAs<FunctionProtoType>();
+ CanQual<FunctionProtoType> ContextTy
+ = S.Context.getCanonicalType(Context->getType())
+ ->getAs<FunctionProtoType>();
+
+ // There isn't any way that I know of to add qualifiers
+ // during instantiation.
+ if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
+ return false;
+
+ if (FriendTy->getNumArgs() != ContextTy->getNumArgs())
+ return false;
+
+ if (!MightInstantiateTo(S,
+ ContextTy->getResultType(),
+ FriendTy->getResultType()))
+ return false;
+
+ for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I)
+ if (!MightInstantiateTo(S,
+ ContextTy->getArgType(I),
+ FriendTy->getArgType(I)))
+ return false;
+
+ return true;
+}
+
+static bool MightInstantiateTo(Sema &S,
+ FunctionTemplateDecl *Context,
+ FunctionTemplateDecl *Friend) {
+ return MightInstantiateTo(S,
+ Context->getTemplatedDecl(),
+ Friend->getTemplatedDecl());
+}
+
static Sema::AccessResult MatchesFriend(Sema &S,
const EffectiveContext &EC,
const CXXRecordDecl *Friend) {
- // FIXME: close matches becuse of dependency
if (EC.includesClass(Friend))
return Sema::AR_accessible;
+ if (EC.isDependent()) {
+ CanQualType FriendTy
+ = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend));
+
+ for (EffectiveContext::record_iterator
+ I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
+ CanQualType ContextTy
+ = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
+ if (MightInstantiateTo(S, ContextTy, FriendTy))
+ return Sema::AR_dependent;
+ }
+ }
+
return Sema::AR_inaccessible;
}
static Sema::AccessResult MatchesFriend(Sema &S,
const EffectiveContext &EC,
- FriendDecl *Friend) {
- if (Type *T = Friend->getFriendType()) {
- CanQualType CT = T->getCanonicalTypeUnqualified();
- if (const RecordType *RT = CT->getAs<RecordType>())
- return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
-
- // TODO: we can fail early for a lot of type classes.
- if (T->isDependentType())
- return Sema::AR_dependent;
+ CanQualType Friend) {
+ if (const RecordType *RT = Friend->getAs<RecordType>())
+ return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
- return Sema::AR_inaccessible;
- }
+ // TODO: we can do better than this
+ if (Friend->isDependentType())
+ return Sema::AR_dependent;
- NamedDecl *D
- = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl());
+ return Sema::AR_inaccessible;
+}
- // FIXME: declarations with dependent or templated scope.
+/// Determines whether the given friend class template matches
+/// anything in the effective context.
+static Sema::AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ ClassTemplateDecl *Friend) {
+ Sema::AccessResult OnFailure = Sema::AR_inaccessible;
- // For class templates, we want to check whether any of the records
- // are possible specializations of the template.
- if (isa<ClassTemplateDecl>(D)) {
- for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
- I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
- CXXRecordDecl *Record = *I;
- ClassTemplateDecl *CTD;
+ // Check whether the friend is the template of a class in the
+ // context chain.
+ for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
+ I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
+ CXXRecordDecl *Record = *I;
- // A specialization of the template...
- if (isa<ClassTemplateSpecializationDecl>(Record)) {
- CTD = cast<ClassTemplateSpecializationDecl>(Record)
- ->getSpecializedTemplate();
+ // Figure out whether the current class has a template:
+ ClassTemplateDecl *CTD;
- // ... or the template pattern itself.
- } else {
- CTD = Record->getDescribedClassTemplate();
- }
+ // A specialization of the template...
+ if (isa<ClassTemplateSpecializationDecl>(Record)) {
+ CTD = cast<ClassTemplateSpecializationDecl>(Record)
+ ->getSpecializedTemplate();
- if (CTD && D == CTD->getCanonicalDecl())
- return Sema::AR_accessible;
+ // ... or the template pattern itself.
+ } else {
+ CTD = Record->getDescribedClassTemplate();
+ if (!CTD) continue;
}
- return Sema::AR_inaccessible;
+ // It's a match.
+ if (Friend == CTD->getCanonicalDecl())
+ return Sema::AR_accessible;
+
+ // If the context isn't dependent, it can't be a dependent match.
+ if (!EC.isDependent())
+ continue;
+
+ // If the template names don't match, it can't be a dependent
+ // match. This isn't true in C++0x because of template aliases.
+ if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
+ continue;
+
+ // If the class's context can't instantiate to the friend's
+ // context, it can't be a dependent match.
+ if (!MightInstantiateTo(S, CTD->getDeclContext(),
+ Friend->getDeclContext()))
+ continue;
+
+ // Otherwise, it's a dependent match.
+ OnFailure = Sema::AR_dependent;
+ }
+
+ return OnFailure;
+}
+
+/// Determines whether the given friend function matches anything in
+/// the effective context.
+static Sema::AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FunctionDecl *Friend) {
+ Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+
+ for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
+ I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
+ if (Friend == *I)
+ return Sema::AR_accessible;
+
+ if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
+ OnFailure = Sema::AR_dependent;
}
- // Same thing for function templates.
- if (isa<FunctionTemplateDecl>(D)) {
- if (!EC.Function) return Sema::AR_inaccessible;
+ return OnFailure;
+}
+
+/// Determines whether the given friend function template matches
+/// anything in the effective context.
+static Sema::AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FunctionTemplateDecl *Friend) {
+ if (EC.Functions.empty()) return Sema::AR_inaccessible;
- FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate();
+ Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+
+ for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
+ I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
+
+ FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
if (!FTD)
- FTD = EC.Function->getDescribedFunctionTemplate();
+ FTD = (*I)->getDescribedFunctionTemplate();
+ if (!FTD)
+ continue;
+
+ FTD = FTD->getCanonicalDecl();
- if (FTD && D == FTD->getCanonicalDecl())
+ if (Friend == FTD)
return Sema::AR_accessible;
-
- return Sema::AR_inaccessible;
+
+ if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
+ OnFailure = Sema::AR_dependent;
}
- // Friend functions. FIXME: close matches due to dependency.
- //
- // The decl pointers in EC have been canonicalized, so pointer
- // equality is sufficient.
- if (D == EC.Function)
- return Sema::AR_accessible;
+ return OnFailure;
+}
- if (isa<CXXRecordDecl>(D))
- return MatchesFriend(S, EC, cast<CXXRecordDecl>(D));
+/// Determines whether the given friend declaration matches anything
+/// in the effective context.
+static Sema::AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FriendDecl *FriendD) {
+ if (TypeSourceInfo *T = FriendD->getFriendType())
+ return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
- return Sema::AR_inaccessible;
+ NamedDecl *Friend
+ = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
+
+ // FIXME: declarations with dependent or templated scope.
+
+ if (isa<ClassTemplateDecl>(Friend))
+ return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
+
+ if (isa<FunctionTemplateDecl>(Friend))
+ return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
+
+ if (isa<CXXRecordDecl>(Friend))
+ return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
+
+ assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
+ return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
}
static Sema::AccessResult GetFriendKind(Sema &S,
const EffectiveContext &EC,
const CXXRecordDecl *Class) {
- // A class always has access to its own members.
- if (EC.includesClass(Class))
- return Sema::AR_accessible;
-
Sema::AccessResult OnFailure = Sema::AR_inaccessible;
// Okay, check friends.
@@ -209,9 +397,88 @@ static Sema::AccessResult GetFriendKind(Sema &S,
return OnFailure;
}
+static Sema::AccessResult HasAccess(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *NamingClass,
+ AccessSpecifier Access) {
+ assert(NamingClass->getCanonicalDecl() == NamingClass &&
+ "declaration should be canonicalized before being passed here");
+
+ if (Access == AS_public) return Sema::AR_accessible;
+ assert(Access == AS_private || Access == AS_protected);
+
+ for (EffectiveContext::record_iterator
+ I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
+ // All the declarations in EC have been canonicalized, so pointer
+ // equality from this point on will work fine.
+ const CXXRecordDecl *ECRecord = *I;
+
+ // [B2] and [M2]
+ if (ECRecord == NamingClass)
+ return Sema::AR_accessible;
+
+ // [B3] and [M3]
+ if (Access == AS_protected &&
+ ECRecord->isDerivedFrom(const_cast<CXXRecordDecl*>(NamingClass)))
+ return Sema::AR_accessible;
+ }
+
+ return GetFriendKind(S, EC, NamingClass);
+}
+
/// Finds the best path from the naming class to the declaring class,
/// taking friend declarations into account.
///
+/// C++0x [class.access.base]p5:
+/// A member m is accessible at the point R when named in class N if
+/// [M1] m as a member of N is public, or
+/// [M2] m as a member of N is private, and R occurs in a member or
+/// friend of class N, or
+/// [M3] m as a member of N is protected, and R occurs in a member or
+/// friend of class N, or in a member or friend of a class P
+/// derived from N, where m as a member of P is public, private,
+/// or protected, or
+/// [M4] there exists a base class B of N that is accessible at R, and
+/// m is accessible at R when named in class B.
+///
+/// C++0x [class.access.base]p4:
+/// A base class B of N is accessible at R, if
+/// [B1] an invented public member of B would be a public member of N, or
+/// [B2] R occurs in a member or friend of class N, and an invented public
+/// member of B would be a private or protected member of N, or
+/// [B3] R occurs in a member or friend of a class P derived from N, and an
+/// invented public member of B would be a private or protected member
+/// of P, or
+/// [B4] there exists a class S such that B is a base class of S accessible
+/// at R and S is a base class of N accessible at R.
+///
+/// Along a single inheritance path we can restate both of these
+/// iteratively:
+///
+/// First, we note that M1-4 are equivalent to B1-4 if the member is
+/// treated as a notional base of its declaring class with inheritance
+/// access equivalent to the member's access. Therefore we need only
+/// ask whether a class B is accessible from a class N in context R.
+///
+/// Let B_1 .. B_n be the inheritance path in question (i.e. where
+/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of
+/// B_i). For i in 1..n, we will calculate ACAB(i), the access to the
+/// closest accessible base in the path:
+/// Access(a, b) = (* access on the base specifier from a to b *)
+/// Merge(a, forbidden) = forbidden
+/// Merge(a, private) = forbidden
+/// Merge(a, b) = min(a,b)
+/// Accessible(c, forbidden) = false
+/// Accessible(c, private) = (R is c) || IsFriend(c, R)
+/// Accessible(c, protected) = (R derived from c) || IsFriend(c, R)
+/// Accessible(c, public) = true
+/// ACAB(n) = public
+/// ACAB(i) =
+/// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in
+/// if Accessible(B_i, AccessToBase) then public else AccessToBase
+///
+/// B is an accessible base of N at R iff ACAB(1) = public.
+///
/// \param FinalAccess the access of the "final step", or AS_none if
/// there is no final step.
/// \return null if friendship is dependent
@@ -230,6 +497,8 @@ static CXXBasePath *FindBestPath(Sema &S,
assert(FinalAccess != AS_none && "forbidden access after declaring class");
+ bool AnyDependent = false;
+
// Derive the friend-modified access along each path.
for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
PI != PE; ++PI) {
@@ -251,19 +520,15 @@ static CXXBasePath *FindBestPath(Sema &S,
}
AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
- if (BaseAccess != AS_public) {
- switch (GetFriendKind(S, EC, I->Class)) {
- case Sema::AR_inaccessible:
- PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
- break;
- case Sema::AR_accessible:
- PathAccess = AS_public;
- break;
- case Sema::AR_dependent:
- return 0;
- case Sema::AR_delayed:
- llvm_unreachable("friend resolution is never delayed"); break;
- }
+ PathAccess = std::max(PathAccess, BaseAccess);
+ switch (HasAccess(S, EC, I->Class, PathAccess)) {
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_accessible: PathAccess = AS_public; break;
+ case Sema::AR_dependent:
+ AnyDependent = true;
+ goto Next;
+ case Sema::AR_delayed:
+ llvm_unreachable("friend resolution is never delayed"); break;
}
}
@@ -272,9 +537,23 @@ static CXXBasePath *FindBestPath(Sema &S,
if (BestPath == 0 || PathAccess < BestPath->Access) {
BestPath = &*PI;
BestPath->Access = PathAccess;
+
+ // Short-circuit if we found a public path.
+ if (BestPath->Access == AS_public)
+ return BestPath;
}
+
+ Next: ;
}
+ assert((!BestPath || BestPath->Access != AS_public) &&
+ "fell out of loop with public path");
+
+ // We didn't find a public path, but at least one path was subject
+ // to dependent friendship, so delay the check.
+ if (AnyDependent)
+ return 0;
+
return BestPath;
}
@@ -282,16 +561,27 @@ static CXXBasePath *FindBestPath(Sema &S,
/// to become inaccessible.
static void DiagnoseAccessPath(Sema &S,
const EffectiveContext &EC,
- CXXRecordDecl *NamingClass,
- CXXRecordDecl *DeclaringClass,
- NamedDecl *D, AccessSpecifier Access) {
+ const Sema::AccessedEntity &Entity) {
+ AccessSpecifier Access = Entity.getAccess();
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
+ NamingClass = NamingClass->getCanonicalDecl();
+
+ NamedDecl *D;
+ CXXRecordDecl *DeclaringClass;
+ if (Entity.isMemberAccess()) {
+ D = Entity.getTargetDecl();
+ DeclaringClass = FindDeclaringClass(D);
+ } else {
+ D = 0;
+ DeclaringClass = Entity.getBaseClass();
+ }
+ DeclaringClass = DeclaringClass->getCanonicalDecl();
+
// Easy case: the decl's natural access determined its path access.
// We have to check against AS_private here in case Access is AS_none,
// indicating a non-public member of a private base class.
- //
- // DependentFriend should be impossible here.
if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
- switch (GetFriendKind(S, EC, DeclaringClass)) {
+ switch (HasAccess(S, EC, DeclaringClass, D->getAccess())) {
case Sema::AR_inaccessible: {
S.Diag(D->getLocation(), diag::note_access_natural)
<< (unsigned) (Access == AS_protected)
@@ -357,144 +647,166 @@ static void DiagnoseAccessPath(Sema &S,
llvm_unreachable("access not apparently constrained by path");
}
-/// Diagnose an inaccessible class member.
-static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
- const EffectiveContext &EC,
- CXXRecordDecl *NamingClass,
- AccessSpecifier Access,
- const Sema::AccessedEntity &Entity) {
- NamedDecl *D = Entity.getTargetDecl();
- CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
+static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
+ const EffectiveContext &EC,
+ const Sema::AccessedEntity &Entity) {
+ const CXXRecordDecl *NamingClass = Entity.getNamingClass();
+ NamedDecl *D;
+ const CXXRecordDecl *DeclaringClass;
+ if (Entity.isMemberAccess()) {
+ D = Entity.getTargetDecl();
+ DeclaringClass = FindDeclaringClass(D);
+ } else {
+ D = 0;
+ DeclaringClass = Entity.getBaseClass();
+ }
S.Diag(Loc, Entity.getDiag())
- << (Access == AS_protected)
- << D->getDeclName()
+ << (Entity.getAccess() == AS_protected)
+ << (D ? D->getDeclName() : DeclarationName())
<< S.Context.getTypeDeclType(NamingClass)
<< S.Context.getTypeDeclType(DeclaringClass);
- DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
+ DiagnoseAccessPath(S, EC, Entity);
}
-/// Diagnose an inaccessible hierarchy conversion.
-static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
- const EffectiveContext &EC,
- AccessSpecifier Access,
- const Sema::AccessedEntity &Entity) {
- S.Diag(Loc, Entity.getDiag())
- << (Access == AS_protected)
- << DeclarationName()
- << S.Context.getTypeDeclType(Entity.getDerivedClass())
- << S.Context.getTypeDeclType(Entity.getBaseClass());
- DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
- Entity.getBaseClass(), 0, Access);
-}
+/// Determines whether the accessed entity is accessible. Public members
+/// have been weeded out by this point.
+static Sema::AccessResult IsAccessible(Sema &S,
+ const EffectiveContext &EC,
+ const Sema::AccessedEntity &Entity) {
+ // Determine the actual naming class.
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
+ while (NamingClass->isAnonymousStructOrUnion())
+ NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
+ NamingClass = NamingClass->getCanonicalDecl();
-static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
- const EffectiveContext &EC,
- CXXRecordDecl *NamingClass,
- AccessSpecifier Access,
- const Sema::AccessedEntity &Entity) {
- if (Entity.isMemberAccess())
- DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
- else
- DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
-}
+ AccessSpecifier UnprivilegedAccess = Entity.getAccess();
+ assert(UnprivilegedAccess != AS_public && "public access not weeded out");
+ // Before we try to recalculate access paths, try to white-list
+ // accesses which just trade in on the final step, i.e. accesses
+ // which don't require [M4] or [B4]. These are by far the most
+ // common forms of access.
+ if (UnprivilegedAccess != AS_none) {
+ switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess)) {
+ case Sema::AR_dependent:
+ // This is actually an interesting policy decision. We don't
+ // *have* to delay immediately here: we can do the full access
+ // calculation in the hope that friendship on some intermediate
+ // class will make the declaration accessible non-dependently.
+ // But that's not cheap, and odds are very good (note: assertion
+ // made without data) that the friend declaration will determine
+ // access.
+ return Sema::AR_dependent;
+
+ case Sema::AR_accessible: return Sema::AR_accessible;
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_delayed:
+ llvm_unreachable("friendship never subject to contextual delay");
+ }
+ }
-/// Try to elevate access using friend declarations. This is
-/// potentially quite expensive.
-static void TryElevateAccess(Sema &S,
- const EffectiveContext &EC,
- const Sema::AccessedEntity &Entity,
- AccessSpecifier &Access) {
+ // Determine the declaring class.
CXXRecordDecl *DeclaringClass;
if (Entity.isMemberAccess()) {
DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
} else {
DeclaringClass = Entity.getBaseClass();
}
- CXXRecordDecl *NamingClass = Entity.getNamingClass();
+ DeclaringClass = DeclaringClass->getCanonicalDecl();
+
+ // We lower member accesses to base accesses by pretending that the
+ // member is a base class of its declaring class.
+ AccessSpecifier FinalAccess;
- // Adjust the declaration of the referred entity.
- AccessSpecifier DeclAccess = AS_public;
if (Entity.isMemberAccess()) {
+ // Determine if the declaration is accessible from EC when named
+ // in its declaring class.
NamedDecl *Target = Entity.getTargetDecl();
- DeclAccess = Target->getAccess();
- if (DeclAccess != AS_public) {
- switch (GetFriendKind(S, EC, DeclaringClass)) {
- case Sema::AR_accessible: DeclAccess = AS_public; break;
- case Sema::AR_inaccessible: break;
- case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
- case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
- }
+ FinalAccess = Target->getAccess();
+ switch (HasAccess(S, EC, DeclaringClass, FinalAccess)) {
+ case Sema::AR_accessible: FinalAccess = AS_public; break;
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_dependent: return Sema::AR_dependent; // see above
+ case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
}
- if (DeclaringClass == NamingClass) {
- Access = DeclAccess;
- return;
- }
+ if (DeclaringClass == NamingClass)
+ return (FinalAccess == AS_public
+ ? Sema::AR_accessible
+ : Sema::AR_inaccessible);
+ } else {
+ FinalAccess = AS_public;
}
assert(DeclaringClass != NamingClass);
// Append the declaration's access if applicable.
CXXBasePaths Paths;
- CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
- DeclaringClass, DeclAccess, Paths);
- if (!Path) {
- // FIXME: delay dependent friendship
- return;
- }
+ CXXBasePath *Path = FindBestPath(S, EC, NamingClass, DeclaringClass,
+ FinalAccess, Paths);
+ if (!Path)
+ return Sema::AR_dependent;
+
+ assert(Path->Access <= UnprivilegedAccess &&
+ "access along best path worse than direct?");
+ if (Path->Access == AS_public)
+ return Sema::AR_accessible;
+ return Sema::AR_inaccessible;
+}
- // Grab the access along the best path (note that this includes the
- // final-step access).
- AccessSpecifier NewAccess = Path->Access;
- assert(NewAccess <= Access && "access along best path worse than direct?");
- Access = NewAccess;
+static void DelayAccess(Sema &S,
+ const EffectiveContext &EC,
+ SourceLocation Loc,
+ const Sema::AccessedEntity &Entity) {
+ assert(EC.isDependent() && "delaying non-dependent access");
+ DeclContext *DC = EC.getInnerContext();
+ assert(DC->isDependentContext() && "delaying non-dependent access");
+ DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
+ Loc,
+ Entity.isMemberAccess(),
+ Entity.getAccess(),
+ Entity.getTargetDecl(),
+ Entity.getNamingClass(),
+ Entity.getDiag());
}
/// Checks access to an entity from the given effective context.
static Sema::AccessResult CheckEffectiveAccess(Sema &S,
const EffectiveContext &EC,
SourceLocation Loc,
- Sema::AccessedEntity const &Entity) {
- AccessSpecifier Access = Entity.getAccess();
- assert(Access != AS_public && "called for public access!");
+ const Sema::AccessedEntity &Entity) {
+ assert(Entity.getAccess() != AS_public && "called for public access!");
- // Find a non-anonymous naming class. For records with access,
- // there should always be one of these.
- CXXRecordDecl *NamingClass = Entity.getNamingClass();
- while (NamingClass->isAnonymousStructOrUnion())
- NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
+ switch (IsAccessible(S, EC, Entity)) {
+ case Sema::AR_dependent:
+ DelayAccess(S, EC, Loc, Entity);
+ return Sema::AR_dependent;
- // White-list accesses from classes with privileges equivalent to the
- // naming class --- but only if the access path isn't forbidden
- // (i.e. an access of a private member from a subclass).
- if (Access != AS_none && EC.includesClass(NamingClass))
- return Sema::AR_accessible;
+ case Sema::AR_delayed:
+ llvm_unreachable("IsAccessible cannot contextually delay");
- // Try to elevate access.
- // FIXME: delay if elevation was dependent?
- // TODO: on some code, it might be better to do the protected check
- // without trying to elevate first.
- TryElevateAccess(S, EC, Entity, Access);
- if (Access == AS_public) return Sema::AR_accessible;
+ case Sema::AR_inaccessible:
+ if (!Entity.isQuiet())
+ DiagnoseBadAccess(S, Loc, EC, Entity);
+ return Sema::AR_inaccessible;
- // Protected access.
- if (Access == AS_protected) {
- // FIXME: implement [class.protected]p1
- for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
- I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I)
- if ((*I)->isDerivedFrom(NamingClass))
- return Sema::AR_accessible;
+ case Sema::AR_accessible:
+ break;
+ }
- // FIXME: delay if we can't decide class derivation yet.
+ // We only consider the natural access of the declaration when
+ // deciding whether to do the protected check.
+ if (Entity.isMemberAccess() && Entity.getAccess() == AS_protected) {
+ NamedDecl *D = Entity.getTargetDecl();
+ if (isa<FieldDecl>(D) ||
+ (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())) {
+ // FIXME: implement [class.protected]
+ }
}
- // Okay, that's it, reject it.
- if (!Entity.isQuiet())
- DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
- return Sema::AR_inaccessible;
+ return Sema::AR_accessible;
}
static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
@@ -526,6 +838,37 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
DD.Triggered = true;
}
+void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ SourceLocation Loc = DD.getAccessLoc();
+ AccessSpecifier Access = DD.getAccess();
+
+ Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),
+ TemplateArgs);
+ if (!NamingD) return;
+ Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),
+ TemplateArgs);
+ if (!TargetD) return;
+
+ if (DD.isAccessToMember()) {
+ AccessedEntity Entity(Context,
+ AccessedEntity::Member,
+ cast<CXXRecordDecl>(NamingD),
+ Access,
+ cast<NamedDecl>(TargetD));
+ Entity.setDiag(DD.getDiagnostic());
+ CheckAccess(*this, Loc, Entity);
+ } else {
+ AccessedEntity Entity(Context,
+ AccessedEntity::Base,
+ cast<CXXRecordDecl>(TargetD),
+ cast<CXXRecordDecl>(NamingD),
+ Access);
+ Entity.setDiag(DD.getDiagnostic());
+ CheckAccess(*this, Loc, Entity);
+ }
+}
+
Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
DeclAccessPair Found) {
if (!getLangOptions().AccessControl ||
@@ -533,7 +876,8 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
+ AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
+ Found);
Entity.setDiag(diag::err_access) << E->getSourceRange();
return CheckAccess(*this, E->getNameLoc(), Entity);
@@ -547,7 +891,8 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
+ AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
+ Found);
Entity.setDiag(diag::err_access) << E->getSourceRange();
return CheckAccess(*this, E->getMemberLoc(), Entity);
@@ -565,7 +910,7 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
return AR_accessible;
CXXRecordDecl *NamingClass = Dtor->getParent();
- AccessedEntity Entity(AccessedEntity::Member, NamingClass,
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
DeclAccessPair::make(Dtor, Access));
Entity.setDiag(PDiag); // TODO: avoid copy
@@ -581,7 +926,7 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
- AccessedEntity Entity(AccessedEntity::Member, NamingClass,
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
DeclAccessPair::make(Constructor, Access));
Entity.setDiag(diag::err_access_ctor);
@@ -599,7 +944,7 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
return AR_accessible;
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
- AccessedEntity Entity(AccessedEntity::Member, NamingClass,
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
DeclAccessPair::make(Target, Access));
Entity.setDiag(Diag);
return CheckAccess(*this, UseLoc, Entity);
@@ -616,7 +961,7 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
Entity.setDiag(diag::err_access)
<< PlacementRange;
@@ -637,7 +982,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
assert(RT && "found member operator but object expr not of record type");
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
- AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
Entity.setDiag(diag::err_access)
<< ObjectExpr->getSourceRange()
<< (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
@@ -645,6 +990,32 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
return CheckAccess(*this, OpLoc, Entity);
}
+Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
+ DeclAccessPair Found) {
+ if (!getLangOptions().AccessControl ||
+ Found.getAccess() == AS_none ||
+ Found.getAccess() == AS_public)
+ return AR_accessible;
+
+ OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer();
+ NestedNameSpecifier *Qualifier = Ovl->getQualifier();
+ assert(Qualifier && "address of overloaded member without qualifier");
+
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ SS.setRange(Ovl->getQualifierRange());
+ DeclContext *DC = computeDeclContext(SS);
+ assert(DC && DC->isRecord() && "scope did not resolve to record");
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(DC);
+
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
+ Entity.setDiag(diag::err_access)
+ << Ovl->getSourceRange();
+
+ return CheckAccess(*this, Ovl->getNameLoc(), Entity);
+}
+
+
/// Checks access for a hierarchy conversion.
///
/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
@@ -671,7 +1042,8 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
- AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access);
+ AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD,
+ Path.Access);
if (DiagID)
Entity.setDiag(DiagID) << Derived << Base;
@@ -688,7 +1060,7 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
if (I.getAccess() != AS_public) {
- AccessedEntity Entity(AccessedEntity::Member,
+ AccessedEntity Entity(Context, AccessedEntity::Member,
R.getNamingClass(),
I.getPair());
Entity.setDiag(diag::err_access);
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 014cec2..11c8e6d 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -315,7 +315,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
assert(DestPointer && "Reference to void is not possible");
} else if (DestRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
- PDiag(diag::err_bad_dynamic_cast_incomplete)
+ Self.PDiag(diag::err_bad_dynamic_cast_incomplete)
<< DestRange))
return;
} else {
@@ -353,7 +353,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const RecordType *SrcRecord = SrcPointee->getAs<RecordType>();
if (SrcRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
- PDiag(diag::err_bad_dynamic_cast_incomplete)
+ Self.PDiag(diag::err_bad_dynamic_cast_incomplete)
<< SrcExpr->getSourceRange()))
return;
} else {
@@ -621,8 +621,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
return TC_Failed;
}
- // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation
- // than nothing.
+ // FIXME: We should probably have an AST node for lvalue-to-rvalue
+ // conversions.
return TC_Success;
}
@@ -698,8 +698,8 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
QualType OrigDestType, unsigned &msg,
CastExpr::CastKind &Kind) {
// We can only work with complete types. But don't complain if it doesn't work
- if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, PDiag(0)) ||
- Self.RequireCompleteType(OpRange.getBegin(), DestType, PDiag(0)))
+ if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, Self.PDiag(0)) ||
+ Self.RequireCompleteType(OpRange.getBegin(), DestType, Self.PDiag(0)))
return TC_NotApplicable;
// Downcast can only happen in class hierarchies, so we need classes.
@@ -808,8 +808,10 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
return TC_NotApplicable;
bool WasOverloadedFunction = false;
+ DeclAccessPair FoundOverload;
if (FunctionDecl *Fn
- = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false)) {
+ = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false,
+ FoundOverload)) {
CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
SrcType = Self.Context.getMemberPointerType(Fn->getType(),
Self.Context.getTypeDeclType(M->getParent()).getTypePtr());
@@ -870,13 +872,14 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
// allowing complaints if something goes wrong.
FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr,
DestType,
- true);
+ true,
+ FoundOverload);
if (!Fn) {
msg = 0;
return TC_Failed;
}
- SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, Fn);
+ SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn);
if (!SrcExpr) {
msg = 0;
return TC_Failed;
@@ -913,27 +916,24 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// At this point of CheckStaticCast, if the destination is a reference,
// this has to work. There is no other way that works.
// On the other hand, if we're checking a C-style cast, we've still got
- // the reinterpret_cast way. So in C-style mode, we first try the call
- // with an ICS to suppress errors.
- if (CStyle) {
- ImplicitConversionSequence ICS;
- if(Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false, /*ForceRValue=*/false,
- &ICS))
- return TC_NotApplicable;
+ // the reinterpret_cast way.
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
+ InitializationKind InitKind = InitializationKind::CreateCast(OpRange,
+ CStyle);
+ InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
+ if (InitSeq.getKind() == InitializationSequence::FailedSequence && CStyle)
+ return TC_NotApplicable;
+
+ Sema::OwningExprResult Result
+ = InitSeq.Perform(Self, Entity, InitKind,
+ Action::MultiExprArg(Self, (void**)&SrcExpr, 1));
+ if (Result.isInvalid()) {
+ msg = 0;
+ return TC_Failed;
}
- // Now we're committed either way.
- if(!Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false, 0,
- /*IgnoreBaseAccess=*/CStyle))
- return TC_Success;
-
- // We already got an error message.
- msg = 0;
- return TC_Failed;
+
+ SrcExpr = Result.takeAs<Expr>();
+ return TC_Success;
}
if (DestType->isRecordType()) {
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 95b79ab..c90f75e 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -486,13 +486,13 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_suggest)
<< Name << LookupCtx << Found.getLookupName() << SS.getRange()
- << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(Found.getNameLoc(),
+ Found.getLookupName().getAsString());
else
Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
<< Name << Found.getLookupName()
- << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(Found.getNameLoc(),
+ Found.getLookupName().getAsString());
if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
Diag(ND->getLocation(), diag::note_previous_decl)
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 0a33485..f2520fc 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -184,13 +184,11 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__sync_fetch_and_or:
case Builtin::BI__sync_fetch_and_and:
case Builtin::BI__sync_fetch_and_xor:
- case Builtin::BI__sync_fetch_and_nand:
case Builtin::BI__sync_add_and_fetch:
case Builtin::BI__sync_sub_and_fetch:
case Builtin::BI__sync_and_and_fetch:
case Builtin::BI__sync_or_and_fetch:
case Builtin::BI__sync_xor_and_fetch:
- case Builtin::BI__sync_nand_and_fetch:
case Builtin::BI__sync_val_compare_and_swap:
case Builtin::BI__sync_bool_compare_and_swap:
case Builtin::BI__sync_lock_test_and_set:
@@ -222,11 +220,6 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
if (const FormatAttr *Format = FDecl->getAttr<FormatAttr>()) {
if (CheckablePrintfAttr(Format, TheCall)) {
bool HasVAListArg = Format->getFirstArg() == 0;
- if (!HasVAListArg) {
- if (const FunctionProtoType *Proto
- = FDecl->getType()->getAs<FunctionProtoType>())
- HasVAListArg = !Proto->isVariadic();
- }
CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
HasVAListArg ? 0 : Format->getFirstArg() - 1);
}
@@ -257,12 +250,6 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
return false;
bool HasVAListArg = Format->getFirstArg() == 0;
- if (!HasVAListArg) {
- const FunctionType *FT =
- Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
- if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
- HasVAListArg = !Proto->isVariadic();
- }
CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
HasVAListArg ? 0 : Format->getFirstArg() - 1);
@@ -315,14 +302,12 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
BUILTIN_ROW(__sync_fetch_and_or),
BUILTIN_ROW(__sync_fetch_and_and),
BUILTIN_ROW(__sync_fetch_and_xor),
- BUILTIN_ROW(__sync_fetch_and_nand),
BUILTIN_ROW(__sync_add_and_fetch),
BUILTIN_ROW(__sync_sub_and_fetch),
BUILTIN_ROW(__sync_and_and_fetch),
BUILTIN_ROW(__sync_or_and_fetch),
BUILTIN_ROW(__sync_xor_and_fetch),
- BUILTIN_ROW(__sync_nand_and_fetch),
BUILTIN_ROW(__sync_val_compare_and_swap),
BUILTIN_ROW(__sync_bool_compare_and_swap),
@@ -357,26 +342,24 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
case Builtin::BI__sync_fetch_and_or: BuiltinIndex = 2; break;
case Builtin::BI__sync_fetch_and_and: BuiltinIndex = 3; break;
case Builtin::BI__sync_fetch_and_xor: BuiltinIndex = 4; break;
- case Builtin::BI__sync_fetch_and_nand:BuiltinIndex = 5; break;
- case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 6; break;
- case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 7; break;
- case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 8; break;
- case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 9; break;
- case Builtin::BI__sync_xor_and_fetch: BuiltinIndex =10; break;
- case Builtin::BI__sync_nand_and_fetch:BuiltinIndex =11; break;
+ case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 5; break;
+ case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 6; break;
+ case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 7; break;
+ case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 8; break;
+ case Builtin::BI__sync_xor_and_fetch: BuiltinIndex = 9; break;
case Builtin::BI__sync_val_compare_and_swap:
- BuiltinIndex = 12;
+ BuiltinIndex = 10;
NumFixed = 2;
break;
case Builtin::BI__sync_bool_compare_and_swap:
- BuiltinIndex = 13;
+ BuiltinIndex = 11;
NumFixed = 2;
break;
- case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 14; break;
+ case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 12; break;
case Builtin::BI__sync_lock_release:
- BuiltinIndex = 15;
+ BuiltinIndex = 13;
NumFixed = 0;
break;
}
@@ -1045,6 +1028,7 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler {
Sema &S;
const StringLiteral *FExpr;
const Expr *OrigFormatExpr;
+ const unsigned FirstDataArg;
const unsigned NumDataArgs;
const bool IsObjCLiteral;
const char *Beg; // Start of format string.
@@ -1056,11 +1040,12 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler {
bool atFirstArg;
public:
CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
- const Expr *origFormatExpr,
+ const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
const CallExpr *theCall, unsigned formatIdx)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
+ FirstDataArg(firstDataArg),
NumDataArgs(numDataArgs),
IsObjCLiteral(isObjCLiteral), Beg(beg),
HasVAListArg(hasVAListArg),
@@ -1183,11 +1168,9 @@ void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) {
}
const Expr *CheckPrintfHandler::getDataArg(unsigned i) const {
- return TheCall->getArg(FormatIdx + i + 1);
+ return TheCall->getArg(FirstDataArg + i);
}
-
-
void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS,
llvm::StringRef flag,
llvm::StringRef cspec,
@@ -1329,9 +1312,18 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
return true;
if (argIndex >= NumDataArgs) {
- S.Diag(getLocationOfByte(CS.getStart()),
- diag::warn_printf_insufficient_data_args)
- << getFormatSpecifierRange(startSpecifier, specifierLen);
+ if (FS.usesPositionalArg()) {
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_positional_arg_exceeds_data_args)
+ << (argIndex+1) << NumDataArgs
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ }
+ else {
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_insufficient_data_args)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ }
+
// Don't do any more checking.
return false;
}
@@ -1400,7 +1392,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
return;
}
- CheckPrintfHandler H(*this, FExpr, OrigFormatExpr,
+ CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
TheCall->getNumArgs() - firstDataArg,
isa<ObjCStringLiteral>(OrigFormatExpr), Str,
HasVAListArg, TheCall, format_idx);
@@ -2262,10 +2254,6 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
}
}
-
- if (getLangOptions().CPlusPlus)
- if (const RecordType *RT = Param->getType()->getAs<RecordType>())
- FinalizeVarWithDestructor(Param, RT);
}
return HasInvalidParm;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e11e161..f3d0dcf 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -14,7 +14,6 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
-#include "AnalysisBasedWarnings.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -89,8 +88,8 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
return 0;
// We know from the grammar that this name refers to a type, so build a
- // TypenameType node to describe the type.
- // FIXME: Record somewhere that this TypenameType node has no "typename"
+ // DependentNameType node to describe the type.
+ // FIXME: Record somewhere that this DependentNameType node has no "typename"
// keyword associated with it.
return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
II, SS->getRange()).getAsOpaquePtr();
@@ -199,7 +198,9 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
} else if (UnresolvedUsingTypenameDecl *UUDecl =
dyn_cast<UnresolvedUsingTypenameDecl>(IIDecl)) {
// FIXME: preserve source structure information.
- T = Context.getTypenameType(UUDecl->getTargetNestedNameSpecifier(), &II);
+ T = Context.getDependentNameType(ETK_None,
+ UUDecl->getTargetNestedNameSpecifier(),
+ &II);
} else {
// If it's not plausibly a type, suppress diagnostics.
Result.suppressDiagnostics();
@@ -256,13 +257,13 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
if (!SS || !SS->isSet())
Diag(IILoc, diag::err_unknown_typename_suggest)
<< &II << Lookup.getLookupName()
- << CodeModificationHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
+ << FixItHint::CreateReplacement(SourceRange(IILoc),
+ Result->getNameAsString());
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_unknown_nested_typename_suggest)
<< &II << DC << Lookup.getLookupName() << SS->getRange()
- << CodeModificationHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
+ << FixItHint::CreateReplacement(SourceRange(IILoc),
+ Result->getNameAsString());
else
llvm_unreachable("could not have corrected a typo here");
@@ -286,8 +287,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
Diag(SS->getRange().getBegin(), diag::err_typename_missing)
<< (NestedNameSpecifier *)SS->getScopeRep() << II.getName()
<< SourceRange(SS->getRange().getBegin(), IILoc)
- << CodeModificationHint::CreateInsertion(SS->getRange().getBegin(),
- "typename ");
+ << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
SuggestedType = ActOnTypenameType(SourceLocation(), *SS, II, IILoc).get();
} else {
assert(SS && SS->isInvalid() &&
@@ -512,14 +512,30 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
// Types of valid local variables should be complete, so this should succeed.
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
- if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+
+ // White-list anything with an __attribute__((unused)) type.
+ QualType Ty = VD->getType();
+
+ // Only look at the outermost level of typedef.
+ if (const TypedefType *TT = dyn_cast<TypedefType>(Ty)) {
+ if (TT->getDecl()->hasAttr<UnusedAttr>())
+ return false;
+ }
+
+ if (const TagType *TT = Ty->getAs<TagType>()) {
+ const TagDecl *Tag = TT->getDecl();
+ if (Tag->hasAttr<UnusedAttr>())
+ return false;
+
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
if (!RD->hasTrivialConstructor())
return false;
if (!RD->hasTrivialDestructor())
return false;
}
}
+
+ // TODO: __attribute__((unused)) templates?
}
return true;
@@ -575,8 +591,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
(IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
Diag(RecoverLoc, diag::err_undef_interface_suggest)
<< Id << IDecl->getDeclName()
- << CodeModificationHint::CreateReplacement(RecoverLoc,
- IDecl->getNameAsString());
+ << FixItHint::CreateReplacement(RecoverLoc, IDecl->getNameAsString());
Diag(IDecl->getLocation(), diag::note_previous_decl)
<< IDecl->getDeclName();
@@ -982,25 +997,28 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// other tests to run.
const FunctionType *OldType = OldQType->getAs<FunctionType>();
const FunctionType *NewType = New->getType()->getAs<FunctionType>();
- if (OldType->getCallConv() != CC_Default &&
- NewType->getCallConv() == CC_Default) {
- NewQType = Context.getCallConvType(NewQType, OldType->getCallConv());
+ const FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo();
+ const FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
+ if (OldTypeInfo.getCC() != CC_Default &&
+ NewTypeInfo.getCC() == CC_Default) {
+ NewQType = Context.getCallConvType(NewQType, OldTypeInfo.getCC());
New->setType(NewQType);
NewQType = Context.getCanonicalType(NewQType);
- } else if (!Context.isSameCallConv(OldType->getCallConv(),
- NewType->getCallConv())) {
+ } else if (!Context.isSameCallConv(OldTypeInfo.getCC(),
+ NewTypeInfo.getCC())) {
// Calling conventions really aren't compatible, so complain.
Diag(New->getLocation(), diag::err_cconv_change)
- << FunctionType::getNameForCallConv(NewType->getCallConv())
- << (OldType->getCallConv() == CC_Default)
- << (OldType->getCallConv() == CC_Default ? "" :
- FunctionType::getNameForCallConv(OldType->getCallConv()));
+ << FunctionType::getNameForCallConv(NewTypeInfo.getCC())
+ << (OldTypeInfo.getCC() == CC_Default)
+ << (OldTypeInfo.getCC() == CC_Default ? "" :
+ FunctionType::getNameForCallConv(OldTypeInfo.getCC()));
Diag(Old->getLocation(), diag::note_previous_declaration);
return true;
}
// FIXME: diagnose the other way around?
- if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) {
+ if (OldType->getNoReturnAttr() &&
+ !NewType->getNoReturnAttr()) {
NewQType = Context.getNoReturnType(NewQType);
New->setType(NewQType);
assert(NewQType.isCanonical());
@@ -1094,8 +1112,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
OldProto->isVariadic(),
OldProto->getTypeQuals(),
false, false, 0, 0,
- OldProto->getNoReturnAttr(),
- OldProto->getCallConv());
+ OldProto->getExtInfo());
New->setType(NewQType);
New->setHasInheritedPrototype();
@@ -1176,8 +1193,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
ArgTypes.size(),
OldProto->isVariadic(), 0,
false, false, 0, 0,
- OldProto->getNoReturnAttr(),
- OldProto->getCallConv()));
+ OldProto->getExtInfo()));
return MergeCompatibleFunctionDecls(New, Old);
}
@@ -2132,7 +2148,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
<< D.getCXXScopeSpec().getRange();
D.setInvalidType();
// Pretend we didn't see the scope specifier.
- DC = 0;
+ DC = CurContext;
+ Previous.clear();
}
if (getLangOptions().CPlusPlus) {
@@ -2328,8 +2345,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (SC == VarDecl::Static) {
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
- << CodeModificationHint::CreateRemoval(
- D.getDeclSpec().getStorageClassSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
} else if (SC == VarDecl::None)
SC = VarDecl::Static;
}
@@ -2405,7 +2421,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Diagnose shadowed variables before filtering for scope.
if (!D.getCXXScopeSpec().isSet())
- DiagnoseShadow(S, D, Previous);
+ CheckShadow(S, NewVD, Previous);
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
@@ -2458,19 +2474,16 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
return NewVD;
}
-/// \brief Diagnose variable or built-in function shadowing.
-///
-/// This method is called as soon as a NamedDecl materializes to check
-/// if it shadows another local or global variable, or a built-in function.
+/// \brief Diagnose variable or built-in function shadowing. Implements
+/// -Wshadow.
///
-/// For performance reasons, the lookup results are reused from the calling
-/// context.
+/// This method is called whenever a VarDecl is added to a "useful"
+/// scope.
///
/// \param S the scope in which the shadowing name is being declared
/// \param R the lookup of the name
///
-void Sema::DiagnoseShadow(Scope *S, Declarator &D,
- const LookupResult& R) {
+void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
// Return if warning is ignored.
if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored)
return;
@@ -2524,6 +2537,14 @@ void Sema::DiagnoseShadow(Scope *S, Declarator &D,
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
}
+/// \brief Check -Wshadow without the advantage of a previous lookup.
+void Sema::CheckShadow(Scope *S, VarDecl *D) {
+ LookupResult R(*this, D->getDeclName(), D->getLocation(),
+ Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ LookupName(R, S);
+ CheckShadow(S, D, R);
+}
+
/// \brief Perform semantic checking on a newly-created variable
/// declaration.
///
@@ -2913,6 +2934,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
} else {
// This is a function template specialization.
isFunctionTemplateSpecialization = true;
+
+ // C++0x [temp.expl.spec]p20 forbids "template<> void foo(int);".
+ if (isFriend && isFunctionTemplateSpecialization) {
+ // We want to remove the "template<>", found here.
+ SourceRange RemoveRange = TemplateParams->getSourceRange();
+
+ // If we remove the template<> and the name is not a
+ // template-id, we're actually silently creating a problem:
+ // the friend declaration will refer to an untemplated decl,
+ // and clearly the user wants a template specialization. So
+ // we need to insert '<>' after the name.
+ SourceLocation InsertLoc;
+ if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
+ InsertLoc = D.getName().getSourceRange().getEnd();
+ InsertLoc = PP.getLocForEndOfToken(InsertLoc);
+ }
+
+ Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend)
+ << Name << RemoveRange
+ << FixItHint::CreateRemoval(RemoveRange)
+ << FixItHint::CreateInsertion(InsertLoc, "<>");
+ }
}
// FIXME: Free this memory properly.
@@ -2931,8 +2974,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
} else if (!CurContext->isRecord()) {
// 'virtual' was specified outside of the class.
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class)
- << CodeModificationHint::CreateRemoval(
- D.getDeclSpec().getVirtualSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc());
} else {
// Okay: Add virtual to the method.
CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC);
@@ -2949,16 +2991,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 'explicit' was specified outside of the class.
Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_out_of_class)
- << CodeModificationHint::CreateRemoval(
- D.getDeclSpec().getExplicitSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
} else if (!isa<CXXConstructorDecl>(NewFD) &&
!isa<CXXConversionDecl>(NewFD)) {
// 'explicit' was specified on a function that wasn't a constructor
// or conversion function.
Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_non_ctor_or_conv_function)
- << CodeModificationHint::CreateRemoval(
- D.getDeclSpec().getExplicitSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
}
}
@@ -2971,13 +3011,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
"previously-undeclared friend function being created "
"in a non-namespace context");
+ // For now, claim that the objects have no previous declaration.
if (FunctionTemplate) {
- FunctionTemplate->setObjectOfFriendDecl(
- /* PreviouslyDeclared= */ !Previous.empty());
+ FunctionTemplate->setObjectOfFriendDecl(false);
FunctionTemplate->setAccess(AS_public);
+ } else {
+ NewFD->setObjectOfFriendDecl(false);
}
- else
- NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ !Previous.empty());
NewFD->setAccess(AS_public);
}
@@ -2993,8 +3033,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// member function definition.
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
- << CodeModificationHint::CreateRemoval(
- D.getDeclSpec().getStorageClassSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
}
// Handle GNU asm-label extension (encoded as an attribute).
@@ -3092,18 +3131,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// too few of them).
Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
- << CodeModificationHint::CreateInsertion(
+ << FixItHint::CreateInsertion(
D.getDeclSpec().getSourceRange().getBegin(),
"template<> ");
isFunctionTemplateSpecialization = true;
+ } else {
+ // "friend void foo<>(int);" is an implicit specialization decl.
+ isFunctionTemplateSpecialization = true;
}
}
if (isFunctionTemplateSpecialization) {
- if (CheckFunctionTemplateSpecialization(NewFD,
- (HasExplicitTemplateArgs ? &TemplateArgs : 0),
- Previous))
- NewFD->setInvalidDecl();
+ if (isFriend && NewFD->getType()->isDependentType()) {
+ // FIXME: When we see a friend of a function template
+ // specialization with a dependent type, we can't match it now;
+ // for now, we just drop it, until we have a reasonable way to
+ // represent the parsed-but-not-matched friend function template
+ // specialization in the AST.
+ return 0;
+ } else if (CheckFunctionTemplateSpecialization(NewFD,
+ (HasExplicitTemplateArgs ? &TemplateArgs : 0),
+ Previous))
+ NewFD->setInvalidDecl();
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
CheckMemberSpecialization(NewFD, Previous))
NewFD->setInvalidDecl();
@@ -3117,6 +3166,17 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
+ if (isFriend && Redeclaration) {
+ AccessSpecifier Access = NewFD->getPreviousDeclaration()->getAccess();
+ if (FunctionTemplate) {
+ FunctionTemplate->setObjectOfFriendDecl(true);
+ FunctionTemplate->setAccess(Access);
+ } else {
+ NewFD->setObjectOfFriendDecl(true);
+ }
+ NewFD->setAccess(Access);
+ }
+
// If we have a function template, check the template parameter
// list. This will check and merge default template arguments.
if (FunctionTemplate) {
@@ -3303,7 +3363,8 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// Turn this into a variadic function with no parameters.
QualType R = Context.getFunctionType(
NewFD->getType()->getAs<FunctionType>()->getResultType(),
- 0, 0, true, 0, false, false, 0, 0, false, CC_Default);
+ 0, 0, true, 0, false, false, 0, 0,
+ FunctionType::ExtInfo());
NewFD->setType(R);
return NewFD->setInvalidDecl();
}
@@ -3747,6 +3808,41 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
return;
}
+/// ActOnInitializerError - Given that there was an error parsing an
+/// initializer for the given declaration, try to return to some form
+/// of sanity.
+void Sema::ActOnInitializerError(DeclPtrTy dcl) {
+ // Our main concern here is re-establishing invariants like "a
+ // variable's type is either dependent or complete".
+ Decl *D = dcl.getAs<Decl>();
+ if (!D || D->isInvalidDecl()) return;
+
+ VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (!VD) return;
+
+ QualType Ty = VD->getType();
+ if (Ty->isDependentType()) return;
+
+ // Require a complete type.
+ if (RequireCompleteType(VD->getLocation(),
+ Context.getBaseElementType(Ty),
+ diag::err_typecheck_decl_incomplete_type)) {
+ VD->setInvalidDecl();
+ return;
+ }
+
+ // Require an abstract type.
+ if (RequireNonAbstractType(VD->getLocation(), Ty,
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType)) {
+ VD->setInvalidDecl();
+ return;
+ }
+
+ // Don't bother complaining about constructors or destructors,
+ // though.
+}
+
void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
bool TypeContainsUndeducedAuto) {
Decl *RealDecl = dcl.getAs<Decl>();
@@ -3984,8 +4080,6 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
II = 0;
D.SetIdentifier(0, D.getIdentifierLoc());
D.setInvalidType(true);
- } else {
- DiagnoseShadow(S, D, R);
}
}
}
@@ -4075,7 +4169,7 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
<< ";\n";
Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared)
<< FTI.ArgInfo[i].Ident
- << CodeModificationHint::CreateInsertion(LocAfterDecls, Code.str());
+ << FixItHint::CreateInsertion(LocAfterDecls, Code.str());
// Implicitly declare the argument as type 'int' for lack of a better
// type.
@@ -4213,14 +4307,21 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
// Check the validity of our function parameters
CheckParmsForFunctionDef(FD);
+ bool ShouldCheckShadow =
+ Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored;
+
// Introduce our parameters into the function scope
for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
Param->setOwningFunction(FD);
// If this has an identifier, add it to the scope stack.
- if (Param->getIdentifier() && FnBodyScope)
+ if (Param->getIdentifier() && FnBodyScope) {
+ if (ShouldCheckShadow)
+ CheckShadow(FnBodyScope, Param);
+
PushOnScopeChains(Param, FnBodyScope);
+ }
}
// Checking attributes of current function definition
@@ -4266,7 +4367,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
else
FD = dyn_cast_or_null<FunctionDecl>(dcl);
- sema::AnalysisBasedWarnings W(*this);
+ sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
if (FD) {
FD->setBody(Body);
@@ -4274,7 +4375,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
// C and C++ allow for main to automagically return 0.
// Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
FD->setHasImplicitReturnZero(true);
- W.disableCheckFallThrough();
+ WP.disableCheckFallThrough();
}
if (!FD->isInvalidDecl())
@@ -4294,8 +4395,6 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
Body->Destroy(Context);
return DeclPtrTy();
}
- if (!IsInstantiation)
- PopDeclContext();
// Verify and clean out per-function state.
@@ -4371,12 +4470,15 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
ObjCMethodDecl *MD = cast<ObjCMethodDecl>(dcl);
ResultType = MD->getResultType();
}
- W.IssueWarnings(dcl);
+ AnalysisWarnings.IssueWarnings(WP, dcl);
}
assert(ExprTemporaries.empty() && "Leftover temporaries in function");
}
+ if (!IsInstantiation)
+ PopDeclContext();
+
PopFunctionOrBlockScope();
// If any errors have occurred, clear out any temporaries that may have
@@ -4577,7 +4679,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
<< (NewTag == TagDecl::TK_class)
<< isTemplate << &Name
- << CodeModificationHint::CreateReplacement(SourceRange(NewTagLoc),
+ << FixItHint::CreateReplacement(SourceRange(NewTagLoc),
OldTag == TagDecl::TK_class? "class" : "struct");
Diag(Previous->getLocation(), diag::note_previous_use);
return true;
@@ -4684,7 +4786,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
// A tag 'foo::bar' must already exist.
- Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange();
+ Diag(NameLoc, diag::err_not_tag_in_scope)
+ << Kind << Name << DC << SS.getRange();
Name = 0;
Invalid = true;
goto CreateNewDecl;
@@ -4732,6 +4835,79 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
}
+ // If we didn't find a previous declaration, and this is a reference
+ // (or friend reference), move to the correct scope. In C++, we
+ // also need to do a redeclaration lookup there, just in case
+ // there's a shadow friend decl.
+ if (Name && Previous.empty() &&
+ (TUK == TUK_Reference || TUK == TUK_Friend)) {
+ if (Invalid) goto CreateNewDecl;
+ assert(SS.isEmpty());
+
+ if (TUK == TUK_Reference) {
+ // C++ [basic.scope.pdecl]p5:
+ // -- for an elaborated-type-specifier of the form
+ //
+ // class-key identifier
+ //
+ // if the elaborated-type-specifier is used in the
+ // decl-specifier-seq or parameter-declaration-clause of a
+ // function defined in namespace scope, the identifier is
+ // declared as a class-name in the namespace that contains
+ // the declaration; otherwise, except as a friend
+ // declaration, the identifier is declared in the smallest
+ // non-class, non-function-prototype scope that contains the
+ // declaration.
+ //
+ // C99 6.7.2.3p8 has a similar (but not identical!) provision for
+ // C structs and unions.
+ //
+ // It is an error in C++ to declare (rather than define) an enum
+ // type, including via an elaborated type specifier. We'll
+ // diagnose that later; for now, declare the enum in the same
+ // scope as we would have picked for any other tag type.
+ //
+ // GNU C also supports this behavior as part of its incomplete
+ // enum types extension, while GNU C++ does not.
+ //
+ // Find the context where we'll be declaring the tag.
+ // FIXME: We would like to maintain the current DeclContext as the
+ // lexical context,
+ while (SearchDC->isRecord())
+ SearchDC = SearchDC->getParent();
+
+ // Find the scope where we'll be declaring the tag.
+ while (S->isClassScope() ||
+ (getLangOptions().CPlusPlus &&
+ S->isFunctionPrototypeScope()) ||
+ ((S->getFlags() & Scope::DeclScope) == 0) ||
+ (S->getEntity() &&
+ ((DeclContext *)S->getEntity())->isTransparentContext()))
+ S = S->getParent();
+ } else {
+ assert(TUK == TUK_Friend);
+ // C++ [namespace.memdef]p3:
+ // If a friend declaration in a non-local class first declares a
+ // class or function, the friend class or function is a member of
+ // the innermost enclosing namespace.
+ SearchDC = SearchDC->getEnclosingNamespaceContext();
+
+ // Look up through our scopes until we find one with an entity which
+ // matches our declaration context.
+ while (S->getEntity() &&
+ ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) {
+ S = S->getParent();
+ assert(S && "No enclosing scope matching the enclosing namespace.");
+ }
+ }
+
+ // In C++, look for a shadow friend decl.
+ if (getLangOptions().CPlusPlus) {
+ Previous.setRedeclarationKind(ForRedeclaration);
+ LookupQualifiedName(Previous, SearchDC);
+ }
+ }
+
if (!Previous.empty()) {
assert(Previous.isSingleResult());
NamedDecl *PrevDecl = Previous.getFoundDecl();
@@ -4750,8 +4926,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (SafeToContinue)
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
- << CodeModificationHint::CreateReplacement(SourceRange(KWLoc),
- PrevTagDecl->getKindName());
+ << FixItHint::CreateReplacement(SourceRange(KWLoc),
+ PrevTagDecl->getKindName());
else
Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
@@ -4829,7 +5005,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
} else {
// PrevDecl is a namespace, template, or anything else
// that lives in the IDNS_Tag identifier namespace.
- if (isDeclInScope(PrevDecl, SearchDC, S)) {
+ if (TUK == TUK_Reference || TUK == TUK_Friend ||
+ isDeclInScope(PrevDecl, SearchDC, S)) {
// The tag name clashes with a namespace name, issue an error and
// recover by making this tag be anonymous.
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
@@ -4843,60 +5020,6 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Previous.clear();
}
}
- } else if (TUK == TUK_Reference && SS.isEmpty() && Name) {
- // C++ [basic.scope.pdecl]p5:
- // -- for an elaborated-type-specifier of the form
- //
- // class-key identifier
- //
- // if the elaborated-type-specifier is used in the
- // decl-specifier-seq or parameter-declaration-clause of a
- // function defined in namespace scope, the identifier is
- // declared as a class-name in the namespace that contains
- // the declaration; otherwise, except as a friend
- // declaration, the identifier is declared in the smallest
- // non-class, non-function-prototype scope that contains the
- // declaration.
- //
- // C99 6.7.2.3p8 has a similar (but not identical!) provision for
- // C structs and unions.
- //
- // It is an error in C++ to declare (rather than define) an enum
- // type, including via an elaborated type specifier. We'll
- // diagnose that later; for now, declare the enum in the same
- // scope as we would have picked for any other tag type.
- //
- // GNU C also supports this behavior as part of its incomplete
- // enum types extension, while GNU C++ does not.
- //
- // Find the context where we'll be declaring the tag.
- // FIXME: We would like to maintain the current DeclContext as the
- // lexical context,
- while (SearchDC->isRecord())
- SearchDC = SearchDC->getParent();
-
- // Find the scope where we'll be declaring the tag.
- while (S->isClassScope() ||
- (getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) ||
- ((S->getFlags() & Scope::DeclScope) == 0) ||
- (S->getEntity() &&
- ((DeclContext *)S->getEntity())->isTransparentContext()))
- S = S->getParent();
-
- } else if (TUK == TUK_Friend && SS.isEmpty() && Name) {
- // C++ [namespace.memdef]p3:
- // If a friend declaration in a non-local class first declares a
- // class or function, the friend class or function is a member of
- // the innermost enclosing namespace.
- SearchDC = SearchDC->getEnclosingNamespaceContext();
-
- // Look up through our scopes until we find one with an entity which
- // matches our declaration context.
- while (S->getEntity() &&
- ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) {
- S = S->getParent();
- assert(S && "No enclosing scope matching the enclosing namespace.");
- }
}
CreateNewDecl:
@@ -5013,7 +5136,7 @@ CreateNewDecl:
New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty());
// Set the access specifier.
- if (!Invalid && TUK != TUK_Friend)
+ if (!Invalid && SearchDC->isRecord())
SetMemberAccessSpecifier(New, PrevDecl, AS);
if (TUK == TUK_Definition)
@@ -5026,13 +5149,11 @@ CreateNewDecl:
if (PrevDecl)
New->setAccess(PrevDecl->getAccess());
- // Friend tag decls are visible in fairly strange ways.
- if (!CurContext->isDependentContext()) {
- DeclContext *DC = New->getDeclContext()->getLookupContext();
- DC->makeDeclVisibleInContext(New, /* Recoverable = */ false);
+ DeclContext *DC = New->getDeclContext()->getLookupContext();
+ DC->makeDeclVisibleInContext(New, /* Recoverable = */ false);
+ if (Name) // can be null along some error paths
if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false);
- }
} else if (Name) {
S = getNonFieldDeclScope(S);
PushOnScopeChains(New, S);
@@ -5261,6 +5382,10 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
FieldDecl *NewFD
= CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL,
AS, PrevDecl, &D);
+
+ if (NewFD->isInvalidDecl())
+ Record->setInvalidDecl();
+
if (NewFD->isInvalidDecl() && PrevDecl) {
// Don't introduce NewFD into scope; there's already something
// with the same name in the same scope.
@@ -5804,7 +5929,7 @@ void Sema::ActOnFields(Scope* S,
} else if (ObjCCategoryDecl *CDecl =
dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension())
- Diag(LBrac, diag::err_misplaced_ivar);
+ Diag(LBrac, diag::err_misplaced_ivar) << CDecl->IsClassExtension();
else {
// FIXME. Class extension does not have a LocEnd field.
// CDecl->setLocEnd(RBrac);
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 73a34f8..cc24735 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -490,6 +490,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // NOTE: We don't add the attribute to a FunctionDecl because the noreturn
+ // trait will be part of the function's type.
+
// Don't apply as a decl attribute to ValueDecl.
// FIXME: probably ought to diagnose this.
if (isa<ValueDecl>(d))
@@ -521,7 +524,8 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d)) {
+ if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) &&
+ !isa<TypeDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
@@ -834,18 +838,24 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
return;
}
- if (!isFunction(D)) {
+ if (!isFunction(D) && !isa<ObjCMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
}
- if (getFunctionType(D)->getResultType()->isVoidType()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_void_function)
- << Attr.getName();
+ if (isFunction(D) && getFunctionType(D)->getResultType()->isVoidType()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method)
+ << Attr.getName() << 0;
return;
}
-
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ if (MD->getResultType()->isVoidType()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method)
+ << Attr.getName() << 1;
+ return;
+ }
+
D->addAttr(::new (S.Context) WarnUnusedResultAttr());
}
@@ -1115,6 +1125,7 @@ enum FormatAttrKind {
NSStringFormat,
StrftimeFormat,
SupportedFormat,
+ IgnoredFormat,
InvalidFormat
};
@@ -1136,6 +1147,10 @@ static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) {
Format == "zcmn_err")
return SupportedFormat;
+ if (Format == "gcc_diag" || Format == "gcc_cdiag" ||
+ Format == "gcc_cxxdiag" || Format == "gcc_tdiag")
+ return IgnoredFormat;
+
return InvalidFormat;
}
@@ -1171,6 +1186,10 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// Check for supported formats.
FormatAttrKind Kind = getFormatAttrKind(Format);
+
+ if (Kind == IgnoredFormat)
+ return;
+
if (Kind == InvalidFormat) {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
<< "format" << Attr.getParameterName()->getName();
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 13a7ead..47df435 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1104,8 +1104,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// member.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
<< MemberOrBase << true << R.getLookupName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
Diag(Member->getLocation(), diag::note_previous_decl)
<< Member->getDeclName();
@@ -1123,8 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// that base class.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
<< MemberOrBase << false << R.getLookupName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec
: VirtualBaseSpec;
@@ -1429,134 +1429,106 @@ bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers,
- bool IsImplicitConstructor,
bool AnyErrors) {
+ if (Constructor->isDependentContext()) {
+ // Just store the initializers as written, they will be checked during
+ // instantiation.
+ if (NumInitializers > 0) {
+ Constructor->setNumBaseOrMemberInitializers(NumInitializers);
+ CXXBaseOrMemberInitializer **baseOrMemberInitializers =
+ new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
+ memcpy(baseOrMemberInitializers, Initializers,
+ NumInitializers * sizeof(CXXBaseOrMemberInitializer*));
+ Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
+ }
+
+ return false;
+ }
+
// We need to build the initializer AST according to order of construction
// and not what user specified in the Initializers list.
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition();
+ if (!ClassDecl)
+ return true;
+
llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
- bool HasDependentBaseInit = false;
bool HadError = false;
for (unsigned i = 0; i < NumInitializers; i++) {
CXXBaseOrMemberInitializer *Member = Initializers[i];
- if (Member->isBaseInitializer()) {
- if (Member->getBaseClass()->isDependentType())
- HasDependentBaseInit = true;
+
+ if (Member->isBaseInitializer())
AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
- } else {
+ else
AllBaseFields[Member->getMember()] = Member;
- }
}
- if (HasDependentBaseInit) {
- // FIXME. This does not preserve the ordering of the initializers.
- // Try (with -Wreorder)
- // template<class X> struct A {};
- // template<class X> struct B : A<X> {
- // B() : x1(10), A<X>() {}
- // int x1;
- // };
- // B<int> x;
- // On seeing one dependent type, we should essentially exit this routine
- // while preserving user-declared initializer list. When this routine is
- // called during instantiatiation process, this routine will rebuild the
- // ordered initializer list correctly.
-
- // If we have a dependent base initialization, we can't determine the
- // association between initializers and bases; just dump the known
- // initializers into the list, and don't try to deal with other bases.
- for (unsigned i = 0; i < NumInitializers; i++) {
- CXXBaseOrMemberInitializer *Member = Initializers[i];
- if (Member->isBaseInitializer())
- AllToInit.push_back(Member);
- }
- } else {
- llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
-
- // Push virtual bases before others.
- for (CXXRecordDecl::base_class_iterator VBase =
- ClassDecl->vbases_begin(),
- E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
- if (VBase->getType()->isDependentType())
- continue;
- if (CXXBaseOrMemberInitializer *Value
- = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
- AllToInit.push_back(Value);
- } else if (!AnyErrors) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeBase(Context, VBase);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
- if (BaseInit.isInvalid()) {
- HadError = true;
- continue;
- }
+ llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
- // Don't attach synthesized base initializers in a dependent
- // context; they'll be checked again at template instantiation
- // time.
- if (CurContext->isDependentContext())
- continue;
-
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(VBase->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
- AllToInit.push_back(CXXBaseInit);
- }
- }
+ // Push virtual bases before others.
+ for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
- for (CXXRecordDecl::base_class_iterator Base =
- ClassDecl->bases_begin(),
- E = ClassDecl->bases_end(); Base != E; ++Base) {
- // Virtuals are in the virtual base list and already constructed.
- if (Base->isVirtual())
- continue;
- // Skip dependent types.
- if (Base->getType()->isDependentType())
+ if (CXXBaseOrMemberInitializer *Value
+ = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
+ AllToInit.push_back(Value);
+ } else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, VBase);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
+ HadError = true;
continue;
- if (CXXBaseOrMemberInitializer *Value
- = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
- AllToInit.push_back(Value);
}
- else if (!AnyErrors) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeBase(Context, Base);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
- if (BaseInit.isInvalid()) {
- HadError = true;
- continue;
- }
-
- // Don't attach synthesized base initializers in a dependent
- // context; they'll be regenerated at template instantiation
- // time.
- if (CurContext->isDependentContext())
- continue;
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(Base->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
- AllToInit.push_back(CXXBaseInit);
+ CXXBaseOrMemberInitializer *CXXBaseInit =
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Context.getTrivialTypeSourceInfo(VBase->getType(),
+ SourceLocation()),
+ SourceLocation(),
+ BaseInit.takeAs<Expr>(),
+ SourceLocation());
+ AllToInit.push_back(CXXBaseInit);
+ }
+ }
+
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); Base != E; ++Base) {
+ // Virtuals are in the virtual base list and already constructed.
+ if (Base->isVirtual())
+ continue;
+
+ if (CXXBaseOrMemberInitializer *Value
+ = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
+ AllToInit.push_back(Value);
+ } else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, Base);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
+ HadError = true;
+ continue;
}
+
+ CXXBaseOrMemberInitializer *CXXBaseInit =
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Context.getTrivialTypeSourceInfo(Base->getType(),
+ SourceLocation()),
+ SourceLocation(),
+ BaseInit.takeAs<Expr>(),
+ SourceLocation());
+ AllToInit.push_back(CXXBaseInit);
}
}
@@ -1624,14 +1596,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
}
else if (FT->isReferenceType()) {
Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
<< 0 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
HadError = true;
}
else if (FT.isConstQualified()) {
Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
<< 1 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
HadError = true;
@@ -1665,121 +1637,70 @@ static void *GetKeyForTopLevelField(FieldDecl *Field) {
return static_cast<void *>(Field);
}
-static void *GetKeyForBase(QualType BaseType) {
- if (const RecordType *RT = BaseType->getAs<RecordType>())
- return (void *)RT;
-
- assert(0 && "Unexpected base type!");
- return 0;
+static void *GetKeyForBase(ASTContext &Context, QualType BaseType) {
+ return Context.getCanonicalType(BaseType).getTypePtr();
}
-static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member,
+static void *GetKeyForMember(ASTContext &Context,
+ CXXBaseOrMemberInitializer *Member,
bool MemberMaybeAnon = false) {
+ if (!Member->isMemberInitializer())
+ return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0));
+
// For fields injected into the class via declaration of an anonymous union,
// use its anonymous union class declaration as the unique key.
- if (Member->isMemberInitializer()) {
- FieldDecl *Field = Member->getMember();
-
- // After SetBaseOrMemberInitializers call, Field is the anonymous union
- // data member of the class. Data member used in the initializer list is
- // in AnonUnionMember field.
- if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
- Field = Member->getAnonUnionMember();
- if (Field->getDeclContext()->isRecord()) {
- RecordDecl *RD = cast<RecordDecl>(Field->getDeclContext());
- if (RD->isAnonymousStructOrUnion())
- return static_cast<void *>(RD);
- }
- return static_cast<void *>(Field);
- }
-
- return GetKeyForBase(QualType(Member->getBaseClass(), 0));
-}
-
-/// ActOnMemInitializers - Handle the member initializers for a constructor.
-void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
- SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits,
- bool AnyErrors) {
- if (!ConstructorDecl)
- return;
+ FieldDecl *Field = Member->getMember();
- AdjustDeclIfTemplate(ConstructorDecl);
-
- CXXConstructorDecl *Constructor
- = dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
-
- if (!Constructor) {
- Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
- return;
- }
-
- if (!Constructor->isDependentContext()) {
- llvm::DenseMap<void*, CXXBaseOrMemberInitializer *>Members;
- bool err = false;
- for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member =
- static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]);
- void *KeyToMember = GetKeyForMember(Member);
- CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
- if (!PrevMember) {
- PrevMember = Member;
- continue;
- }
- if (FieldDecl *Field = Member->getMember())
- Diag(Member->getSourceLocation(),
- diag::error_multiple_mem_initialization)
- << Field->getNameAsString()
- << Member->getSourceRange();
- else {
- Type *BaseClass = Member->getBaseClass();
- assert(BaseClass && "ActOnMemInitializers - neither field or base");
- Diag(Member->getSourceLocation(),
- diag::error_multiple_base_initialization)
- << QualType(BaseClass, 0)
- << Member->getSourceRange();
- }
- Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
- << 0;
- err = true;
- }
-
- if (err)
- return;
- }
+ // After SetBaseOrMemberInitializers call, Field is the anonymous union
+ // data member of the class. Data member used in the initializer list is
+ // in AnonUnionMember field.
+ if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
+ Field = Member->getAnonUnionMember();
+
+ // If the field is a member of an anonymous union, we use record decl of the
+ // union as the key.
+ RecordDecl *RD = Field->getParent();
+ if (RD->isAnonymousStructOrUnion() && RD->isUnion())
+ return static_cast<void *>(RD);
- SetBaseOrMemberInitializers(Constructor,
- reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
- NumMemInits, false, AnyErrors);
+ return static_cast<void *>(Field);
+}
+static void
+DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
+ const CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **MemInits,
+ unsigned NumMemInits) {
if (Constructor->isDependentContext())
return;
- if (Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
+ if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
Diagnostic::Ignored &&
- Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
+ SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
Diagnostic::Ignored)
return;
-
+
// Also issue warning if order of ctor-initializer list does not match order
// of 1) base class declarations and 2) order of non-static data members.
llvm::SmallVector<const void*, 32> AllBaseOrMembers;
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ const CXXRecordDecl *ClassDecl = Constructor->getParent();
+
// Push virtual bases before others.
- for (CXXRecordDecl::base_class_iterator VBase =
+ for (CXXRecordDecl::base_class_const_iterator VBase =
ClassDecl->vbases_begin(),
E = ClassDecl->vbases_end(); VBase != E; ++VBase)
- AllBaseOrMembers.push_back(GetKeyForBase(VBase->getType()));
+ AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
+ VBase->getType()));
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
// Virtuals are alread in the virtual base list and are constructed
// first.
if (Base->isVirtual())
continue;
- AllBaseOrMembers.push_back(GetKeyForBase(Base->getType()));
+ AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
+ Base->getType()));
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
@@ -1790,9 +1711,8 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
int curIndex = 0;
CXXBaseOrMemberInitializer *PrevMember = 0;
for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member =
- static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]);
- void *MemberInCtorList = GetKeyForMember(Member, true);
+ CXXBaseOrMemberInitializer *Member = MemInits[i];
+ void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true);
for (; curIndex < Last; curIndex++)
if (MemberInCtorList == AllBaseOrMembers[curIndex])
@@ -1804,23 +1724,23 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
if (PrevMember->isBaseInitializer()) {
// Diagnostics is for an initialized base class.
Type *BaseClass = PrevMember->getBaseClass();
- Diag(PrevMember->getSourceLocation(),
- diag::warn_base_initialized)
+ SemaRef.Diag(PrevMember->getSourceLocation(),
+ diag::warn_base_initialized)
<< QualType(BaseClass, 0);
} else {
FieldDecl *Field = PrevMember->getMember();
- Diag(PrevMember->getSourceLocation(),
- diag::warn_field_initialized)
+ SemaRef.Diag(PrevMember->getSourceLocation(),
+ diag::warn_field_initialized)
<< Field->getNameAsString();
}
// Also the note!
if (FieldDecl *Field = Member->getMember())
- Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 0
+ SemaRef.Diag(Member->getSourceLocation(),
+ diag::note_fieldorbase_initialized_here) << 0
<< Field->getNameAsString();
else {
Type *BaseClass = Member->getBaseClass();
- Diag(Member->getSourceLocation(),
+ SemaRef.Diag(Member->getSourceLocation(),
diag::note_fieldorbase_initialized_here) << 1
<< QualType(BaseClass, 0);
}
@@ -1832,6 +1752,64 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
}
}
+/// ActOnMemInitializers - Handle the member initializers for a constructor.
+void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
+ SourceLocation ColonLoc,
+ MemInitTy **meminits, unsigned NumMemInits,
+ bool AnyErrors) {
+ if (!ConstructorDecl)
+ return;
+
+ AdjustDeclIfTemplate(ConstructorDecl);
+
+ CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
+
+ if (!Constructor) {
+ Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
+ return;
+ }
+
+ CXXBaseOrMemberInitializer **MemInits =
+ reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits);
+
+ llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members;
+ bool HadError = false;
+ for (unsigned i = 0; i < NumMemInits; i++) {
+ CXXBaseOrMemberInitializer *Member = MemInits[i];
+
+ void *KeyToMember = GetKeyForMember(Context, Member);
+ CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
+ if (!PrevMember) {
+ PrevMember = Member;
+ continue;
+ }
+ if (FieldDecl *Field = Member->getMember())
+ Diag(Member->getSourceLocation(),
+ diag::error_multiple_mem_initialization)
+ << Field->getNameAsString()
+ << Member->getSourceRange();
+ else {
+ Type *BaseClass = Member->getBaseClass();
+ assert(BaseClass && "ActOnMemInitializers - neither field or base");
+ Diag(Member->getSourceLocation(),
+ diag::error_multiple_base_initialization)
+ << QualType(BaseClass, 0)
+ << Member->getSourceRange();
+ }
+ Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
+ << 0;
+ HadError = true;
+ }
+
+ if (HadError)
+ return;
+
+ DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits, NumMemInits);
+
+ SetBaseOrMemberInitializers(Constructor, MemInits, NumMemInits, AnyErrors);
+}
+
void
Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXRecordDecl *ClassDecl) {
@@ -1861,7 +1839,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
CheckDestructorAccess(Field->getLocation(), Dtor,
- PartialDiagnostic(diag::err_access_dtor_field)
+ PDiag(diag::err_access_dtor_field)
<< Field->getDeclName()
<< FieldType);
@@ -1889,7 +1867,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
// FIXME: caret should be on the start of the class name
CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor,
- PartialDiagnostic(diag::err_access_dtor_base)
+ PDiag(diag::err_access_dtor_base)
<< Base->getType()
<< Base->getSourceRange());
@@ -1914,7 +1892,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
CheckDestructorAccess(ClassDecl->getLocation(), Dtor,
- PartialDiagnostic(diag::err_access_dtor_vbase)
+ PDiag(diag::err_access_dtor_vbase)
<< VBase->getType());
MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
@@ -1925,94 +1903,11 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
if (!CDtorDecl)
return;
- AdjustDeclIfTemplate(CDtorDecl);
-
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>()))
- SetBaseOrMemberInitializers(Constructor, 0, 0, false, false);
-}
-
-namespace {
- /// PureVirtualMethodCollector - traverses a class and its superclasses
- /// and determines if it has any pure virtual methods.
- class PureVirtualMethodCollector {
- ASTContext &Context;
-
- public:
- typedef llvm::SmallVector<const CXXMethodDecl*, 8> MethodList;
-
- private:
- MethodList Methods;
-
- void Collect(const CXXRecordDecl* RD, MethodList& Methods);
-
- public:
- PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD)
- : Context(Ctx) {
-
- MethodList List;
- Collect(RD, List);
-
- // Copy the temporary list to methods, and make sure to ignore any
- // null entries.
- for (size_t i = 0, e = List.size(); i != e; ++i) {
- if (List[i])
- Methods.push_back(List[i]);
- }
- }
-
- bool empty() const { return Methods.empty(); }
-
- MethodList::const_iterator methods_begin() { return Methods.begin(); }
- MethodList::const_iterator methods_end() { return Methods.end(); }
- };
-
- void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD,
- MethodList& Methods) {
- // First, collect the pure virtual methods for the base classes.
- for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
- BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
- if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
- const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (BaseDecl && BaseDecl->isAbstract())
- Collect(BaseDecl, Methods);
- }
- }
-
- // Next, zero out any pure virtual methods that this class overrides.
- typedef llvm::SmallPtrSet<const CXXMethodDecl*, 4> MethodSetTy;
-
- MethodSetTy OverriddenMethods;
- size_t MethodsSize = Methods.size();
-
- for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end();
- i != e; ++i) {
- // Traverse the record, looking for methods.
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) {
- // If the method is pure virtual, add it to the methods vector.
- if (MD->isPure())
- Methods.push_back(MD);
-
- // Record all the overridden methods in our set.
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods(); I != E; ++I) {
- // Keep track of the overridden methods.
- OverriddenMethods.insert(*I);
- }
- }
- }
-
- // Now go through the methods and zero out all the ones we know are
- // overridden.
- for (size_t i = 0, e = MethodsSize; i != e; ++i) {
- if (OverriddenMethods.count(Methods[i]))
- Methods[i] = 0;
- }
-
- }
+ SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false);
}
-
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
unsigned DiagID, AbstractDiagSelID SelID,
const CXXRecordDecl *CurrentRD) {
@@ -2066,14 +1961,32 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD))
return true;
- PureVirtualMethodCollector Collector(Context, RD);
+ CXXFinalOverriderMap FinalOverriders;
+ RD->getFinalOverriders(FinalOverriders);
+
+ for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
+ MEnd = FinalOverriders.end();
+ M != MEnd;
+ ++M) {
+ for (OverridingMethods::iterator SO = M->second.begin(),
+ SOEnd = M->second.end();
+ SO != SOEnd; ++SO) {
+ // C++ [class.abstract]p4:
+ // A class is abstract if it contains or inherits at least one
+ // pure virtual function for which the final overrider is pure
+ // virtual.
+
+ //
+ if (SO->second.size() != 1)
+ continue;
- for (PureVirtualMethodCollector::MethodList::const_iterator I =
- Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
+ if (!SO->second.front().Method->isPure())
+ continue;
- Diag(MD->getLocation(), diag::note_pure_virtual_function) <<
- MD->getDeclName();
+ Diag(SO->second.front().Method->getLocation(),
+ diag::note_pure_virtual_function)
+ << SO->second.front().Method->getDeclName();
+ }
}
if (!PureVirtualClassDiagSet)
@@ -2162,22 +2075,79 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); I != E; ++I)
Convs->setAccess(I, (*I)->getAccess());
- if (!Record->isAbstract()) {
- // Collect all the pure virtual methods and see if this is an abstract
- // class after all.
- PureVirtualMethodCollector Collector(Context, Record);
- if (!Collector.empty())
- Record->setAbstract(true);
+ // Determine whether we need to check for final overriders. We do
+ // this either when there are virtual base classes (in which case we
+ // may end up finding multiple final overriders for a given virtual
+ // function) or any of the base classes is abstract (in which case
+ // we might detect that this class is abstract).
+ bool CheckFinalOverriders = false;
+ if (Record->isPolymorphic() && !Record->isInvalidDecl() &&
+ !Record->isDependentType()) {
+ if (Record->getNumVBases())
+ CheckFinalOverriders = true;
+ else if (!Record->isAbstract()) {
+ for (CXXRecordDecl::base_class_const_iterator B = Record->bases_begin(),
+ BEnd = Record->bases_end();
+ B != BEnd; ++B) {
+ CXXRecordDecl *BaseDecl
+ = cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl());
+ if (BaseDecl->isAbstract()) {
+ CheckFinalOverriders = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (CheckFinalOverriders) {
+ CXXFinalOverriderMap FinalOverriders;
+ Record->getFinalOverriders(FinalOverriders);
+
+ for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
+ MEnd = FinalOverriders.end();
+ M != MEnd; ++M) {
+ for (OverridingMethods::iterator SO = M->second.begin(),
+ SOEnd = M->second.end();
+ SO != SOEnd; ++SO) {
+ assert(SO->second.size() > 0 &&
+ "All virtual functions have overridding virtual functions");
+ if (SO->second.size() == 1) {
+ // C++ [class.abstract]p4:
+ // A class is abstract if it contains or inherits at least one
+ // pure virtual function for which the final overrider is pure
+ // virtual.
+ if (SO->second.front().Method->isPure())
+ Record->setAbstract(true);
+ continue;
+ }
+
+ // C++ [class.virtual]p2:
+ // In a derived class, if a virtual member function of a base
+ // class subobject has more than one final overrider the
+ // program is ill-formed.
+ Diag(Record->getLocation(), diag::err_multiple_final_overriders)
+ << (NamedDecl *)M->first << Record;
+ Diag(M->first->getLocation(), diag::note_overridden_virtual_function);
+ for (OverridingMethods::overriding_iterator OM = SO->second.begin(),
+ OMEnd = SO->second.end();
+ OM != OMEnd; ++OM)
+ Diag(OM->Method->getLocation(), diag::note_final_overrider)
+ << (NamedDecl *)M->first << OM->Method->getParent();
+
+ Record->setInvalidDecl();
+ }
+ }
}
- if (Record->isAbstract())
+ if (Record->isAbstract() && !Record->isInvalidDecl())
(void)AbstractClassUsageDiagnoser(*this, Record);
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
- SourceLocation RBrac) {
+ SourceLocation RBrac,
+ AttributeList *AttrList) {
if (!TagDecl)
return;
@@ -2185,7 +2155,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
ActOnFields(S, RLoc, TagDecl,
(DeclPtrTy*)FieldCollector->getCurFields(),
- FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
+ FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList);
CheckCompletedCXXClass(
dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>()));
@@ -2218,8 +2188,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(Context.VoidTy,
0, 0, false, 0,
/*FIXME*/false, false,
- 0, 0, false,
- CC_Default),
+ 0, 0,
+ FunctionType::ExtInfo()),
/*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
@@ -2293,8 +2263,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
&ArgType, 1,
false, 0,
/*FIXME:*/false,
- false, 0, 0, false,
- CC_Default),
+ false, 0, 0,
+ FunctionType::ExtInfo()),
/*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
@@ -2382,8 +2352,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(RetType, &ArgType, 1,
false, 0,
/*FIXME:*/false,
- false, 0, 0, false,
- CC_Default),
+ false, 0, 0,
+ FunctionType::ExtInfo()),
/*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
@@ -2412,8 +2382,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
QualType Ty = Context.getFunctionType(Context.VoidTy,
0, 0, false, 0,
/*FIXME:*/false,
- false, 0, 0, false,
- CC_Default);
+ false, 0, 0, FunctionType::ExtInfo());
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
@@ -2586,8 +2555,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
Proto->hasAnyExceptionSpec(),
Proto->getNumExceptions(),
Proto->exception_begin(),
- Proto->getNoReturnAttr(),
- Proto->getCallConv());
+ Proto->getExtInfo());
}
/// CheckConstructor - Checks a fully-formed constructor for
@@ -2615,7 +2583,7 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation();
Diag(ParamLoc, diag::err_constructor_byvalue_arg)
- << CodeModificationHint::CreateInsertion(ParamLoc, " const &");
+ << FixItHint::CreateInsertion(ParamLoc, " const &");
// FIXME: Rather that making the constructor invalid, we should endeavor
// to fix the type.
@@ -2746,7 +2714,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D,
// will put in a result type of "int" when none was specified.
// FIXME: Exceptions!
return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0,
- false, false, 0, 0, false, CC_Default);
+ false, false, 0, 0, FunctionType::ExtInfo());
}
/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
@@ -2822,8 +2790,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Proto->hasAnyExceptionSpec(),
Proto->getNumExceptions(),
Proto->exception_begin(),
- Proto->getNoReturnAttr(),
- Proto->getCallConv());
+ Proto->getExtInfo());
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
@@ -2962,7 +2929,6 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
} else {
// Anonymous namespaces.
assert(Namespc->isAnonymousNamespace());
- CurContext->addDecl(Namespc);
// Link the anonymous namespace into its parent.
NamespaceDecl *PrevDecl;
@@ -2984,6 +2950,8 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
PrevDecl->setNextNamespace(Namespc);
}
+ CurContext->addDecl(Namespc);
+
// C++ [namespace.unnamed]p1. An unnamed-namespace-definition
// behaves as if it were replaced by
// namespace unique { /* empty body */ }
@@ -3160,8 +3128,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
UsingLoc = Name.getSourceRange().getBegin();
Diag(UsingLoc, diag::warn_access_decl_deprecated)
- << CodeModificationHint::CreateInsertion(SS.getRange().getBegin(),
- "using ");
+ << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using ");
}
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
@@ -3330,6 +3297,11 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
CurContext->addDecl(Shadow);
Shadow->setAccess(UD->getAccess());
+ // Register it as a conversion if appropriate.
+ if (Shadow->getDeclName().getNameKind()
+ == DeclarationName::CXXConversionFunctionName)
+ cast<CXXRecordDecl>(CurContext)->addConversionFunction(Shadow);
+
if (Orig->isInvalidDecl() || UD->isInvalidDecl())
Shadow->setInvalidDecl();
@@ -3364,6 +3336,10 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
/// decl structures are (very reasonably) not designed for removal.
/// (2) avoids this but is very fiddly and phase-dependent.
void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
+ if (Shadow->getDeclName().getNameKind() ==
+ DeclarationName::CXXConversionFunctionName)
+ cast<CXXRecordDecl>(Shadow->getDeclContext())->removeConversion(Shadow);
+
// Remove it from the DeclContext...
Shadow->getDeclContext()->removeDecl(Shadow);
@@ -3377,7 +3353,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
Shadow->getUsingDecl()->removeShadowDecl(Shadow);
// TODO: complain somehow if Shadow was used. It shouldn't
- // be possible for this to happen, because
+ // be possible for this to happen, because...?
}
/// Builds a using declaration.
@@ -3738,8 +3714,10 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
// We already have an alias with the same name that points to the same
// namespace, so don't create a new one.
+ // FIXME: At some point, we'll want to create the (redundant)
+ // declaration to maintain better source information.
if (!R.isAmbiguous() && !R.empty() &&
- AD->getNamespace() == getNamespaceDecl(R.getFoundDecl()))
+ AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl())))
return DeclPtrTy();
}
@@ -3780,7 +3758,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
DeclContext *PreviousContext = CurContext;
CurContext = Constructor;
- if (SetBaseOrMemberInitializers(Constructor, 0, 0, true, false)) {
+ if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
@@ -3847,7 +3825,7 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
BaseClassDecl)) {
CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
BaseAssignOpMethod,
- PartialDiagnostic(diag::err_access_assign_base)
+ PDiag(diag::err_access_assign_base)
<< Base->getType());
MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
@@ -3866,7 +3844,7 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
FieldClassDecl)) {
CheckDirectMemberAccess(Field->getLocation(),
FieldAssignOpMethod,
- PartialDiagnostic(diag::err_access_assign_field)
+ PDiag(diag::err_access_assign_field)
<< Field->getDeclName() << Field->getType());
MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
@@ -3948,7 +3926,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
BaseClassDecl->getCopyConstructor(Context, TypeQuals)) {
CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
BaseCopyCtor,
- PartialDiagnostic(diag::err_access_copy_base)
+ PDiag(diag::err_access_copy_base)
<< Base->getType());
MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
@@ -3967,7 +3945,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
FieldClassDecl->getCopyConstructor(Context, TypeQuals)) {
CheckDirectMemberAccess(Field->getLocation(),
FieldCopyCtor,
- PartialDiagnostic(diag::err_access_copy_field)
+ PDiag(diag::err_access_copy_field)
<< Field->getDeclName() << Field->getType());
MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
@@ -4062,7 +4040,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
MarkDeclarationReferenced(VD->getLocation(), Destructor);
CheckDestructorAccess(VD->getLocation(), Destructor,
- PartialDiagnostic(diag::err_access_dtor_var)
+ PDiag(diag::err_access_dtor_var)
<< VD->getDeclName()
<< VD->getType());
}
@@ -4408,16 +4386,18 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
if (Context.getCanonicalType(T2) == Context.OverloadTy) {
+ DeclAccessPair Found;
FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
- ICS != 0);
+ ICS != 0, Found);
if (Fn) {
// Since we're performing this reference-initialization for
// real, update the initializer with the resulting function.
if (!ICS) {
if (DiagnoseUseOfDecl(Fn, DeclLoc))
- return true;
+ return true;
- Init = FixOverloadedFunctionReference(Init, Fn);
+ CheckAddressOfMemberAccess(Init, Found);
+ Init = FixOverloadedFunctionReference(Init, Found, Fn);
}
T2 = Fn->getType();
@@ -5378,7 +5358,8 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// friend templates because ActOnTag never produces a ClassTemplateDecl
// for a TUK_Friend.
Declarator TheDeclarator(DS, Declarator::MemberContext);
- QualType T = GetTypeForDeclarator(TheDeclarator, S);
+ TypeSourceInfo *TSI;
+ QualType T = GetTypeForDeclarator(TheDeclarator, S, &TSI);
if (TheDeclarator.isInvalidType())
return DeclPtrTy();
@@ -5396,7 +5377,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
//
// FIXME: handle "template <> friend class A<T>;", which
// is possibly well-formed? Who even knows?
- if (TempParams.size() && !isa<ElaboratedType>(T)) {
+ if (TempParams.size() && !T->isElaboratedTypeSpecifier()) {
Diag(Loc, diag::err_tagless_friend_type_template)
<< DS.getSourceRange();
return DeclPtrTy();
@@ -5408,7 +5389,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// * The class-key of the elaborated-type-specifier is required.
// This is one of the rare places in Clang where it's legitimate to
// ask about the "spelling" of the type.
- if (!getLangOptions().CPlusPlus0x && !isa<ElaboratedType>(T)) {
+ if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) {
// If we evaluated the type to a record type, suggest putting
// a tag in front.
if (const RecordType *RT = T->getAs<RecordType>()) {
@@ -5420,8 +5401,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
<< (unsigned) RD->getTagKind()
<< T
<< SourceRange(DS.getFriendSpecLoc())
- << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
- InsertionText);
+ << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText);
return DeclPtrTy();
}else {
Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
@@ -5443,16 +5423,20 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// deadline. It's also a very silly restriction that seriously
// affects inner classes and which nobody else seems to implement;
// thus we never diagnose it, not even in -pedantic.
+ //
+ // But note that we could warn about it: it's always useless to
+ // friend one of your own members (it's not, however, worthless to
+ // friend a member of an arbitrary specialization of your template).
Decl *D;
if (TempParams.size())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
TempParams.size(),
(TemplateParameterList**) TempParams.release(),
- T.getTypePtr(),
+ TSI,
DS.getFriendSpecLoc());
else
- D = FriendDecl::Create(Context, CurContext, Loc, T.getTypePtr(),
+ D = FriendDecl::Create(Context, CurContext, Loc, TSI,
DS.getFriendSpecLoc());
D->setAccess(AS_public);
CurContext->addDecl(D);
@@ -5889,7 +5873,7 @@ static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) {
break;
case TSK_ExplicitInstantiationDeclaration:
- return true; //FIXME: This looks wrong.
+ return false;
case TSK_ExplicitInstantiationDefinition:
// This is method of a explicit instantiation; mark all of the virtual
@@ -5945,7 +5929,8 @@ bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
return true;
}
-void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) {
+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;
@@ -5955,4 +5940,19 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) {
if (MD->isVirtual() && !MD->isPure())
MarkDeclarationReferenced(Loc, MD);
}
+
+ // Only classes that have virtual bases need a VTT.
+ if (RD->getNumVBases() == 0)
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (i->isVirtual())
+ continue;
+ if (Base->getNumVBases() == 0)
+ continue;
+ MarkVirtualMembersReferenced(Loc, Base);
+ }
}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index b2f6717..9bc0846 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -559,8 +559,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
<< ClassName << R.getLookupName();
Diag(IDecl->getLocation(), diag::note_previous_decl)
<< R.getLookupName()
- << CodeModificationHint::CreateReplacement(ClassLoc,
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(ClassLoc,
+ R.getLookupName().getAsString());
IDecl = 0;
} else {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
@@ -667,8 +667,6 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
Diag(ClsIvar->getLocation(), diag::note_previous_definition);
continue;
}
- if (ImplIvar->getAccessControl() != ObjCIvarDecl::Private)
- Diag(ImplIvar->getLocation(), diag::err_non_private_ivar_declaration);
// Instance ivar to Implementation's DeclContext.
ImplIvar->setLexicalDeclContext(ImpDecl);
IDecl->makeDeclVisibleInContext(ImplIvar, false);
@@ -721,12 +719,13 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
}
void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
- bool &IncompleteImpl) {
+ bool &IncompleteImpl, unsigned DiagID) {
if (!IncompleteImpl) {
Diag(ImpLoc, diag::warn_incomplete_impl);
IncompleteImpl = true;
}
- Diag(ImpLoc, diag::warn_undef_method_impl) << method->getDeclName();
+ Diag(method->getLocation(), DiagID)
+ << method->getDeclName();
}
void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
@@ -770,7 +769,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
bool& IncompleteImpl,
const llvm::DenseSet<Selector> &InsMap,
const llvm::DenseSet<Selector> &ClsMap,
- ObjCInterfaceDecl *IDecl) {
+ ObjCContainerDecl *CDecl) {
+ ObjCInterfaceDecl *IDecl;
+ if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl))
+ IDecl = C->getClassInterface();
+ else
+ IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
+ assert (IDecl && "CheckProtocolMethodDefs - IDecl is null");
+
ObjCInterfaceDecl *Super = IDecl->getSuperClass();
ObjCInterfaceDecl *NSIDecl = 0;
if (getLangOptions().NeXTRuntime) {
@@ -808,8 +814,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// uses the protocol.
ObjCMethodDecl *MethodInClass =
IDecl->lookupInstanceMethod(method->getSelector());
- if (!MethodInClass || !MethodInClass->isSynthesized())
- WarnUndefinedMethod(ImpLoc, method, IncompleteImpl);
+ if (!MethodInClass || !MethodInClass->isSynthesized()) {
+ unsigned DIAG = diag::warn_unimplemented_protocol_method;
+ if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) {
+ WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
+ Diag(CDecl->getLocation(), diag::note_required_for_protocol_at)
+ << PDecl->getDeclName();
+ }
+ }
}
}
// check unimplemented class methods
@@ -819,8 +831,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
ObjCMethodDecl *method = *I;
if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
!ClsMap.count(method->getSelector()) &&
- (!Super || !Super->lookupClassMethod(method->getSelector())))
- WarnUndefinedMethod(ImpLoc, method, IncompleteImpl);
+ (!Super || !Super->lookupClassMethod(method->getSelector()))) {
+ unsigned DIAG = diag::warn_unimplemented_protocol_method;
+ if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) {
+ WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
+ Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) <<
+ PDecl->getDeclName();
+ }
+ }
}
// Check on this protocols's referenced protocols, recursively.
for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
@@ -849,7 +867,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
if (!(*I)->isSynthesized() &&
!InsMap.count((*I)->getSelector())) {
if (ImmediateClass)
- WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
+ WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
+ diag::note_undef_method_impl);
continue;
} else {
ObjCMethodDecl *ImpMethodDecl =
@@ -873,7 +892,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
ClsMapSeen.insert((*I)->getSelector());
if (!ClsMap.count((*I)->getSelector())) {
if (ImmediateClass)
- WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
+ WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
+ diag::note_undef_method_impl);
} else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getClassMethod((*I)->getSelector());
@@ -950,7 +970,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
E = C->protocol_end(); PI != E; ++PI)
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
- InsMap, ClsMap, C->getClassInterface());
+ InsMap, ClsMap, CDecl);
// Report unimplemented properties in the category as well.
// When reporting on missing setter/getters, do not report when
// setter/getter is implemented in category's primary class
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 4ce1ce9..53e9385 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -15,6 +15,8 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -94,19 +96,21 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
}
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
+ bool MissingExceptionSpecification = false;
bool MissingEmptyExceptionSpecification = false;
- if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
- diag::note_previous_declaration,
+ if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec),
+ PDiag(diag::note_previous_declaration),
Old->getType()->getAs<FunctionProtoType>(),
Old->getLocation(),
New->getType()->getAs<FunctionProtoType>(),
New->getLocation(),
+ &MissingExceptionSpecification,
&MissingEmptyExceptionSpecification))
return false;
// The failure was something other than an empty exception
// specification; return an error.
- if (!MissingEmptyExceptionSpecification)
+ if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification)
return true;
// The new function declaration is only missing an empty exception
@@ -117,8 +121,10 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// to many libc functions as an optimization. Unfortunately, that
// optimization isn't permitted by the C++ standard, so we're forced
// to work around it here.
- if (isa<FunctionProtoType>(New->getType()) &&
- Context.getSourceManager().isInSystemHeader(Old->getLocation()) &&
+ if (MissingEmptyExceptionSpecification &&
+ isa<FunctionProtoType>(New->getType()) &&
+ (Old->getLocation().isInvalid() ||
+ Context.getSourceManager().isInSystemHeader(Old->getLocation())) &&
Old->isExternC()) {
const FunctionProtoType *NewProto
= cast<FunctionProtoType>(New->getType());
@@ -128,12 +134,91 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
NewProto->isVariadic(),
NewProto->getTypeQuals(),
true, false, 0, 0,
- NewProto->getNoReturnAttr(),
- NewProto->getCallConv());
+ NewProto->getExtInfo());
New->setType(NewType);
return false;
}
+ if (MissingExceptionSpecification && isa<FunctionProtoType>(New->getType())) {
+ const FunctionProtoType *NewProto
+ = cast<FunctionProtoType>(New->getType());
+ const FunctionProtoType *OldProto
+ = Old->getType()->getAs<FunctionProtoType>();
+
+ // Update the type of the function with the appropriate exception
+ // specification.
+ QualType NewType = Context.getFunctionType(NewProto->getResultType(),
+ NewProto->arg_type_begin(),
+ NewProto->getNumArgs(),
+ NewProto->isVariadic(),
+ NewProto->getTypeQuals(),
+ OldProto->hasExceptionSpec(),
+ OldProto->hasAnyExceptionSpec(),
+ OldProto->getNumExceptions(),
+ OldProto->exception_begin(),
+ NewProto->getExtInfo());
+ New->setType(NewType);
+
+ // If exceptions are disabled, suppress the warning about missing
+ // exception specifications for new and delete operators.
+ if (!getLangOptions().Exceptions) {
+ switch (New->getDeclName().getCXXOverloadedOperator()) {
+ case OO_New:
+ case OO_Array_New:
+ case OO_Delete:
+ case OO_Array_Delete:
+ if (New->getDeclContext()->isTranslationUnit())
+ return false;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Warn about the lack of exception specification.
+ llvm::SmallString<128> ExceptionSpecString;
+ llvm::raw_svector_ostream OS(ExceptionSpecString);
+ OS << "throw(";
+ bool OnFirstException = true;
+ for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
+ EEnd = OldProto->exception_end();
+ E != EEnd;
+ ++E) {
+ if (OnFirstException)
+ OnFirstException = false;
+ else
+ OS << ", ";
+
+ OS << E->getAsString(Context.PrintingPolicy);
+ }
+ OS << ")";
+ OS.flush();
+
+ SourceLocation AfterParenLoc;
+ if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
+ TypeLoc TL = TSInfo->getTypeLoc();
+ if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL))
+ AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc());
+ }
+
+ if (AfterParenLoc.isInvalid())
+ Diag(New->getLocation(), diag::warn_missing_exception_specification)
+ << New << OS.str();
+ else {
+ // FIXME: This will get more complicated with C++0x
+ // late-specified return types.
+ Diag(New->getLocation(), diag::warn_missing_exception_specification)
+ << New << OS.str()
+ << FixItHint::CreateInsertion(AfterParenLoc, " " + OS.str().str());
+ }
+
+ if (!Old->getLocation().isInvalid())
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+
+ return false;
+ }
+
Diag(New->getLocation(), diag::err_mismatched_exception_spec);
Diag(Old->getLocation(), diag::note_previous_declaration);
return true;
@@ -146,8 +231,9 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
bool Sema::CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc) {
- return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
- diag::note_previous_declaration,
+ return CheckEquivalentExceptionSpec(
+ PDiag(diag::err_mismatched_exception_spec),
+ PDiag(diag::note_previous_declaration),
Old, OldLoc, New, NewLoc);
}
@@ -155,11 +241,17 @@ bool Sema::CheckEquivalentExceptionSpec(
/// exception specifications. Exception specifications are equivalent if
/// they allow exactly the same set of exception types. It does not matter how
/// that is achieved. See C++ [except.spec]p2.
-bool Sema::CheckEquivalentExceptionSpec(
- const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
- const FunctionProtoType *Old, SourceLocation OldLoc,
- const FunctionProtoType *New, SourceLocation NewLoc,
- bool *MissingEmptyExceptionSpecification) {
+bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
+ const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Old,
+ SourceLocation OldLoc,
+ const FunctionProtoType *New,
+ SourceLocation NewLoc,
+ bool *MissingExceptionSpecification,
+ bool *MissingEmptyExceptionSpecification) {
+ if (MissingExceptionSpecification)
+ *MissingExceptionSpecification = false;
+
if (MissingEmptyExceptionSpecification)
*MissingEmptyExceptionSpecification = false;
@@ -168,13 +260,20 @@ bool Sema::CheckEquivalentExceptionSpec(
if (OldAny && NewAny)
return false;
if (OldAny || NewAny) {
- if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() &&
- !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 &&
+ if (MissingExceptionSpecification && Old->hasExceptionSpec() &&
!New->hasExceptionSpec()) {
- // The old type has a throw() exception specification and the
- // new type has no exception specification, and the caller asked
- // to handle this itself.
- *MissingEmptyExceptionSpecification = true;
+ // The old type has an exception specification of some sort, but
+ // the new type does not.
+ *MissingExceptionSpecification = true;
+
+ if (MissingEmptyExceptionSpecification &&
+ !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0) {
+ // The old type has a throw() exception specification and the
+ // new type has no exception specification, and the caller asked
+ // to handle this itself.
+ *MissingEmptyExceptionSpecification = true;
+ }
+
return true;
}
@@ -350,7 +449,8 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
const FunctionProtoType *Source, SourceLocation SourceLoc)
{
if (CheckSpecForTypesEquivalent(*this,
- PDiag(diag::err_deep_exception_specs_differ) << 0, 0,
+ PDiag(diag::err_deep_exception_specs_differ) << 0,
+ PDiag(),
Target->getResultType(), TargetLoc,
Source->getResultType(), SourceLoc))
return true;
@@ -361,7 +461,8 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
"Functions have different argument counts.");
for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) {
if (CheckSpecForTypesEquivalent(*this,
- PDiag(diag::err_deep_exception_specs_differ) << 1, 0,
+ PDiag(diag::err_deep_exception_specs_differ) << 1,
+ PDiag(),
Target->getArgType(i), TargetLoc,
Source->getArgType(i), SourceLoc))
return true;
@@ -386,15 +487,16 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
// This means that the source of the conversion can only throw a subset of
// the exceptions of the target, and any exception specs on arguments or
// return types must be equivalent.
- return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs,
- 0, ToFunc, From->getSourceRange().getBegin(),
+ return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs),
+ PDiag(), ToFunc,
+ From->getSourceRange().getBegin(),
FromFunc, SourceLocation());
}
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- return CheckExceptionSpecSubset(diag::err_override_exception_spec,
- diag::note_overridden_virtual_function,
+ return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec),
+ PDiag(diag::note_overridden_virtual_function),
Old->getType()->getAs<FunctionProtoType>(),
Old->getLocation(),
New->getType()->getAs<FunctionProtoType>(),
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index fe6f3b9..fbdf080 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -635,7 +635,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
MemberType = Context.getQualifiedType(MemberType, NewQuals);
MarkDeclarationReferenced(Loc, *FI);
- PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI);
+ PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI, *FI);
// FIXME: Might this end up being a qualified name?
Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
OpLoc, MemberType);
@@ -949,8 +949,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
// Actually quite difficult!
if (isInstance)
Diag(R.getNameLoc(), diagnostic) << Name
- << CodeModificationHint::CreateInsertion(R.getNameLoc(),
- "this->");
+ << FixItHint::CreateInsertion(R.getNameLoc(), "this->");
else
Diag(R.getNameLoc(), diagnostic) << Name;
@@ -969,14 +968,14 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
if (SS.isEmpty())
Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << computeDeclContext(SS, false) << R.getLookupName()
<< SS.getRange()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
Diag(ND->getLocation(), diag::note_previous_decl)
<< ND->getDeclName();
@@ -1355,10 +1354,27 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
return Owned((Expr*) 0);
}
-/// \brief Cast member's object to its own class if necessary.
+/// \brief Cast a base object to a member's actual type.
+///
+/// Logically this happens in three phases:
+///
+/// * First we cast from the base type to the naming class.
+/// The naming class is the class into which we were looking
+/// when we found the member; it's the qualifier type if a
+/// qualifier was provided, and otherwise it's the base type.
+///
+/// * Next we cast from the naming class to the declaring class.
+/// If the member we found was brought into a class's scope by
+/// a using declaration, this is that class; otherwise it's
+/// the class declaring the member.
+///
+/// * Finally we cast from the declaring class to the "true"
+/// declaring class of the member. This conversion does not
+/// obey access control.
bool
Sema::PerformObjectMemberConversion(Expr *&From,
NestedNameSpecifier *Qualifier,
+ NamedDecl *FoundDecl,
NamedDecl *Member) {
CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext());
if (!RD)
@@ -1406,6 +1422,9 @@ Sema::PerformObjectMemberConversion(Expr *&From,
if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType))
return false;
+ SourceRange FromRange = From->getSourceRange();
+ SourceLocation FromLoc = FromRange.getBegin();
+
// C++ [class.member.lookup]p8:
// [...] Ambiguities can often be resolved by qualifying a name with its
// class name.
@@ -1424,51 +1443,87 @@ Sema::PerformObjectMemberConversion(Expr *&From,
// x = 17; // error: ambiguous base subobjects
// Derived1::x = 17; // okay, pick the Base subobject of Derived1
// }
- QualType IntermediateRecordType;
- QualType IntermediateType;
if (Qualifier) {
- if (const RecordType *IntermediateRecord
- = Qualifier->getAsType()->getAs<RecordType>()) {
- IntermediateRecordType = QualType(IntermediateRecord, 0);
- IntermediateType = IntermediateRecordType;
+ QualType QType = QualType(Qualifier->getAsType(), 0);
+ assert(!QType.isNull() && "lookup done with dependent qualifier?");
+ assert(QType->isRecordType() && "lookup done with non-record type");
+
+ QualType QRecordType = QualType(QType->getAs<RecordType>(), 0);
+
+ // In C++98, the qualifier type doesn't actually have to be a base
+ // type of the object type, in which case we just ignore it.
+ // Otherwise build the appropriate casts.
+ if (IsDerivedFrom(FromRecordType, QRecordType)) {
+ if (CheckDerivedToBaseConversion(FromRecordType, QRecordType,
+ FromLoc, FromRange))
+ return true;
+
if (PointerConversions)
- IntermediateType = Context.getPointerType(IntermediateType);
+ QType = Context.getPointerType(QType);
+ ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue*/ !PointerConversions);
+
+ FromType = QType;
+ FromRecordType = QRecordType;
+
+ // If the qualifier type was the same as the destination type,
+ // we're done.
+ if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType))
+ return false;
}
}
- if (!IntermediateType.isNull() &&
- IsDerivedFrom(FromRecordType, IntermediateRecordType) &&
- IsDerivedFrom(IntermediateRecordType, DestRecordType)) {
- if (CheckDerivedToBaseConversion(FromRecordType, IntermediateRecordType,
- From->getSourceRange().getBegin(),
- From->getSourceRange()) ||
- CheckDerivedToBaseConversion(IntermediateRecordType, DestRecordType,
- From->getSourceRange().getBegin(),
- From->getSourceRange()))
- return true;
+ bool IgnoreAccess = false;
- ImpCastExprToType(From, IntermediateType, CastExpr::CK_DerivedToBase,
- /*isLvalue=*/!PointerConversions);
- ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
- /*isLvalue=*/!PointerConversions);
- return false;
+ // If we actually found the member through a using declaration, cast
+ // down to the using declaration's type.
+ //
+ // Pointer equality is fine here because only one declaration of a
+ // class ever has member declarations.
+ if (FoundDecl->getDeclContext() != Member->getDeclContext()) {
+ assert(isa<UsingShadowDecl>(FoundDecl));
+ QualType URecordType = Context.getTypeDeclType(
+ cast<CXXRecordDecl>(FoundDecl->getDeclContext()));
+
+ // We only need to do this if the naming-class to declaring-class
+ // conversion is non-trivial.
+ if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) {
+ assert(IsDerivedFrom(FromRecordType, URecordType));
+ if (CheckDerivedToBaseConversion(FromRecordType, URecordType,
+ FromLoc, FromRange))
+ return true;
+
+ QualType UType = URecordType;
+ if (PointerConversions)
+ UType = Context.getPointerType(UType);
+ ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue*/ !PointerConversions);
+ FromType = UType;
+ FromRecordType = URecordType;
+ }
+
+ // We don't do access control for the conversion from the
+ // declaring class to the true declaring class.
+ IgnoreAccess = true;
}
if (CheckDerivedToBaseConversion(FromRecordType,
DestRecordType,
- From->getSourceRange().getBegin(),
- From->getSourceRange()))
+ FromLoc,
+ FromRange,
+ IgnoreAccess))
return true;
- ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
- /*isLvalue=*/true);
+ ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue=*/ !PointerConversions);
return false;
}
/// \brief Build a MemberExpr AST node.
static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
const CXXScopeSpec &SS, ValueDecl *Member,
- SourceLocation Loc, QualType Ty,
+ NamedDecl *FoundDecl, SourceLocation Loc,
+ QualType Ty,
const TemplateArgumentListInfo *TemplateArgs = 0) {
NestedNameSpecifier *Qualifier = 0;
SourceRange QualifierRange;
@@ -1478,7 +1533,7 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
}
return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange,
- Member, Loc, TemplateArgs, Ty);
+ Member, FoundDecl, Loc, TemplateArgs, Ty);
}
/// Builds an implicit member access expression. The current context
@@ -2520,7 +2575,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
SourceLocation OpLoc, const CXXScopeSpec &SS) {
RecordDecl *RDecl = RTy->getDecl();
if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
- PDiag(diag::err_typecheck_incomplete_tag)
+ SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
<< BaseRange))
return true;
@@ -2558,8 +2613,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
(isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << DC << R.getLookupName() << SS.getRange()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
<< ND->getDeclName();
@@ -2692,6 +2747,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
}
assert(R.isSingleResult());
+ NamedDecl *FoundDecl = *R.begin();
NamedDecl *MemberDecl = R.getFoundDecl();
// FIXME: diagnose the presence of template arguments now.
@@ -2754,30 +2810,30 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
}
MarkDeclarationReferenced(MemberLoc, FD);
- if (PerformObjectMemberConversion(BaseExpr, Qualifier, FD))
+ if (PerformObjectMemberConversion(BaseExpr, Qualifier, FoundDecl, FD))
return ExprError();
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- FD, MemberLoc, MemberType));
+ FD, FoundDecl, MemberLoc, MemberType));
}
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, Var);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Var, MemberLoc,
+ Var, FoundDecl, MemberLoc,
Var->getType().getNonReferenceType()));
}
if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- MemberFn, MemberLoc,
+ MemberFn, FoundDecl, MemberLoc,
MemberFn->getType()));
}
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Enum, MemberLoc, Enum->getType()));
+ Enum, FoundDecl, MemberLoc, Enum->getType()));
}
Owned(BaseExpr);
@@ -2836,7 +2892,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
Diag(Loc, diag::err_member_reference_needs_call)
<< QualType(Fun, 0)
- << CodeModificationHint::CreateInsertion(Loc, "()");
+ << FixItHint::CreateInsertion(Loc, "()");
OwningExprResult NewBase
= ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc,
@@ -2955,7 +3011,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// by now.
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< BaseType << int(IsArrow) << BaseExpr->getSourceRange()
- << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ << FixItHint::CreateReplacement(OpLoc, ".");
IsArrow = false;
} else {
Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
@@ -2975,7 +3031,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (PT && PT->getPointeeType()->isRecordType()) {
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< BaseType << int(IsArrow) << BaseExpr->getSourceRange()
- << CodeModificationHint::CreateReplacement(OpLoc, "->");
+ << FixItHint::CreateReplacement(OpLoc, "->");
BaseType = PT->getPointeeType();
IsArrow = true;
}
@@ -3014,8 +3070,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
Diag(R.getNameLoc(),
diag::err_typecheck_member_reference_ivar_suggest)
<< IDecl->getDeclName() << MemberName << IV->getDeclName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- IV->getNameAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ IV->getNameAsString());
Diag(IV->getLocation(), diag::note_previous_decl)
<< IV->getDeclName();
}
@@ -3189,8 +3245,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
Res.getAsSingle<ObjCPropertyDecl>()) {
Diag(R.getNameLoc(), diag::err_property_not_found_suggest)
<< MemberName << BaseType << Res.getLookupName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- Res.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ Res.getLookupName().getAsString());
ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
Diag(Property->getLocation(), diag::note_previous_decl)
<< Property->getDeclName();
@@ -3519,7 +3575,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
if (NumArgs > 0) {
// Pseudo-destructor calls should not have any arguments.
Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args)
- << CodeModificationHint::CreateRemoval(
+ << FixItHint::CreateRemoval(
SourceRange(Args[0]->getLocStart(),
Args[NumArgs-1]->getLocEnd()));
@@ -4594,13 +4650,15 @@ Sema::AssignConvertType
Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
if (lhsType->isObjCBuiltinType()) {
// Class is not compatible with ObjC object pointers.
- if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType())
+ if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType() &&
+ !rhsType->isObjCQualifiedClassType())
return IncompatiblePointer;
return Compatible;
}
if (rhsType->isObjCBuiltinType()) {
// Class is not compatible with ObjC object pointers.
- if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType())
+ if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType() &&
+ !lhsType->isObjCQualifiedClassType())
return IncompatiblePointer;
return Compatible;
}
@@ -5367,12 +5425,10 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
PDiag(diag::warn_stringcompare)
<< isa<ObjCEncodeExpr>(literalStringStripped)
<< literalString->getSourceRange()
- << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ")
- << CodeModificationHint::CreateInsertion(lex->getLocStart(),
- "strcmp(")
- << CodeModificationHint::CreateInsertion(
- PP.getLocForEndOfToken(rex->getLocEnd()),
- resultComparison));
+ << FixItHint::CreateReplacement(SourceRange(Loc), ", ")
+ << FixItHint::CreateInsertion(lex->getLocStart(), "strcmp(")
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(rex->getLocEnd()),
+ resultComparison));
}
}
@@ -5783,7 +5839,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_IncompleteType:
case Expr::MLV_IncompleteVoidType:
return S.RequireCompleteType(Loc, E->getType(),
- PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue)
+ S.PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue)
<< E->getSourceRange());
case Expr::MLV_DuplicateVectorComponents:
Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
@@ -6345,8 +6401,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
const PartialDiagnostic &PD,
SourceRange ParenRange,
- const PartialDiagnostic &SecondPD = PartialDiagnostic(0),
- SourceRange SecondParenRange = SourceRange()) {
+ const PartialDiagnostic &SecondPD,
+ SourceRange SecondParenRange) {
SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
// We can't display the parentheses, so just dig the
@@ -6356,8 +6412,8 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
}
Self.Diag(Loc, PD)
- << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
- << CodeModificationHint::CreateInsertion(EndLoc, ")");
+ << FixItHint::CreateInsertion(ParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
if (!SecondPD.getDiagID())
return;
@@ -6371,8 +6427,8 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
}
Self.Diag(Loc, SecondPD)
- << CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(")
- << CodeModificationHint::CreateInsertion(EndLoc, ")");
+ << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
}
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
@@ -6401,20 +6457,20 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc,
if (BinOp::isComparisonOp(lhsopc))
SuggestParentheses(Self, OpLoc,
- PDiag(diag::warn_precedence_bitwise_rel)
+ Self.PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(lhs->getLocStart(), OpLoc)
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
lhs->getSourceRange(),
- PDiag(diag::note_precedence_bitwise_first)
+ Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
else if (BinOp::isComparisonOp(rhsopc))
SuggestParentheses(Self, OpLoc,
- PDiag(diag::warn_precedence_bitwise_rel)
+ Self.PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(OpLoc, rhs->getLocEnd())
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
rhs->getSourceRange(),
- PDiag(diag::note_precedence_bitwise_first)
+ Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
}
@@ -6750,7 +6806,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
Res = BuildAnonymousStructUnionMemberReference(
OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
} else {
- PerformObjectMemberConversion(Res, /*Qualifier=*/0, MemberDecl);
+ PerformObjectMemberConversion(Res, /*Qualifier=*/0,
+ *R.begin(), MemberDecl);
// MemberDecl->getType() doesn't get the right qualifiers, but it
// doesn't matter here.
Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
@@ -6849,8 +6906,8 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// The parameter list is optional, if there was none, assume ().
if (!T->isFunctionType())
- T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0, false,
- CC_Default);
+ T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0,
+ FunctionType::ExtInfo());
CurBlock->hasPrototype = true;
CurBlock->isVariadic = false;
@@ -6905,13 +6962,21 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
CurBlock->Params.size());
CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
+
+ bool ShouldCheckShadow =
+ Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored;
+
for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
E = CurBlock->TheDecl->param_end(); AI != E; ++AI) {
(*AI)->setOwningFunction(CurBlock->TheDecl);
// If this has an identifier, add it to the scope stack.
- if ((*AI)->getIdentifier())
+ if ((*AI)->getIdentifier()) {
+ if (ShouldCheckShadow)
+ CheckShadow(CurBlock->TheScope, *AI);
+
PushOnScopeChains(*AI, CurBlock->TheScope);
+ }
}
// Check for a valid sentinel attribute on this block.
@@ -6967,11 +7032,11 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
QualType BlockTy;
if (!BSI->hasPrototype)
BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0,
- NoReturn, CC_Default);
+ FunctionType::ExtInfo(NoReturn, 0, CC_Default));
else
BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
BSI->isVariadic, 0, false, false, 0, 0,
- NoReturn, CC_Default);
+ FunctionType::ExtInfo(NoReturn, 0, CC_Default));
// FIXME: Check that return/parameter types are complete/non-abstract
DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
@@ -7004,8 +7069,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
}
// Issue any analysis-based warnings.
- sema::AnalysisBasedWarnings W(*this);
- W.IssueWarnings(BSI->TheDecl, BlockTy);
+ const sema::AnalysisBasedWarnings::Policy &WP =
+ AnalysisWarnings.getDefaultPolicy();
+ AnalysisWarnings.IssueWarnings(WP, BSI->TheDecl, BlockTy);
Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs);
@@ -7066,11 +7132,8 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
return Owned(new (Context) GNUNullExpr(Ty, TokenLoc));
}
-static void
-MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef,
- QualType DstType,
- Expr *SrcExpr,
- CodeModificationHint &Hint) {
+static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
+ Expr *SrcExpr, FixItHint &Hint) {
if (!SemaRef.getLangOptions().ObjC1)
return;
@@ -7091,7 +7154,7 @@ MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef,
if (!SL || SL->isWide())
return;
- Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@");
+ Hint = FixItHint::CreateInsertion(SL->getLocStart(), "@");
}
bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
@@ -7101,7 +7164,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
// Decode the result (notice that AST's are still created for extensions).
bool isInvalid = false;
unsigned DiagKind;
- CodeModificationHint Hint;
+ FixItHint Hint;
switch (ConvTy) {
default: assert(0 && "Unknown conversion type");
@@ -7113,7 +7176,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
DiagKind = diag::ext_typecheck_convert_int_pointer;
break;
case IncompatiblePointer:
- MakeObjCStringLiteralCodeModificationHint(*this, DstType, SrcExpr, Hint);
+ MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint);
DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
break;
case IncompatiblePointerSign:
@@ -7480,10 +7543,10 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
Diag(Loc, diagnostic)
<< E->getSourceRange()
- << CodeModificationHint::CreateInsertion(Open, "(")
- << CodeModificationHint::CreateInsertion(Close, ")");
+ << FixItHint::CreateInsertion(Open, "(")
+ << FixItHint::CreateInsertion(Close, ")");
Diag(Loc, diag::note_condition_assign_to_comparison)
- << CodeModificationHint::CreateReplacement(Loc, "==");
+ << FixItHint::CreateReplacement(Loc, "==");
}
bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 366089f..501c877 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -948,7 +948,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
= Context.getFunctionType(Context.VoidTy, ArgTypes.data(),
ArgTypes.size(),
Proto->isVariadic(),
- 0, false, false, 0, 0, false, CC_Default);
+ 0, false, false, 0, 0,
+ FunctionType::ExtInfo());
}
for (LookupResult::iterator D = FoundDelete.begin(),
@@ -1062,10 +1063,15 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// Watch out for variadic allocator function.
unsigned NumArgsInFnDecl = FnDecl->getNumParams();
for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) {
- if (PerformCopyInitialization(Args[i],
- FnDecl->getParamDecl(i)->getType(),
- AA_Passing))
+ OwningExprResult Result
+ = PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ FnDecl->getParamDecl(i)),
+ SourceLocation(),
+ Owned(Args[i]->Retain()));
+ if (Result.isInvalid())
return true;
+
+ Args[i] = Result.takeAs<Expr>();
}
Operator = FnDecl;
CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl);
@@ -1204,7 +1210,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0,
true, false,
HasBadAllocExceptionSpec? 1 : 0,
- &BadAllocType, false, CC_Default);
+ &BadAllocType,
+ FunctionType::ExtInfo());
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
FnType, /*TInfo=*/0, FunctionDecl::None, false, true);
@@ -1295,17 +1302,21 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
QualType Type = Ex->getType();
if (const RecordType *Record = Type->getAs<RecordType>()) {
- llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions;
+ llvm::SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions;
+
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();
-
+ const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = I.getDecl();
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
// Skip over templated conversion functions; they aren't considered.
- if (isa<FunctionTemplateDecl>(*I))
+ if (isa<FunctionTemplateDecl>(D))
continue;
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
QualType ConvType = Conv->getConversionType().getNonReferenceType();
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
@@ -1315,9 +1326,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (ObjectPtrConversions.size() == 1) {
// We have a single conversion to a pointer-to-object type. Perform
// that conversion.
+ // TODO: don't redo the conversion calculation.
Operand.release();
- if (!PerformImplicitConversion(Ex,
- ObjectPtrConversions.front()->getConversionType(),
+ if (!PerformImplicitConversion(Ex,
+ ObjectPtrConversions.front()->getConversionType(),
AA_Converting)) {
Operand = Owned(Ex);
Type = Ex->getType();
@@ -1326,10 +1338,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
else if (ObjectPtrConversions.size() > 1) {
Diag(StartLoc, diag::err_ambiguous_delete_operand)
<< Type << Ex->getSourceRange();
- for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) {
- CXXConversionDecl *Conv = ObjectPtrConversions[i];
- NoteOverloadCandidate(Conv);
- }
+ for (unsigned i= 0; i < ObjectPtrConversions.size(); i++)
+ NoteOverloadCandidate(ObjectPtrConversions[i]);
return ExprError();
}
}
@@ -1643,14 +1653,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Function_To_Pointer:
if (Context.getCanonicalType(FromType) == Context.OverloadTy) {
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true);
+ DeclAccessPair Found;
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType,
+ true, Found);
if (!Fn)
return true;
if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
return true;
- From = FixOverloadedFunctionReference(From, Fn);
+ From = FixOverloadedFunctionReference(From, Found, Fn);
FromType = From->getType();
// If there's already an address-of operator in the expression, we have
@@ -1846,7 +1858,7 @@ QualType Sema::CheckPointerToMemberOperands(
else {
Diag(Loc, diag::err_bad_memptr_lhs)
<< OpSpelling << 1 << LType
- << CodeModificationHint::CreateReplacement(SourceRange(Loc), ".*");
+ << FixItHint::CreateReplacement(SourceRange(Loc), ".*");
return QualType();
}
}
@@ -1891,58 +1903,44 @@ QualType Sema::CheckPointerToMemberOperands(
return Result;
}
-/// \brief Get the target type of a standard or user-defined conversion.
-static QualType TargetType(const ImplicitConversionSequence &ICS) {
- switch (ICS.getKind()) {
- case ImplicitConversionSequence::StandardConversion:
- return ICS.Standard.getToType(2);
- case ImplicitConversionSequence::UserDefinedConversion:
- return ICS.UserDefined.After.getToType(2);
- case ImplicitConversionSequence::AmbiguousConversion:
- return ICS.Ambiguous.getToType();
-
- case ImplicitConversionSequence::EllipsisConversion:
- case ImplicitConversionSequence::BadConversion:
- llvm_unreachable("function not valid for ellipsis or bad conversions");
- }
- return QualType(); // silence warnings
-}
-
/// \brief Try to convert a type to another according to C++0x 5.16p3.
///
/// This is part of the parameter validation for the ? operator. If either
/// value operand is a class type, the two operands are attempted to be
/// converted to each other. This function does the conversion in one direction.
-/// It emits a diagnostic and returns true only if it finds an ambiguous
-/// conversion.
+/// It returns true if the program is ill-formed and has already been diagnosed
+/// as such.
static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
SourceLocation QuestionLoc,
- ImplicitConversionSequence &ICS) {
+ bool &HaveConversion,
+ QualType &ToType) {
+ HaveConversion = false;
+ ToType = To->getType();
+
+ InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(),
+ SourceLocation());
// C++0x 5.16p3
// The process for determining whether an operand expression E1 of type T1
// can be converted to match an operand expression E2 of type T2 is defined
// as follows:
// -- If E2 is an lvalue:
- if (To->isLvalue(Self.Context) == Expr::LV_Valid) {
+ bool ToIsLvalue = (To->isLvalue(Self.Context) == Expr::LV_Valid);
+ if (ToIsLvalue) {
// E1 can be converted to match E2 if E1 can be implicitly converted to
// type "lvalue reference to T2", subject to the constraint that in the
// conversion the reference must bind directly to E1.
- if (!Self.CheckReferenceInit(From,
- Self.Context.getLValueReferenceType(To->getType()),
- To->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- &ICS))
- {
- assert((ICS.isStandard() || ICS.isUserDefined()) &&
- "expected a definite conversion");
- bool DirectBinding =
- ICS.isStandard() ? ICS.Standard.DirectBinding
- : ICS.UserDefined.After.DirectBinding;
- if (DirectBinding)
- return false;
+ QualType T = Self.Context.getLValueReferenceType(ToType);
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
+
+ InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
+ if (InitSeq.isDirectReferenceBinding()) {
+ ToType = T;
+ HaveConversion = true;
+ return false;
}
+
+ if (InitSeq.isAmbiguous())
+ return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
}
// -- If E2 is an rvalue, or if the conversion above cannot be done:
@@ -1952,47 +1950,47 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
QualType TTy = To->getType();
const RecordType *FRec = FTy->getAs<RecordType>();
const RecordType *TRec = TTy->getAs<RecordType>();
- bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy);
- if (FRec && TRec && (FRec == TRec ||
- FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
+ bool FDerivedFromT = FRec && TRec && FRec != TRec &&
+ Self.IsDerivedFrom(FTy, TTy);
+ if (FRec && TRec &&
+ (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
// E1 can be converted to match E2 if the class of T2 is the
// same type as, or a base class of, the class of T1, and
// [cv2 > cv1].
if (FRec == TRec || FDerivedFromT) {
if (TTy.isAtLeastAsQualifiedAs(FTy)) {
- // Could still fail if there's no copy constructor.
- // FIXME: Is this a hard error then, or just a conversion failure? The
- // standard doesn't say.
- ICS = Self.TryCopyInitialization(From, TTy,
- /*SuppressUserConversions=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- } else {
- ICS.setBad(BadConversionSequence::bad_qualifiers, From, TTy);
- }
- } else {
- // Can't implicitly convert FTy to a derived class TTy.
- // TODO: more specific error for this.
- ICS.setBad(BadConversionSequence::no_conversion, From, TTy);
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
+ InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
+ if (InitSeq.getKind() != InitializationSequence::FailedSequence) {
+ HaveConversion = true;
+ return false;
+ }
+
+ if (InitSeq.isAmbiguous())
+ return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
+ }
}
- } else {
- // -- Otherwise: E1 can be converted to match E2 if E1 can be
- // implicitly converted to the type that expression E2 would have
- // if E2 were converted to an rvalue.
- // First find the decayed type.
- if (TTy->isFunctionType())
- TTy = Self.Context.getPointerType(TTy);
- else if (TTy->isArrayType())
- TTy = Self.Context.getArrayDecayedType(TTy);
-
- // Now try the implicit conversion.
- // FIXME: This doesn't detect ambiguities.
- ICS = Self.TryImplicitConversion(From, TTy,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
+
+ return false;
}
+
+ // -- Otherwise: E1 can be converted to match E2 if E1 can be
+ // implicitly converted to the type that expression E2 would have
+ // if E2 were converted to an rvalue (or the type it has, if E2 is
+ // an rvalue).
+ //
+ // This actually refers very narrowly to the lvalue-to-rvalue conversion, not
+ // to the array-to-pointer or function-to-pointer conversions.
+ if (!TTy->getAs<TagType>())
+ TTy = TTy.getUnqualifiedType();
+
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
+ InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
+ HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence;
+ ToType = TTy;
+ if (InitSeq.isAmbiguous())
+ return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
+
return false;
}
@@ -2041,37 +2039,17 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
/// \brief Perform an "extended" implicit conversion as returned by
/// TryClassUnification.
-///
-/// TryClassUnification generates ICSs that include reference bindings.
-/// PerformImplicitConversion is not suitable for this; it chokes if the
-/// second part of a standard conversion is ICK_DerivedToBase. This function
-/// handles the reference binding specially.
-static bool ConvertForConditional(Sema &Self, Expr *&E,
- const ImplicitConversionSequence &ICS) {
- if (ICS.isStandard() && ICS.Standard.ReferenceBinding) {
- assert(ICS.Standard.DirectBinding &&
- "TryClassUnification should never generate indirect ref bindings");
- // FIXME: CheckReferenceInit should be able to reuse the ICS instead of
- // redoing all the work.
- return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
- TargetType(ICS)),
- /*FIXME:*/E->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false);
- }
- if (ICS.isUserDefined() && ICS.UserDefined.After.ReferenceBinding) {
- assert(ICS.UserDefined.After.DirectBinding &&
- "TryClassUnification should never generate indirect ref bindings");
- return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
- TargetType(ICS)),
- /*FIXME:*/E->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false);
- }
- if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, Sema::AA_Converting))
+static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) {
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
+ InitializationKind Kind = InitializationKind::CreateCopy(E->getLocStart(),
+ SourceLocation());
+ InitializationSequence InitSeq(Self, Entity, Kind, &E, 1);
+ Sema::OwningExprResult Result = InitSeq.Perform(Self, Entity, Kind,
+ Sema::MultiExprArg(Self, (void **)&E, 1));
+ if (Result.isInvalid())
return true;
+
+ E = Result.takeAs<Expr>();
return false;
}
@@ -2139,17 +2117,17 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// Otherwise, if the second and third operand have different types, and
// either has (cv) class type, and attempt is made to convert each of those
// operands to the other.
- if (Context.getCanonicalType(LTy) != Context.getCanonicalType(RTy) &&
+ if (!Context.hasSameType(LTy, RTy) &&
(LTy->isRecordType() || RTy->isRecordType())) {
ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft;
// These return true if a single direction is already ambiguous.
- if (TryClassUnification(*this, LHS, RHS, QuestionLoc, ICSLeftToRight))
+ QualType L2RType, R2LType;
+ bool HaveL2R, HaveR2L;
+ if (TryClassUnification(*this, LHS, RHS, QuestionLoc, HaveL2R, L2RType))
return QualType();
- if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft))
+ if (TryClassUnification(*this, RHS, LHS, QuestionLoc, HaveR2L, R2LType))
return QualType();
-
- bool HaveL2R = !ICSLeftToRight.isBad();
- bool HaveR2L = !ICSRightToLeft.isBad();
+
// If both can be converted, [...] the program is ill-formed.
if (HaveL2R && HaveR2L) {
Diag(QuestionLoc, diag::err_conditional_ambiguous)
@@ -2161,11 +2139,11 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// the chosen operand and the converted operands are used in place of the
// original operands for the remainder of this section.
if (HaveL2R) {
- if (ConvertForConditional(*this, LHS, ICSLeftToRight))
+ if (ConvertForConditional(*this, LHS, L2RType))
return QualType();
LTy = LHS->getType();
} else if (HaveR2L) {
- if (ConvertForConditional(*this, RHS, ICSRightToLeft))
+ if (ConvertForConditional(*this, RHS, R2LType))
return QualType();
RTy = RHS->getType();
}
@@ -2174,7 +2152,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// C++0x 5.16p4
// If the second and third operands are lvalues and have the same type,
// the result is of that type [...]
- bool Same = Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy);
+ bool Same = Context.hasSameType(LTy, RTy);
if (Same && LHS->isLvalue(Context) == Expr::LV_Valid &&
RHS->isLvalue(Context) == Expr::LV_Valid)
return LTy;
@@ -2235,7 +2213,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
return Composite;
}
- // Similarly, attempt to find composite type of twp objective-c pointers.
+ // Similarly, attempt to find composite type of two objective-c pointers.
Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc);
if (!Composite.isNull())
return Composite;
@@ -2611,7 +2589,7 @@ Sema::OwningExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc);
Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
<< isa<CXXPseudoDestructorExpr>(E)
- << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
+ << FixItHint::CreateInsertion(ExpectedLParenLoc, "()");
return ActOnCallExpr(/*Scope*/ 0,
move(MemExpr),
@@ -2645,7 +2623,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
// The user wrote "p->" when she probably meant "p."; fix it.
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< ObjectType << true
- << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ << FixItHint::CreateReplacement(OpLoc, ".");
if (isSFINAEContext())
return ExprError();
@@ -2750,7 +2728,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
// The user wrote "p->" when she probably meant "p."; fix it.
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< ObjectType << true
- << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ << FixItHint::CreateReplacement(OpLoc, ".");
if (isSFINAEContext())
return ExprError();
@@ -2874,8 +2852,10 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
}
CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
+ NamedDecl *FoundDecl,
CXXMethodDecl *Method) {
- if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, Method))
+ if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0,
+ FoundDecl, Method))
assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?");
MemberExpr *ME =
@@ -2919,7 +2899,8 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc,
assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
// Create an implicit call expr that calls it.
- CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method);
+ // FIXME: pass the FoundDecl for the user-defined conversion here
+ CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method, Method);
return MaybeBindToTemporary(CE);
}
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index c98ba43..d5a22ca 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -289,7 +289,10 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
IdentifierInfo *receiverNamePtr = &receiverName;
ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr);
-
+ if (!IFace) {
+ Diag(receiverNameLoc, diag::err_expected_ident_or_lparen);
+ return ExprError();
+ }
// Search for a declared property first.
Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName);
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index f86ae51..648e43b 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -504,13 +504,11 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
diag::warn_missing_braces)
<< StructuredSubobjectInitList->getSourceRange()
- << CodeModificationHint::CreateInsertion(
- StructuredSubobjectInitList->getLocStart(),
- "{")
- << CodeModificationHint::CreateInsertion(
- SemaRef.PP.getLocForEndOfToken(
+ << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(),
+ "{")
+ << FixItHint::CreateInsertion(SemaRef.PP.getLocForEndOfToken(
StructuredSubobjectInitList->getLocEnd()),
- "}");
+ "}");
}
}
@@ -571,8 +569,8 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
if (T->isScalarType() && !TopLevelObject)
SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init)
<< IList->getSourceRange()
- << CodeModificationHint::CreateRemoval(IList->getLocStart())
- << CodeModificationHint::CreateRemoval(IList->getLocEnd());
+ << FixItHint::CreateRemoval(IList->getLocStart())
+ << FixItHint::CreateRemoval(IList->getLocEnd());
}
void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
@@ -1363,8 +1361,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
SemaRef.Diag(D->getFieldLoc(),
diag::err_field_designator_unknown_suggest)
<< FieldName << CurrentObjectType << R.getLookupName()
- << CodeModificationHint::CreateReplacement(D->getFieldLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(D->getFieldLoc(),
+ R.getLookupName().getAsString());
SemaRef.Diag(ReplacementField->getLocation(),
diag::note_previous_decl)
<< ReplacementField->getDeclName();
@@ -2001,14 +1999,48 @@ void InitializationSequence::Step::Destroy() {
}
}
+bool InitializationSequence::isDirectReferenceBinding() const {
+ return getKind() == ReferenceBinding && Steps.back().Kind == SK_BindReference;
+}
+
+bool InitializationSequence::isAmbiguous() const {
+ if (getKind() != FailedSequence)
+ return false;
+
+ switch (getFailureKind()) {
+ case FK_TooManyInitsForReference:
+ case FK_ArrayNeedsInitList:
+ case FK_ArrayNeedsInitListOrStringLiteral:
+ case FK_AddressOfOverloadFailed: // FIXME: Could do better
+ case FK_NonConstLValueReferenceBindingToTemporary:
+ case FK_NonConstLValueReferenceBindingToUnrelated:
+ case FK_RValueReferenceBindingToLValue:
+ case FK_ReferenceInitDropsQualifiers:
+ case FK_ReferenceInitFailed:
+ case FK_ConversionFailed:
+ case FK_TooManyInitsForScalar:
+ case FK_ReferenceBindingToInitList:
+ case FK_InitListBadDestinationType:
+ case FK_DefaultInitOfConst:
+ return false;
+
+ case FK_ReferenceInitOverloadFailed:
+ case FK_UserConversionOverloadFailed:
+ case FK_ConstructorOverloadFailed:
+ return FailedOverloadResult == OR_Ambiguous;
+ }
+
+ return false;
+}
+
void InitializationSequence::AddAddressOverloadResolutionStep(
- FunctionDecl *Function) {
+ FunctionDecl *Function,
+ DeclAccessPair Found) {
Step S;
S.Kind = SK_ResolveAddressOfOverloadedFunction;
S.Type = Function->getType();
- // Access is currently ignored for these.
S.Function.Function = Function;
- S.Function.FoundDecl = DeclAccessPair::make(Function, AS_none);
+ S.Function.FoundDecl = Found;
Steps.push_back(S);
}
@@ -2341,15 +2373,17 @@ static void TryReferenceInitialization(Sema &S,
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
+ DeclAccessPair Found;
FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer,
T1,
- false);
+ false,
+ Found);
if (!Fn) {
Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
return;
}
- Sequence.AddAddressOverloadResolutionStep(Fn);
+ Sequence.AddAddressOverloadResolutionStep(Fn, Found);
cv2T2 = Fn->getType();
T2 = cv2T2.getUnqualifiedType();
}
@@ -2802,7 +2836,7 @@ static void TryUserDefinedConversion(Sema &S,
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = cast<CXXConversionDecl>(*I);
+ Conv = cast<CXXConversionDecl>(D);
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
@@ -3314,8 +3348,9 @@ InitializationSequence::Perform(Sema &S,
case SK_ResolveAddressOfOverloadedFunction:
// Overload resolution determined which function invoke; update the
// initializer to reflect that choice.
- // Access control was done in overload resolution.
+ S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl);
CurInit = S.FixOverloadedFunctionReference(move(CurInit),
+ Step->Function.FoundDecl,
Step->Function.Function);
break;
@@ -3382,6 +3417,7 @@ InitializationSequence::Perform(Sema &S,
bool IsCopy = false;
FunctionDecl *Fn = Step->Function.Function;
DeclAccessPair FoundFn = Step->Function.FoundDecl;
+ bool IsLvalue = false;
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
@@ -3414,7 +3450,7 @@ InitializationSequence::Perform(Sema &S,
} else {
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
-
+ IsLvalue = Conversion->getResultType()->isLValueReferenceType();
S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0,
FoundFn);
@@ -3422,7 +3458,7 @@ InitializationSequence::Perform(Sema &S,
// derived-to-base conversion? I believe the answer is "no", because
// we don't want to turn off access control here for c-style casts.
if (S.PerformObjectArgumentInitialization(CurInitExpr, /*Qualifier=*/0,
- Conversion))
+ FoundFn, Conversion))
return S.ExprError();
// Do a little dance to make sure that CurInit has the proper
@@ -3430,7 +3466,8 @@ InitializationSequence::Perform(Sema &S,
CurInit.release();
// Build the actual call to the conversion function.
- CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, Conversion));
+ CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn,
+ Conversion));
if (CurInit.isInvalid() || !CurInit.get())
return S.ExprError();
@@ -3444,7 +3481,7 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(),
CastKind,
CurInitExpr,
- false));
+ IsLvalue));
if (!IsCopy)
CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit));
@@ -3614,11 +3651,14 @@ bool InitializationSequence::Diagnose(Sema &S,
<< (Failure == FK_ArrayNeedsInitListOrStringLiteral);
break;
- case FK_AddressOfOverloadFailed:
+ case FK_AddressOfOverloadFailed: {
+ DeclAccessPair Found;
S.ResolveAddressOfOverloadedFunction(Args[0],
DestType.getNonReferenceType(),
- true);
+ true,
+ Found);
break;
+ }
case FK_ReferenceInitOverloadFailed:
case FK_UserConversionOverloadFailed:
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 18a0938..7c6327f 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -599,12 +599,20 @@ public:
step_iterator step_begin() const { return Steps.begin(); }
step_iterator step_end() const { return Steps.end(); }
+ /// \brief Determine whether this initialization is a direct reference
+ /// binding (C++ [dcl.init.ref]).
+ bool isDirectReferenceBinding() const;
+
+ /// \brief Determine whether this initialization failed due to an ambiguity.
+ bool isAmbiguous() const;
+
/// \brief Add a new step in the initialization that resolves the address
/// of an overloaded function to a specific function declaration.
///
/// \param Function the function to which the overloaded function reference
/// resolves.
- void AddAddressOverloadResolutionStep(FunctionDecl *Function);
+ void AddAddressOverloadResolutionStep(FunctionDecl *Function,
+ DeclAccessPair Found);
/// \brief Add a new step in the initialization that performs a derived-to-
/// base cast.
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 9ae520d..a29c4d4 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -304,6 +304,23 @@ void LookupResult::configure() {
SemaRef.getLangOptions().CPlusPlus,
isForRedeclaration());
IsAcceptableFn = getResultFilter(LookupKind);
+
+ // If we're looking for one of the allocation or deallocation
+ // operators, make sure that the implicitly-declared new and delete
+ // operators can be found.
+ if (!isForRedeclaration()) {
+ switch (Name.getCXXOverloadedOperator()) {
+ case OO_New:
+ case OO_Delete:
+ case OO_Array_New:
+ case OO_Array_Delete:
+ SemaRef.DeclareGlobalNewDelete();
+ break;
+
+ default:
+ break;
+ }
+ }
}
// Necessary because CXXBasePaths is not complete in Sema.h
@@ -539,13 +556,13 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// Compute the type of the function that we would expect the conversion
// function to have, if it were to match the name given.
// FIXME: Calling convention!
+ FunctionType::ExtInfo ConvProtoInfo = ConvProto->getExtInfo();
QualType ExpectedType
= R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
0, 0, ConvProto->isVariadic(),
ConvProto->getTypeQuals(),
false, false, 0, 0,
- ConvProto->getNoReturnAttr(),
- CC_Default);
+ ConvProtoInfo.withCallingConv(CC_Default));
// Perform template argument deduction against the type that we would
// expect the function to have.
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 41ed6c6..f815068 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -44,9 +44,6 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
Diag(AtLoc, diag::error_reference_property);
return DeclPtrTy();
}
- // Validate the attributes on the @property.
- CheckObjCPropertyAttributes(T, AtLoc, Attributes);
-
// Proceed with constructing the ObjCPropertDecls.
ObjCContainerDecl *ClassDecl =
cast<ObjCContainerDecl>(ClassCategory.getAs<Decl>());
@@ -60,10 +57,13 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
isOverridingProperty, T,
MethodImplKind);
- return DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
+ DeclPtrTy Res = DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
GetterSel, SetterSel,
isAssign, isReadWrite,
Attributes, T, MethodImplKind));
+ // Validate the attributes on the @property.
+ CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+ return Res;
}
Sema::DeclPtrTy
@@ -93,6 +93,11 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
ObjCPropertyDecl *PDecl =
ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(),
PropertyId, AtLoc, T);
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
+ if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
+
DC->addDecl(PDecl);
// We need to look in the @interface to see if the @property was
@@ -378,7 +383,9 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
if (PropType != IvarType) {
if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
Diag(PropertyLoc, diag::error_property_ivar_type)
- << property->getDeclName() << Ivar->getDeclName();
+ << 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.
}
@@ -391,7 +398,9 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
if (lhsType != rhsType &&
lhsType->isArithmeticType()) {
Diag(PropertyLoc, diag::error_property_ivar_type)
- << property->getDeclName() << Ivar->getDeclName();
+ << 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.
@@ -973,10 +982,13 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
AddInstanceMethodToGlobalPool(SetterMethod);
}
-void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
+void Sema::CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy,
SourceLocation Loc,
unsigned &Attributes) {
// FIXME: Improve the reported location.
+ Decl *PDecl = PropertyPtrTy.getAs<Decl>();
+ ObjCPropertyDecl *PropertyDecl = dyn_cast_or_null<ObjCPropertyDecl>(PDecl);
+ QualType PropertyTy = PropertyDecl->getType();
// readonly and readwrite/assign/retain/copy conflict.
if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
@@ -1001,7 +1013,8 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
!PropertyTy->isObjCObjectPointerType() &&
!PropertyTy->isBlockPointerType() &&
- !Context.isObjCNSObjectType(PropertyTy)) {
+ !Context.isObjCNSObjectType(PropertyTy) &&
+ !PropertyDecl->getAttr<ObjCNSObjectAttr>()) {
Diag(Loc, diag::err_objc_property_requires_object)
<< (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 410bf9a..bc10a58 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -567,6 +567,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// array-to-pointer conversion, or function-to-pointer conversion
// (C++ 4p1).
+ DeclAccessPair AccessPair;
+
// Lvalue-to-rvalue conversion (C++ 4.1):
// An lvalue (3.10) of a non-function, non-array type T can be
// converted to an rvalue.
@@ -612,7 +614,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// function. (C++ 4.3p1).
FromType = Context.getPointerType(FromType);
} else if (FunctionDecl *Fn
- = ResolveAddressOfOverloadedFunction(From, ToType, false)) {
+ = ResolveAddressOfOverloadedFunction(From, ToType, false,
+ AccessPair)) {
// Address of overloaded function (C++ [over.over]).
SCS.First = ICK_Function_To_Pointer;
@@ -1579,10 +1582,10 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
CXXConversionDecl *Conv;
FunctionTemplateDecl *ConvTemplate;
- if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(*I)))
- Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(D)))
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = dyn_cast<CXXConversionDecl>(*I);
+ Conv = cast<CXXConversionDecl>(D);
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
@@ -2201,44 +2204,6 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType,
}
}
-/// PerformCopyInitialization - Copy-initialize an object of type @p ToType with
-/// the expression @p From. Returns true (and emits a diagnostic) if there was
-/// an error, returns false if the initialization succeeded. Elidable should
-/// be true when the copy may be elided (C++ 12.8p15). Overload resolution works
-/// differently in C++0x for this case.
-bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
- AssignmentAction Action, bool Elidable) {
- if (!getLangOptions().CPlusPlus) {
- // In C, argument passing is the same as performing an assignment.
- QualType FromType = From->getType();
-
- AssignConvertType ConvTy =
- CheckSingleAssignmentConstraints(ToType, From);
- if (ConvTy != Compatible &&
- CheckTransparentUnionArgumentConstraints(ToType, From) == Compatible)
- ConvTy = Compatible;
-
- return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType,
- FromType, From, Action);
- }
-
- if (ToType->isReferenceType())
- return CheckReferenceInit(From, ToType,
- /*FIXME:*/From->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false);
-
- if (!PerformImplicitConversion(From, ToType, Action,
- /*AllowExplicit=*/false, Elidable))
- return false;
- if (!DiagnoseMultipleUserDefinedConversion(From, ToType))
- return Diag(From->getSourceRange().getBegin(),
- diag::err_typecheck_convert_incompatible)
- << ToType << From->getType() << Action << From->getSourceRange();
- return true;
-}
-
/// TryObjectArgumentInitialization - Try to initialize the object
/// parameter of the given member function (@c Method) from the
/// expression @p From.
@@ -2316,6 +2281,7 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType,
bool
Sema::PerformObjectArgumentInitialization(Expr *&From,
NestedNameSpecifier *Qualifier,
+ NamedDecl *FoundDecl,
CXXMethodDecl *Method) {
QualType FromRecordType, DestType;
QualType ImplicitParamRecordType =
@@ -2340,7 +2306,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From,
<< ImplicitParamRecordType << FromRecordType << From->getSourceRange();
if (ICS.Standard.Second == ICK_Derived_To_Base)
- return PerformObjectMemberConversion(From, Qualifier, Method);
+ return PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method);
if (!Context.hasSameType(From->getType(), DestType))
ImpCastExprToType(From, DestType, CastExpr::CK_NoOp,
@@ -3344,13 +3310,16 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
= ClassDecl->getVisibleConversionFunctions();
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = I.getDecl();
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
// Skip conversion function templates; they don't tell us anything
// about which builtin types we can convert to.
- if (isa<FunctionTemplateDecl>(*I))
+ if (isa<FunctionTemplateDecl>(D))
continue;
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
if (AllowExplicitConversions || !Conv->isExplicit()) {
AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false,
VisibleQuals);
@@ -3412,7 +3381,10 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
- if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) {
+ NamedDecl *D = I.getDecl();
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+ if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D)) {
QualType CanTy = Context.getCanonicalType(Conv->getConversionType());
if (const ReferenceType *ResTypeRef = CanTy->getAs<ReferenceType>())
CanTy = ResTypeRef->getPointeeType();
@@ -4733,7 +4705,7 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
if (!ICS.isAmbiguous()) continue;
S.DiagnoseAmbiguousConversion(ICS, OpLoc,
- PDiag(diag::note_ambiguous_type_conversion));
+ S.PDiag(diag::note_ambiguous_type_conversion));
}
}
@@ -4980,7 +4952,8 @@ static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) {
/// routine will emit diagnostics if there is an error.
FunctionDecl *
Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
- bool Complain) {
+ bool Complain,
+ DeclAccessPair &FoundResult) {
QualType FunctionType = ToType;
bool IsMember = false;
if (const PointerType *ToTypePtr = ToType->getAs<PointerType>())
@@ -5018,6 +4991,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
+ llvm::SmallVector<FunctionDecl *, 4> NonMatches;
+
bool FoundNonTemplateFunction = false;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
E = OvlExpr->decls_end(); I != E; ++I) {
@@ -5097,9 +5072,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
return 0;
else if (Matches.size() == 1) {
FunctionDecl *Result = Matches[0].second;
+ FoundResult = Matches[0].first;
MarkDeclarationReferenced(From->getLocStart(), Result);
if (Complain)
- CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
+ CheckAddressOfMemberAccess(OvlExpr, Matches[0].first);
return Result;
}
@@ -5131,10 +5107,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
<< (unsigned) oc_function_template);
assert(Result != MatchesCopy.end() && "no most-specialized template");
MarkDeclarationReferenced(From->getLocStart(), *Result);
- if (Complain) {
- DeclAccessPair FoundDecl = Matches[Result - MatchesCopy.begin()].first;
- CheckUnresolvedAccess(*this, OvlExpr, FoundDecl);
- }
+ FoundResult = Matches[Result - MatchesCopy.begin()].first;
+ if (Complain)
+ CheckUnresolvedAccess(*this, OvlExpr, FoundResult);
return cast<FunctionDecl>(*Result);
}
@@ -5153,6 +5128,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// selected function.
if (Matches.size() == 1) {
MarkDeclarationReferenced(From->getLocStart(), Matches[0].second);
+ FoundResult = Matches[0].first;
if (Complain)
CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
return cast<FunctionDecl>(Matches[0].second);
@@ -5433,7 +5409,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
case OR_Success: {
FunctionDecl *FDecl = Best->Function;
CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
- Fn = FixOverloadedFunctionReference(Fn, FDecl);
+ Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc);
}
@@ -5560,7 +5536,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl);
- if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method))
+ if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0,
+ Best->FoundDecl, Method))
return ExprError();
} else {
// Convert the arguments.
@@ -5754,7 +5731,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return ExprError();
if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0,
- Method))
+ Best->FoundDecl, Method))
return ExprError();
Args[1] = RHS = Arg1.takeAs<Expr>();
@@ -5921,7 +5898,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0,
- Method))
+ Best->FoundDecl, Method))
return ExprError();
// Convert the arguments.
@@ -6026,10 +6003,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
MemberExpr *MemExpr;
CXXMethodDecl *Method = 0;
+ NamedDecl *FoundDecl = 0;
NestedNameSpecifier *Qualifier = 0;
if (isa<MemberExpr>(NakedMemExpr)) {
MemExpr = cast<MemberExpr>(NakedMemExpr);
Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl());
+ FoundDecl = MemExpr->getFoundDecl();
Qualifier = MemExpr->getQualifier();
} else {
UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr);
@@ -6079,6 +6058,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
+ FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
break;
@@ -6106,7 +6086,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
return ExprError();
}
- MemExprE = FixOverloadedFunctionReference(MemExprE, Method);
+ MemExprE = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method);
// If overload resolution picked a static member, build a
// non-member call based on that function.
@@ -6131,9 +6111,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
return ExprError();
// Convert the object argument (for a non-static member function call).
+ // We only need to do this if there was actually an overload; otherwise
+ // it was done at lookup.
Expr *ObjectArg = MemExpr->getBase();
if (!Method->isStatic() &&
- PerformObjectArgumentInitialization(ObjectArg, Qualifier, Method))
+ PerformObjectArgumentInitialization(ObjectArg, Qualifier,
+ FoundDecl, Method))
return ExprError();
MemExpr->setBase(ObjectArg);
@@ -6173,7 +6156,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
if (RequireCompleteType(LParenLoc, Object->getType(),
- PartialDiagnostic(diag::err_incomplete_object_call)
+ PDiag(diag::err_incomplete_object_call)
<< Object->getSourceRange()))
return true;
@@ -6293,7 +6276,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// Create an implicit member expr to refer to the conversion operator.
// and then call it.
- CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Conv);
+ CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Best->FoundDecl,
+ Conv);
return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc,
MultiExprArg(*this, (ExprTy**)Args, NumArgs),
@@ -6353,7 +6337,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// Initialize the implicit object parameter.
IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0,
- Method);
+ Best->FoundDecl, Method);
TheCall->setArg(0, Object);
@@ -6474,7 +6458,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
- if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, Method))
+ if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0,
+ Best->FoundDecl, Method))
return ExprError();
// No concerns about early exits now.
@@ -6501,9 +6486,11 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
/// perhaps a '&' around it). We have resolved the overloaded function
/// to the function declaration Fn, so patch up the expression E to
/// refer (possibly indirectly) to Fn. Returns the new expr.
-Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
+Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found,
+ FunctionDecl *Fn) {
if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
- Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
+ Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(),
+ Found, Fn);
if (SubExpr == PE->getSubExpr())
return PE->Retain();
@@ -6511,7 +6498,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
}
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn);
+ Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(),
+ Found, Fn);
assert(Context.hasSameType(ICE->getSubExpr()->getType(),
SubExpr->getType()) &&
"Implicit cast type cannot be determined from overload");
@@ -6535,7 +6523,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
// Fix the sub expression, which really has to be an
// UnresolvedLookupExpr holding an overloaded member function
// or template.
- Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
+ Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
+ Found, Fn);
if (SubExpr == UnOp->getSubExpr())
return UnOp->Retain();
@@ -6556,7 +6545,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
MemPtrType, UnOp->getOperatorLoc());
}
}
- Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
+ Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
+ Found, Fn);
if (SubExpr == UnOp->getSubExpr())
return UnOp->Retain();
@@ -6618,6 +6608,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
MemExpr->getQualifier(),
MemExpr->getQualifierRange(),
Fn,
+ Found,
MemExpr->getMemberLoc(),
TemplateArgs,
Fn->getType());
@@ -6628,8 +6619,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
}
Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E,
+ NamedDecl *Found,
FunctionDecl *Fn) {
- return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Fn));
+ return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn));
}
} // end namespace clang
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index fd65c32..791de8c 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -119,7 +119,13 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
}
}
-
+ else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
+ Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
+ return;
+ }
+ }
Diag(Loc, DiagID) << R1 << R2;
}
@@ -427,48 +433,50 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
// Make sure that the condition expression has a complete type,
// otherwise we'll never find any conversions.
if (S.RequireCompleteType(SwitchLoc, CondType,
- PDiag(diag::err_switch_incomplete_class_type)
+ S.PDiag(diag::err_switch_incomplete_class_type)
<< CondExpr->getSourceRange()))
return true;
- llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions;
- llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions;
+ UnresolvedSet<4> ViableConversions;
+ UnresolvedSet<4> ExplicitConversions;
if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
const UnresolvedSetImpl *Conversions
= cast<CXXRecordDecl>(RecordTy->getDecl())
->getVisibleConversionFunctions();
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
- if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I))
+ if (CXXConversionDecl *Conversion
+ = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl()))
if (Conversion->getConversionType().getNonReferenceType()
->isIntegralType()) {
if (Conversion->isExplicit())
- ExplicitConversions.push_back(Conversion);
+ ExplicitConversions.addDecl(I.getDecl(), I.getAccess());
else
- ViableConversions.push_back(Conversion);
+ ViableConversions.addDecl(I.getDecl(), I.getAccess());
}
}
switch (ViableConversions.size()) {
case 0:
if (ExplicitConversions.size() == 1) {
+ DeclAccessPair Found = ExplicitConversions[0];
+ CXXConversionDecl *Conversion =
+ cast<CXXConversionDecl>(Found->getUnderlyingDecl());
// The user probably meant to invoke the given explicit
// conversion; use it.
QualType ConvTy
- = ExplicitConversions[0]->getConversionType()
- .getNonReferenceType();
+ = Conversion->getConversionType().getNonReferenceType();
std::string TypeStr;
ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy);
S.Diag(SwitchLoc, diag::err_switch_explicit_conversion)
<< CondType << ConvTy << CondExpr->getSourceRange()
- << CodeModificationHint::CreateInsertion(CondExpr->getLocStart(),
- "static_cast<" + TypeStr + ">(")
- << CodeModificationHint::CreateInsertion(
+ << FixItHint::CreateInsertion(CondExpr->getLocStart(),
+ "static_cast<" + TypeStr + ">(")
+ << FixItHint::CreateInsertion(
S.PP.getLocForEndOfToken(CondExpr->getLocEnd()),
")");
- S.Diag(ExplicitConversions[0]->getLocation(),
- diag::note_switch_conversion)
+ S.Diag(Conversion->getLocation(), diag::note_switch_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
// If we aren't in a SFINAE context, build a call to the
@@ -476,25 +484,32 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
if (S.isSFINAEContext())
return true;
- CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ExplicitConversions[0]);
+ S.CheckMemberOperatorAccess(CondExpr->getExprLoc(),
+ CondExpr, 0, Found);
+ CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found, Conversion);
}
// We'll complain below about a non-integral condition type.
break;
- case 1:
+ case 1: {
// Apply this conversion.
- CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]);
+ DeclAccessPair Found = ViableConversions[0];
+ S.CheckMemberOperatorAccess(CondExpr->getExprLoc(),
+ CondExpr, 0, Found);
+ CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found,
+ cast<CXXConversionDecl>(Found->getUnderlyingDecl()));
break;
+ }
default:
S.Diag(SwitchLoc, diag::err_switch_multiple_conversions)
<< CondType << CondExpr->getSourceRange();
for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
- QualType ConvTy
- = ViableConversions[I]->getConversionType().getNonReferenceType();
- S.Diag(ViableConversions[I]->getLocation(),
- diag::note_switch_conversion)
+ CXXConversionDecl *Conv
+ = cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
+ QualType ConvTy = Conv->getConversionType().getNonReferenceType();
+ S.Diag(Conv->getLocation(), diag::note_switch_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
}
return true;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 434d556..40ec4bcb 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -161,7 +161,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep();
Diag(IILoc, diag::err_template_kw_missing)
<< Qualifier << II.getName()
- << CodeModificationHint::CreateInsertion(IILoc, "template ");
+ << FixItHint::CreateInsertion(IILoc, "template ");
SuggestedTemplate
= TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II));
SuggestedKind = TNK_Dependent_template_name;
@@ -240,12 +240,12 @@ void Sema::LookupTemplateName(LookupResult &Found,
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
<< Name << LookupCtx << Found.getLookupName() << SS.getRange()
- << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
+ << FixItHint::CreateReplacement(Found.getNameLoc(),
Found.getLookupName().getAsString());
else
Diag(Found.getNameLoc(), diag::err_no_template_suggest)
<< Name << Found.getLookupName()
- << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
+ << FixItHint::CreateReplacement(Found.getNameLoc(),
Found.getLookupName().getAsString());
if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>())
Diag(Template->getLocation(), diag::note_previous_decl)
@@ -822,8 +822,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
- << CodeModificationHint::CreateReplacement(KWLoc,
- PrevRecordDecl->getKindName());
+ << FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName());
Diag(PrevRecordDecl->getLocation(), diag::note_previous_use);
Kind = PrevRecordDecl->getTagKind();
}
@@ -1295,8 +1294,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
} else {
Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header)
<< SS.getRange()
- << CodeModificationHint::CreateInsertion(FirstTemplateLoc,
- "template<> ");
+ << FixItHint::CreateInsertion(FirstTemplateLoc, "template<> ");
IsExplicitSpecialization = true;
}
return 0;
@@ -1499,8 +1497,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult,
if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) {
Diag(TagLoc, diag::err_use_with_wrong_tag)
<< Type
- << CodeModificationHint::CreateReplacement(SourceRange(TagLoc),
- D->getKindName());
+ << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName());
Diag(D->getLocation(), diag::note_previous_use);
}
}
@@ -1897,7 +1894,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
- TemplateArgumentListBuilder &Converted) {
+ TemplateArgumentListBuilder &Converted,
+ CheckTemplateArgumentKind CTAK) {
// Check template type parameters.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
return CheckTemplateTypeArgument(TTP, Arg, Converted);
@@ -1937,7 +1935,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Expression: {
Expr *E = Arg.getArgument().getAsExpr();
TemplateArgument Result;
- if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
+ if (CheckTemplateArgument(NTTP, NTTPType, E, Result, CTAK))
return true;
Converted.Append(Result);
@@ -2268,18 +2266,20 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
/// \brief Checks whether the given template argument is the address
/// of an object or function according to C++ [temp.arg.nontype]p1.
-bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
- NamedDecl *&Entity) {
+static bool
+CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
+ NonTypeTemplateParmDecl *Param,
+ QualType ParamType,
+ Expr *ArgIn,
+ TemplateArgument &Converted) {
bool Invalid = false;
+ Expr *Arg = ArgIn;
+ QualType ArgType = Arg->getType();
// See through any implicit casts we added to fix the type.
while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
Arg = Cast->getSubExpr();
- // C++0x allows nullptr, and there's no further checking to be done for that.
- if (Arg->getType()->isNullPtrType())
- return false;
-
// C++ [temp.arg.nontype]p1:
//
// A template-argument for a non-type, non-template
@@ -2296,8 +2296,8 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
// Ignore (and complain about) any excess parentheses.
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
if (!Invalid) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_extra_parens)
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_extra_parens)
<< Arg->getSourceRange();
Invalid = true;
}
@@ -2305,77 +2305,227 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
Arg = Parens->getSubExpr();
}
+ bool AddressTaken = false;
+ SourceLocation AddrOpLoc;
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
- if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+ if (UnOp->getOpcode() == UnaryOperator::AddrOf) {
DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
+ AddressTaken = true;
+ AddrOpLoc = UnOp->getOperatorLoc();
+ }
} else
DRE = dyn_cast<DeclRefExpr>(Arg);
- if (!DRE)
- return Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_decl_ref)
- << Arg->getSourceRange();
+ if (!DRE) {
+ if (S.Context.hasSameUnqualifiedType(ArgType, S.Context.OverloadTy)) {
+ S.Diag(Arg->getLocStart(),
+ diag::err_template_arg_unresolved_overloaded_function)
+ << ParamType << Arg->getSourceRange();
+ } else {
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
+ << Arg->getSourceRange();
+ }
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
// Stop checking the precise nature of the argument if it is value dependent,
// it should be checked when instantiated.
- if (Arg->isValueDependent())
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(ArgIn->Retain());
return false;
+ }
- if (!isa<ValueDecl>(DRE->getDecl()))
- return Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_object_or_func_form)
+ if (!isa<ValueDecl>(DRE->getDecl())) {
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_object_or_func_form)
<< Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ NamedDecl *Entity = 0;
// Cannot refer to non-static data members
- if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl()))
- return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field)
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl())) {
+ S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field)
<< Field << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
// Cannot refer to non-static member functions
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl()))
- if (!Method->isStatic())
- return Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_method)
+ if (!Method->isStatic()) {
+ S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_method)
<< Method << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
// Functions must have external linkage.
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
if (!isExternalLinkage(Func->getLinkage())) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_function_not_extern)
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_function_not_extern)
<< Func << Arg->getSourceRange();
- Diag(Func->getLocation(), diag::note_template_arg_internal_object)
+ S.Diag(Func->getLocation(), diag::note_template_arg_internal_object)
<< true;
return true;
}
// Okay: we've named a function with external linkage.
Entity = Func;
- return Invalid;
- }
- if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ // If the template parameter has pointer type, the function decays.
+ if (ParamType->isPointerType() && !AddressTaken)
+ ArgType = S.Context.getPointerType(Func->getType());
+ else if (AddressTaken && ParamType->isReferenceType()) {
+ // If we originally had an address-of operator, but the
+ // parameter has reference type, complain and (if things look
+ // like they will work) drop the address-of operator.
+ if (!S.Context.hasSameUnqualifiedType(Func->getType(),
+ ParamType.getNonReferenceType())) {
+ S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+ << ParamType;
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+ << ParamType
+ << FixItHint::CreateRemoval(AddrOpLoc);
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+
+ ArgType = Func->getType();
+ }
+ } else if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
if (!isExternalLinkage(Var->getLinkage())) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_object_not_extern)
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_object_not_extern)
<< Var << Arg->getSourceRange();
- Diag(Var->getLocation(), diag::note_template_arg_internal_object)
+ S.Diag(Var->getLocation(), diag::note_template_arg_internal_object)
<< true;
return true;
}
+ // A value of reference type is not an object.
+ if (Var->getType()->isReferenceType()) {
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_reference_var)
+ << Var->getType() << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
// Okay: we've named an object with external linkage
Entity = Var;
- return Invalid;
- }
- // We found something else, but we don't know specifically what it is.
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_object_or_func)
+ // If the template parameter has pointer type, we must have taken
+ // the address of this object.
+ if (ParamType->isReferenceType()) {
+ if (AddressTaken) {
+ // If we originally had an address-of operator, but the
+ // parameter has reference type, complain and (if things look
+ // like they will work) drop the address-of operator.
+ if (!S.Context.hasSameUnqualifiedType(Var->getType(),
+ ParamType.getNonReferenceType())) {
+ S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+ << ParamType;
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+ << ParamType
+ << FixItHint::CreateRemoval(AddrOpLoc);
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+
+ ArgType = Var->getType();
+ }
+ } else if (!AddressTaken && ParamType->isPointerType()) {
+ if (Var->getType()->isArrayType()) {
+ // Array-to-pointer decay.
+ ArgType = S.Context.getArrayDecayedType(Var->getType());
+ } else {
+ // If the template parameter has pointer type but the address of
+ // this object was not taken, complain and (possibly) recover by
+ // taking the address of the entity.
+ ArgType = S.Context.getPointerType(Var->getType());
+ if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) {
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_address_of)
+ << ParamType;
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_address_of)
+ << ParamType
+ << FixItHint::CreateInsertion(Arg->getLocStart(), "&");
+
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ }
+ }
+ } else {
+ // We found something else, but we don't know specifically what it is.
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_object_or_func)
<< Arg->getSourceRange();
- Diag(DRE->getDecl()->getLocation(),
- diag::note_template_arg_refers_here);
- return true;
+ S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here);
+ return true;
+ }
+
+ if (ParamType->isPointerType() &&
+ !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
+ S.IsQualificationConversion(ArgType, ParamType)) {
+ // For pointer-to-object types, qualification conversions are
+ // permitted.
+ } else {
+ if (const ReferenceType *ParamRef = ParamType->getAs<ReferenceType>()) {
+ if (!ParamRef->getPointeeType()->isFunctionType()) {
+ // C++ [temp.arg.nontype]p5b3:
+ // For a non-type template-parameter of type reference to
+ // object, no conversions apply. The type referred to by the
+ // reference may be more cv-qualified than the (otherwise
+ // identical) type of the template- argument. The
+ // template-parameter is bound directly to the
+ // template-argument, which shall be an lvalue.
+
+ // FIXME: Other qualifiers?
+ unsigned ParamQuals = ParamRef->getPointeeType().getCVRQualifiers();
+ unsigned ArgQuals = ArgType.getCVRQualifiers();
+
+ if ((ParamQuals | ArgQuals) != ParamQuals) {
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_ref_bind_ignores_quals)
+ << ParamType << Arg->getType()
+ << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+ }
+ }
+
+ // At this point, the template argument refers to an object or
+ // function with external linkage. We now need to check whether the
+ // argument and parameter types are compatible.
+ if (!S.Context.hasSameUnqualifiedType(ArgType,
+ ParamType.getNonReferenceType())) {
+ // We can't perform this conversion or binding.
+ if (ParamType->isReferenceType())
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind)
+ << ParamType << Arg->getType() << Arg->getSourceRange();
+ else
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible)
+ << Arg->getType() << ParamType << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+ }
+
+ // Create the template argument.
+ Converted = TemplateArgument(Entity->getCanonicalDecl());
+ return false;
}
/// \brief Checks whether the given template argument is a pointer to
@@ -2388,10 +2538,6 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
Arg = Cast->getSubExpr();
- // C++0x allows nullptr, and there's no further checking to be done for that.
- if (Arg->getType()->isNullPtrType())
- return false;
-
// C++ [temp.arg.nontype]p1:
//
// A template-argument for a non-type, non-template
@@ -2478,12 +2624,12 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
/// If no error was detected, Converted receives the converted template argument.
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
- TemplateArgument &Converted) {
+ TemplateArgument &Converted,
+ CheckTemplateArgumentKind CTAK) {
SourceLocation StartLoc = Arg->getSourceRange().getBegin();
// If either the parameter has a dependent type or the argument is
// type-dependent, there's nothing we can check now.
- // FIXME: Add template argument to Converted!
if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) {
// FIXME: Produce a cloned, canonical expression?
Converted = TemplateArgument(Arg);
@@ -2525,17 +2671,27 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- // FIXME: We need some way to more easily get the unqualified form
- // of the types without going all the way to the
- // canonical type.
- if (Context.getCanonicalType(ParamType).getCVRQualifiers())
- ParamType = Context.getCanonicalType(ParamType).getUnqualifiedType();
- if (Context.getCanonicalType(ArgType).getCVRQualifiers())
- ArgType = Context.getCanonicalType(ArgType).getUnqualifiedType();
+ // From here on out, all we care about are the unqualified forms
+ // of the parameter and argument types.
+ ParamType = ParamType.getUnqualifiedType();
+ ArgType = ArgType.getUnqualifiedType();
// Try to convert the argument to the parameter's type.
if (Context.hasSameType(ParamType, ArgType)) {
// Okay: no conversion necessary
+ } else if (CTAK == CTAK_Deduced) {
+ // C++ [temp.deduct.type]p17:
+ // If, in the declaration of a function template with a non-type
+ // template-parameter, the non-type template- parameter is used
+ // in an expression in the function parameter-list and, if the
+ // corresponding template-argument is deduced, the
+ // template-argument type shall match the type of the
+ // template-parameter exactly, except that a template-argument
+ // deduced from an array bound may be of any integral type.
+ Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
+ << ArgType << ParamType;
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
} else if (IsIntegralPromotion(Arg, ArgType, ParamType) ||
!ParamType->isEnumeralType()) {
// This is an integral promotion or conversion.
@@ -2554,38 +2710,39 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType());
if (!Arg->isValueDependent()) {
- // Check that an unsigned parameter does not receive a negative
- // value.
+ llvm::APSInt OldValue = Value;
+
+ // Coerce the template argument's value to the value it will have
+ // based on the template parameter's type.
+ unsigned AllowedBits = Context.getTypeSize(IntegerType);
+ if (Value.getBitWidth() != AllowedBits)
+ Value.extOrTrunc(AllowedBits);
+ Value.setIsSigned(IntegerType->isSignedIntegerType());
+
+ // Complain if an unsigned parameter received a negative value.
if (IntegerType->isUnsignedIntegerType()
- && (Value.isSigned() && Value.isNegative())) {
- Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_negative)
- << Value.toString(10) << Param->getType()
+ && (OldValue.isSigned() && OldValue.isNegative())) {
+ Diag(Arg->getSourceRange().getBegin(), diag::warn_template_arg_negative)
+ << OldValue.toString(10) << Value.toString(10) << Param->getType()
<< Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
}
- // Check that we don't overflow the template parameter type.
- unsigned AllowedBits = Context.getTypeSize(IntegerType);
+ // Complain if we overflowed the template parameter's type.
unsigned RequiredBits;
if (IntegerType->isUnsignedIntegerType())
- RequiredBits = Value.getActiveBits();
- else if (Value.isUnsigned())
- RequiredBits = Value.getActiveBits() + 1;
+ RequiredBits = OldValue.getActiveBits();
+ else if (OldValue.isUnsigned())
+ RequiredBits = OldValue.getActiveBits() + 1;
else
- RequiredBits = Value.getMinSignedBits();
+ RequiredBits = OldValue.getMinSignedBits();
if (RequiredBits > AllowedBits) {
Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_too_large)
- << Value.toString(10) << Param->getType()
+ diag::warn_template_arg_too_large)
+ << OldValue.toString(10) << Value.toString(10) << Param->getType()
<< Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
}
-
- if (Value.getBitWidth() != AllowedBits)
- Value.extOrTrunc(AllowedBits);
- Value.setIsSigned(IntegerType->isSignedIntegerType());
}
// Add the value of this argument to the list of converted
@@ -2604,6 +2761,18 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return false;
}
+ DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction
+
+ // C++0x [temp.arg.nontype]p5 bullets 2, 4 and 6 permit conversion
+ // from a template argument of type std::nullptr_t to a non-type
+ // template parameter of type pointer to object, pointer to
+ // function, or pointer-to-member, respectively.
+ if (ArgType->isNullPtrType() &&
+ (ParamType->isPointerType() || ParamType->isMemberPointerType())) {
+ Converted = TemplateArgument((NamedDecl *)0);
+ return false;
+ }
+
// Handle pointer-to-function, reference-to-function, and
// pointer-to-member-function all in (roughly) the same way.
if (// -- For a non-type template-parameter of type pointer to
@@ -2611,7 +2780,6 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// applied. If the template-argument represents a set of
// overloaded functions (or a pointer to such), the matching
// function is selected from the set (13.4).
- // In C++0x, any std::nullptr_t value can be converted.
(ParamType->isPointerType() &&
ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type reference to
@@ -2625,38 +2793,30 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// template-argument represents a set of overloaded member
// functions, the matching member function is selected from
// the set (13.4).
- // Again, C++0x allows a std::nullptr_t value.
(ParamType->isMemberPointerType() &&
ParamType->getAs<MemberPointerType>()->getPointeeType()
->isFunctionType())) {
- if (Context.hasSameUnqualifiedType(ArgType,
- ParamType.getNonReferenceType())) {
- // We don't have to do anything: the types already match.
- } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() ||
- ParamType->isMemberPointerType())) {
- ArgType = ParamType;
- if (ParamType->isMemberPointerType())
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer);
- else
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast);
- } else if (ArgType->isFunctionType() && ParamType->isPointerType()) {
- ArgType = Context.getPointerType(ArgType);
- ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay);
- } else if (FunctionDecl *Fn
- = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) {
+
+ if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType,
+ true,
+ FoundResult)) {
if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
return true;
- Arg = FixOverloadedFunctionReference(Arg, Fn);
+ Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
ArgType = Arg->getType();
- if (ArgType->isFunctionType() && ParamType->isPointerType()) {
- ArgType = Context.getPointerType(Arg->getType());
- ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay);
- }
}
- if (!Context.hasSameUnqualifiedType(ArgType,
- ParamType.getNonReferenceType())) {
+ if (!ParamType->isMemberPointerType())
+ return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
+ ParamType,
+ Arg, Converted);
+
+ if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType())) {
+ ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp,
+ Arg->isLvalue(Context) == Expr::LV_Valid);
+ } else if (!Context.hasSameUnqualifiedType(ArgType,
+ ParamType.getNonReferenceType())) {
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
@@ -2665,21 +2825,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- if (ParamType->isMemberPointerType())
- return CheckTemplateArgumentPointerToMember(Arg, Converted);
-
- NamedDecl *Entity = 0;
- if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
- return true;
-
- if (Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
- } else {
- if (Entity)
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
- }
- return false;
+ return CheckTemplateArgumentPointerToMember(Arg, Converted);
}
if (ParamType->isPointerType()) {
@@ -2690,40 +2836,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamType->getAs<PointerType>()->getPointeeType()->isObjectType() &&
"Only object pointers allowed here");
- if (ArgType->isNullPtrType()) {
- ArgType = ParamType;
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast);
- } else if (ArgType->isArrayType()) {
- ArgType = Context.getArrayDecayedType(ArgType);
- ImpCastExprToType(Arg, ArgType, CastExpr::CK_ArrayToPointerDecay);
- }
-
- if (IsQualificationConversion(ArgType, ParamType)) {
- ArgType = ParamType;
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp);
- }
-
- if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) {
- // We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_convertible)
- << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
-
- NamedDecl *Entity = 0;
- if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
- return true;
-
- if (Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
- } else {
- if (Entity)
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
- }
- return false;
+ return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
+ ParamType,
+ Arg, Converted);
}
if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) {
@@ -2736,53 +2851,31 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamRefType->getPointeeType()->isObjectType() &&
"Only object references allowed here");
- QualType ReferredType = ParamRefType->getPointeeType();
- if (!Context.hasSameUnqualifiedType(ReferredType, ArgType)) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_no_ref_bind)
- << InstantiatedParamType << Arg->getType()
- << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
-
- unsigned ParamQuals
- = Context.getCanonicalType(ReferredType).getCVRQualifiers();
- unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers();
+ if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg,
+ ParamRefType->getPointeeType(),
+ true,
+ FoundResult)) {
+ if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+ return true;
- if ((ParamQuals | ArgQuals) != ParamQuals) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_ref_bind_ignores_quals)
- << InstantiatedParamType << Arg->getType()
- << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
+ Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
+ ArgType = Arg->getType();
}
- NamedDecl *Entity = 0;
- if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
- return true;
-
- if (Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
- } else {
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
- }
- return false;
+ return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
+ ParamType,
+ Arg, Converted);
}
// -- For a non-type template-parameter of type pointer to data
// member, qualification conversions (4.4) are applied.
- // C++0x allows std::nullptr_t values.
assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
// Types match exactly: nothing more to do here.
- } else if (ArgType->isNullPtrType()) {
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer);
} else if (IsQualificationConversion(ArgType, ParamType)) {
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp);
+ ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp,
+ Arg->isLvalue(Context) == Expr::LV_Valid);
} else {
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
@@ -2837,6 +2930,109 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
Arg.getLocation());
}
+/// \brief Given a non-type template argument that refers to a
+/// declaration and the type of its corresponding non-type template
+/// parameter, produce an expression that properly refers to that
+/// declaration.
+Sema::OwningExprResult
+Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
+ QualType ParamType,
+ SourceLocation Loc) {
+ assert(Arg.getKind() == TemplateArgument::Declaration &&
+ "Only declaration template arguments permitted here");
+ ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
+
+ if (VD->getDeclContext()->isRecord() &&
+ (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) {
+ // If the value is a class member, we might have a pointer-to-member.
+ // Determine whether the non-type template template parameter is of
+ // pointer-to-member type. If so, we need to build an appropriate
+ // expression for a pointer-to-member, since a "normal" DeclRefExpr
+ // would refer to the member itself.
+ if (ParamType->isMemberPointerType()) {
+ QualType ClassType
+ = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext()));
+ NestedNameSpecifier *Qualifier
+ = NestedNameSpecifier::Create(Context, 0, false, ClassType.getTypePtr());
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ OwningExprResult RefExpr = BuildDeclRefExpr(VD,
+ VD->getType().getNonReferenceType(),
+ Loc,
+ &SS);
+ if (RefExpr.isInvalid())
+ return ExprError();
+
+ RefExpr = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr));
+ assert(!RefExpr.isInvalid() &&
+ Context.hasSameType(((Expr*) RefExpr.get())->getType(),
+ ParamType));
+ return move(RefExpr);
+ }
+ }
+
+ QualType T = VD->getType().getNonReferenceType();
+ if (ParamType->isPointerType()) {
+ // When the non-type template parameter is a pointer, take the
+ // address of the declaration.
+ OwningExprResult RefExpr = BuildDeclRefExpr(VD, T, Loc);
+ if (RefExpr.isInvalid())
+ return ExprError();
+
+ if (T->isFunctionType() || T->isArrayType()) {
+ // Decay functions and arrays.
+ Expr *RefE = (Expr *)RefExpr.get();
+ DefaultFunctionArrayConversion(RefE);
+ if (RefE != RefExpr.get()) {
+ RefExpr.release();
+ RefExpr = Owned(RefE);
+ }
+
+ return move(RefExpr);
+ }
+
+ // Take the address of everything else
+ return CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr));
+ }
+
+ // If the non-type template parameter has reference type, qualify the
+ // resulting declaration reference with the extra qualifiers on the
+ // type that the reference refers to.
+ if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>())
+ T = Context.getQualifiedType(T, TargetRef->getPointeeType().getQualifiers());
+
+ return BuildDeclRefExpr(VD, T, Loc);
+}
+
+/// \brief Construct a new expression that refers to the given
+/// integral template argument with the given source-location
+/// information.
+///
+/// This routine takes care of the mapping from an integral template
+/// argument (which may have any integral type) to the appropriate
+/// literal value.
+Sema::OwningExprResult
+Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
+ SourceLocation Loc) {
+ assert(Arg.getKind() == TemplateArgument::Integral &&
+ "Operation is only value for integral template arguments");
+ QualType T = Arg.getIntegralType();
+ if (T->isCharType() || T->isWideCharType())
+ return Owned(new (Context) CharacterLiteral(
+ Arg.getAsIntegral()->getZExtValue(),
+ T->isWideCharType(),
+ T,
+ Loc));
+ if (T->isBooleanType())
+ return Owned(new (Context) CXXBoolLiteralExpr(
+ Arg.getAsIntegral()->getBoolValue(),
+ T,
+ Loc));
+
+ return Owned(new (Context) IntegerLiteral(*Arg.getAsIntegral(), T, Loc));
+}
+
+
/// \brief Determine whether the given template parameter lists are
/// equivalent.
///
@@ -3341,7 +3537,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
} else if (TemplateParams) {
if (TUK == TUK_Friend)
Diag(KWLoc, diag::err_template_spec_friend)
- << CodeModificationHint::CreateRemoval(
+ << FixItHint::CreateRemoval(
SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc()))
<< SourceRange(LAngleLoc, RAngleLoc);
@@ -3349,7 +3545,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
isExplicitSpecialization = true;
} else if (TUK != TUK_Friend) {
Diag(KWLoc, diag::err_template_spec_needs_header)
- << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
+ << FixItHint::CreateInsertion(KWLoc, "template<> ");
isExplicitSpecialization = true;
}
@@ -3367,7 +3563,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
*ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
- << CodeModificationHint::CreateReplacement(KWLoc,
+ << FixItHint::CreateReplacement(KWLoc,
ClassTemplate->getTemplatedDecl()->getKindName());
Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
diag::note_previous_use);
@@ -3409,8 +3605,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// to the implicit argument list of the primary template.
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
<< (TUK == TUK_Definition)
- << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc,
- RAngleLoc));
+ << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
ClassTemplate->getIdentifier(),
TemplateNameLoc,
@@ -3644,7 +3839,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (TUK == TUK_Friend) {
FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
TemplateNameLoc,
- WrittenTy->getType().getTypePtr(),
+ WrittenTy,
/*FIXME:*/KWLoc);
Friend->setAccess(AS_public);
CurContext->addDecl(Friend);
@@ -3948,11 +4143,11 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
UnresolvedSetIterator Result
= getMostSpecialized(Candidates.begin(), Candidates.end(),
TPOC_Other, FD->getLocation(),
- PartialDiagnostic(diag::err_function_template_spec_no_match)
+ PDiag(diag::err_function_template_spec_no_match)
<< FD->getDeclName(),
- PartialDiagnostic(diag::err_function_template_spec_ambiguous)
+ PDiag(diag::err_function_template_spec_ambiguous)
<< FD->getDeclName() << (ExplicitTemplateArgs != 0),
- PartialDiagnostic(diag::note_function_template_spec_matched));
+ PDiag(diag::note_function_template_spec_matched));
if (Result == Candidates.end())
return true;
@@ -3961,9 +4156,14 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
+
+ // If this is a friend declaration, then we're not really declaring
+ // an explicit specialization.
+ bool isFriend = (FD->getFriendObjectKind() != Decl::FOK_None);
// Check the scope of this explicit specialization.
- if (CheckTemplateSpecializationScope(*this,
+ if (!isFriend &&
+ CheckTemplateSpecializationScope(*this,
Specialization->getPrimaryTemplate(),
Specialization, FD->getLocation(),
false))
@@ -3980,7 +4180,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
assert(SpecInfo && "Function template specialization info missing?");
bool SuppressNew = false;
- if (CheckSpecializationInstantiationRedecl(FD->getLocation(),
+ if (!isFriend &&
+ CheckSpecializationInstantiationRedecl(FD->getLocation(),
TSK_ExplicitSpecialization,
Specialization,
SpecInfo->getTemplateSpecializationKind(),
@@ -3990,7 +4191,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Mark the prior declaration as an explicit specialization, so that later
// clients know that this is an explicit specialization.
- SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
+ if (!isFriend)
+ SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
// Turn the given function declaration into a function template
// specialization, with the template arguments from the previous
@@ -3999,7 +4201,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
new (Context) TemplateArgumentList(
*Specialization->getTemplateSpecializationArgs()),
/*InsertPos=*/0,
- TSK_ExplicitSpecialization);
+ SpecInfo->getTemplateSpecializationKind());
// The "previous declaration" for this function template specialization is
// the prior function template specialization.
@@ -4250,7 +4452,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
*ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
- << CodeModificationHint::CreateReplacement(KWLoc,
+ << FixItHint::CreateReplacement(KWLoc,
ClassTemplate->getTemplatedDecl()->getKindName());
Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
diag::note_previous_use);
@@ -4388,8 +4590,17 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Instantiate the members of this class template specialization.
Def = cast_or_null<ClassTemplateSpecializationDecl>(
Specialization->getDefinition());
- if (Def)
+ if (Def) {
+ TemplateSpecializationKind Old_TSK = Def->getTemplateSpecializationKind();
+
+ // Fix a TSK_ExplicitInstantiationDeclaration followed by a
+ // TSK_ExplicitInstantiationDefinition
+ if (Old_TSK == TSK_ExplicitInstantiationDeclaration &&
+ TSK == TSK_ExplicitInstantiationDefinition)
+ Def->setTemplateSpecializationKind(TSK);
+
InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
+ }
return DeclPtrTy::make(Specialization);
}
@@ -4559,7 +4770,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x)
Diag(D.getDeclSpec().getInlineSpecLoc(),
diag::err_explicit_instantiation_inline)
- <<CodeModificationHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
+ <<FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
// FIXME: check for constexpr specifier.
@@ -4699,9 +4910,9 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
UnresolvedSetIterator Result
= getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other,
D.getIdentifierLoc(),
- PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name,
- PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name,
- PartialDiagnostic(diag::note_explicit_instantiation_candidate));
+ PDiag(diag::err_explicit_instantiation_not_known) << Name,
+ PDiag(diag::err_explicit_instantiation_ambiguous) << Name,
+ PDiag(diag::note_explicit_instantiation_candidate));
if (Result == Matches.end())
return true;
@@ -4781,14 +4992,16 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!NNS)
return true;
- QualType T = CheckTypenameType(NNS, *Name, SourceRange(TagLoc, NameLoc));
- if (T.isNull())
- return true;
-
- TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
- QualType ElabType = Context.getElaboratedType(T, TagKind);
+ ElaboratedTypeKeyword Keyword = ETK_None;
+ switch (TagDecl::getTagKindForTypeSpec(TagSpec)) {
+ case TagDecl::TK_struct: Keyword = ETK_Struct; break;
+ case TagDecl::TK_class: Keyword = ETK_Class; break;
+ case TagDecl::TK_union: Keyword = ETK_Union; break;
+ case TagDecl::TK_enum: Keyword = ETK_Enum; break;
+ }
+ assert(Keyword != ETK_None && "Invalid tag kind!");
- return ElabType.getAsOpaquePtr();
+ return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
}
Sema::TypeResult
@@ -4824,7 +5037,8 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
}
- return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
+ return Context.getDependentNameType(ETK_Typename, NNS, TemplateId)
+ .getAsOpaquePtr();
}
/// \brief Build the type that describes a C++ typename specifier,
@@ -4839,7 +5053,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
// If the nested-name-specifier does not refer to the current
// instantiation, then build a typename type.
if (!CurrentInstantiation)
- return Context.getTypenameType(NNS, &II);
+ return Context.getDependentNameType(ETK_Typename, NNS, &II);
// The nested-name-specifier refers to the current instantiation, so the
// "typename" keyword itself is superfluous. In C++03, the program is
@@ -4875,7 +5089,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.
- return Context.getTypenameType(NNS, &II);
+ return Context.getDependentNameType(ETK_Typename, NNS, &II);
case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
@@ -4960,16 +5174,16 @@ namespace {
/// \brief Transforms a typename type by determining whether the type now
/// refers to a member of the current instantiation, and then
/// type-checking and building a QualifiedNameType (when possible).
- QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL,
+ QualType TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL,
QualType ObjectType);
};
}
QualType
-CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB,
- TypenameTypeLoc TL,
+CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
+ DependentNameTypeLoc TL,
QualType ObjectType) {
- TypenameType *T = TL.getTypePtr();
+ DependentNameType *T = TL.getTypePtr();
NestedNameSpecifier *NNS
= TransformNestedNameSpecifier(T->getQualifier(),
@@ -5001,15 +5215,17 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB,
NewTemplateId == QualType(TemplateId, 0))
Result = QualType(T, 0);
else
- Result = getDerived().RebuildTypenameType(NNS, NewTemplateId);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(),
+ NNS, NewTemplateId);
} else
- Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(),
- SourceRange(TL.getNameLoc()));
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(),
+ NNS, T->getIdentifier(),
+ SourceRange(TL.getNameLoc()));
if (Result.isNull())
return QualType();
- TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result);
+ DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
@@ -5034,7 +5250,7 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB,
/// typename X<T>::pointer X<T>::data() { ... }
/// \endcode
///
-/// Here, the type "typename X<T>::pointer" will be created as a TypenameType,
+/// Here, the type "typename X<T>::pointer" will be created as a DependentNameType,
/// since we do not know that we can look into X<T> when we parsed the type.
/// This function will rebuild the type, performing the lookup of "pointer"
/// in X<T> and returning a QualifiedNameType whose canonical type is the same
diff --git a/lib/Sema/SemaTemplate.h b/lib/Sema/SemaTemplate.h
index 2bfb25a..ca59e27 100644
--- a/lib/Sema/SemaTemplate.h
+++ b/lib/Sema/SemaTemplate.h
@@ -99,6 +99,40 @@ namespace clang {
/// template specialization to a function template.
TPOC_Other
};
+
+ /// \brief Captures a template argument whose value has been deduced
+ /// via c++ template argument deduction.
+ class DeducedTemplateArgument : public TemplateArgument {
+ /// \brief For a non-type template argument, whether the value was
+ /// deduced from an array bound.
+ bool DeducedFromArrayBound;
+
+ public:
+ DeducedTemplateArgument()
+ : TemplateArgument(), DeducedFromArrayBound(false) { }
+
+ DeducedTemplateArgument(const TemplateArgument &Arg,
+ bool DeducedFromArrayBound = false)
+ : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { }
+
+ /// \brief Construct an integral non-type template argument that
+ /// has been deduced, possible from an array bound.
+ DeducedTemplateArgument(const llvm::APSInt &Value,
+ QualType ValueType,
+ bool DeducedFromArrayBound)
+ : TemplateArgument(Value, ValueType),
+ DeducedFromArrayBound(DeducedFromArrayBound) { }
+
+ /// \brief For a non-type template argument, determine whether the
+ /// template argument was deduced from an array bound.
+ bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; }
+
+ /// \brief Specify whether the given non-type template argument
+ /// was deduced from an array bound.
+ void setDeducedFromArrayBound(bool Deduced) {
+ DeducedFromArrayBound = Deduced;
+ }
+ };
}
#endif // LLVM_CLANG_SEMA_TEMPLATE_H
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 326519d..d61a767 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -48,13 +48,34 @@ namespace clang {
using namespace clang;
+/// \brief Compare two APSInts, extending and switching the sign as
+/// necessary to compare their values regardless of underlying type.
+static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) {
+ if (Y.getBitWidth() > X.getBitWidth())
+ X.extend(Y.getBitWidth());
+ else if (Y.getBitWidth() < X.getBitWidth())
+ Y.extend(X.getBitWidth());
+
+ // If there is a signedness mismatch, correct it.
+ if (X.isSigned() != Y.isSigned()) {
+ // If the signed value is negative, then the values cannot be the same.
+ if ((Y.isSigned() && Y.isNegative()) || (X.isSigned() && X.isNegative()))
+ return false;
+
+ Y.setIsSigned(true);
+ X.setIsSigned(true);
+ }
+
+ return X == Y;
+}
+
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const TemplateArgument &Param,
const TemplateArgument &Arg,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced);
/// \brief If the given expression is of a form that permits the deduction
/// of a non-type template parameter, return the declaration of that
@@ -74,50 +95,38 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
static Sema::TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
- llvm::APSInt Value,
+ llvm::APSInt Value, QualType ValueType,
+ bool DeducedFromArrayBound,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
if (Deduced[NTTP->getIndex()].isNull()) {
- QualType T = NTTP->getType();
-
- // FIXME: Make sure we didn't overflow our data type!
- unsigned AllowedBits = S.Context.getTypeSize(T);
- if (Value.getBitWidth() != AllowedBits)
- Value.extOrTrunc(AllowedBits);
- Value.setIsSigned(T->isSignedIntegerType());
-
- Deduced[NTTP->getIndex()] = TemplateArgument(Value, T);
+ Deduced[NTTP->getIndex()] = DeducedTemplateArgument(Value, ValueType,
+ DeducedFromArrayBound);
return Sema::TDK_Success;
}
- assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral);
-
- // If the template argument was previously deduced to a negative value,
- // then our deduction fails.
- const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral();
- if (PrevValuePtr->isNegative()) {
+ if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral) {
Info.Param = NTTP;
Info.FirstArg = Deduced[NTTP->getIndex()];
- Info.SecondArg = TemplateArgument(Value, NTTP->getType());
- return Sema::TDK_Inconsistent;
+ Info.SecondArg = TemplateArgument(Value, ValueType);
+ return Sema::TDK_Inconsistent;
}
- llvm::APSInt PrevValue = *PrevValuePtr;
- if (Value.getBitWidth() > PrevValue.getBitWidth())
- PrevValue.zext(Value.getBitWidth());
- else if (Value.getBitWidth() < PrevValue.getBitWidth())
- Value.zext(PrevValue.getBitWidth());
-
- if (Value != PrevValue) {
+ // Extent the smaller of the two values.
+ llvm::APSInt PrevValue = *Deduced[NTTP->getIndex()].getAsIntegral();
+ if (!hasSameExtendedValue(PrevValue, Value)) {
Info.Param = NTTP;
Info.FirstArg = Deduced[NTTP->getIndex()];
- Info.SecondArg = TemplateArgument(Value, NTTP->getType());
+ Info.SecondArg = TemplateArgument(Value, ValueType);
return Sema::TDK_Inconsistent;
}
+ if (!DeducedFromArrayBound)
+ Deduced[NTTP->getIndex()].setDeducedFromArrayBound(false);
+
return Sema::TDK_Success;
}
@@ -130,15 +139,14 @@ DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
Expr *Value,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
assert((Value->isTypeDependent() || Value->isValueDependent()) &&
"Expression template argument must be type- or value-dependent.");
if (Deduced[NTTP->getIndex()].isNull()) {
- // FIXME: Clone the Value?
- Deduced[NTTP->getIndex()] = TemplateArgument(Value);
+ Deduced[NTTP->getIndex()] = TemplateArgument(Value->Retain());
return Sema::TDK_Success;
}
@@ -173,7 +181,7 @@ DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
Decl *D,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
@@ -207,7 +215,7 @@ DeduceTemplateArguments(Sema &S,
TemplateName Param,
TemplateName Arg,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
if (!ParamDecl) {
// The parameter type is dependent and is not a template template parameter,
@@ -271,7 +279,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateSpecializationType *Param,
QualType Arg,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(Arg.isCanonical() && "Argument type must be canonical");
// Check whether the template argument is a dependent template-id.
@@ -363,7 +371,7 @@ DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
@@ -569,7 +577,9 @@ DeduceTemplateArguments(Sema &S,
if (const ConstantArrayType *ConstantArrayArg
= dyn_cast<ConstantArrayType>(ArrayArg)) {
llvm::APSInt Size(ConstantArrayArg->getSize());
- return DeduceNonTypeTemplateArgument(S, NTTP, Size,
+ return DeduceNonTypeTemplateArgument(S, NTTP, Size,
+ S.Context.getSizeType(),
+ /*ArrayBound=*/true,
Info, Deduced);
}
if (const DependentSizedArrayType *DependentArrayArg
@@ -763,7 +773,7 @@ DeduceTemplateArguments(Sema &S,
case Type::TypeOfExpr:
case Type::TypeOf:
- case Type::Typename:
+ case Type::DependentName:
// No template argument deduction for these types
return Sema::TDK_Success;
@@ -781,7 +791,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument &Param,
const TemplateArgument &Arg,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
switch (Param.getKind()) {
case TemplateArgument::Null:
assert(false && "Null template argument in parameter list");
@@ -816,8 +826,7 @@ DeduceTemplateArguments(Sema &S,
case TemplateArgument::Integral:
if (Arg.getKind() == TemplateArgument::Integral) {
- // FIXME: Zero extension + sign checking here?
- if (*Param.getAsIntegral() == *Arg.getAsIntegral())
+ if (hasSameExtendedValue(*Param.getAsIntegral(), *Arg.getAsIntegral()))
return Sema::TDK_Success;
Info.FirstArg = Param;
@@ -840,9 +849,10 @@ DeduceTemplateArguments(Sema &S,
if (NonTypeTemplateParmDecl *NTTP
= getDeducedParameterFromExpr(Param.getAsExpr())) {
if (Arg.getKind() == TemplateArgument::Integral)
- // FIXME: Sign problems here
return DeduceNonTypeTemplateArgument(S, NTTP,
*Arg.getAsIntegral(),
+ Arg.getIntegralType(),
+ /*ArrayBound=*/false,
Info, Deduced);
if (Arg.getKind() == TemplateArgument::Expression)
return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(),
@@ -874,7 +884,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(ParamList.size() == ArgList.size());
for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
if (Sema::TemplateDeductionResult Result
@@ -963,7 +973,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// specialization can be deduced from the actual template argument
// list (14.8.2).
SFINAETrap Trap(*this);
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(*this,
@@ -987,13 +997,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Decl *Param
= const_cast<NamedDecl *>(
Partial->getTemplateParameters()->getParam(I));
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
- Info.Param = TTP;
- else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param))
- Info.Param = NTTP;
- else
- Info.Param = cast<TemplateTemplateParmDecl>(Param);
+ Info.Param = makeTemplateParameter(Param);
return TDK_Incomplete;
}
@@ -1010,6 +1014,9 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// verify that the instantiated template arguments are both valid
// and are equivalent to the template arguments originally provided
// to the class template.
+ // FIXME: Do we have to correct the types of deduced non-type template
+ // arguments (in particular, integral non-type template arguments?).
+ Sema::LocalInstantiationScope InstScope(*this);
ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
const TemplateArgumentLoc *PartialTemplateArgs
= Partial->getTemplateArgsAsWritten();
@@ -1112,7 +1119,7 @@ Sema::TemplateDeductionResult
Sema::SubstituteExplicitTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
const TemplateArgumentListInfo &ExplicitTemplateArgs,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
llvm::SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
TemplateDeductionInfo &Info) {
@@ -1225,12 +1232,67 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_Success;
}
+/// \brief Allocate a TemplateArgumentLoc where all locations have
+/// been initialized to the given location.
+///
+/// \param S The semantic analysis object.
+///
+/// \param The template argument we are producing template argument
+/// location information for.
+///
+/// \param NTTPType For a declaration template argument, the type of
+/// the non-type template parameter that corresponds to this template
+/// argument.
+///
+/// \param Loc The source location to use for the resulting template
+/// argument.
+static TemplateArgumentLoc
+getTrivialTemplateArgumentLoc(Sema &S,
+ const TemplateArgument &Arg,
+ QualType NTTPType,
+ SourceLocation Loc) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ llvm_unreachable("Can't get a NULL template argument here");
+ break;
+
+ case TemplateArgument::Type:
+ return TemplateArgumentLoc(Arg,
+ S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
+
+ case TemplateArgument::Declaration: {
+ Expr *E
+ = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+ .takeAs<Expr>();
+ return TemplateArgumentLoc(TemplateArgument(E), E);
+ }
+
+ case TemplateArgument::Integral: {
+ Expr *E
+ = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
+ return TemplateArgumentLoc(TemplateArgument(E), E);
+ }
+
+ case TemplateArgument::Template:
+ return TemplateArgumentLoc(Arg, SourceRange(), Loc);
+
+ case TemplateArgument::Expression:
+ return TemplateArgumentLoc(Arg, Arg.getAsExpr());
+
+ case TemplateArgument::Pack:
+ llvm_unreachable("Template parameter packs are not yet supported");
+ }
+
+ return TemplateArgumentLoc();
+}
+
/// \brief Finish template argument deduction for a function template,
/// checking the deduced template arguments for completeness and forming
/// the function template specialization.
Sema::TemplateDeductionResult
Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ unsigned NumExplicitlySpecified,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
TemplateParameterList *TemplateParams
@@ -1253,13 +1315,71 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// explicitly specified, template argument deduction fails.
TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size());
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
+ NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I);
if (!Deduced[I].isNull()) {
- Builder.Append(Deduced[I]);
+ if (I < NumExplicitlySpecified ||
+ Deduced[I].getKind() == TemplateArgument::Type) {
+ // We have already fully type-checked and converted this
+ // argument (because it was explicitly-specified) or no
+ // additional checking is necessary (because it's a template
+ // type parameter). Just record the presence of this
+ // parameter.
+ Builder.Append(Deduced[I]);
+ continue;
+ }
+
+ // We have deduced this argument, so it still needs to be
+ // checked and converted.
+
+ // First, for a non-type template parameter type that is
+ // initialized by a declaration, we need the type of the
+ // corresponding non-type template parameter.
+ QualType NTTPType;
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (Deduced[I].getKind() == TemplateArgument::Declaration) {
+ NTTPType = NTTP->getType();
+ if (NTTPType->isDependentType()) {
+ TemplateArgumentList TemplateArgs(Context, Builder,
+ /*TakeArgs=*/false);
+ NTTPType = SubstType(NTTPType,
+ MultiLevelTemplateArgumentList(TemplateArgs),
+ NTTP->getLocation(),
+ NTTP->getDeclName());
+ if (NTTPType.isNull()) {
+ Info.Param = makeTemplateParameter(Param);
+ return TDK_SubstitutionFailure;
+ }
+ }
+ }
+ }
+
+ // Convert the deduced template argument into a template
+ // argument that we can check, almost as if the user had written
+ // the template argument explicitly.
+ TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this,
+ Deduced[I],
+ NTTPType,
+ SourceLocation());
+
+ // Check the template argument, converting it as necessary.
+ if (CheckTemplateArgument(Param, Arg,
+ FunctionTemplate,
+ FunctionTemplate->getLocation(),
+ FunctionTemplate->getSourceRange().getEnd(),
+ Builder,
+ Deduced[I].wasDeducedFromArrayBound()
+ ? CTAK_DeducedFromArrayBound
+ : CTAK_Deduced)) {
+ Info.Param = makeTemplateParameter(
+ const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+ return TDK_SubstitutionFailure;
+ }
+
continue;
}
// Substitute into the default template argument, if available.
- NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I);
TemplateArgumentLoc DefArg
= SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate,
FunctionTemplate->getLocation(),
@@ -1279,7 +1399,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
FunctionTemplate,
FunctionTemplate->getLocation(),
FunctionTemplate->getSourceRange().getEnd(),
- Builder)) {
+ Builder,
+ CTAK_Deduced)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
return TDK_SubstitutionFailure;
@@ -1390,7 +1511,8 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
// Type deduction is done independently for each P/A pair, and
// the deduced template argument values are then combined.
// So we do not reject deductions which were made elsewhere.
- llvm::SmallVector<TemplateArgument, 8> Deduced(TemplateParams->size());
+ llvm::SmallVector<DeducedTemplateArgument, 8>
+ Deduced(TemplateParams->size());
Sema::TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
unsigned TDF = 0;
@@ -1458,10 +1580,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// The types of the parameters from which we will perform template argument
// deduction.
+ Sema::LocalInstantiationScope InstScope(*this);
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
llvm::SmallVector<QualType, 4> ParamTypes;
+ unsigned NumExplicitlySpecified = 0;
if (ExplicitTemplateArgs) {
TemplateDeductionResult Result =
SubstituteExplicitTemplateArguments(FunctionTemplate,
@@ -1472,6 +1596,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Info);
if (Result)
return Result;
+
+ NumExplicitlySpecified = Deduced.size();
} else {
// Just fill in the parameter types from the function declaration.
for (unsigned I = 0; I != CheckArgs; ++I)
@@ -1574,6 +1700,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
}
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+ NumExplicitlySpecified,
Specialization, Info);
}
@@ -1612,7 +1739,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType FunctionType = Function->getType();
// Substitute any explicit template arguments.
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Sema::LocalInstantiationScope InstScope(*this);
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
+ unsigned NumExplicitlySpecified = 0;
llvm::SmallVector<QualType, 4> ParamTypes;
if (ExplicitTemplateArgs) {
if (TemplateDeductionResult Result
@@ -1621,6 +1750,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Deduced, ParamTypes,
&FunctionType, Info))
return Result;
+
+ NumExplicitlySpecified = Deduced.size();
}
// Template argument deduction for function templates in a SFINAE context.
@@ -1639,6 +1770,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
}
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+ NumExplicitlySpecified,
Specialization, Info);
}
@@ -1707,7 +1839,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// A) as described in 14.8.2.4.
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
// C++0x [temp.deduct.conv]p4:
@@ -1739,9 +1871,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// modulo the various allowed differences.
// Finish template argument deduction.
+ Sema::LocalInstantiationScope InstScope(*this);
FunctionDecl *Spec = 0;
TemplateDeductionResult Result
- = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info);
+ = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec,
+ Info);
Specialization = cast_or_null<CXXConversionDecl>(Spec);
return Result;
}
@@ -1799,11 +1933,11 @@ enum DeductionQualifierComparison {
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
DeduceTemplateArgumentsDuringPartialOrdering(Sema &S,
- TemplateParameterList *TemplateParams,
+ TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
- llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
CanQualType Param = S.Context.getCanonicalType(ParamIn);
CanQualType Arg = S.Context.getCanonicalType(ArgIn);
@@ -1877,7 +2011,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
assert(Proto1 && Proto2 && "Function templates must have prototypes");
TemplateParameterList *TemplateParams = FT2->getTemplateParameters();
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
// C++0x [temp.deduct.partial]p3:
@@ -2204,7 +2338,7 @@ Sema::getMoreSpecializedPartialSpecialization(
// computation is slightly simpler than the general problem of function
// template partial ordering, because class template partial specializations
// are more constrained. We know that every template parameter is deduc
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Sema::TemplateDeductionInfo Info(Context, Loc);
// Determine whether PS1 is at least as specialized as PS2
@@ -2421,10 +2555,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
OnlyDeduced, Depth, Used);
break;
- case Type::Typename:
+ case Type::DependentName:
if (!OnlyDeduced)
MarkUsedTemplateParameters(SemaRef,
- cast<TypenameType>(T)->getQualifier(),
+ cast<DependentNameType>(T)->getQualifier(),
OnlyDeduced, Depth, Used);
break;
@@ -2525,8 +2659,9 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
/// \brief Marks all of the template parameters that will be deduced by a
/// call to the given function template.
-void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallVectorImpl<bool> &Deduced) {
+void
+Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallVectorImpl<bool> &Deduced) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
Deduced.clear();
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 0d6acd0..d21862b 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -394,7 +394,11 @@ void Sema::PrintInstantiationStack() {
= cast<FunctionTemplateDecl>((Decl *)Active->Entity);
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
diag::note_explicit_template_arg_substitution_here)
- << FnTmpl << Active->InstantiationRange;
+ << FnTmpl
+ << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(),
+ Active->TemplateArgs,
+ Active->NumTemplateArgs)
+ << Active->InstantiationRange;
break;
}
@@ -405,13 +409,21 @@ void Sema::PrintInstantiationStack() {
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
diag::note_partial_spec_deduct_instantiation_here)
<< Context.getTypeDeclType(PartialSpec)
+ << getTemplateArgumentBindingsText(
+ PartialSpec->getTemplateParameters(),
+ Active->TemplateArgs,
+ Active->NumTemplateArgs)
<< Active->InstantiationRange;
} else {
FunctionTemplateDecl *FnTmpl
= cast<FunctionTemplateDecl>((Decl *)Active->Entity);
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
diag::note_function_template_deduction_instantiation_here)
- << FnTmpl << Active->InstantiationRange;
+ << FnTmpl
+ << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(),
+ Active->TemplateArgs,
+ Active->NumTemplateArgs)
+ << Active->InstantiationRange;
}
break;
@@ -677,8 +689,8 @@ TemplateInstantiator::RebuildElaboratedType(QualType T,
if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) {
SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
<< Id
- << CodeModificationHint::CreateReplacement(SourceRange(TagLocation),
- TD->getKindName());
+ << FixItHint::CreateReplacement(SourceRange(TagLocation),
+ TD->getKindName());
SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
}
}
@@ -745,101 +757,13 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
DeclarationName());
assert(!TargetType.isNull() && "type substitution failed for param type");
assert(!TargetType->isDependentType() && "param type still dependent");
-
- if (VD->getDeclContext()->isRecord() &&
- (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) {
- // If the value is a class member, we might have a pointer-to-member.
- // Determine whether the non-type template template parameter is of
- // pointer-to-member type. If so, we need to build an appropriate
- // expression for a pointer-to-member, since a "normal" DeclRefExpr
- // would refer to the member itself.
- if (TargetType->isMemberPointerType()) {
- QualType ClassType
- = SemaRef.Context.getTypeDeclType(
- cast<RecordDecl>(VD->getDeclContext()));
- NestedNameSpecifier *Qualifier
- = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
- ClassType.getTypePtr());
- CXXScopeSpec SS;
- SS.setScopeRep(Qualifier);
- OwningExprResult RefExpr
- = SemaRef.BuildDeclRefExpr(VD,
- VD->getType().getNonReferenceType(),
- E->getLocation(),
- &SS);
- if (RefExpr.isInvalid())
- return SemaRef.ExprError();
-
- RefExpr = SemaRef.CreateBuiltinUnaryOp(E->getLocation(),
- UnaryOperator::AddrOf,
- move(RefExpr));
- assert(!RefExpr.isInvalid() &&
- SemaRef.Context.hasSameType(((Expr*) RefExpr.get())->getType(),
- TargetType));
- return move(RefExpr);
- }
- }
-
- QualType T = VD->getType().getNonReferenceType();
-
- if (TargetType->isPointerType()) {
- // C++03 [temp.arg.nontype]p5:
- // - For a non-type template-parameter of type pointer to
- // object, qualification conversions and the array-to-pointer
- // conversion are applied.
- // - For a non-type template-parameter of type pointer to
- // function, only the function-to-pointer conversion is
- // applied.
-
- OwningExprResult RefExpr
- = SemaRef.BuildDeclRefExpr(VD, T, E->getLocation());
- if (RefExpr.isInvalid())
- return SemaRef.ExprError();
-
- // Decay functions and arrays.
- Expr *RefE = (Expr *)RefExpr.get();
- SemaRef.DefaultFunctionArrayConversion(RefE);
- if (RefE != RefExpr.get()) {
- RefExpr.release();
- RefExpr = SemaRef.Owned(RefE);
- }
-
- // Qualification conversions.
- RefExpr.release();
- SemaRef.ImpCastExprToType(RefE, TargetType.getUnqualifiedType(),
- CastExpr::CK_NoOp);
- return SemaRef.Owned(RefE);
- }
-
- // If the non-type template parameter has reference type, qualify the
- // resulting declaration reference with the extra qualifiers on the
- // type that the reference refers to.
- if (const ReferenceType *TargetRef = TargetType->getAs<ReferenceType>())
- T = SemaRef.Context.getQualifiedType(T,
- TargetRef->getPointeeType().getQualifiers());
-
- return SemaRef.BuildDeclRefExpr(VD, T, E->getLocation());
+ return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg,
+ TargetType,
+ E->getLocation());
}
- assert(Arg.getKind() == TemplateArgument::Integral);
- QualType T = Arg.getIntegralType();
- if (T->isCharType() || T->isWideCharType())
- return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
- Arg.getAsIntegral()->getZExtValue(),
- T->isWideCharType(),
- T,
- E->getSourceRange().getBegin()));
- if (T->isBooleanType())
- return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
- Arg.getAsIntegral()->getBoolValue(),
- T,
- E->getSourceRange().getBegin()));
-
- assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
- return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
- *Arg.getAsIntegral(),
- T,
- E->getSourceRange().getBegin()));
+ return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg,
+ E->getSourceRange().getBegin());
}
@@ -873,8 +797,11 @@ TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
llvm::SmallVectorImpl<QualType> &PTypes,
llvm::SmallVectorImpl<ParmVarDecl*> &PVars) {
// Create a local instantiation scope for the parameters.
- Sema::LocalInstantiationScope
- Scope(SemaRef, SemaRef.CurrentInstantiationScope != 0);
+ // FIXME: When we implement the C++0x late-specified return type,
+ // we will need to move this scope out to the function type itself.
+ bool IsTemporaryScope = (SemaRef.CurrentInstantiationScope != 0);
+ Sema::LocalInstantiationScope Scope(SemaRef, IsTemporaryScope,
+ IsTemporaryScope);
if (TreeTransform<TemplateInstantiator>::
TransformFunctionTypeParams(TL, PTypes, PVars))
@@ -1159,6 +1086,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
DeclContext *PreviousContext = CurContext;
CurContext = Instantiation;
+ // If this is an instantiation of a local class, merge this local
+ // instantiation scope with the enclosing scope. Otherwise, every
+ // instantiation of a class has its own local instantiation scope.
+ bool MergeWithParentScope = !Instantiation->isDefinedOutsideFunctionOrMethod();
+ Sema::LocalInstantiationScope Scope(*this, MergeWithParentScope);
+
// Start the definition of this instantiation.
Instantiation->startDefinition();
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index dbe041c..3375ccc 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
@@ -285,17 +286,19 @@ static bool InstantiateInitializer(Sema &S, Expr *Init,
}
if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) {
- if (InstantiateInitializationArguments(S,
- Construct->getArgs(),
- Construct->getNumArgs(),
- TemplateArgs,
- CommaLocs, NewArgs))
- return true;
-
- // FIXME: Fake locations!
- LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart());
- RParenLoc = CommaLocs.empty()? LParenLoc : CommaLocs.back();
- return false;
+ if (!isa<CXXTemporaryObjectExpr>(Construct)) {
+ if (InstantiateInitializationArguments(S,
+ Construct->getArgs(),
+ Construct->getNumArgs(),
+ TemplateArgs,
+ CommaLocs, NewArgs))
+ return true;
+
+ // FIXME: Fake locations!
+ LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart());
+ RParenLoc = CommaLocs.empty()? LParenLoc : CommaLocs.back();
+ return false;
+ }
}
Sema::OwningExprResult Result = S.SubstExpr(Init, TemplateArgs);
@@ -477,13 +480,17 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
// Handle friend type expressions by simply substituting template
// parameters into the pattern type.
- if (Type *Ty = D->getFriendType()) {
- QualType T = SemaRef.SubstType(QualType(Ty,0), TemplateArgs,
- D->getLocation(), DeclarationName());
- if (T.isNull()) return 0;
+ if (TypeSourceInfo *Ty = D->getFriendType()) {
+ TypeSourceInfo *InstTy =
+ SemaRef.SubstType(Ty, TemplateArgs,
+ D->getLocation(), DeclarationName());
+ if (!InstTy) return 0;
+
+ // This assertion is valid because the source type was necessarily
+ // an elaborated-type-specifier with a record tag.
+ assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType());
- assert(getLangOptions().CPlusPlus0x || T->isRecordType());
- FU = T.getTypePtr();
+ FU = InstTy;
// Handle everything else by appropriate substitution.
} else {
@@ -496,22 +503,12 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
Decl *NewND;
// Hack to make this work almost well pending a rewrite.
- if (ND->getDeclContext()->isRecord()) {
- if (!ND->getDeclContext()->isDependentContext()) {
- NewND = SemaRef.FindInstantiatedDecl(D->getLocation(), ND,
- TemplateArgs);
- } else {
- // FIXME: Hack to avoid crashing when incorrectly trying to instantiate
- // templated friend declarations. This doesn't produce a correct AST;
- // however this is sufficient for some AST analysis. The real solution
- // must be put in place during the pending rewrite. See PR5848.
- return 0;
- }
- } else if (D->wasSpecialization()) {
+ if (D->wasSpecialization()) {
// Totally egregious hack to work around PR5866
return 0;
- } else
+ } else {
NewND = Visit(ND);
+ }
if (!NewND) return 0;
FU = cast<NamedDecl>(NewND);
@@ -638,6 +635,8 @@ namespace {
}
Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
+
// Create a local instantiation scope for this class template, which
// will contain the instantiations of the template parameters.
Sema::LocalInstantiationScope Scope(SemaRef);
@@ -647,32 +646,106 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
return NULL;
CXXRecordDecl *Pattern = D->getTemplatedDecl();
+
+ // Instantiate the qualifier. We have to do this first in case
+ // we're a friend declaration, because if we are then we need to put
+ // the new declaration in the appropriate context.
+ NestedNameSpecifier *Qualifier = Pattern->getQualifier();
+ if (Qualifier) {
+ Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
+ Pattern->getQualifierRange(),
+ TemplateArgs);
+ if (!Qualifier) return 0;
+ }
+
+ CXXRecordDecl *PrevDecl = 0;
+ ClassTemplateDecl *PrevClassTemplate = 0;
+
+ // If this isn't a friend, then it's a member template, in which
+ // case we just want to build the instantiation in the
+ // specialization. If it is a friend, we want to build it in
+ // the appropriate context.
+ DeclContext *DC = Owner;
+ if (isFriend) {
+ if (Qualifier) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ SS.setRange(Pattern->getQualifierRange());
+ DC = SemaRef.computeDeclContext(SS);
+ if (!DC) return 0;
+ } else {
+ DC = SemaRef.FindInstantiatedContext(Pattern->getLocation(),
+ Pattern->getDeclContext(),
+ TemplateArgs);
+ }
+
+ // Look for a previous declaration of the template in the owning
+ // context.
+ LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(),
+ Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ SemaRef.LookupQualifiedName(R, DC);
+
+ if (R.isSingleResult()) {
+ PrevClassTemplate = R.getAsSingle<ClassTemplateDecl>();
+ if (PrevClassTemplate)
+ PrevDecl = PrevClassTemplate->getTemplatedDecl();
+ }
+
+ if (!PrevClassTemplate && Qualifier) {
+ SemaRef.Diag(Pattern->getLocation(), diag::err_not_tag_in_scope)
+ << D->getTemplatedDecl()->getTagKind() << Pattern->getDeclName() << DC
+ << Pattern->getQualifierRange();
+ return 0;
+ }
+
+ if (PrevClassTemplate) {
+ TemplateParameterList *PrevParams
+ = PrevClassTemplate->getTemplateParameters();
+
+ // Make sure the parameter lists match.
+ if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams,
+ /*Complain=*/true,
+ Sema::TPL_TemplateMatch))
+ return 0;
+
+ // Do some additional validation, then merge default arguments
+ // from the existing declarations.
+ if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
+ Sema::TPC_ClassTemplate))
+ return 0;
+ }
+ }
+
CXXRecordDecl *RecordInst
- = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner,
+ = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), DC,
Pattern->getLocation(), Pattern->getIdentifier(),
- Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL,
+ Pattern->getTagKeywordLoc(), PrevDecl,
/*DelayTypeCreation=*/true);
- // Substitute the nested name specifier, if any.
- if (SubstQualifier(Pattern, RecordInst))
- return 0;
+ if (Qualifier)
+ RecordInst->setQualifierInfo(Qualifier, Pattern->getQualifierRange());
ClassTemplateDecl *Inst
- = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getIdentifier(), InstParams, RecordInst, 0);
+ = ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(),
+ D->getIdentifier(), InstParams, RecordInst,
+ PrevClassTemplate);
RecordInst->setDescribedClassTemplate(Inst);
- if (D->getFriendObjectKind())
- Inst->setObjectOfFriendDecl(true);
- else
+ if (isFriend) {
+ Inst->setObjectOfFriendDecl(PrevClassTemplate != 0);
+ // TODO: do we want to track the instantiation progeny of this
+ // friend target decl?
+ } else {
Inst->setAccess(D->getAccess());
- Inst->setInstantiatedFromMemberTemplate(D);
+ Inst->setInstantiatedFromMemberTemplate(D);
+ }
// Trigger creation of the type for the instantiation.
SemaRef.Context.getInjectedClassNameType(RecordInst,
Inst->getInjectedClassNameSpecialization(SemaRef.Context));
// Finish handling of friends.
- if (Inst->getFriendObjectKind()) {
+ if (isFriend) {
+ DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false);
return Inst;
}
@@ -762,16 +835,18 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
assert(InstTemplate &&
"VisitFunctionDecl/CXXMethodDecl didn't create a template!");
+ bool isFriend = (InstTemplate->getFriendObjectKind() != Decl::FOK_None);
+
// Link the instantiation back to the pattern *unless* this is a
// non-definition friend declaration.
if (!InstTemplate->getInstantiatedFromMemberTemplate() &&
- !(InstTemplate->getFriendObjectKind() &&
- !D->getTemplatedDecl()->isThisDeclarationADefinition()))
+ !(isFriend && !D->getTemplatedDecl()->isThisDeclarationADefinition()))
InstTemplate->setInstantiatedFromMemberTemplate(D);
- // Add non-friends into the owner.
- if (!InstTemplate->getFriendObjectKind())
+ // Make declarations visible in the appropriate context.
+ if (!isFriend)
Owner->addDecl(InstTemplate);
+
return InstTemplate;
}
@@ -843,6 +918,12 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return Info->Function;
}
+ bool isFriend;
+ if (FunctionTemplate)
+ isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None);
+ else
+ isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
+
bool MergeWithParentScope = (TemplateParams != 0) ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
@@ -855,14 +936,29 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return 0;
QualType T = TInfo->getType();
+ NestedNameSpecifier *Qualifier = D->getQualifier();
+ if (Qualifier) {
+ Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
+ D->getQualifierRange(),
+ TemplateArgs);
+ if (!Qualifier) return 0;
+ }
+
// If we're instantiating a local function declaration, put the result
// in the owner; otherwise we need to find the instantiated context.
DeclContext *DC;
if (D->getDeclContext()->isFunctionOrMethod())
DC = Owner;
- else
+ else if (isFriend && Qualifier) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ SS.setRange(D->getQualifierRange());
+ DC = SemaRef.computeDeclContext(SS);
+ if (!DC) return 0;
+ } else {
DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(),
TemplateArgs);
+ }
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
@@ -870,11 +966,16 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
D->getStorageClass(),
D->isInlineSpecified(), D->hasWrittenPrototype());
- // Substitute the nested name specifier, if any.
- if (SubstQualifier(D, Function))
- return 0;
+ if (Qualifier)
+ Function->setQualifierInfo(Qualifier, D->getQualifierRange());
- Function->setLexicalDeclContext(Owner);
+ DeclContext *LexicalDC = Owner;
+ if (!isFriend && D->isOutOfLine()) {
+ assert(D->getDeclContext()->isFileContext());
+ LexicalDC = D->getDeclContext();
+ }
+
+ Function->setLexicalDeclContext(LexicalDC);
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
@@ -896,17 +997,29 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
// which means substituting int for T, but leaving "f" as a friend function
// template.
// Build the function template itself.
- FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner,
+ FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, DC,
Function->getLocation(),
Function->getDeclName(),
TemplateParams, Function);
Function->setDescribedFunctionTemplate(FunctionTemplate);
- FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+
+ FunctionTemplate->setLexicalDeclContext(LexicalDC);
+
+ if (isFriend && D->isThisDeclarationADefinition()) {
+ // TODO: should we remember this connection regardless of whether
+ // the friend declaration provided a body?
+ FunctionTemplate->setInstantiatedFromMemberTemplate(
+ D->getDescribedFunctionTemplate());
+ }
} else if (FunctionTemplate) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
+ } else if (isFriend && D->isThisDeclarationADefinition()) {
+ // TODO: should we remember this connection regardless of whether
+ // the friend declaration provided a body?
+ Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
if (InitFunctionInstantiation(Function, D))
@@ -938,9 +1051,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
// If the original function was part of a friend declaration,
// inherit its namespace state and add it to the owner.
- NamedDecl *FromFriendD
- = TemplateParams? cast<NamedDecl>(D->getDescribedFunctionTemplate()) : D;
- if (FromFriendD->getFriendObjectKind()) {
+ if (isFriend) {
NamedDecl *ToFriendD = 0;
NamedDecl *PrevDecl;
if (TemplateParams) {
@@ -951,11 +1062,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrevDecl = Function->getPreviousDeclaration();
}
ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL);
- if (!Owner->isDependentContext() && !PrevDecl)
- DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false);
-
- if (!TemplateParams)
- Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+ DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false);
}
return Function;
@@ -985,6 +1092,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
return Info->Function;
}
+ bool isFriend;
+ if (FunctionTemplate)
+ isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None);
+ else
+ isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
+
bool MergeWithParentScope = (TemplateParams != 0) ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
@@ -997,8 +1110,31 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
return 0;
QualType T = TInfo->getType();
+ NestedNameSpecifier *Qualifier = D->getQualifier();
+ if (Qualifier) {
+ Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
+ D->getQualifierRange(),
+ TemplateArgs);
+ if (!Qualifier) return 0;
+ }
+
+ DeclContext *DC = Owner;
+ if (isFriend) {
+ if (Qualifier) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ SS.setRange(D->getQualifierRange());
+ DC = SemaRef.computeDeclContext(SS);
+ } else {
+ DC = SemaRef.FindInstantiatedContext(D->getLocation(),
+ D->getDeclContext(),
+ TemplateArgs);
+ }
+ if (!DC) return 0;
+ }
+
// Build the instantiated method declaration.
- CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXMethodDecl *Method = 0;
DeclarationName Name = D->getDeclName();
@@ -1035,9 +1171,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
D->isStatic(), D->isInlineSpecified());
}
- // Substitute the nested name specifier, if any.
- if (SubstQualifier(D, Method))
- return 0;
+ if (Qualifier)
+ Method->setQualifierInfo(Qualifier, D->getQualifierRange());
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
@@ -1057,7 +1192,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->getLocation(),
Method->getDeclName(),
TemplateParams, Method);
- if (D->isOutOfLine())
+ if (isFriend) {
+ FunctionTemplate->setLexicalDeclContext(Owner);
+ FunctionTemplate->setObjectOfFriendDecl(true);
+ } else if (D->isOutOfLine())
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (FunctionTemplate) {
@@ -1065,7 +1203,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setFunctionTemplateSpecialization(FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
- } else {
+ } else if (!isFriend) {
// Record that this is an instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
@@ -1073,7 +1211,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
- if (D->isOutOfLine())
+ if (isFriend) {
+ Method->setLexicalDeclContext(Owner);
+ Method->setObjectOfFriendDecl(true);
+ } else if (D->isOutOfLine())
Method->setLexicalDeclContext(D->getLexicalDeclContext());
// Attach the parameters
@@ -1087,8 +1228,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
LookupResult Previous(SemaRef, Name, SourceLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
- if (!FunctionTemplate || TemplateParams) {
- SemaRef.LookupQualifiedName(Previous, Owner);
+ if (!FunctionTemplate || TemplateParams || isFriend) {
+ SemaRef.LookupQualifiedName(Previous, Record);
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
@@ -1108,9 +1249,19 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setAccess(D->getAccess());
- if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) &&
- !Method->getFriendObjectKind())
- Owner->addDecl(Method);
+ if (FunctionTemplate) {
+ // If there's a function template, let our caller handle it.
+ } 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
+ Owner->addDecl(DeclToAdd);
+ }
return Method;
}
@@ -1694,8 +1845,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
Proto->hasAnyExceptionSpec(),
Exceptions.size(),
Exceptions.data(),
- Proto->getNoReturnAttr(),
- Proto->getCallConv()));
+ Proto->getExtInfo()));
}
return false;
@@ -1839,6 +1989,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
/*IsInstantiation=*/true);
+ PerformDependentDiagnostics(PatternDecl, TemplateArgs);
+
CurContext = PreviousContext;
DeclGroupRef DG(Function);
@@ -2475,3 +2627,17 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true);
}
}
+
+void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ for (DeclContext::ddiag_iterator I = Pattern->ddiag_begin(),
+ E = Pattern->ddiag_end(); I != E; ++I) {
+ DependentDiagnostic *DD = *I;
+
+ switch (DD->getKind()) {
+ case DependentDiagnostic::Access:
+ HandleDependentAccessCheck(*DD, TemplateArgs);
+ break;
+ }
+ }
+}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index a79853a..8278691 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -183,8 +183,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
if (DS.isEmpty()) {
TheSema.Diag(DeclLoc, diag::ext_missing_declspec)
<< DS.getSourceRange()
- << CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(),
- "int");
+ << FixItHint::CreateInsertion(DS.getSourceRange().getBegin(), "int");
}
} else if (!DS.hasTypeSpecifier()) {
// C99 and C++ require a type specifier. For example, C99 6.7.2p2 says:
@@ -680,8 +679,11 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
return QualType();
}
if (ConstVal == 0) {
- // GCC accepts zero sized static arrays.
- Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size)
+ // GCC accepts zero sized static arrays. We allow them when
+ // we're not in a SFINAE context.
+ Diag(ArraySize->getLocStart(),
+ isSFINAEContext()? diag::err_typecheck_zero_array_size
+ : diag::ext_typecheck_zero_array_size)
<< ArraySize->getSourceRange();
}
T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
@@ -798,7 +800,8 @@ QualType Sema::BuildFunctionType(QualType T,
return QualType();
return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic,
- Quals, false, false, 0, 0, false, CC_Default);
+ Quals, false, false, 0, 0,
+ FunctionType::ExtInfo());
}
/// \brief Build a member pointer type \c T Class::*.
@@ -1135,7 +1138,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FTI.hasExceptionSpec,
FTI.hasAnyExceptionSpec,
Exceptions.size(), Exceptions.data(),
- false, CC_Default);
+ FunctionType::ExtInfo());
} else if (FTI.isVariadic) {
// We allow a zero-parameter variadic function in C if the
// function is marked with the "overloadable"
@@ -1152,7 +1155,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (!Overloadable)
Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg);
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0,
- false, false, 0, 0, false, CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
} else {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T);
@@ -1228,7 +1232,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FTI.hasExceptionSpec,
FTI.hasAnyExceptionSpec,
Exceptions.size(), Exceptions.data(),
- false, CC_Default);
+ FunctionType::ExtInfo());
}
// For GCC compatibility, we allow attributes that apply only to
@@ -1257,7 +1261,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
NestedNameSpecifier *NNSPrefix = NNS->getPrefix();
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
- ClsType = Context.getTypenameType(NNSPrefix, NNS->getAsIdentifier());
+ ClsType = Context.getDependentNameType(ETK_None, NNSPrefix,
+ NNS->getAsIdentifier());
break;
case NestedNameSpecifier::Namespace:
@@ -1326,7 +1331,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Strip the cv-quals from the type.
T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(),
FnTy->getNumArgs(), FnTy->isVariadic(), 0,
- false, false, 0, 0, false, CC_Default);
+ false, false, 0, 0, FunctionType::ExtInfo());
}
}
@@ -1734,6 +1739,30 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
return false;
}
+ if (Attr.getKind() == AttributeList::AT_regparm) {
+ // The warning is emitted elsewhere
+ if (Attr.getNumArgs() != 1) {
+ return false;
+ }
+
+ // Delay if this is not a function or pointer to block.
+ if (!Type->isFunctionPointerType()
+ && !Type->isBlockPointerType()
+ && !Type->isFunctionType())
+ return true;
+
+ // Otherwise we can process right away.
+ Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt NumParams(32);
+
+ // The warning is emitted elsewhere
+ if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context))
+ return false;
+
+ Type = S.Context.getRegParmType(Type, NumParams.getZExtValue());
+ return false;
+ }
+
// Otherwise, a calling convention.
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
@@ -1863,6 +1892,7 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result,
case AttributeList::AT_cdecl:
case AttributeList::AT_fastcall:
case AttributeList::AT_stdcall:
+ case AttributeList::AT_regparm:
// Don't process these on the DeclSpec.
if (IsDeclSpec ||
ProcessFnAttr(S, Result, *AL))
@@ -1942,6 +1972,16 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
if (diag == 0)
return true;
+ const TagType *Tag = 0;
+ if (const RecordType *Record = T->getAs<RecordType>())
+ Tag = Record;
+ else if (const EnumType *Enum = T->getAs<EnumType>())
+ Tag = Enum;
+
+ // Avoid diagnosing invalid decls as incomplete.
+ if (Tag && Tag->getDecl()->isInvalidDecl())
+ return true;
+
// We have an incomplete type. Produce a diagnostic.
Diag(Loc, PD) << T;
@@ -1950,13 +1990,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
Diag(Note.first, Note.second);
// If the type was a forward declaration of a class/struct/union
- // type, produce
- const TagType *Tag = 0;
- if (const RecordType *Record = T->getAs<RecordType>())
- Tag = Record;
- else if (const EnumType *Enum = T->getAs<EnumType>())
- Tag = Enum;
-
+ // type, produce a note.
if (Tag && !Tag->getDecl()->isInvalidDecl())
Diag(Tag->getDecl()->getLocation(),
Tag->isBeingDefined() ? diag::note_type_being_defined
@@ -1966,6 +2000,18 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return true;
}
+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)));
+}
+
/// \brief Retrieve a version of the type 'T' that is qualified by the
/// nested-name-specifier contained in SS.
QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
@@ -1983,7 +2029,7 @@ QualType Sema::BuildTypeofExprType(Expr *E) {
// function template specialization wherever deduction cannot occur.
if (FunctionDecl *Specialization
= ResolveSingleFunctionTemplateSpecialization(E)) {
- E = FixOverloadedFunctionReference(E, Specialization);
+ E = FixOverloadedFunctionReference(E, Specialization, Specialization);
if (!E)
return QualType();
} else {
@@ -2003,7 +2049,7 @@ QualType Sema::BuildDecltypeType(Expr *E) {
// function template specialization wherever deduction cannot occur.
if (FunctionDecl *Specialization
= ResolveSingleFunctionTemplateSpecialization(E)) {
- E = FixOverloadedFunctionReference(E, Specialization);
+ E = FixOverloadedFunctionReference(E, Specialization, Specialization);
if (!E)
return QualType();
} else {
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index d6f3352..f9ffd3f 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -537,18 +537,22 @@ public:
/// \brief Build a new typename type that refers to a template-id.
///
- /// By default, builds a new TypenameType type from the nested-name-specifier
+ /// By default, builds a new DependentNameType type from the
+ /// nested-name-specifier
/// and the given type. Subclasses may override this routine to provide
/// different behavior.
- QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) {
+ QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, QualType T) {
if (NNS->isDependent()) {
+ // If the name is still dependent, just build a new dependent name type.
CXXScopeSpec SS;
SS.setScopeRep(NNS);
if (!SemaRef.computeDeclContext(SS))
- return SemaRef.Context.getTypenameType(NNS,
+ return SemaRef.Context.getDependentNameType(Keyword, NNS,
cast<TemplateSpecializationType>(T));
}
-
+
+ // FIXME: Handle elaborated-type-specifiers separately.
return SemaRef.Context.getQualifiedNameType(NNS, T);
}
@@ -557,10 +561,80 @@ public:
/// By default, performs semantic analysis when building the typename type
/// (or qualified name type). Subclasses may override this routine to provide
/// different behavior.
- QualType RebuildTypenameType(NestedNameSpecifier *NNS,
- const IdentifierInfo *Id,
- SourceRange SR) {
- return SemaRef.CheckTypenameType(NNS, *Id, SR);
+ QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const IdentifierInfo *Id,
+ SourceRange SR) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(NNS);
+
+ if (NNS->isDependent()) {
+ // If the name is still dependent, just build a new dependent name type.
+ if (!SemaRef.computeDeclContext(SS))
+ return SemaRef.Context.getDependentNameType(Keyword, NNS, Id);
+ }
+
+ TagDecl::TagKind Kind = TagDecl::TK_enum;
+ switch (Keyword) {
+ case ETK_None:
+ // FIXME: Note the lack of the "typename" specifier!
+ // Fall through
+ case ETK_Typename:
+ return SemaRef.CheckTypenameType(NNS, *Id, SR);
+
+ case ETK_Class: Kind = TagDecl::TK_class; break;
+ case ETK_Struct: Kind = TagDecl::TK_struct; break;
+ case ETK_Union: Kind = TagDecl::TK_union; break;
+ case ETK_Enum: Kind = TagDecl::TK_enum; break;
+ }
+
+ // We had a dependent elaborated-type-specifier that as been transformed
+ // into a non-dependent elaborated-type-specifier. Find the tag we're
+ // referring to.
+ LookupResult Result(SemaRef, Id, SR.getEnd(), Sema::LookupTagName);
+ DeclContext *DC = SemaRef.computeDeclContext(SS, false);
+ if (!DC)
+ return QualType();
+
+ TagDecl *Tag = 0;
+ SemaRef.LookupQualifiedName(Result, DC);
+ switch (Result.getResultKind()) {
+ 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");
+ return QualType();
+
+ case LookupResult::Ambiguous:
+ // Let the LookupResult structure handle ambiguities.
+ return QualType();
+ }
+
+ if (!Tag) {
+ // FIXME: Would be nice to highlight just the source range.
+ SemaRef.Diag(SR.getEnd(), diag::err_not_tag_in_scope)
+ << Kind << Id << DC;
+ return QualType();
+ }
+
+ // FIXME: Terrible location information
+ if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, SR.getEnd(), *Id)) {
+ SemaRef.Diag(SR.getBegin(), diag::err_use_with_wrong_tag) << Id;
+ SemaRef.Diag(Tag->getLocation(), diag::note_previous_use);
+ return QualType();
+ }
+
+ // Build the elaborated-type-specifier type.
+ QualType T = SemaRef.Context.getTypeDeclType(Tag);
+ T = SemaRef.Context.getQualifiedNameType(NNS, T);
+ return SemaRef.Context.getElaboratedType(T, Kind);
}
/// \brief Build a new nested-name-specifier given the prefix and an
@@ -977,6 +1051,7 @@ public:
SourceRange QualifierRange,
SourceLocation MemberLoc,
ValueDecl *Member,
+ NamedDecl *FoundDecl,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
NamedDecl *FirstQualifierInScope) {
if (!Member->getDeclName()) {
@@ -984,7 +1059,8 @@ public:
assert(!Qualifier && "Can't have an unnamed field with a qualifier!");
Expr *BaseExpr = Base.takeAs<Expr>();
- if (getSema().PerformObjectMemberConversion(BaseExpr, Qualifier, Member))
+ if (getSema().PerformObjectMemberConversion(BaseExpr, Qualifier,
+ FoundDecl, Member))
return getSema().ExprError();
MemberExpr *ME =
@@ -1002,9 +1078,11 @@ public:
QualType BaseType = ((Expr*) Base.get())->getType();
+ // FIXME: this involves duplicating earlier analysis in a lot of
+ // cases; we should avoid this when possible.
LookupResult R(getSema(), Member->getDeclName(), MemberLoc,
Sema::LookupMemberName);
- R.addDecl(Member);
+ R.addDecl(FoundDecl);
R.resolveKind();
return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
@@ -2992,10 +3070,10 @@ TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB,
}
template<typename Derived>
-QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB,
- TypenameTypeLoc TL,
+QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
+ DependentNameTypeLoc TL,
QualType ObjectType) {
- TypenameType *T = TL.getTypePtr();
+ DependentNameType *T = TL.getTypePtr();
/* FIXME: preserve source information better than this */
SourceRange SR(TL.getNameLoc());
@@ -3019,14 +3097,16 @@ QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB,
NewTemplateId == QualType(TemplateId, 0))
return QualType(T, 0);
- Result = getDerived().RebuildTypenameType(NNS, NewTemplateId);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ NewTemplateId);
} else {
- Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(), SR);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ T->getIdentifier(), SR);
}
if (Result.isNull())
return QualType();
- TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result);
+ DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
@@ -3868,10 +3948,21 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
if (!Member)
return SemaRef.ExprError();
+ NamedDecl *FoundDecl = E->getFoundDecl();
+ if (FoundDecl == E->getMemberDecl()) {
+ FoundDecl = Member;
+ } else {
+ FoundDecl = cast_or_null<NamedDecl>(
+ getDerived().TransformDecl(E->getMemberLoc(), FoundDecl));
+ if (!FoundDecl)
+ return SemaRef.ExprError();
+ }
+
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase() &&
Qualifier == E->getQualifier() &&
Member == E->getMemberDecl() &&
+ FoundDecl == E->getFoundDecl() &&
!E->hasExplicitTemplateArgumentList()) {
// Mark it referenced in the new context regardless.
@@ -3908,6 +3999,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
E->getQualifierRange(),
E->getMemberLoc(),
Member,
+ FoundDecl,
(E->hasExplicitTemplateArgumentList()
? &TransArgs : 0),
FirstQualifierInScope);
@@ -5118,7 +5210,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
!ArgumentChanged) {
// FIXME: Instantiation-specific
SemaRef.MarkDeclarationReferenced(E->getTypeBeginLoc(), Constructor);
- return SemaRef.Owned(E->Retain());
+ return SemaRef.MaybeBindToTemporary(E->Retain());
}
// FIXME: Bogus location information
OpenPOWER on IntegriCloud