aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2010-01-23 11:10:26 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2010-01-23 11:10:26 +0000
commit5044f5c816adfd5cba17f1adee1a10127296d0bf (patch)
treec69d3f4f13d508570bb5257a6aea735f88bdf09c /lib/Sema
parentee791dde723a2089c681d2ab6a9d4f96379d5f49 (diff)
downloadsrc-5044f5c816adfd5cba17f1adee1a10127296d0bf.tar.gz
src-5044f5c816adfd5cba17f1adee1a10127296d0bf.zip
Notes
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp4
-rw-r--r--lib/Sema/Lookup.h104
-rw-r--r--lib/Sema/Sema.h69
-rw-r--r--lib/Sema/SemaAccess.cpp99
-rw-r--r--lib/Sema/SemaCXXCast.cpp31
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp26
-rw-r--r--lib/Sema/SemaChecking.cpp527
-rw-r--r--lib/Sema/SemaCodeComplete.cpp36
-rw-r--r--lib/Sema/SemaDecl.cpp418
-rw-r--r--lib/Sema/SemaDeclCXX.cpp59
-rw-r--r--lib/Sema/SemaDeclObjC.cpp214
-rw-r--r--lib/Sema/SemaExpr.cpp112
-rw-r--r--lib/Sema/SemaExprCXX.cpp20
-rw-r--r--lib/Sema/SemaExprObjC.cpp12
-rw-r--r--lib/Sema/SemaInit.cpp38
-rw-r--r--lib/Sema/SemaInit.h15
-rw-r--r--lib/Sema/SemaLookup.cpp42
-rw-r--r--lib/Sema/SemaOverload.cpp269
-rw-r--r--lib/Sema/SemaOverload.h11
-rw-r--r--lib/Sema/SemaStmt.cpp8
-rw-r--r--lib/Sema/SemaTemplate.cpp25
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp57
-rw-r--r--lib/Sema/SemaType.cpp15
-rw-r--r--lib/Sema/TreeTransform.h133
24 files changed, 1559 insertions, 785 deletions
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index fbd14502b7e5..8c4caafeac24 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -572,11 +572,11 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
break;
case Decl::ObjCImplementation:
- Kind = CXCursor_ObjCClassDefn;
+ Kind = CXCursor_ObjCImplementationDecl;
break;
case Decl::ObjCCategoryImpl:
- Kind = CXCursor_ObjCCategoryDefn;
+ Kind = CXCursor_ObjCCategoryImplDecl;
break;
default:
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index 9064de6aa019..f4cea2e88a6d 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -123,9 +123,7 @@ public:
Temporary
};
- typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy;
- typedef DeclsTy::const_iterator iterator;
-
+ typedef UnresolvedSetImpl::iterator iterator;
typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS);
LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc,
@@ -133,6 +131,7 @@ public:
Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration)
: ResultKind(NotFound),
Paths(0),
+ NamingClass(0),
SemaRef(SemaRef),
Name(Name),
NameLoc(NameLoc),
@@ -152,6 +151,7 @@ public:
LookupResult(TemporaryToken _, const LookupResult &Other)
: ResultKind(NotFound),
Paths(0),
+ NamingClass(0),
SemaRef(Other.SemaRef),
Name(Other.Name),
NameLoc(Other.NameLoc),
@@ -224,8 +224,8 @@ public:
return Ambiguity;
}
- iterator begin() const { return Decls.begin(); }
- iterator end() const { return Decls.end(); }
+ iterator begin() const { return iterator(Decls.begin()); }
+ iterator end() const { return iterator(Decls.end()); }
/// \brief Return true if no decls were found
bool empty() const { return Decls.empty(); }
@@ -247,32 +247,57 @@ public:
return IDNS;
}
- /// \brief Add a declaration to these results. Does not test the
- /// acceptance criteria.
+ /// \brief Returns whether these results arose from performing a
+ /// lookup into a class.
+ bool isClassLookup() const {
+ return NamingClass != 0;
+ }
+
+ /// \brief Returns the 'naming class' for this lookup, i.e. the
+ /// class which was looked into to find these results.
+ ///
+ /// C++0x [class.access.base]p5:
+ /// The access to a member is affected by the class in which the
+ /// member is named. This naming class is the class in which the
+ /// member name was looked up and found. [Note: this class can be
+ /// explicit, e.g., when a qualified-id is used, or implicit,
+ /// e.g., when a class member access operator (5.2.5) is used
+ /// (including cases where an implicit "this->" is added). If both
+ /// a class member access operator and a qualified-id are used to
+ /// name the member (as in p->T::m), the class naming the member
+ /// is the class named by the nested-name-specifier of the
+ /// qualified-id (that is, T). -- end note ]
+ ///
+ /// This is set by the lookup routines when they find results in a class.
+ CXXRecordDecl *getNamingClass() const {
+ return NamingClass;
+ }
+
+ /// \brief Sets the 'naming class' for this lookup.
+ void setNamingClass(CXXRecordDecl *Record) {
+ NamingClass = Record;
+ }
+
+ /// \brief Add a declaration to these results with its natural access.
+ /// Does not test the acceptance criteria.
void addDecl(NamedDecl *D) {
- Decls.push_back(D);
+ addDecl(D, D->getAccess());
+ }
+
+ /// \brief Add a declaration to these results with the given access.
+ /// Does not test the acceptance criteria.
+ void addDecl(NamedDecl *D, AccessSpecifier AS) {
+ Decls.addDecl(D, AS);
ResultKind = Found;
}
/// \brief Add all the declarations from another set of lookup
/// results.
void addAllDecls(const LookupResult &Other) {
- Decls.append(Other.begin(), Other.end());
+ Decls.append(Other.Decls.begin(), Other.Decls.end());
ResultKind = Found;
}
- /// \brief Hides a set of declarations.
- template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) {
- unsigned I = 0, N = Decls.size();
- while (I < N) {
- if (Set.count(Decls[I]))
- Decls[I] = Decls[--N];
- else
- I++;
- }
- Decls.set_size(N);
- }
-
/// \brief Determine whether no result was found because we could not
/// search into dependent base classes of the current instantiation.
bool wasNotFoundInCurrentInstantiation() const {
@@ -319,13 +344,13 @@ public:
NamedDecl *getFoundDecl() const {
assert(getResultKind() == Found
&& "getFoundDecl called on non-unique result");
- return Decls[0]->getUnderlyingDecl();
+ return (*begin())->getUnderlyingDecl();
}
/// Fetches a representative decl. Useful for lazy diagnostics.
NamedDecl *getRepresentativeDecl() const {
assert(!Decls.empty() && "cannot get representative of empty set");
- return Decls[0];
+ return *begin();
}
/// \brief Asks if the result is a single tag decl.
@@ -403,7 +428,7 @@ public:
/// sugared.
class Filter {
LookupResult &Results;
- unsigned I;
+ LookupResult::iterator I;
bool Changed;
#ifndef NDEBUG
bool CalledDone;
@@ -411,7 +436,7 @@ public:
friend class LookupResult;
Filter(LookupResult &Results)
- : Results(Results), I(0), Changed(false)
+ : Results(Results), I(Results.begin()), Changed(false)
#ifndef NDEBUG
, CalledDone(false)
#endif
@@ -426,23 +451,30 @@ public:
#endif
bool hasNext() const {
- return I != Results.Decls.size();
+ return I != Results.end();
}
NamedDecl *next() {
- assert(I < Results.Decls.size() && "next() called on empty filter");
- return Results.Decls[I++];
+ assert(I != Results.end() && "next() called on empty filter");
+ return *I++;
}
/// Erase the last element returned from this iterator.
void erase() {
- Results.Decls[--I] = Results.Decls.back();
- Results.Decls.pop_back();
+ Results.Decls.erase(--I);
Changed = true;
}
+ /// Replaces the current entry with the given one, preserving the
+ /// access bits.
void replace(NamedDecl *D) {
- Results.Decls[I-1] = D;
+ Results.Decls.replace(I-1, D);
+ Changed = true;
+ }
+
+ /// Replaces the current entry with the given one.
+ void replace(NamedDecl *D, AccessSpecifier AS) {
+ Results.Decls.replace(I-1, D, AS);
Changed = true;
}
@@ -466,6 +498,8 @@ private:
void diagnose() {
if (isAmbiguous())
SemaRef.DiagnoseAmbiguousLookup(*this);
+ else if (isClassLookup() && SemaRef.getLangOptions().AccessControl)
+ SemaRef.CheckAccess(*this);
}
void setAmbiguous(AmbiguityKind AK) {
@@ -482,7 +516,7 @@ private:
assert(ResultKind != Found || Decls.size() == 1);
assert(ResultKind != FoundOverloaded || Decls.size() > 1 ||
(Decls.size() == 1 &&
- isa<FunctionTemplateDecl>(Decls[0]->getUnderlyingDecl())));
+ isa<FunctionTemplateDecl>((*begin())->getUnderlyingDecl())));
assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved());
assert(ResultKind != Ambiguous || Decls.size() > 1 ||
(Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects));
@@ -492,8 +526,7 @@ private:
}
bool sanityCheckUnresolved() const {
- for (DeclsTy::const_iterator I = Decls.begin(), E = Decls.end();
- I != E; ++I)
+ for (iterator I = begin(), E = end(); I != E; ++I)
if (isa<UnresolvedUsingValueDecl>(*I))
return true;
return false;
@@ -504,8 +537,9 @@ private:
// Results.
LookupResultKind ResultKind;
AmbiguityKind Ambiguity; // ill-defined unless ambiguous
- DeclsTy Decls;
+ UnresolvedSet<8> Decls;
CXXBasePaths *Paths;
+ CXXRecordDecl *NamingClass;
// Parameters.
Sema &SemaRef;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index fab729299936..06e9e3ae9e64 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1291,6 +1291,17 @@ public:
ObjCContainerDecl* IDecl,
bool IncompleteImpl = false);
+ /// DiagnoseUnimplementedProperties - This routine warns on those properties
+ /// which must be implemented by this implementation.
+ void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl *CDecl,
+ const llvm::DenseSet<Selector>& InsMap);
+
+ /// CollectImmediateProperties - This routine collects all properties in
+ /// the class and its conforming protocols; but not those it its super class.
+ void CollectImmediateProperties(ObjCContainerDecl *CDecl,
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap);
+
/// AtomicPropertySetterGetterRules - This routine enforces the rule (via
/// warning) when atomic property has one but not the other user-declared
/// setter or getter.
@@ -1651,6 +1662,11 @@ public:
virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
TypeTy *Ty, SourceLocation RParenLoc,
ExprArg Op);
+ OwningExprResult BuildCStyleCastExpr(SourceLocation LParenLoc,
+ TypeSourceInfo *Ty,
+ SourceLocation RParenLoc,
+ ExprArg Op);
+
virtual bool TypeIsVectorType(TypeTy *Ty) {
return GetTypeFromParser(Ty)->isVectorType();
}
@@ -1658,13 +1674,18 @@ public:
OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME);
OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
SourceLocation RParenLoc, ExprArg E,
- QualType Ty);
+ TypeSourceInfo *TInfo);
virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc,
TypeTy *Ty,
SourceLocation RParenLoc,
ExprArg Op);
+ OwningExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc,
+ TypeSourceInfo *TInfo,
+ SourceLocation RParenLoc,
+ ExprArg InitExpr);
+
virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc,
MultiExprArg InitList,
SourceLocation RParenLoc);
@@ -1920,6 +1941,13 @@ public:
ExprArg E,
SourceLocation RParenLoc);
+ OwningExprResult BuildCXXNamedCast(SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ TypeSourceInfo *Ty,
+ ExprArg E,
+ SourceRange AngleBrackets,
+ SourceRange Parens);
+
/// ActOnCXXTypeid - Parse typeid( something ).
virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
SourceLocation LParenLoc, bool isType,
@@ -2033,7 +2061,6 @@ public:
bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS);
bool isUnknownSpecialization(const CXXScopeSpec &SS);
- bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS);
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
/// global scope ('::').
@@ -2334,6 +2361,9 @@ public:
CXXBasePaths &Paths,
bool NoPrivileges = false);
+ void CheckAccess(const LookupResult &R);
+ bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access);
+
bool CheckBaseClassAccess(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
CXXBasePaths& Paths, SourceLocation AccessLoc,
@@ -3153,13 +3183,17 @@ public:
/// relevant to this particular scope).
LocalInstantiationScope *Outer;
+ /// \brief Whether we have already exited this scope.
+ bool Exited;
+
// This class is non-copyable
LocalInstantiationScope(const LocalInstantiationScope &);
LocalInstantiationScope &operator=(const LocalInstantiationScope &);
public:
LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
- : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) {
+ : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
+ Exited(false) {
if (!CombineWithOuterScope)
SemaRef.CurrentInstantiationScope = this;
else
@@ -3168,7 +3202,15 @@ public:
}
~LocalInstantiationScope() {
+ if (!Exited)
+ SemaRef.CurrentInstantiationScope = Outer;
+ }
+
+ /// \brief Exit this local instantiation scope early.
+ void Exit() {
SemaRef.CurrentInstantiationScope = Outer;
+ LocalDecls.clear();
+ Exited = true;
}
Decl *getInstantiationOf(const Decl *D) {
@@ -3215,7 +3257,16 @@ public:
/// but have not yet been performed.
std::deque<PendingImplicitInstantiation> PendingImplicitInstantiations;
- void PerformPendingImplicitInstantiations();
+ /// \brief The queue of implicit template instantiations that are required
+ /// and must be performed within the current local scope.
+ ///
+ /// This queue is only used for member functions of local classes in
+ /// templates, which must be instantiated in the same scope as their
+ /// enclosing function, so that they can reference function-local
+ /// types, static variables, enumerators, etc.
+ std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
+
+ void PerformPendingImplicitInstantiations(bool LocalOnly = false);
TypeSourceInfo *SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -3300,6 +3351,7 @@ public:
SourceLocation SuperLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList);
@@ -3317,6 +3369,7 @@ public:
SourceLocation AtProtoInterfaceLoc,
IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
const DeclPtrTy *ProtoRefNames, unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList);
@@ -3327,6 +3380,7 @@ public:
SourceLocation CategoryLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc);
virtual DeclPtrTy ActOnStartClassImplementation(
@@ -3373,14 +3427,13 @@ public:
ObjCMethodDecl *MethodDecl,
bool IsInstance);
- void MergeProtocolPropertiesIntoClass(Decl *CDecl,
- DeclPtrTy MergeProtocols);
+ void CompareProperties(Decl *CDecl, DeclPtrTy MergeProtocols);
void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
ObjCInterfaceDecl *ID);
- void MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
- ObjCProtocolDecl *PDecl);
+ void MatchOneProtocolPropertiesInClass(Decl *CDecl,
+ ObjCProtocolDecl *PDecl);
virtual void ActOnAtEnd(SourceRange AtEnd,
DeclPtrTy classDecl,
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index b7cc37b6c9a7..51f9e300ef90 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
@@ -137,3 +138,101 @@ bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
return false;
}
+
+/// Diagnose the path which caused the given declaration to become
+/// inaccessible.
+static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D,
+ AccessSpecifier Access) {
+ // Easy case: the decl's natural access determined its path access.
+ if (Access == D->getAccess() || D->getAccess() == AS_private) {
+ S.Diag(D->getLocation(), diag::note_access_natural)
+ << (unsigned) (Access == AS_protected);
+ return;
+ }
+
+ // TODO: flesh this out
+ S.Diag(D->getLocation(), diag::note_access_constrained_by_path)
+ << (unsigned) (Access == AS_protected);
+}
+
+/// Checks access to the given declaration in the current context.
+///
+/// \param R the means via which the access was made; must have a naming
+/// class set
+/// \param D the declaration accessed
+/// \param Access the best access along any inheritance path from the
+/// naming class to the declaration. AS_none means the path is impossible
+bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D,
+ AccessSpecifier Access) {
+ assert(R.getNamingClass() && "performing access check without naming class");
+
+ // If the access path is public, it's accessible everywhere.
+ if (Access == AS_public)
+ return false;
+
+ // Otherwise, derive the current class context.
+ DeclContext *DC = CurContext;
+ while (isa<CXXRecordDecl>(DC) &&
+ cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion())
+ DC = DC->getParent();
+
+ CXXRecordDecl *CurRecord;
+ if (isa<CXXRecordDecl>(DC))
+ CurRecord = cast<CXXRecordDecl>(DC);
+ else if (isa<CXXMethodDecl>(DC))
+ CurRecord = cast<CXXMethodDecl>(DC)->getParent();
+ else {
+ Diag(R.getNameLoc(), diag::err_access_outside_class)
+ << (Access == AS_protected);
+ DiagnoseAccessPath(*this, R, D, Access);
+ return true;
+ }
+
+ CXXRecordDecl *NamingClass = R.getNamingClass();
+ while (NamingClass->isAnonymousStructOrUnion())
+ // This should be guaranteed by the fact that the decl has
+ // non-public access. If not, we should make it guaranteed!
+ NamingClass = cast<CXXRecordDecl>(NamingClass);
+
+ // White-list accesses from within the declaring class.
+ if (Access != AS_none &&
+ CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl())
+ return false;
+
+ // Protected access.
+ if (Access == AS_protected) {
+ // FIXME: implement [class.protected]p1
+ if (CurRecord->isDerivedFrom(NamingClass))
+ return false;
+
+ // FIXME: dependent classes
+ }
+
+ // FIXME: friends
+
+ // Okay, it's a bad access, reject it.
+
+
+ CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+
+ if (Access == AS_protected) {
+ Diag(R.getNameLoc(), diag::err_access_protected)
+ << Context.getTypeDeclType(DeclaringClass)
+ << Context.getTypeDeclType(CurRecord);
+ DiagnoseAccessPath(*this, R, D, Access);
+ return true;
+ }
+
+ assert(Access == AS_private || Access == AS_none);
+ Diag(R.getNameLoc(), diag::err_access_private)
+ << Context.getTypeDeclType(DeclaringClass)
+ << Context.getTypeDeclType(CurRecord);
+ DiagnoseAccessPath(*this, R, D, Access);
+ return true;
+}
+
+/// Checks access to all the declarations in the given result set.
+void Sema::CheckAccess(const LookupResult &R) {
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ CheckAccess(R, *I, I.getAccess());
+}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index f924bd3bb121..57c4f9bc2a27 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -116,11 +116,26 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
SourceLocation RAngleBracketLoc,
SourceLocation LParenLoc, ExprArg E,
SourceLocation RParenLoc) {
+
+ TypeSourceInfo *DestTInfo;
+ QualType DestType = GetTypeFromParser(Ty, &DestTInfo);
+ if (!DestTInfo)
+ DestTInfo = Context.getTrivialTypeSourceInfo(DestType, SourceLocation());
+
+ return BuildCXXNamedCast(OpLoc, Kind, DestTInfo, move(E),
+ SourceRange(LAngleBracketLoc, RAngleBracketLoc),
+ SourceRange(LParenLoc, RParenLoc));
+}
+
+Action::OwningExprResult
+Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
+ TypeSourceInfo *DestTInfo, ExprArg E,
+ SourceRange AngleBrackets, SourceRange Parens) {
Expr *Ex = E.takeAs<Expr>();
- // FIXME: Preserve type source info.
- QualType DestType = GetTypeFromParser(Ty);
- SourceRange OpRange(OpLoc, RParenLoc);
- SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc);
+ QualType DestType = DestTInfo->getType();
+
+ SourceRange OpRange(OpLoc, Parens.getEnd());
+ SourceRange DestRange = AngleBrackets;
// If the type is dependent, we won't do the semantic analysis now.
// FIXME: should we check this in a more fine-grained manner?
@@ -133,14 +148,14 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
if (!TypeDependent)
CheckConstCast(*this, Ex, DestType, OpRange, DestRange);
return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(),
- Ex, DestType, OpLoc));
+ Ex, DestTInfo, OpLoc));
case tok::kw_dynamic_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
if (!TypeDependent)
CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind);
return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
- Kind, Ex, DestType, OpLoc));
+ Kind, Ex, DestTInfo, OpLoc));
}
case tok::kw_reinterpret_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
@@ -148,7 +163,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind);
return Owned(new (Context) CXXReinterpretCastExpr(
DestType.getNonReferenceType(),
- Kind, Ex, DestType, OpLoc));
+ Kind, Ex, DestTInfo, OpLoc));
}
case tok::kw_static_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
@@ -169,7 +184,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
}
return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
- Kind, Ex, DestType, OpLoc));
+ Kind, Ex, DestTInfo, OpLoc));
}
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 8594583ec3ef..7a0b6252064d 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -30,9 +30,9 @@ getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext,
if (T.isNull())
return 0;
- T = Context.getCanonicalType(T);
+ T = Context.getCanonicalType(T).getUnqualifiedType();
- for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) {
+ for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) {
// If we've hit a namespace or the global scope, then the
// nested-name-specifier can't refer to the current instantiation.
if (Ctx->isFileContext())
@@ -210,28 +210,6 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
return getCurrentInstantiationOf(NNS) == 0;
}
-/// \brief Determine whether the given scope specifier refers to a
-/// current instantiation that has any dependent base clases.
-///
-/// This check is typically used when we've performed lookup into the
-/// current instantiation of a template, but that lookup failed. When
-/// there are dependent bases present, however, the lookup needs to be
-/// delayed until template instantiation time.
-bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) {
- if (!SS.isSet())
- return false;
-
- NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep();
- if (!NNS->isDependent())
- return false;
-
- CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS);
- if (!CurrentInstantiation)
- return false;
-
- return CurrentInstantiation->hasAnyDependentBases();
-}
-
/// \brief If the given nested name specifier refers to the current
/// instantiation, return the declaration that corresponds to that
/// current instantiation (C++0x [temp.dep.type]p1).
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 5f124e457223..6ff8b1d75371 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -13,14 +13,22 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/STLExtras.h"
#include <limits>
+#include <queue>
using namespace clang;
/// getLocationOfStringLiteralByte - Return a source location that points to the
@@ -2029,3 +2037,522 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
return;
}
+// MarkLive - Mark all the blocks reachable from e as live. Returns the total
+// number of blocks just marked live.
+static unsigned MarkLive(CFGBlock *e, llvm::BitVector &live) {
+ unsigned count = 0;
+ std::queue<CFGBlock*> workq;
+ // Prep work queue
+ live.set(e->getBlockID());
+ ++count;
+ workq.push(e);
+ // Solve
+ while (!workq.empty()) {
+ CFGBlock *item = workq.front();
+ workq.pop();
+ for (CFGBlock::succ_iterator I=item->succ_begin(),
+ E=item->succ_end();
+ I != E;
+ ++I) {
+ if ((*I) && !live[(*I)->getBlockID()]) {
+ live.set((*I)->getBlockID());
+ ++count;
+ workq.push(*I);
+ }
+ }
+ }
+ return count;
+}
+
+static SourceLocation GetUnreachableLoc(CFGBlock &b, SourceRange &R1,
+ SourceRange &R2) {
+ Stmt *S;
+ unsigned sn = 0;
+ R1 = R2 = SourceRange();
+
+ top:
+ if (sn < b.size())
+ S = b[sn].getStmt();
+ else if (b.getTerminator())
+ S = b.getTerminator();
+ else
+ return SourceLocation();
+
+ switch (S->getStmtClass()) {
+ case Expr::BinaryOperatorClass: {
+ BinaryOperator *BO = cast<BinaryOperator>(S);
+ if (BO->getOpcode() == BinaryOperator::Comma) {
+ if (sn+1 < b.size())
+ return b[sn+1].getStmt()->getLocStart();
+ CFGBlock *n = &b;
+ while (1) {
+ if (n->getTerminator())
+ return n->getTerminator()->getLocStart();
+ if (n->succ_size() != 1)
+ return SourceLocation();
+ n = n[0].succ_begin()[0];
+ if (n->pred_size() != 1)
+ return SourceLocation();
+ if (!n->empty())
+ return n[0][0].getStmt()->getLocStart();
+ }
+ }
+ R1 = BO->getLHS()->getSourceRange();
+ R2 = BO->getRHS()->getSourceRange();
+ return BO->getOperatorLoc();
+ }
+ case Expr::UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(S);
+ R1 = UO->getSubExpr()->getSourceRange();
+ return UO->getOperatorLoc();
+ }
+ case Expr::CompoundAssignOperatorClass: {
+ const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
+ R1 = CAO->getLHS()->getSourceRange();
+ R2 = CAO->getRHS()->getSourceRange();
+ return CAO->getOperatorLoc();
+ }
+ case Expr::ConditionalOperatorClass: {
+ const ConditionalOperator *CO = cast<ConditionalOperator>(S);
+ return CO->getQuestionLoc();
+ }
+ case Expr::MemberExprClass: {
+ const MemberExpr *ME = cast<MemberExpr>(S);
+ R1 = ME->getSourceRange();
+ return ME->getMemberLoc();
+ }
+ case Expr::ArraySubscriptExprClass: {
+ const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
+ R1 = ASE->getLHS()->getSourceRange();
+ R2 = ASE->getRHS()->getSourceRange();
+ return ASE->getRBracketLoc();
+ }
+ case Expr::CStyleCastExprClass: {
+ const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
+ R1 = CSC->getSubExpr()->getSourceRange();
+ return CSC->getLParenLoc();
+ }
+ case Expr::CXXFunctionalCastExprClass: {
+ const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
+ R1 = CE->getSubExpr()->getSourceRange();
+ return CE->getTypeBeginLoc();
+ }
+ case Expr::ImplicitCastExprClass:
+ ++sn;
+ goto top;
+ case Stmt::CXXTryStmtClass: {
+ return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
+ }
+ default: ;
+ }
+ R1 = S->getSourceRange();
+ return S->getLocStart();
+}
+
+static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live,
+ SourceManager &SM) {
+ std::queue<CFGBlock*> workq;
+ // Prep work queue
+ workq.push(e);
+ SourceRange R1, R2;
+ SourceLocation top = GetUnreachableLoc(*e, R1, R2);
+ bool FromMainFile = false;
+ bool FromSystemHeader = false;
+ bool TopValid = false;
+ if (top.isValid()) {
+ FromMainFile = SM.isFromMainFile(top);
+ FromSystemHeader = SM.isInSystemHeader(top);
+ TopValid = true;
+ }
+ // Solve
+ while (!workq.empty()) {
+ CFGBlock *item = workq.front();
+ workq.pop();
+ SourceLocation c = GetUnreachableLoc(*item, R1, R2);
+ if (c.isValid()
+ && (!TopValid
+ || (SM.isFromMainFile(c) && !FromMainFile)
+ || (FromSystemHeader && !SM.isInSystemHeader(c))
+ || SM.isBeforeInTranslationUnit(c, top))) {
+ top = c;
+ FromMainFile = SM.isFromMainFile(top);
+ FromSystemHeader = SM.isInSystemHeader(top);
+ }
+ live.set(item->getBlockID());
+ for (CFGBlock::succ_iterator I=item->succ_begin(),
+ E=item->succ_end();
+ I != E;
+ ++I) {
+ if ((*I) && !live[(*I)->getBlockID()]) {
+ live.set((*I)->getBlockID());
+ workq.push(*I);
+ }
+ }
+ }
+ return top;
+}
+
+static int LineCmp(const void *p1, const void *p2) {
+ SourceLocation *Line1 = (SourceLocation *)p1;
+ SourceLocation *Line2 = (SourceLocation *)p2;
+ return !(*Line1 < *Line2);
+}
+
+namespace {
+ struct ErrLoc {
+ SourceLocation Loc;
+ SourceRange R1;
+ SourceRange R2;
+ ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2)
+ : Loc(l), R1(r1), R2(r2) { }
+ };
+}
+
+/// CheckUnreachable - Check for unreachable code.
+void Sema::CheckUnreachable(AnalysisContext &AC) {
+ unsigned count;
+ // We avoid checking when there are errors, as the CFG won't faithfully match
+ // the user's code.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+ if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
+ return;
+
+ CFG *cfg = AC.getCFG();
+ if (cfg == 0)
+ return;
+
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ // Mark all live things first.
+ count = MarkLive(&cfg->getEntry(), live);
+
+ if (count == cfg->getNumBlockIDs())
+ // If there are no dead blocks, we're done.
+ return;
+
+ SourceRange R1, R2;
+
+ llvm::SmallVector<ErrLoc, 24> lines;
+ bool AddEHEdges = AC.getAddEHEdges();
+ // First, give warnings for blocks with no predecessors, as they
+ // can't be part of a loop.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()]) {
+ if (b.pred_begin() == b.pred_end()) {
+ if (!AddEHEdges && b.getTerminator()
+ && isa<CXXTryStmt>(b.getTerminator())) {
+ // When not adding EH edges from calls, catch clauses
+ // can otherwise seem dead. Avoid noting them as dead.
+ count += MarkLive(&b, live);
+ continue;
+ }
+ SourceLocation c = GetUnreachableLoc(b, R1, R2);
+ if (!c.isValid()) {
+ // Blocks without a location can't produce a warning, so don't mark
+ // reachable blocks from here as live.
+ live.set(b.getBlockID());
+ ++count;
+ continue;
+ }
+ lines.push_back(ErrLoc(c, R1, R2));
+ // Avoid excessive errors by marking everything reachable from here
+ count += MarkLive(&b, live);
+ }
+ }
+ }
+
+ if (count < cfg->getNumBlockIDs()) {
+ // And then give warnings for the tops of loops.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()])
+ // Avoid excessive errors by marking everything reachable from here
+ lines.push_back(ErrLoc(MarkLiveTop(&b, live, Context.getSourceManager()), SourceRange(), SourceRange()));
+ }
+ }
+
+ llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp);
+ for (llvm::SmallVector<ErrLoc, 24>::iterator I = lines.begin(),
+ E = lines.end();
+ I != E;
+ ++I)
+ if (I->Loc.isValid())
+ Diag(I->Loc, diag::warn_unreachable) << I->R1 << I->R2;
+}
+
+/// CheckFallThrough - Check that we don't fall off the end of a
+/// Statement that should return a value.
+///
+/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
+/// MaybeFallThrough iff we might or might not fall off the end,
+/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
+/// return. We assume NeverFallThrough iff we never fall off the end of the
+/// statement but we may return. We assume that functions not marked noreturn
+/// will return.
+Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) {
+ CFG *cfg = AC.getCFG();
+ if (cfg == 0)
+ // FIXME: This should be NeverFallThrough
+ return NeverFallThroughOrReturn;
+
+ // The CFG leaves in dead things, and we don't want the dead code paths to
+ // confuse us, so we mark all live things first.
+ std::queue<CFGBlock*> workq;
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ unsigned count = MarkLive(&cfg->getEntry(), live);
+
+ bool AddEHEdges = AC.getAddEHEdges();
+ if (!AddEHEdges && count != cfg->getNumBlockIDs())
+ // When there are things remaining dead, and we didn't add EH edges
+ // from CallExprs to the catch clauses, we have to go back and
+ // mark them as live.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()]) {
+ if (b.pred_begin() == b.pred_end()) {
+ if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator()))
+ // When not adding EH edges from calls, catch clauses
+ // can otherwise seem dead. Avoid noting them as dead.
+ count += MarkLive(&b, live);
+ continue;
+ }
+ }
+ }
+
+ // Now we know what is live, we check the live precessors of the exit block
+ // and look for fall through paths, being careful to ignore normal returns,
+ // and exceptional paths.
+ bool HasLiveReturn = false;
+ bool HasFakeEdge = false;
+ bool HasPlainEdge = false;
+ bool HasAbnormalEdge = false;
+ for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(),
+ E = cfg->getExit().pred_end();
+ I != E;
+ ++I) {
+ CFGBlock& B = **I;
+ if (!live[B.getBlockID()])
+ continue;
+ if (B.size() == 0) {
+ if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
+ HasAbnormalEdge = true;
+ continue;
+ }
+
+ // A labeled empty statement, or the entry block...
+ HasPlainEdge = true;
+ continue;
+ }
+ Stmt *S = B[B.size()-1];
+ if (isa<ReturnStmt>(S)) {
+ HasLiveReturn = true;
+ continue;
+ }
+ if (isa<ObjCAtThrowStmt>(S)) {
+ HasFakeEdge = true;
+ continue;
+ }
+ if (isa<CXXThrowExpr>(S)) {
+ HasFakeEdge = true;
+ continue;
+ }
+ if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
+ if (AS->isMSAsm()) {
+ HasFakeEdge = true;
+ HasLiveReturn = true;
+ continue;
+ }
+ }
+ if (isa<CXXTryStmt>(S)) {
+ HasAbnormalEdge = true;
+ continue;
+ }
+
+ bool NoReturnEdge = false;
+ if (CallExpr *C = dyn_cast<CallExpr>(S)) {
+ if (B.succ_begin()[0] != &cfg->getExit()) {
+ HasAbnormalEdge = true;
+ continue;
+ }
+ Expr *CEE = C->getCallee()->IgnoreParenCasts();
+ if (CEE->getType().getNoReturnAttr()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VD->hasAttr<NoReturnAttr>()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ }
+ }
+ }
+ // FIXME: Add noreturn message sends.
+ if (NoReturnEdge == false)
+ HasPlainEdge = true;
+ }
+ if (!HasPlainEdge) {
+ if (HasLiveReturn)
+ return NeverFallThrough;
+ return NeverFallThroughOrReturn;
+ }
+ if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
+ return MaybeFallThrough;
+ // This says AlwaysFallThrough for calls to functions that are not marked
+ // noreturn, that don't return. If people would like this warning to be more
+ // accurate, such functions should be marked as noreturn.
+ return AlwaysFallThrough;
+}
+
+/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
+/// function that should return a value. Check that we don't fall off the end
+/// of a noreturn function. We assume that functions and blocks not marked
+/// noreturn will return.
+void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
+ AnalysisContext &AC) {
+ // FIXME: Would be nice if we had a better way to control cascading errors,
+ // but for now, avoid them. The problem is that when Parse sees:
+ // int foo() { return a; }
+ // The return is eaten and the Sema code sees just:
+ // int foo() { }
+ // which this code would then warn about.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+
+ bool ReturnsVoid = false;
+ bool HasNoReturn = false;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // If the result type of the function is a dependent type, we don't know
+ // whether it will be void or not, so don't
+ if (FD->getResultType()->isDependentType())
+ return;
+ if (FD->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (FD->hasAttr<NoReturnAttr>())
+ HasNoReturn = true;
+ } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (MD->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (MD->hasAttr<NoReturnAttr>())
+ HasNoReturn = true;
+ }
+
+ // Short circuit for compilation speed.
+ if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
+ == Diagnostic::Ignored || ReturnsVoid)
+ && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
+ == Diagnostic::Ignored || !HasNoReturn)
+ && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+ == Diagnostic::Ignored || !ReturnsVoid))
+ return;
+ // FIXME: Function try block
+ if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
+ switch (CheckFallThrough(AC)) {
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function);
+ break;
+ case NeverFallThroughOrReturn:
+ if (ReturnsVoid && !HasNoReturn)
+ Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function);
+ break;
+ case NeverFallThrough:
+ break;
+ }
+ }
+}
+
+/// CheckFallThroughForBlock - Check that we don't fall off the end of a block
+/// that should return a value. Check that we don't fall off the end of a
+/// noreturn block. We assume that functions and blocks not marked noreturn
+/// will return.
+void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body,
+ AnalysisContext &AC) {
+ // FIXME: Would be nice if we had a better way to control cascading errors,
+ // but for now, avoid them. The problem is that when Parse sees:
+ // int foo() { return a; }
+ // The return is eaten and the Sema code sees just:
+ // int foo() { }
+ // which this code would then warn about.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+ bool ReturnsVoid = false;
+ bool HasNoReturn = false;
+ if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){
+ if (FT->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (FT->getNoReturnAttr())
+ HasNoReturn = true;
+ }
+
+ // Short circuit for compilation speed.
+ if (ReturnsVoid
+ && !HasNoReturn
+ && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+ == Diagnostic::Ignored || !ReturnsVoid))
+ return;
+ // FIXME: Funtion try block
+ if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
+ switch (CheckFallThrough(AC)) {
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
+ break;
+ case NeverFallThroughOrReturn:
+ if (ReturnsVoid)
+ Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block);
+ break;
+ case NeverFallThrough:
+ break;
+ }
+ }
+}
+
+/// CheckParmsForFunctionDef - Check that the parameters of the given
+/// function are appropriate for the definition of a function. This
+/// takes care of any checks that cannot be performed on the
+/// declaration itself, e.g., that the types of each of the function
+/// parameters are complete.
+bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
+ bool HasInvalidParm = false;
+ for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
+ ParmVarDecl *Param = FD->getParamDecl(p);
+
+ // C99 6.7.5.3p4: the parameters in a parameter type list in a
+ // function declarator that is part of a function definition of
+ // that function shall not have incomplete type.
+ //
+ // This is also C++ [dcl.fct]p6.
+ if (!Param->isInvalidDecl() &&
+ RequireCompleteType(Param->getLocation(), Param->getType(),
+ diag::err_typecheck_decl_incomplete_type)) {
+ Param->setInvalidDecl();
+ HasInvalidParm = true;
+ }
+
+ // C99 6.9.1p5: If the declarator includes a parameter type list, the
+ // declaration of each parameter shall include an identifier.
+ if (Param->getIdentifier() == 0 &&
+ !Param->isImplicit() &&
+ !getLangOptions().CPlusPlus)
+ Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+ }
+
+ return HasInvalidParm;
+}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index a4cda014aae2..fcd419bb10fb 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2234,30 +2234,36 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
// FIXME: What if we're calling a pseudo-destructor?
// FIXME: What if we're calling a member function?
+ typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate;
+ llvm::SmallVector<ResultCandidate, 8> Results;
+
Expr *NakedFn = Fn->IgnoreParenCasts();
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn))
AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet,
/*PartialOverloading=*/ true);
else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(NakedFn)) {
FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl());
- if (FDecl)
- AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet,
- false, false, /*PartialOverloading*/ true);
+ if (FDecl) {
+ if (!FDecl->getType()->getAs<FunctionProtoType>())
+ Results.push_back(ResultCandidate(FDecl));
+ else
+ AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet,
+ false, false, /*PartialOverloading*/ true);
+ }
}
- // Sort the overload candidate set by placing the best overloads first.
- std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
- IsBetterOverloadCandidate(*this));
+ if (!CandidateSet.empty()) {
+ // Sort the overload candidate set by placing the best overloads first.
+ std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
+ IsBetterOverloadCandidate(*this));
- // Add the remaining viable overload candidates as code-completion reslults.
- typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate;
- llvm::SmallVector<ResultCandidate, 8> Results;
-
- for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
- CandEnd = CandidateSet.end();
- Cand != CandEnd; ++Cand) {
- if (Cand->Viable)
- Results.push_back(ResultCandidate(Cand->Function));
+ // Add the remaining viable overload candidates as code-completion reslults.
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+ CandEnd = CandidateSet.end();
+ Cand != CandEnd; ++Cand) {
+ if (Cand->Viable)
+ Results.push_back(ResultCandidate(Cand->Function));
+ }
}
if (Results.empty())
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0ccb8f2b1d5f..fbe02894ace5 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -18,13 +18,10 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/Analysis/CFG.h"
#include "clang/AST/CXXInheritance.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Template.h"
@@ -34,13 +31,10 @@
// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's)
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include <algorithm>
#include <cstring>
#include <functional>
-#include <queue>
using namespace clang;
/// getDeclName - Return a pretty name for the specified decl if possible, or
@@ -1305,382 +1299,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
// Keep a chain of previous declarations.
New->setPreviousDeclaration(Old);
-}
-
-static void MarkLive(CFGBlock *e, llvm::BitVector &live) {
- std::queue<CFGBlock*> workq;
- // Prep work queue
- workq.push(e);
- // Solve
- while (!workq.empty()) {
- CFGBlock *item = workq.front();
- workq.pop();
- live.set(item->getBlockID());
- for (CFGBlock::succ_iterator I=item->succ_begin(),
- E=item->succ_end();
- I != E;
- ++I) {
- if ((*I) && !live[(*I)->getBlockID()]) {
- live.set((*I)->getBlockID());
- workq.push(*I);
- }
- }
- }
-}
-
-static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live,
- SourceManager &SM) {
- std::queue<CFGBlock*> workq;
- // Prep work queue
- workq.push(e);
- SourceLocation top;
- if (!e->empty())
- top = e[0][0].getStmt()->getLocStart();
- bool FromMainFile = false;
- bool FromSystemHeader = false;
- bool TopValid = false;
- if (top.isValid()) {
- FromMainFile = SM.isFromMainFile(top);
- FromSystemHeader = SM.isInSystemHeader(top);
- TopValid = true;
- }
- // Solve
- while (!workq.empty()) {
- CFGBlock *item = workq.front();
- workq.pop();
- SourceLocation c;
- if (!item->empty())
- c = item[0][0].getStmt()->getLocStart();
- else if (item->getTerminator())
- c = item->getTerminator()->getLocStart();
- if (c.isValid()
- && (!TopValid
- || (SM.isFromMainFile(c) && !FromMainFile)
- || (FromSystemHeader && !SM.isInSystemHeader(c))
- || SM.isBeforeInTranslationUnit(c, top))) {
- top = c;
- FromMainFile = SM.isFromMainFile(top);
- FromSystemHeader = SM.isInSystemHeader(top);
- }
- live.set(item->getBlockID());
- for (CFGBlock::succ_iterator I=item->succ_begin(),
- E=item->succ_end();
- I != E;
- ++I) {
- if ((*I) && !live[(*I)->getBlockID()]) {
- live.set((*I)->getBlockID());
- workq.push(*I);
- }
- }
- }
- return top;
-}
-namespace {
-class LineCmp {
- SourceManager &SM;
-public:
- LineCmp(SourceManager &sm) : SM(sm) {
- }
- bool operator () (SourceLocation l1, SourceLocation l2) {
- return l1 < l2;
- }
-};
-}
-
-/// CheckUnreachable - Check for unreachable code.
-void Sema::CheckUnreachable(AnalysisContext &AC) {
- // We avoid checking when there are errors, as the CFG won't faithfully match
- // the user's code.
- if (getDiagnostics().hasErrorOccurred())
- return;
- if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
- return;
-
- CFG *cfg = AC.getCFG();
- if (cfg == 0)
- return;
-
- llvm::BitVector live(cfg->getNumBlockIDs());
- // Mark all live things first.
- MarkLive(&cfg->getEntry(), live);
-
- llvm::SmallVector<SourceLocation, 24> lines;
- // First, give warnings for blocks with no predecessors, as they
- // can't be part of a loop.
- for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
- CFGBlock &b = **I;
- if (!live[b.getBlockID()]) {
- if (b.pred_begin() == b.pred_end()) {
- if (!b.empty())
- lines.push_back(b[0].getStmt()->getLocStart());
- else if (b.getTerminator())
- lines.push_back(b.getTerminator()->getLocStart());
- // Avoid excessive errors by marking everything reachable from here
- MarkLive(&b, live);
- }
- }
- }
-
- // And then give warnings for the tops of loops.
- for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
- CFGBlock &b = **I;
- if (!live[b.getBlockID()])
- // Avoid excessive errors by marking everything reachable from here
- lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager()));
- }
-
- std::sort(lines.begin(), lines.end(), LineCmp(Context.getSourceManager()));
- for (llvm::SmallVector<SourceLocation, 24>::iterator I = lines.begin(),
- E = lines.end();
- I != E;
- ++I)
- if (I->isValid())
- Diag(*I, diag::warn_unreachable);
-}
-
-/// CheckFallThrough - Check that we don't fall off the end of a
-/// Statement that should return a value.
-///
-/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
-/// MaybeFallThrough iff we might or might not fall off the end,
-/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
-/// return. We assume NeverFallThrough iff we never fall off the end of the
-/// statement but we may return. We assume that functions not marked noreturn
-/// will return.
-Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) {
- CFG *cfg = AC.getCFG();
- if (cfg == 0)
- // FIXME: This should be NeverFallThrough
- return NeverFallThroughOrReturn;
-
- // The CFG leaves in dead things, and we don't want to dead code paths to
- // confuse us, so we mark all live things first.
- std::queue<CFGBlock*> workq;
- llvm::BitVector live(cfg->getNumBlockIDs());
- MarkLive(&cfg->getEntry(), live);
-
- // Now we know what is live, we check the live precessors of the exit block
- // and look for fall through paths, being careful to ignore normal returns,
- // and exceptional paths.
- bool HasLiveReturn = false;
- bool HasFakeEdge = false;
- bool HasPlainEdge = false;
- for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(),
- E = cfg->getExit().pred_end();
- I != E;
- ++I) {
- CFGBlock& B = **I;
- if (!live[B.getBlockID()])
- continue;
- if (B.size() == 0) {
- // A labeled empty statement, or the entry block...
- HasPlainEdge = true;
- continue;
- }
- Stmt *S = B[B.size()-1];
- if (isa<ReturnStmt>(S)) {
- HasLiveReturn = true;
- continue;
- }
- if (isa<ObjCAtThrowStmt>(S)) {
- HasFakeEdge = true;
- continue;
- }
- if (isa<CXXThrowExpr>(S)) {
- HasFakeEdge = true;
- continue;
- }
- if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
- if (AS->isMSAsm()) {
- HasFakeEdge = true;
- HasLiveReturn = true;
- continue;
- }
- }
-
- bool NoReturnEdge = false;
- if (CallExpr *C = dyn_cast<CallExpr>(S)) {
- Expr *CEE = C->getCallee()->IgnoreParenCasts();
- if (CEE->getType().getNoReturnAttr()) {
- NoReturnEdge = true;
- HasFakeEdge = true;
- } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
- ValueDecl *VD = DRE->getDecl();
- if (VD->hasAttr<NoReturnAttr>()) {
- NoReturnEdge = true;
- HasFakeEdge = true;
- }
- }
- }
- // FIXME: Add noreturn message sends.
- if (NoReturnEdge == false)
- HasPlainEdge = true;
- }
- if (!HasPlainEdge) {
- if (HasLiveReturn)
- return NeverFallThrough;
- return NeverFallThroughOrReturn;
- }
- if (HasFakeEdge || HasLiveReturn)
- return MaybeFallThrough;
- // This says AlwaysFallThrough for calls to functions that are not marked
- // noreturn, that don't return. If people would like this warning to be more
- // accurate, such functions should be marked as noreturn.
- return AlwaysFallThrough;
-}
-
-/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
-/// function that should return a value. Check that we don't fall off the end
-/// of a noreturn function. We assume that functions and blocks not marked
-/// noreturn will return.
-void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
- AnalysisContext &AC) {
- // FIXME: Would be nice if we had a better way to control cascading errors,
- // but for now, avoid them. The problem is that when Parse sees:
- // int foo() { return a; }
- // The return is eaten and the Sema code sees just:
- // int foo() { }
- // which this code would then warn about.
- if (getDiagnostics().hasErrorOccurred())
- return;
-
- bool ReturnsVoid = false;
- bool HasNoReturn = false;
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // If the result type of the function is a dependent type, we don't know
- // whether it will be void or not, so don't
- if (FD->getResultType()->isDependentType())
- return;
- if (FD->getResultType()->isVoidType())
- ReturnsVoid = true;
- if (FD->hasAttr<NoReturnAttr>())
- HasNoReturn = true;
- } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (MD->getResultType()->isVoidType())
- ReturnsVoid = true;
- if (MD->hasAttr<NoReturnAttr>())
- HasNoReturn = true;
- }
-
- // Short circuit for compilation speed.
- if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
- == Diagnostic::Ignored || ReturnsVoid)
- && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
- == Diagnostic::Ignored || !HasNoReturn)
- && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
- == Diagnostic::Ignored || !ReturnsVoid))
- return;
- // FIXME: Function try block
- if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(AC)) {
- case MaybeFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function);
- break;
- case AlwaysFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function);
- break;
- case NeverFallThroughOrReturn:
- if (ReturnsVoid && !HasNoReturn)
- Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function);
- break;
- case NeverFallThrough:
- break;
- }
- }
-}
-
-/// CheckFallThroughForBlock - Check that we don't fall off the end of a block
-/// that should return a value. Check that we don't fall off the end of a
-/// noreturn block. We assume that functions and blocks not marked noreturn
-/// will return.
-void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body,
- AnalysisContext &AC) {
- // FIXME: Would be nice if we had a better way to control cascading errors,
- // but for now, avoid them. The problem is that when Parse sees:
- // int foo() { return a; }
- // The return is eaten and the Sema code sees just:
- // int foo() { }
- // which this code would then warn about.
- if (getDiagnostics().hasErrorOccurred())
- return;
- bool ReturnsVoid = false;
- bool HasNoReturn = false;
- if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){
- if (FT->getResultType()->isVoidType())
- ReturnsVoid = true;
- if (FT->getNoReturnAttr())
- HasNoReturn = true;
- }
-
- // Short circuit for compilation speed.
- if (ReturnsVoid
- && !HasNoReturn
- && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
- == Diagnostic::Ignored || !ReturnsVoid))
- return;
- // FIXME: Funtion try block
- if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(AC)) {
- case MaybeFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block);
- break;
- case AlwaysFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
- break;
- case NeverFallThroughOrReturn:
- if (ReturnsVoid)
- Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block);
- break;
- case NeverFallThrough:
- break;
- }
- }
-}
-
-/// CheckParmsForFunctionDef - Check that the parameters of the given
-/// function are appropriate for the definition of a function. This
-/// takes care of any checks that cannot be performed on the
-/// declaration itself, e.g., that the types of each of the function
-/// parameters are complete.
-bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
- bool HasInvalidParm = false;
- for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
- ParmVarDecl *Param = FD->getParamDecl(p);
-
- // C99 6.7.5.3p4: the parameters in a parameter type list in a
- // function declarator that is part of a function definition of
- // that function shall not have incomplete type.
- //
- // This is also C++ [dcl.fct]p6.
- if (!Param->isInvalidDecl() &&
- RequireCompleteType(Param->getLocation(), Param->getType(),
- diag::err_typecheck_decl_incomplete_type)) {
- Param->setInvalidDecl();
- HasInvalidParm = true;
- }
-
- // C99 6.9.1p5: If the declarator includes a parameter type list, the
- // declaration of each parameter shall include an identifier.
- if (Param->getIdentifier() == 0 &&
- !Param->isImplicit() &&
- !getLangOptions().CPlusPlus)
- Diag(Param->getLocation(), diag::err_parameter_name_omitted);
- }
-
- return HasInvalidParm;
+ // Inherit access appropriately.
+ New->setAccess(Old->getAccess());
}
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
@@ -1773,6 +1394,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
/// \return true if this is a forbidden redeclaration
static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
Scope *S,
+ DeclContext *Owner,
DeclarationName Name,
SourceLocation NameLoc,
unsigned diagnostic) {
@@ -1785,6 +1407,11 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
// Pick a representative declaration.
NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl();
+ if (PrevDecl && Owner->isRecord()) {
+ RecordDecl *Record = cast<RecordDecl>(Owner);
+ if (!SemaRef.isDeclInScope(PrevDecl, Record, S))
+ return false;
+ }
SemaRef.Diag(NameLoc, diagnostic) << Name;
SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
@@ -1819,7 +1446,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
FEnd = AnonRecord->field_end();
F != FEnd; ++F) {
if ((*F)->getDeclName()) {
- if (CheckAnonMemberRedeclaration(*this, S, (*F)->getDeclName(),
+ if (CheckAnonMemberRedeclaration(*this, S, Owner, (*F)->getDeclName(),
(*F)->getLocation(), diagKind)) {
// C++ [class.union]p2:
// The names of the members of an anonymous union shall be
@@ -3243,7 +2870,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Synthesize a parameter for each argument type.
for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(),
AE = FT->arg_type_end(); AI != AE; ++AI) {
- ParmVarDecl *Param = ParmVarDecl::Create(Context, DC,
+ ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD,
SourceLocation(), 0,
*AI, /*TInfo=*/0,
VarDecl::None, 0);
@@ -3322,6 +2949,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
+ // Fake up an access specifier if it's supposed to be a class member.
+ if (isa<CXXRecordDecl>(NewFD->getDeclContext()))
+ NewFD->setAccess(AS_public);
+
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
// Note that this is not the case for explicit specializations of
@@ -3332,7 +2963,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
- } else if (!Redeclaration) {
+ } else if (!Redeclaration &&
+ !(isFriend && CurContext->isDependentContext())) {
// The user tried to provide an out-of-line definition for a
// function that is a member of a class or namespace, but there
// was no such member function declared (C++ [class.mfct]p2,
@@ -4236,8 +3868,13 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
QualType T = adjustParameterType(parmDeclType);
+ // Temporarily put parameter variables in the translation unit, not
+ // the enclosing context. This prevents them from accidentally
+ // looking like class members in C++.
+ DeclContext *DC = Context.getTranslationUnitDecl();
+
ParmVarDecl *New
- = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II,
+ = ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II,
T, TInfo, StorageClass, 0);
if (D.isInvalidType())
@@ -4476,7 +4113,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
Decl *dcl = D.getAs<Decl>();
Stmt *Body = BodyArg.takeAs<Stmt>();
- AnalysisContext AC(dcl);
+ // 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(dcl, false);
FunctionDecl *FD = 0;
FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
if (FunTmpl)
@@ -6064,7 +5703,8 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
// Verify that there isn't already something declared with this name in this
// scope.
- NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName);
+ NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName,
+ ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(IdLoc, PrevDecl);
@@ -6092,8 +5732,10 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
IdLoc, Id, Owned(Val));
// Register this decl in the current scope stack.
- if (New)
+ if (New) {
+ New->setAccess(TheEnumDecl->getAccess());
PushOnScopeChains(New, S);
+ }
return DeclPtrTy::make(New);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index a81a04e45e18..9ec95f3d170d 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1062,8 +1062,23 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!TyD) {
if (R.isAmbiguous()) return true;
+ if (SS.isSet() && isDependentScopeSpecifier(SS)) {
+ bool NotUnknownSpecialization = false;
+ DeclContext *DC = computeDeclContext(SS, false);
+ if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC))
+ NotUnknownSpecialization = !Record->hasAnyDependentBases();
+
+ if (!NotUnknownSpecialization) {
+ // When the scope specifier can refer to a member of an unknown
+ // specialization, we take it as a type name.
+ BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(),
+ *MemberOrBase, SS.getRange());
+ R.clear();
+ }
+ }
+
// If no results were found, try to correct typos.
- if (R.empty() &&
+ if (R.empty() && BaseType.isNull() &&
CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) {
if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) {
if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) {
@@ -1106,20 +1121,22 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
}
}
- if (!TyD) {
+ if (!TyD && BaseType.isNull()) {
Diag(IdLoc, diag::err_mem_init_not_member_or_class)
<< MemberOrBase << SourceRange(IdLoc, RParenLoc);
return true;
}
}
- BaseType = Context.getTypeDeclType(TyD);
- if (SS.isSet()) {
- NestedNameSpecifier *Qualifier =
- static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ if (BaseType.isNull()) {
+ BaseType = Context.getTypeDeclType(TyD);
+ if (SS.isSet()) {
+ NestedNameSpecifier *Qualifier =
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep());
- // FIXME: preserve source range information
- BaseType = Context.getQualifiedNameType(Qualifier, BaseType);
+ // FIXME: preserve source range information
+ BaseType = Context.getQualifiedNameType(Qualifier, BaseType);
+ }
}
}
@@ -4470,9 +4487,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet;
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
@@ -5594,26 +5611,24 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType();
QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType();
- QualType CNewTy = Context.getCanonicalType(NewTy);
- QualType COldTy = Context.getCanonicalType(OldTy);
-
- if (CNewTy == COldTy &&
- CNewTy.getLocalCVRQualifiers() == COldTy.getLocalCVRQualifiers())
+ if (Context.hasSameType(NewTy, OldTy))
return false;
// Check if the return types are covariant
QualType NewClassTy, OldClassTy;
/// Both types must be pointers or references to classes.
- if (PointerType *NewPT = dyn_cast<PointerType>(NewTy)) {
- if (PointerType *OldPT = dyn_cast<PointerType>(OldTy)) {
+ if (const PointerType *NewPT = NewTy->getAs<PointerType>()) {
+ if (const PointerType *OldPT = OldTy->getAs<PointerType>()) {
NewClassTy = NewPT->getPointeeType();
OldClassTy = OldPT->getPointeeType();
}
- } else if (ReferenceType *NewRT = dyn_cast<ReferenceType>(NewTy)) {
- if (ReferenceType *OldRT = dyn_cast<ReferenceType>(OldTy)) {
- NewClassTy = NewRT->getPointeeType();
- OldClassTy = OldRT->getPointeeType();
+ } else if (const ReferenceType *NewRT = NewTy->getAs<ReferenceType>()) {
+ if (const ReferenceType *OldRT = OldTy->getAs<ReferenceType>()) {
+ if (NewRT->getTypeClass() == OldRT->getTypeClass()) {
+ NewClassTy = NewRT->getPointeeType();
+ OldClassTy = OldRT->getPointeeType();
+ }
}
}
@@ -5661,7 +5676,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
}
// The qualifiers of the return types must be the same.
- if (CNewTy.getLocalCVRQualifiers() != COldTy.getLocalCVRQualifiers()) {
+ if (NewTy.getLocalCVRQualifiers() != OldTy.getLocalCVRQualifiers()) {
Diag(New->getLocation(),
diag::err_covariant_return_type_different_qualifications)
<< New->getDeclName() << NewTy << OldTy;
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index f2fc1f4f56df..1b07d19882e0 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -81,6 +81,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *SuperName, SourceLocation SuperLoc,
const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc, AttributeList *AttrList) {
assert(ClassName && "Missing class identifier");
@@ -201,7 +202,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
/// Check then save referenced protocols.
if (NumProtoRefs) {
IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
- Context);
+ ProtoLocs, Context);
IDecl->setLocEnd(EndProtoLoc);
}
@@ -279,6 +280,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
SourceLocation ProtocolLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList) {
// FIXME: Deal with AttrList.
@@ -312,7 +314,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
if (NumProtoRefs) {
/// Check then save referenced protocols.
- PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context);
+ PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ ProtoLocs, Context);
PDecl->setLocEnd(EndProtoLoc);
}
@@ -432,17 +435,17 @@ void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
}
}
-/// MergeOneProtocolPropertiesIntoClass - This routine goes thru the list
-/// of properties declared in a protocol and adds them to the list
-/// of properties for current class/category if it is not there already.
+/// MatchOneProtocolPropertiesInClass - This routine goes thru the list
+/// of properties declared in a protocol and compares their attribute against
+/// the same property declared in the class or category.
void
-Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
+Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
ObjCProtocolDecl *PDecl) {
ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
if (!IDecl) {
// Category
ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
- assert (CatDecl && "MergeOneProtocolPropertiesIntoClass");
+ assert (CatDecl && "MatchOneProtocolPropertiesInClass");
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
E = PDecl->prop_end(); P != E; ++P) {
ObjCPropertyDecl *Pr = (*P);
@@ -471,35 +474,35 @@ Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
}
}
-/// MergeProtocolPropertiesIntoClass - This routine merges properties
-/// declared in 'MergeItsProtocols' objects (which can be a class or an
-/// inherited protocol into the list of properties for class/category 'CDecl'
+/// CompareProperties - This routine compares properties
+/// declared in 'ClassOrProtocol' objects (which can be a class or an
+/// inherited protocol with the list of properties for class/category 'CDecl'
///
-void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
- DeclPtrTy MergeItsProtocols) {
- Decl *ClassDecl = MergeItsProtocols.getAs<Decl>();
+void Sema::CompareProperties(Decl *CDecl,
+ DeclPtrTy ClassOrProtocol) {
+ Decl *ClassDecl = ClassOrProtocol.getAs<Decl>();
ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
if (!IDecl) {
// Category
ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
- assert (CatDecl && "MergeProtocolPropertiesIntoClass");
+ assert (CatDecl && "CompareProperties");
if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(),
E = MDecl->protocol_end(); P != E; ++P)
- // Merge properties of category (*P) into IDECL's
- MergeOneProtocolPropertiesIntoClass(CatDecl, *P);
+ // Match properties of category with those of protocol (*P)
+ MatchOneProtocolPropertiesInClass(CatDecl, *P);
- // Go thru the list of protocols for this category and recursively merge
- // their properties into this class as well.
+ // Go thru the list of protocols for this category and recursively match
+ // their properties with those in the category.
for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(),
E = CatDecl->protocol_end(); P != E; ++P)
- MergeProtocolPropertiesIntoClass(CatDecl, DeclPtrTy::make(*P));
+ CompareProperties(CatDecl, DeclPtrTy::make(*P));
} else {
ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
E = MD->protocol_end(); P != E; ++P)
- MergeOneProtocolPropertiesIntoClass(CatDecl, *P);
+ MatchOneProtocolPropertiesInClass(CatDecl, *P);
}
return;
}
@@ -507,19 +510,19 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(),
E = MDecl->protocol_end(); P != E; ++P)
- // Merge properties of class (*P) into IDECL's
- MergeOneProtocolPropertiesIntoClass(IDecl, *P);
+ // Match properties of class IDecl with those of protocol (*P).
+ MatchOneProtocolPropertiesInClass(IDecl, *P);
- // Go thru the list of protocols for this class and recursively merge
- // their properties into this class as well.
+ // Go thru the list of protocols for this class and recursively match
+ // their properties with those declared in the class.
for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(),
E = IDecl->protocol_end(); P != E; ++P)
- MergeProtocolPropertiesIntoClass(IDecl, DeclPtrTy::make(*P));
+ CompareProperties(IDecl, DeclPtrTy::make(*P));
} else {
ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
E = MD->protocol_end(); P != E; ++P)
- MergeOneProtocolPropertiesIntoClass(IDecl, *P);
+ MatchOneProtocolPropertiesInClass(IDecl, *P);
}
}
@@ -559,6 +562,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
unsigned NumElts,
AttributeList *attrList) {
llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols;
+ llvm::SmallVector<SourceLocation, 8> ProtoLocs;
for (unsigned i = 0; i != NumElts; ++i) {
IdentifierInfo *Ident = IdentList[i].first;
@@ -571,11 +575,13 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
if (attrList)
ProcessDeclAttributeList(TUScope, PDecl, attrList);
Protocols.push_back(PDecl);
+ ProtoLocs.push_back(IdentList[i].second);
}
ObjCForwardProtocolDecl *PDecl =
ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc,
- &Protocols[0], Protocols.size());
+ Protocols.data(), Protocols.size(),
+ ProtoLocs.data());
CurContext->addDecl(PDecl);
CheckObjCDeclScope(PDecl);
return DeclPtrTy::make(PDecl);
@@ -588,9 +594,11 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
SourceLocation CategoryLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc) {
ObjCCategoryDecl *CDecl =
- ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, CategoryName);
+ ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc,
+ CategoryLoc, CategoryName);
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
@@ -623,12 +631,12 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
if (NumProtoRefs) {
CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
- Context);
- CDecl->setLocEnd(EndProtoLoc);
+ ProtoLocs, Context);
// Protocols in the class extension belong to the class.
if (!CDecl->getIdentifier())
IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs,
- NumProtoRefs,Context);
+ NumProtoRefs, ProtoLocs,
+ Context);
}
CheckObjCDeclScope(CDecl);
@@ -650,6 +658,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
// Category @implementation with no corresponding @interface.
// Create and install one.
CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(),
+ SourceLocation(), SourceLocation(),
CatName);
CatIDecl->setClassInterface(IDecl);
CatIDecl->insertNextClassCategory();
@@ -1077,6 +1086,92 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
}
}
+/// CollectImmediateProperties - This routine collects all properties in
+/// the class and its conforming protocols; but not those it its super class.
+void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
+ if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
+ E = IDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+ if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
+ E = CATDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
+ E = CATDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+ else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()];
+ if (!PropEntry)
+ PropEntry = Prop;
+ }
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+}
+
+void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl *CDecl,
+ const llvm::DenseSet<Selector>& InsMap) {
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
+ CollectImmediateProperties(CDecl, PropMap);
+ if (PropMap.empty())
+ return;
+
+ llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
+ for (ObjCImplDecl::propimpl_iterator
+ I = IMPDecl->propimpl_begin(),
+ EI = IMPDecl->propimpl_end(); I != EI; ++I)
+ PropImplMap.insert((*I)->getPropertyDecl());
+
+ for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
+ P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = P->second;
+ // Is there a matching propery synthesize/dynamic?
+ if (Prop->isInvalidDecl() ||
+ Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
+ PropImplMap.count(Prop))
+ continue;
+
+ if (!InsMap.count(Prop->getGetterName())) {
+ Diag(Prop->getLocation(),
+ isa<ObjCCategoryDecl>(CDecl) ?
+ diag::warn_setter_getter_impl_required_in_category :
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Prop->getGetterName();
+ Diag(IMPDecl->getLocation(),
+ diag::note_property_impl_required);
+ }
+
+ if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
+ Diag(Prop->getLocation(),
+ isa<ObjCCategoryDecl>(CDecl) ?
+ diag::warn_setter_getter_impl_required_in_category :
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Prop->getSetterName();
+ Diag(IMPDecl->getLocation(),
+ diag::note_property_impl_required);
+ }
+ }
+}
+
void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool IncompleteImpl) {
@@ -1091,39 +1186,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
// an implementation or 2) there is a @synthesize/@dynamic implementation
// of the property in the @implementation.
if (isa<ObjCInterfaceDecl>(CDecl))
- for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(),
- E = CDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- if (Prop->isInvalidDecl())
- continue;
- ObjCPropertyImplDecl *PI = 0;
- // Is there a matching propery synthesize/dynamic?
- for (ObjCImplDecl::propimpl_iterator
- I = IMPDecl->propimpl_begin(),
- EI = IMPDecl->propimpl_end(); I != EI; ++I)
- if ((*I)->getPropertyDecl() == Prop) {
- PI = (*I);
- break;
- }
- if (PI)
- continue;
- if (!InsMap.count(Prop->getGetterName())) {
- Diag(Prop->getLocation(),
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Prop->getGetterName();
- Diag(IMPDecl->getLocation(),
- diag::note_property_impl_required);
- }
-
- if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
- Diag(Prop->getLocation(),
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Prop->getSetterName();
- Diag(IMPDecl->getLocation(),
- diag::note_property_impl_required);
- }
- }
-
+ DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap);
+
llvm::DenseSet<Selector> ClsMap;
for (ObjCImplementationDecl::classmeth_iterator
I = IMPDecl->classmeth_begin(),
@@ -1163,7 +1227,18 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
E = C->protocol_end(); PI != E; ++PI)
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
InsMap, ClsMap, C->getClassInterface());
- }
+ // 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
+ // implementation.
+ if (ObjCInterfaceDecl *ID = C->getClassInterface())
+ if (ObjCImplDecl *IMP = ID->getImplementation()) {
+ for (ObjCImplementationDecl::instmeth_iterator
+ I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I)
+ InsMap.insert((*I)->getSelector());
+ }
+ DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap);
+ }
} else
assert(false && "invalid ObjCContainerDecl type.");
}
@@ -1694,14 +1769,14 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
// Compares properties declared in this class to those of its
// super class.
ComparePropertiesInBaseAndSuper(I);
- MergeProtocolPropertiesIntoClass(I, DeclPtrTy::make(I));
+ CompareProperties(I, DeclPtrTy::make(I));
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
// Categories are used to extend the class by declaring new methods.
// By the same token, they are also used to add new properties. No
// need to compare the added property to those in the class.
- // Merge protocol properties into category
- MergeProtocolPropertiesIntoClass(C, DeclPtrTy::make(C));
+ // Compare protocol properties with those in category
+ CompareProperties(C, DeclPtrTy::make(C));
if (C->getIdentifier() == 0)
DiagnoseClassExtensionDupMethods(C, C->getClassInterface());
}
@@ -2111,7 +2186,8 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
assert(DC && "ClassDecl is not a DeclContext");
ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
FD.D.getIdentifierLoc(),
- FD.D.getIdentifier(), T);
+ FD.D.getIdentifier(),
+ AtLoc, T);
DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName());
if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
Diag(PDecl->getLocation(), diag::err_duplicate_property);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 034accd1c4e1..50976f7b704b 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3082,15 +3082,9 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
- if (Getter || Setter) {
+ if (Getter) {
QualType PType;
-
- if (Getter)
- PType = Getter->getResultType();
- else
- // Get the expression type from Setter's incoming parameter.
- PType = (*(Setter->param_end() -1))->getType();
- // FIXME: we must check that the setter has property type.
+ PType = Getter->getResultType();
return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
Setter, MemberLoc, BaseExpr));
}
@@ -3663,11 +3657,21 @@ Action::OwningExprResult
Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg InitExpr) {
assert((Ty != 0) && "ActOnCompoundLiteral(): missing type");
-
- QualType literalType = GetTypeFromParser(Ty);
-
// FIXME: put back this assert when initializers are worked out.
//assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
+
+ TypeSourceInfo *TInfo;
+ QualType literalType = GetTypeFromParser(Ty, &TInfo);
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(literalType);
+
+ return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, move(InitExpr));
+}
+
+Action::OwningExprResult
+Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
+ SourceLocation RParenLoc, ExprArg InitExpr) {
+ QualType literalType = TInfo->getType();
Expr *literalExpr = static_cast<Expr*>(InitExpr.get());
if (literalType->isArrayType()) {
@@ -3703,8 +3707,7 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
Result.release();
- // FIXME: Store the TInfo to preserve type information better.
- return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType,
+ return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
literalExpr, isFileScope));
}
@@ -3906,26 +3909,38 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr,
Action::OwningExprResult
Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg Op) {
- CastExpr::CastKind Kind = CastExpr::CK_Unknown;
-
assert((Ty != 0) && (Op.get() != 0) &&
"ActOnCastExpr(): missing type or expr");
- Expr *castExpr = (Expr *)Op.get();
- //FIXME: Preserve type source info.
- QualType castType = GetTypeFromParser(Ty);
+ TypeSourceInfo *castTInfo;
+ QualType castType = GetTypeFromParser(Ty, &castTInfo);
+ if (!castTInfo)
+ castTInfo = Context.getTrivialTypeSourceInfo(castType);
// If the Expr being casted is a ParenListExpr, handle it specially.
+ Expr *castExpr = (Expr *)Op.get();
if (isa<ParenListExpr>(castExpr))
- return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),castType);
+ return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),
+ castTInfo);
+
+ return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, move(Op));
+}
+
+Action::OwningExprResult
+Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
+ SourceLocation RParenLoc, ExprArg Op) {
+ Expr *castExpr = static_cast<Expr*>(Op.get());
+
CXXMethodDecl *Method = 0;
- if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr,
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
Kind, Method))
return ExprError();
if (Method) {
- OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, castType, Kind,
- Method, move(Op));
+ // FIXME: preserve type source info here
+ OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, Ty->getType(),
+ Kind, Method, move(Op));
if (CastArg.isInvalid())
return ExprError();
@@ -3935,8 +3950,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty,
Op.release();
}
- return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(),
- Kind, castExpr, castType,
+ return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(),
+ Kind, castExpr, Ty,
LParenLoc, RParenLoc));
}
@@ -3961,8 +3976,9 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg EA) {
Action::OwningExprResult
Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
SourceLocation RParenLoc, ExprArg Op,
- QualType Ty) {
+ TypeSourceInfo *TInfo) {
ParenListExpr *PE = (ParenListExpr *)Op.get();
+ QualType Ty = TInfo->getType();
// If this is an altivec initializer, '(' type ')' '(' init, ..., init ')'
// then handle it as such.
@@ -3982,13 +3998,12 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0],
initExprs.size(), RParenLoc);
E->setType(Ty);
- return ActOnCompoundLiteral(LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,
- Owned(E));
+ return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Owned(E));
} else {
// This is not an AltiVec-style cast, so turn the ParenListExpr into a
// sequence of BinOp comma operators.
Op = MaybeConvertParenListExprToParenExpr(S, move(Op));
- return ActOnCastExpr(S, LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,move(Op));
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, move(Op));
}
}
@@ -4702,8 +4717,9 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
// Build a compound literal constructing a value of the transparent
// union type from this initializer list.
- E = new (C) CompoundLiteralExpr(SourceLocation(), UnionType, Initializer,
- false);
+ TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType);
+ E = new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType,
+ Initializer, false);
}
Sema::AssignConvertType
@@ -6785,10 +6801,13 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
- E = CurBlock->TheDecl->param_end(); AI != E; ++AI)
+ 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())
PushOnScopeChains(*AI, CurBlock->TheScope);
+ }
// Check for a valid sentinel attribute on this block.
if (!CurBlock->isVariadic &&
@@ -6868,6 +6887,26 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
+
+ bool Good = true;
+ // Check goto/label use.
+ for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
+ I = BSI->LabelMap.begin(), E = BSI->LabelMap.end(); I != E; ++I) {
+ LabelStmt *L = I->second;
+
+ // Verify that we have no forward references left. If so, there was a goto
+ // or address of a label taken, but no definition of it.
+ if (L->getSubStmt() != 0)
+ continue;
+
+ // Emit error.
+ Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName();
+ Good = false;
+ }
+ BSI->LabelMap.clear();
+ if (!Good)
+ return ExprError();
+
AnalysisContext AC(BSI->TheDecl);
CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC);
CheckUnreachable(AC);
@@ -7203,8 +7242,15 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
AlreadyInstantiated = true;
}
- if (!AlreadyInstantiated)
- PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc));
+ if (!AlreadyInstantiated) {
+ if (isa<CXXRecordDecl>(Function->getDeclContext()) &&
+ cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass())
+ PendingLocalImplicitInstantiations.push_back(std::make_pair(Function,
+ Loc));
+ else
+ PendingImplicitInstantiations.push_back(std::make_pair(Function,
+ Loc));
+ }
}
// FIXME: keep track of references to static functions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index d10e11fdb4a3..b004fc3dba72 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -196,8 +196,10 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
assert(TypeRep && "Missing type!");
- // FIXME: Preserve type source info.
- QualType Ty = GetTypeFromParser(TypeRep);
+ TypeSourceInfo *TInfo;
+ QualType Ty = GetTypeFromParser(TypeRep, &TInfo);
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation());
unsigned NumExprs = exprs.size();
Expr **Exprs = (Expr**)exprs.get();
SourceLocation TyBeginLoc = TypeRange.getBegin();
@@ -252,7 +254,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
}
return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
- Ty, TyBeginLoc, Kind,
+ TInfo, TyBeginLoc, Kind,
Exprs[0], RParenLoc));
}
@@ -891,9 +893,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (const RecordType *Record = Type->getAs<RecordType>()) {
llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions;
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- const UnresolvedSet *Conversions = RD->getVisibleConversionFunctions();
+ const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
// Skip over templated conversion functions; they aren't considered.
if (isa<FunctionTemplateDecl>(*I))
@@ -1448,12 +1450,14 @@ QualType Sema::CheckPointerToMemberOperands(
// overkill?
if (!IsDerivedFrom(LType, Class, Paths) ||
Paths.isAmbiguous(Context.getCanonicalType(Class))) {
- const char *ReplaceStr = isIndirect ? ".*" : "->*";
Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling
- << (int)isIndirect << lex->getType() <<
- CodeModificationHint::CreateReplacement(SourceRange(Loc), ReplaceStr);
+ << (int)isIndirect << lex->getType();
return QualType();
}
+ // Cast LHS to type of use.
+ QualType UseType = isIndirect ? Context.getPointerType(Class) : Class;
+ bool isLValue = !isIndirect && lex->isLvalue(Context) == Expr::LV_Valid;
+ ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue);
}
if (isa<CXXZeroInitValueExpr>(rex->IgnoreParens())) {
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 85889fa5d6d9..ea8f4e3e890f 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -398,7 +398,17 @@ Sema::ExprResult Sema::ActOnClassMessage(
return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
selectorLoc, rbrac, Args, NumArgs);
}
- return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
+ else if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(SuperDecl)) {
+ const ObjCInterfaceType *OCIT;
+ OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>();
+ if (!OCIT) {
+ Diag(receiverLoc, diag::err_invalid_receiver_to_message);
+ return true;
+ }
+ ClassDecl = OCIT->getDecl();
+ }
+ else
+ return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
}
} else
ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc);
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 1970f56e284b..fd62e1afce4f 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -382,7 +382,8 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
if (hadError)
return;
- if (ElementEntity.getKind() == InitializedEntity::EK_ArrayOrVectorElement)
+ if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement ||
+ ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
ElementEntity.setElementIndex(Init);
if (Init >= NumInits || !ILE->getInit(Init)) {
@@ -1828,12 +1829,15 @@ bool Sema::CheckInitList(const InitializedEntity &Entity,
InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index,
const InitializedEntity &Parent)
- : Kind(EK_ArrayOrVectorElement), Parent(&Parent), Index(Index)
+ : Parent(&Parent), Index(Index)
{
- if (const ArrayType *AT = Context.getAsArrayType(Parent.getType()))
+ if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) {
+ Kind = EK_ArrayElement;
Type = AT->getElementType();
- else
+ } else {
+ Kind = EK_VectorElement;
Type = Parent.getType()->getAs<VectorType>()->getElementType();
+ }
}
InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
@@ -1862,7 +1866,8 @@ DeclarationName InitializedEntity::getName() const {
case EK_New:
case EK_Temporary:
case EK_Base:
- case EK_ArrayOrVectorElement:
+ case EK_ArrayElement:
+ case EK_VectorElement:
return DeclarationName();
}
@@ -1882,7 +1887,8 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
case EK_New:
case EK_Temporary:
case EK_Base:
- case EK_ArrayOrVectorElement:
+ case EK_ArrayElement:
+ case EK_VectorElement:
return 0;
}
@@ -2141,11 +2147,10 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// refers to.
QualType ToType = AllowRValues? cv1T1 : DestType;
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
- E = Conversions->end();
- I != E; ++I) {
+ for (UnresolvedSetImpl::const_iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
@@ -2662,9 +2667,9 @@ static void TryUserDefinedConversion(Sema &S,
CXXRecordDecl *SourceRecordDecl
= cast<CXXRecordDecl>(SourceRecordType->getDecl());
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= SourceRecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::const_iterator I = Conversions->begin(),
E = Conversions->end();
I != E; ++I) {
NamedDecl *D = *I;
@@ -2917,7 +2922,8 @@ getAssignmentAction(const InitializedEntity &Entity) {
return Sema::AA_Casting;
case InitializedEntity::EK_Member:
- case InitializedEntity::EK_ArrayOrVectorElement:
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_VectorElement:
return Sema::AA_Initializing;
}
@@ -2935,7 +2941,8 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity,
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Member:
- case InitializedEntity::EK_ArrayOrVectorElement:
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_VectorElement:
return false;
case InitializedEntity::EK_Parameter:
@@ -2981,7 +2988,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Member:
- case InitializedEntity::EK_ArrayOrVectorElement:
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_VectorElement:
// We don't need to copy for any of these initialized entities.
return move(CurInit);
}
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 5eb819a69176..d7d3756020f8 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -47,6 +47,11 @@ public:
/// \brief The entity being initialized is an exception object that
/// is being thrown.
EK_Exception,
+ /// \brief The entity being initialized is a non-static data member
+ /// subobject.
+ EK_Member,
+ /// \brief The entity being initialized is an element of an array.
+ EK_ArrayElement,
/// \brief The entity being initialized is an object (or array of
/// objects) allocated via new.
EK_New,
@@ -54,12 +59,10 @@ public:
EK_Temporary,
/// \brief The entity being initialized is a base member subobject.
EK_Base,
- /// \brief The entity being initialized is a non-static data member
- /// subobject.
- EK_Member,
- /// \brief The entity being initialized is an element of an array
+ /// \brief The entity being initialized is an element of a vector.
/// or vector.
- EK_ArrayOrVectorElement
+ EK_VectorElement
+
};
private:
@@ -211,7 +214,7 @@ public:
/// \brief If this is already the initializer for an array or vector
/// element, sets the element index.
void setElementIndex(unsigned Index) {
- assert(getKind() == EK_ArrayOrVectorElement);
+ assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement);
this->Index = Index;
}
};
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index cda245deba13..f5d2a7d89988 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -317,16 +317,16 @@ void LookupResult::resolveKind() {
// Fast case: no possible ambiguity.
if (N == 0) {
- assert(ResultKind == NotFound);
+ assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation);
return;
}
// If there's a single decl, we need to examine it to decide what
// kind of lookup this is.
if (N == 1) {
- if (isa<FunctionTemplateDecl>(Decls[0]))
+ if (isa<FunctionTemplateDecl>(*Decls.begin()))
ResultKind = FoundOverloaded;
- else if (isa<UnresolvedUsingValueDecl>(Decls[0]))
+ else if (isa<UnresolvedUsingValueDecl>(*Decls.begin()))
ResultKind = FoundUnresolvedValue;
return;
}
@@ -445,8 +445,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
DeclContext::lookup_const_iterator I, E;
for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
- if (R.isAcceptableDecl(*I)) {
- R.addDecl(*I);
+ NamedDecl *D = *I;
+ if (R.isAcceptableDecl(D)) {
+ R.addDecl(D);
Found = true;
}
}
@@ -463,10 +464,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
if (!Record->isDefinition())
return Found;
- const UnresolvedSet *Unresolved = Record->getConversionFunctions();
- for (UnresolvedSet::iterator U = Unresolved->begin(),
- UEnd = Unresolved->end();
- U != UEnd; ++U) {
+ const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions();
+ for (UnresolvedSetImpl::iterator U = Unresolved->begin(),
+ UEnd = Unresolved->end(); U != UEnd; ++U) {
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
if (!ConvTemplate)
continue;
@@ -967,6 +967,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Perform qualified name lookup into the LookupCtx.
if (LookupDirect(R, LookupCtx)) {
R.resolveKind();
+ if (isa<CXXRecordDecl>(LookupCtx))
+ R.setNamingClass(cast<CXXRecordDecl>(LookupCtx));
return true;
}
@@ -1039,6 +1041,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
R.getLookupName().getAsOpaquePtr(), Paths))
return false;
+ R.setNamingClass(LookupRec);
+
// C++ [class.member.lookup]p2:
// [...] If the resulting set of declarations are not all from
// sub-objects of the same type, or the set has a nonstatic member
@@ -1048,10 +1052,15 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// FIXME: support using declarations!
QualType SubobjectType;
int SubobjectNumber = 0;
+ AccessSpecifier SubobjectAccess = AS_private;
for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
Path != PathEnd; ++Path) {
const CXXBasePathElement &PathElement = Path->back();
+ // Pick the best (i.e. most permissive i.e. numerically lowest) access
+ // across all paths.
+ SubobjectAccess = std::min(SubobjectAccess, Path->Access);
+
// Determine whether we're looking at a distinct sub-object or not.
if (SubobjectType.isNull()) {
// This is the first subobject we've looked at. Record its type.
@@ -1106,8 +1115,12 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Lookup in a base class succeeded; return these results.
DeclContext::lookup_iterator I, E;
- for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I)
- R.addDecl(*I);
+ for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) {
+ NamedDecl *D = *I;
+ AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess,
+ D->getAccess());
+ R.addDecl(D, AS);
+ }
R.resolveKind();
return true;
}
@@ -1243,7 +1256,12 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
Diag((*DI)->getLocation(), diag::note_hiding_object);
// For recovery purposes, go ahead and implement the hiding.
- Result.hideDecls(TagDecls);
+ LookupResult::Filter F = Result.makeFilter();
+ while (F.hasNext()) {
+ if (TagDecls.count(F.next()))
+ F.erase();
+ }
+ F.done();
return true;
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 6ec4d1b60018..44a8f15e57b6 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -25,7 +25,6 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
-#include <cstdio>
namespace clang {
@@ -183,51 +182,53 @@ isPointerConversionToVoidPointer(ASTContext& Context) const {
/// DebugPrint - Print this standard conversion sequence to standard
/// error. Useful for debugging overloading issues.
void StandardConversionSequence::DebugPrint() const {
+ llvm::raw_ostream &OS = llvm::errs();
bool PrintedSomething = false;
if (First != ICK_Identity) {
- fprintf(stderr, "%s", GetImplicitConversionName(First));
+ OS << GetImplicitConversionName(First);
PrintedSomething = true;
}
if (Second != ICK_Identity) {
if (PrintedSomething) {
- fprintf(stderr, " -> ");
+ OS << " -> ";
}
- fprintf(stderr, "%s", GetImplicitConversionName(Second));
+ OS << GetImplicitConversionName(Second);
if (CopyConstructor) {
- fprintf(stderr, " (by copy constructor)");
+ OS << " (by copy constructor)";
} else if (DirectBinding) {
- fprintf(stderr, " (direct reference binding)");
+ OS << " (direct reference binding)";
} else if (ReferenceBinding) {
- fprintf(stderr, " (reference binding)");
+ OS << " (reference binding)";
}
PrintedSomething = true;
}
if (Third != ICK_Identity) {
if (PrintedSomething) {
- fprintf(stderr, " -> ");
+ OS << " -> ";
}
- fprintf(stderr, "%s", GetImplicitConversionName(Third));
+ OS << GetImplicitConversionName(Third);
PrintedSomething = true;
}
if (!PrintedSomething) {
- fprintf(stderr, "No conversions required");
+ OS << "No conversions required";
}
}
/// DebugPrint - Print this user-defined conversion sequence to standard
/// error. Useful for debugging overloading issues.
void UserDefinedConversionSequence::DebugPrint() const {
+ llvm::raw_ostream &OS = llvm::errs();
if (Before.First || Before.Second || Before.Third) {
Before.DebugPrint();
- fprintf(stderr, " -> ");
+ OS << " -> ";
}
- fprintf(stderr, "'%s'", ConversionFunction->getNameAsString().c_str());
+ OS << "'" << ConversionFunction->getNameAsString() << "'";
if (After.First || After.Second || After.Third) {
- fprintf(stderr, " -> ");
+ OS << " -> ";
After.DebugPrint();
}
}
@@ -235,27 +236,28 @@ void UserDefinedConversionSequence::DebugPrint() const {
/// DebugPrint - Print this implicit conversion sequence to standard
/// error. Useful for debugging overloading issues.
void ImplicitConversionSequence::DebugPrint() const {
+ llvm::raw_ostream &OS = llvm::errs();
switch (ConversionKind) {
case StandardConversion:
- fprintf(stderr, "Standard conversion: ");
+ OS << "Standard conversion: ";
Standard.DebugPrint();
break;
case UserDefinedConversion:
- fprintf(stderr, "User-defined conversion: ");
+ OS << "User-defined conversion: ";
UserDefined.DebugPrint();
break;
case EllipsisConversion:
- fprintf(stderr, "Ellipsis conversion");
+ OS << "Ellipsis conversion";
break;
case AmbiguousConversion:
- fprintf(stderr, "Ambiguous conversion");
+ OS << "Ambiguous conversion";
break;
case BadConversion:
- fprintf(stderr, "Bad conversion");
+ OS << "Bad conversion";
break;
}
- fprintf(stderr, "\n");
+ OS << "\n";
}
void AmbiguousConversionSequence::construct() {
@@ -1100,7 +1102,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
bool &IncompatibleObjC) {
if (!getLangOptions().ObjC1)
return false;
-
+
// First, we handle all conversions on ObjC object pointer types.
const ObjCObjectPointerType* ToObjCPtr = ToType->getAs<ObjCObjectPointerType>();
const ObjCObjectPointerType *FromObjCPtr =
@@ -1141,8 +1143,23 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
QualType ToPointeeType;
if (const PointerType *ToCPtr = ToType->getAs<PointerType>())
ToPointeeType = ToCPtr->getPointeeType();
- else if (const BlockPointerType *ToBlockPtr = ToType->getAs<BlockPointerType>())
+ else if (const BlockPointerType *ToBlockPtr =
+ ToType->getAs<BlockPointerType>()) {
+ // Objective C++: We're able to convert from a pointer to any object
+ // to a block pointer type.
+ if (FromObjCPtr && FromObjCPtr->isObjCBuiltinType()) {
+ ConvertedType = ToType;
+ return true;
+ }
ToPointeeType = ToBlockPtr->getPointeeType();
+ }
+ else if (FromType->getAs<BlockPointerType>() &&
+ ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) {
+ // Objective C++: We're able to convert from a block pointer type to a
+ // pointer to any object.
+ ConvertedType = ToType;
+ return true;
+ }
else
return false;
@@ -1164,6 +1181,16 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ConvertedType = ToType;
return true;
}
+ // Allow conversion of pointee being objective-c pointer to another one;
+ // as in I* to id.
+ if (FromPointeeType->getAs<ObjCObjectPointerType>() &&
+ ToPointeeType->getAs<ObjCObjectPointerType>() &&
+ isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
+ IncompatibleObjC)) {
+ ConvertedType = ToType;
+ return true;
+ }
+
// If we have pointers to functions or blocks, check whether the only
// differences in the argument and result types are in Objective-C
// pointer conversions. If so, we permit the conversion (but
@@ -1523,9 +1550,9 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
if (CXXRecordDecl *FromRecordDecl
= dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
// Add all of the conversion functions as candidates.
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= FromRecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
@@ -2756,7 +2783,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_bad_conversion;
+ Candidate.FailureKind = ovl_fail_trivial_conversion;
return;
}
@@ -2794,7 +2821,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
case ImplicitConversionSequence::BadConversion:
Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_bad_conversion;
+ Candidate.FailureKind = ovl_fail_bad_final_conversion;
break;
default:
@@ -2869,6 +2896,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
if (ObjectInit.isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
+ Candidate.Conversions[0] = ObjectInit;
return;
}
@@ -3270,9 +3298,9 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
}
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= ClassDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
// Skip conversion function templates; they don't tell us anything
@@ -3334,10 +3362,10 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
}
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- const UnresolvedSet *Conversions =
+ const UnresolvedSetImpl *Conversions =
ClassDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) {
QualType CanTy = Context.getCanonicalType(Conv->getConversionType());
@@ -4386,7 +4414,8 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
QualType FromTy = Conv.Bad.getFromType();
QualType ToTy = Conv.Bad.getToType();
- // Do some hand-waving analysis to see if the non-viability is due to a
+ // Do some hand-waving analysis to see if the non-viability is due
+ // to a qualifier mismatch.
CanQualType CFromTy = S.Context.getCanonicalType(FromTy);
CanQualType CToTy = S.Context.getCanonicalType(ToTy);
if (CanQual<ReferenceType> RT = CToTy->getAs<ReferenceType>())
@@ -4436,6 +4465,20 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
return;
}
+ // Diagnose references or pointers to incomplete types differently,
+ // since it's far from impossible that the incompleteness triggered
+ // the failure.
+ QualType TempFromTy = FromTy.getNonReferenceType();
+ if (const PointerType *PTy = TempFromTy->getAs<PointerType>())
+ TempFromTy = PTy->getPointeeType();
+ if (TempFromTy->isIncompleteType()) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
+ return;
+ }
+
// TODO: specialize more based on the kind of mismatch
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv)
<< (unsigned) FnKind << FnDesc
@@ -4503,6 +4546,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return DiagnoseArityMismatch(S, Cand, NumArgs);
case ovl_fail_bad_deduction:
+ case ovl_fail_trivial_conversion:
+ case ovl_fail_bad_final_conversion:
return S.NoteOverloadCandidate(Fn);
case ovl_fail_bad_conversion:
@@ -4582,12 +4627,23 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
}
}
+SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) {
+ if (Cand->Function)
+ return Cand->Function->getLocation();
+ if (Cand->IsSurrogate)
+ return Cand->Surrogate->getLocation();
+ return SourceLocation();
+}
+
struct CompareOverloadCandidatesForDisplay {
Sema &S;
CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {}
bool operator()(const OverloadCandidate *L,
const OverloadCandidate *R) {
+ // Fast-path this check.
+ if (L == R) return false;
+
// Order first by viability.
if (L->Viable) {
if (!R->Viable) return true;
@@ -4600,25 +4656,132 @@ struct CompareOverloadCandidatesForDisplay {
} else if (R->Viable)
return false;
- // Put declared functions first.
- if (L->Function) {
- if (!R->Function) return true;
- return S.SourceMgr.isBeforeInTranslationUnit(L->Function->getLocation(),
- R->Function->getLocation());
- } else if (R->Function) return false;
-
- // Then surrogates.
- if (L->IsSurrogate) {
- if (!R->IsSurrogate) return true;
- return S.SourceMgr.isBeforeInTranslationUnit(L->Surrogate->getLocation(),
- R->Surrogate->getLocation());
- } else if (R->IsSurrogate) return false;
-
- // And builtins just come in a jumble.
- return false;
+ assert(L->Viable == R->Viable);
+
+ // Criteria by which we can sort non-viable candidates:
+ if (!L->Viable) {
+ // 1. Arity mismatches come after other candidates.
+ if (L->FailureKind == ovl_fail_too_many_arguments ||
+ L->FailureKind == ovl_fail_too_few_arguments)
+ return false;
+ if (R->FailureKind == ovl_fail_too_many_arguments ||
+ R->FailureKind == ovl_fail_too_few_arguments)
+ return true;
+
+ // 2. Bad conversions come first and are ordered by the number
+ // of bad conversions and quality of good conversions.
+ if (L->FailureKind == ovl_fail_bad_conversion) {
+ if (R->FailureKind != ovl_fail_bad_conversion)
+ return true;
+
+ // If there's any ordering between the defined conversions...
+ // FIXME: this might not be transitive.
+ assert(L->Conversions.size() == R->Conversions.size());
+
+ int leftBetter = 0;
+ for (unsigned I = 0, E = L->Conversions.size(); I != E; ++I) {
+ switch (S.CompareImplicitConversionSequences(L->Conversions[I],
+ R->Conversions[I])) {
+ case ImplicitConversionSequence::Better:
+ leftBetter++;
+ break;
+
+ case ImplicitConversionSequence::Worse:
+ leftBetter--;
+ break;
+
+ case ImplicitConversionSequence::Indistinguishable:
+ break;
+ }
+ }
+ if (leftBetter > 0) return true;
+ if (leftBetter < 0) return false;
+
+ } else if (R->FailureKind == ovl_fail_bad_conversion)
+ return false;
+
+ // TODO: others?
+ }
+
+ // Sort everything else by location.
+ SourceLocation LLoc = GetLocationForCandidate(L);
+ SourceLocation RLoc = GetLocationForCandidate(R);
+
+ // Put candidates without locations (e.g. builtins) at the end.
+ if (LLoc.isInvalid()) return false;
+ if (RLoc.isInvalid()) return true;
+
+ return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc);
}
};
+/// CompleteNonViableCandidate - Normally, overload resolution only
+/// computes up to the first
+void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
+ Expr **Args, unsigned NumArgs) {
+ assert(!Cand->Viable);
+
+ // Don't do anything on failures other than bad conversion.
+ if (Cand->FailureKind != ovl_fail_bad_conversion) return;
+
+ // Skip forward to the first bad conversion.
+ unsigned ConvIdx = 0;
+ unsigned ConvCount = Cand->Conversions.size();
+ while (true) {
+ assert(ConvIdx != ConvCount && "no bad conversion in candidate");
+ ConvIdx++;
+ if (Cand->Conversions[ConvIdx - 1].isBad())
+ break;
+ }
+
+ if (ConvIdx == ConvCount)
+ return;
+
+ // FIXME: these should probably be preserved from the overload
+ // operation somehow.
+ bool SuppressUserConversions = false;
+ bool ForceRValue = false;
+
+ const FunctionProtoType* Proto;
+ unsigned ArgIdx = ConvIdx;
+
+ if (Cand->IsSurrogate) {
+ QualType ConvType
+ = Cand->Surrogate->getConversionType().getNonReferenceType();
+ if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
+ ConvType = ConvPtrType->getPointeeType();
+ Proto = ConvType->getAs<FunctionProtoType>();
+ ArgIdx--;
+ } else if (Cand->Function) {
+ Proto = Cand->Function->getType()->getAs<FunctionProtoType>();
+ if (isa<CXXMethodDecl>(Cand->Function) &&
+ !isa<CXXConstructorDecl>(Cand->Function))
+ ArgIdx--;
+ } else {
+ // Builtin binary operator with a bad first conversion.
+ assert(ConvCount <= 3);
+ for (; ConvIdx != ConvCount; ++ConvIdx)
+ Cand->Conversions[ConvIdx]
+ = S.TryCopyInitialization(Args[ConvIdx],
+ Cand->BuiltinTypes.ParamTypes[ConvIdx],
+ SuppressUserConversions, ForceRValue,
+ /*InOverloadResolution*/ true);
+ return;
+ }
+
+ // Fill in the rest of the conversions.
+ unsigned NumArgsInProto = Proto->getNumArgs();
+ for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
+ if (ArgIdx < NumArgsInProto)
+ Cand->Conversions[ConvIdx]
+ = S.TryCopyInitialization(Args[ArgIdx], Proto->getArgType(ArgIdx),
+ SuppressUserConversions, ForceRValue,
+ /*InOverloadResolution=*/true);
+ else
+ Cand->Conversions[ConvIdx].setEllipsis();
+ }
+}
+
} // end anonymous namespace
/// PrintOverloadCandidates - When overload resolution fails, prints
@@ -4636,9 +4799,15 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size());
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
LastCand = CandidateSet.end();
- Cand != LastCand; ++Cand)
- if (Cand->Viable || OCD == OCD_AllCandidates)
+ Cand != LastCand; ++Cand) {
+ if (Cand->Viable)
Cands.push_back(Cand);
+ else if (OCD == OCD_AllCandidates) {
+ CompleteNonViableCandidate(*this, Cand, Args, NumArgs);
+ Cands.push_back(Cand);
+ }
+ }
+
std::sort(Cands.begin(), Cands.end(),
CompareOverloadCandidatesForDisplay(*this));
@@ -5909,9 +6078,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// functions for each conversion function declared in an
// accessible base class provided the function is not hidden
// within T by another intervening declaration.
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 20add007f7c0..f8353e3db1bd 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -390,7 +390,16 @@ namespace clang {
ovl_fail_too_many_arguments,
ovl_fail_too_few_arguments,
ovl_fail_bad_conversion,
- ovl_fail_bad_deduction
+ ovl_fail_bad_deduction,
+
+ /// This conversion candidate was not considered because it
+ /// duplicates the work of a trivial or derived-to-base
+ /// conversion.
+ ovl_fail_trivial_conversion,
+
+ /// This conversion candidate is not viable because its result
+ /// type is not implicitly convertible to the desired type.
+ ovl_fail_bad_final_conversion
};
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 7855a7f60935..0c207fa6e87d 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -412,10 +412,10 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions;
llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions;
if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= cast<CXXRecordDecl>(RecordTy->getDecl())
->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I))
if (Conversion->getConversionType().getNonReferenceType()
@@ -879,10 +879,6 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
Action::OwningStmtResult
Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
IdentifierInfo *LabelII) {
- // If we are in a block, reject all gotos for now.
- if (CurBlock)
- return StmtError(Diag(GotoLoc, diag::err_goto_in_block));
-
// Look up the record for this label identifier.
LabelStmt *&LabelDecl = getLabelMap()[LabelII];
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 2fad8325d4dd..00401560c6a0 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -449,8 +449,8 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
Loc = KeyLoc;
TemplateTypeParmDecl *Param
- = TemplateTypeParmDecl::Create(Context, CurContext, Loc,
- Depth, Position, ParamName, Typename,
+ = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(),
+ Loc, Depth, Position, ParamName, Typename,
Ellipsis);
if (Invalid)
Param->setInvalidDecl();
@@ -572,7 +572,8 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
}
NonTypeTemplateParmDecl *Param
- = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(),
+ = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
+ D.getIdentifierLoc(),
Depth, Position, ParamName, T, TInfo);
if (Invalid)
Param->setInvalidDecl();
@@ -625,8 +626,8 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
// Construct the parameter object.
TemplateTemplateParmDecl *Param =
- TemplateTemplateParmDecl::Create(Context, CurContext, TmpLoc, Depth,
- Position, Name,
+ TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
+ TmpLoc, Depth, Position, Name,
(TemplateParameterList*)Params);
// Make sure the parameter is valid.
@@ -1586,9 +1587,12 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext) {
- if ((ObjectType &&
- computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) ||
- (SS.isSet() && computeDeclContext(SS, EnteringContext))) {
+ DeclContext *LookupCtx = 0;
+ if (SS.isSet())
+ LookupCtx = computeDeclContext(SS, EnteringContext);
+ if (!LookupCtx && ObjectType)
+ LookupCtx = computeDeclContext(QualType::getFromOpaquePtr(ObjectType));
+ if (LookupCtx) {
// C++0x [temp.names]p5:
// If a name prefixed by the keyword template is not the name of
// a template, the program is ill-formed. [Note: the keyword
@@ -1608,8 +1612,9 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
TemplateTy Template;
TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
EnteringContext, Template);
- if (TNK == TNK_Non_template &&
- isCurrentInstantiationWithDependentBases(SS)) {
+ if (TNK == TNK_Non_template && LookupCtx->isDependentContext() &&
+ isa<CXXRecordDecl>(LookupCtx) &&
+ cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) {
// This is a dependent template.
} else if (TNK == TNK_Non_template) {
Diag(Name.getSourceRange().getBegin(),
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e909c4f0b9b6..23a9430d746f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -150,6 +150,7 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev));
}
+ Typedef->setAccess(D->getAccess());
Owner->addDecl(Typedef);
return Typedef;
@@ -208,6 +209,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
if (D->isOutOfLine())
Var->setLexicalDeclContext(D->getLexicalDeclContext());
+ Var->setAccess(D->getAccess());
+
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
bool Redeclaration = false;
@@ -375,6 +378,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
}
Field->setImplicit(D->isImplicit());
+ Field->setAccess(D->getAccess());
Owner->addDecl(Field);
return Field;
@@ -559,6 +563,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
return Inst;
}
+ Inst->setAccess(D->getAccess());
Owner->addDecl(Inst);
// First, we sort the partial specializations by location, so
@@ -634,6 +639,8 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (!Instantiated)
return 0;
+ Instantiated->setAccess(D->getAccess());
+
// Link the instantiated function template declaration to the function
// template from which it was instantiated.
FunctionTemplateDecl *InstTemplate
@@ -717,7 +724,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return Info->Function;
}
- Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0);
+ bool MergeWithParentScope = (TemplateParams != 0) ||
+ !(isa<Decl>(Owner) &&
+ cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
+ Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
llvm::SmallVector<ParmVarDecl *, 4> Params;
QualType T = SubstFunctionType(D, Params);
@@ -844,7 +854,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
return Info->Function;
}
- Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0);
+ bool MergeWithParentScope = (TemplateParams != 0) ||
+ !(isa<Decl>(Owner) &&
+ cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
+ Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
llvm::SmallVector<ParmVarDecl *, 4> Params;
QualType T = SubstFunctionType(D, Params);
@@ -958,6 +971,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
if (D->isPure())
SemaRef.CheckPureMethod(Method, SourceRange());
+ Method->setAccess(D->getAccess());
+
if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) &&
!Method->getFriendObjectKind())
Owner->addDecl(Method);
@@ -997,7 +1012,9 @@ ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
// Allocate the parameter
ParmVarDecl *Param
- = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ = ParmVarDecl::Create(SemaRef.Context,
+ SemaRef.Context.getTranslationUnitDecl(),
+ D->getLocation(),
D->getIdentifier(), T, DI, D->getStorageClass(), 0);
// Mark the default argument as being uninstantiated.
@@ -1542,7 +1559,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
Proto->hasAnyExceptionSpec(),
Exceptions.size(),
Exceptions.data(),
- Proto->getNoReturnAttr()));
+ Proto->getNoReturnAttr(),
+ Proto->getCallConv()));
}
return false;
@@ -1647,8 +1665,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function));
// Introduce a new scope where local variable instantiations will be
- // recorded.
- LocalInstantiationScope Scope(*this);
+ // recorded, unless we're actually a member function within a local
+ // class, in which case we need to merge our results with the parent
+ // scope (of the enclosing function).
+ bool MergeWithParentScope = false;
+ if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Function->getDeclContext()))
+ MergeWithParentScope = Rec->isLocalClass();
+
+ LocalInstantiationScope Scope(*this, MergeWithParentScope);
// Introduce the instantiated function parameters into the local
// instantiation scope.
@@ -1685,6 +1709,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
DeclGroupRef DG(Function);
Consumer.HandleTopLevelDecl(DG);
+ // This class may have local implicit instantiations that need to be
+ // instantiation within this scope.
+ PerformPendingImplicitInstantiations(/*LocalOnly=*/true);
+ Scope.Exit();
+
if (Recursive) {
// Instantiate any pending implicit instantiations found during the
// instantiation of this template.
@@ -2217,10 +2246,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
-void Sema::PerformPendingImplicitInstantiations() {
- while (!PendingImplicitInstantiations.empty()) {
- PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front();
- PendingImplicitInstantiations.pop_front();
+void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
+ while (!PendingLocalImplicitInstantiations.empty() ||
+ (!LocalOnly && !PendingImplicitInstantiations.empty())) {
+ PendingImplicitInstantiation Inst;
+
+ if (PendingLocalImplicitInstantiations.empty()) {
+ Inst = PendingImplicitInstantiations.front();
+ PendingImplicitInstantiations.pop_front();
+ } else {
+ Inst = PendingLocalImplicitInstantiations.front();
+ PendingLocalImplicitInstantiations.pop_front();
+ }
// Instantiate function definitions
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) {
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 9515834bb84a..906576115a56 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1374,6 +1374,21 @@ namespace {
Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo);
TL.setUnderlyingTInfo(TInfo);
}
+ void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
+ // By default, use the source location of the type specifier.
+ TL.setBuiltinLoc(DS.getTypeSpecTypeLoc());
+ if (TL.needsExtraLocalData()) {
+ // Set info for the written builtin specifiers.
+ TL.getWrittenBuiltinSpecs() = DS.getWrittenBuiltinSpecs();
+ // Try to have a meaningful source location.
+ if (TL.getWrittenSignSpec() != TSS_unspecified)
+ // Sign spec loc overrides the others (e.g., 'unsigned long').
+ TL.setBuiltinLoc(DS.getTypeSpecSignLoc());
+ else if (TL.getWrittenWidthSpec() != TSW_unspecified)
+ // Width spec loc overrides type spec loc (e.g., 'short int').
+ TL.setBuiltinLoc(DS.getTypeSpecWidthLoc());
+ }
+ }
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
TL.initialize(DS.getTypeSpecTypeLoc());
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 445ef0dac797..b2102afdfc42 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1014,15 +1014,12 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildCStyleCaseExpr(SourceLocation LParenLoc,
- QualType ExplicitTy,
+ OwningExprResult RebuildCStyleCastExpr(SourceLocation LParenLoc,
+ TypeSourceInfo *TInfo,
SourceLocation RParenLoc,
ExprArg SubExpr) {
- return getSema().ActOnCastExpr(/*Scope=*/0,
- LParenLoc,
- ExplicitTy.getAsOpaquePtr(),
- RParenLoc,
- move(SubExpr));
+ return getSema().BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc,
+ move(SubExpr));
}
/// \brief Build a new compound literal expression.
@@ -1030,11 +1027,11 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCompoundLiteralExpr(SourceLocation LParenLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RParenLoc,
ExprArg Init) {
- return getSema().ActOnCompoundLiteral(LParenLoc, T.getAsOpaquePtr(),
- RParenLoc, move(Init));
+ return getSema().BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc,
+ move(Init));
}
/// \brief Build a new extended vector element access expression.
@@ -1194,30 +1191,30 @@ public:
OwningExprResult RebuildCXXNamedCastExpr(SourceLocation OpLoc,
Stmt::StmtClass Class,
SourceLocation LAngleLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RAngleLoc,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
switch (Class) {
case Stmt::CXXStaticCastExprClass:
- return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, T,
+ return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, TInfo,
RAngleLoc, LParenLoc,
move(SubExpr), RParenLoc);
case Stmt::CXXDynamicCastExprClass:
- return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, T,
+ return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, TInfo,
RAngleLoc, LParenLoc,
move(SubExpr), RParenLoc);
case Stmt::CXXReinterpretCastExprClass:
- return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, T,
+ return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, TInfo,
RAngleLoc, LParenLoc,
move(SubExpr),
RParenLoc);
case Stmt::CXXConstCastExprClass:
- return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, T,
+ return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, TInfo,
RAngleLoc, LParenLoc,
move(SubExpr), RParenLoc);
@@ -1235,14 +1232,15 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXStaticCastExpr(SourceLocation OpLoc,
SourceLocation LAngleLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RAngleLoc,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
- return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_static_cast,
- LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
- LParenLoc, move(SubExpr), RParenLoc);
+ return getSema().BuildCXXNamedCast(OpLoc, tok::kw_static_cast,
+ TInfo, move(SubExpr),
+ SourceRange(LAngleLoc, RAngleLoc),
+ SourceRange(LParenLoc, RParenLoc));
}
/// \brief Build a new C++ dynamic_cast expression.
@@ -1251,14 +1249,15 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXDynamicCastExpr(SourceLocation OpLoc,
SourceLocation LAngleLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RAngleLoc,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
- return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_dynamic_cast,
- LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
- LParenLoc, move(SubExpr), RParenLoc);
+ return getSema().BuildCXXNamedCast(OpLoc, tok::kw_dynamic_cast,
+ TInfo, move(SubExpr),
+ SourceRange(LAngleLoc, RAngleLoc),
+ SourceRange(LParenLoc, RParenLoc));
}
/// \brief Build a new C++ reinterpret_cast expression.
@@ -1267,14 +1266,15 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXReinterpretCastExpr(SourceLocation OpLoc,
SourceLocation LAngleLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RAngleLoc,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
- return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_reinterpret_cast,
- LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
- LParenLoc, move(SubExpr), RParenLoc);
+ return getSema().BuildCXXNamedCast(OpLoc, tok::kw_reinterpret_cast,
+ TInfo, move(SubExpr),
+ SourceRange(LAngleLoc, RAngleLoc),
+ SourceRange(LParenLoc, RParenLoc));
}
/// \brief Build a new C++ const_cast expression.
@@ -1283,14 +1283,15 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXConstCastExpr(SourceLocation OpLoc,
SourceLocation LAngleLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RAngleLoc,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
- return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_const_cast,
- LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
- LParenLoc, move(SubExpr), RParenLoc);
+ return getSema().BuildCXXNamedCast(OpLoc, tok::kw_const_cast,
+ TInfo, move(SubExpr),
+ SourceRange(LAngleLoc, RAngleLoc),
+ SourceRange(LParenLoc, RParenLoc));
}
/// \brief Build a new C++ functional-style cast expression.
@@ -1298,13 +1299,13 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXFunctionalCastExpr(SourceRange TypeRange,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
void *Sub = SubExpr.takeAs<Expr>();
return getSema().ActOnCXXTypeConstructExpr(TypeRange,
- T.getAsOpaquePtr(),
+ TInfo->getType().getAsOpaquePtr(),
LParenLoc,
Sema::MultiExprArg(getSema(), &Sub, 1),
/*CommaLocs=*/0,
@@ -2137,7 +2138,11 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) {
template<typename Derived>
QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB,
BuiltinTypeLoc T) {
- return TransformTypeSpecType(TLB, T);
+ BuiltinTypeLoc NewT = TLB.push<BuiltinTypeLoc>(T.getType());
+ NewT.setBuiltinLoc(T.getBuiltinLoc());
+ if (T.needsExtraLocalData())
+ NewT.getWrittenBuiltinSpecs() = T.getWrittenBuiltinSpecs();
+ return T.getType();
}
template<typename Derived>
@@ -3815,15 +3820,17 @@ TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) {
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
- QualType T;
+ TypeSourceInfo *OldT;
+ TypeSourceInfo *NewT;
{
// FIXME: Source location isn't quite accurate.
SourceLocation TypeStartLoc
= SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName());
- T = getDerived().TransformType(E->getTypeAsWritten());
- if (T.isNull())
+ OldT = E->getTypeInfoAsWritten();
+ NewT = getDerived().TransformType(OldT);
+ if (!NewT)
return SemaRef.ExprError();
}
@@ -3833,11 +3840,12 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- T == E->getTypeAsWritten() &&
+ OldT == NewT &&
SubExpr.get() == E->getSubExpr())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCStyleCaseExpr(E->getLParenLoc(), T,
+ return getDerived().RebuildCStyleCastExpr(E->getLParenLoc(),
+ NewT,
E->getRParenLoc(),
move(SubExpr));
}
@@ -3845,28 +3853,25 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) {
- QualType T;
- {
- // FIXME: Source location isn't quite accurate.
- SourceLocation FakeTypeLoc
- = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
- TemporaryBase Rebase(*this, FakeTypeLoc, DeclarationName());
-
- T = getDerived().TransformType(E->getType());
- if (T.isNull())
- return SemaRef.ExprError();
- }
+ TypeSourceInfo *OldT = E->getTypeSourceInfo();
+ TypeSourceInfo *NewT = getDerived().TransformType(OldT);
+ if (!NewT)
+ return SemaRef.ExprError();
OwningExprResult Init = getDerived().TransformExpr(E->getInitializer());
if (Init.isInvalid())
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- T == E->getType() &&
+ OldT == NewT &&
Init.get() == E->getInitializer())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), T,
+ // Note: the expression type doesn't necessarily match the
+ // type-as-written, but that's okay, because it should always be
+ // derivable from the initializer.
+
+ return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), NewT,
/*FIXME:*/E->getInitializer()->getLocEnd(),
move(Init));
}
@@ -4237,15 +4242,17 @@ TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) {
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
- QualType ExplicitTy;
+ TypeSourceInfo *OldT;
+ TypeSourceInfo *NewT;
{
// FIXME: Source location isn't quite accurate.
SourceLocation TypeStartLoc
= SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName());
- ExplicitTy = getDerived().TransformType(E->getTypeAsWritten());
- if (ExplicitTy.isNull())
+ OldT = E->getTypeInfoAsWritten();
+ NewT = getDerived().TransformType(OldT);
+ if (!NewT)
return SemaRef.ExprError();
}
@@ -4255,7 +4262,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- ExplicitTy == E->getTypeAsWritten() &&
+ OldT == NewT &&
SubExpr.get() == E->getSubExpr())
return SemaRef.Owned(E->Retain());
@@ -4269,7 +4276,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
E->getStmtClass(),
FakeLAngleLoc,
- ExplicitTy,
+ NewT,
FakeRAngleLoc,
FakeRAngleLoc,
move(SubExpr),
@@ -4305,12 +4312,14 @@ template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
CXXFunctionalCastExpr *E) {
- QualType ExplicitTy;
+ TypeSourceInfo *OldT;
+ TypeSourceInfo *NewT;
{
TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
- ExplicitTy = getDerived().TransformType(E->getTypeAsWritten());
- if (ExplicitTy.isNull())
+ OldT = E->getTypeInfoAsWritten();
+ NewT = getDerived().TransformType(OldT);
+ if (!NewT)
return SemaRef.ExprError();
}
@@ -4320,14 +4329,14 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- ExplicitTy == E->getTypeAsWritten() &&
+ OldT == NewT &&
SubExpr.get() == E->getSubExpr())
return SemaRef.Owned(E->Retain());
// FIXME: The end of the type's source range is wrong
return getDerived().RebuildCXXFunctionalCastExpr(
/*FIXME:*/SourceRange(E->getTypeBeginLoc()),
- ExplicitTy,
+ NewT,
/*FIXME:*/E->getSubExpr()->getLocStart(),
move(SubExpr),
E->getRParenLoc());