summaryrefslogtreecommitdiffstats
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/JumpDiagnostics.cpp14
-rw-r--r--lib/Sema/Sema.cpp62
-rw-r--r--lib/Sema/Sema.h183
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp48
-rw-r--r--lib/Sema/SemaChecking.cpp465
-rw-r--r--lib/Sema/SemaCodeComplete.cpp9
-rw-r--r--lib/Sema/SemaDecl.cpp182
-rw-r--r--lib/Sema/SemaDeclAttr.cpp236
-rw-r--r--lib/Sema/SemaDeclCXX.cpp170
-rw-r--r--lib/Sema/SemaDeclObjC.cpp98
-rw-r--r--lib/Sema/SemaExpr.cpp188
-rw-r--r--lib/Sema/SemaExprCXX.cpp787
-rw-r--r--lib/Sema/SemaExprObjC.cpp16
-rw-r--r--lib/Sema/SemaInit.cpp25
-rw-r--r--lib/Sema/SemaLookup.cpp40
-rw-r--r--lib/Sema/SemaOverload.cpp116
-rw-r--r--lib/Sema/SemaOverload.h68
-rw-r--r--lib/Sema/SemaStmt.cpp29
-rw-r--r--lib/Sema/SemaTemplate.cpp58
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp21
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp23
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp238
-rw-r--r--lib/Sema/SemaType.cpp31
-rw-r--r--lib/Sema/TargetAttributesSema.cpp112
-rw-r--r--lib/Sema/TreeTransform.h472
25 files changed, 2550 insertions, 1141 deletions
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 2b37e9d..7cf207f 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -77,7 +77,7 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
/// diagnostic that should be emitted if control goes over it. If not, return 0.
-static unsigned GetDiagForGotoScopeDecl(const Decl *D) {
+static unsigned GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->getType()->isVariablyModifiedType())
return diag::note_protected_by_vla;
@@ -85,6 +85,9 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D) {
return diag::note_protected_by_cleanup;
if (VD->hasAttr<BlocksAttr>())
return diag::note_protected_by___block;
+ if (isCPlusPlus && VD->hasLocalStorage() && VD->hasInit())
+ return diag::note_protected_by_variable_init;
+
} else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
return diag::note_protected_by_vla_typedef;
@@ -116,18 +119,17 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
Stmt *SubStmt = *CI;
if (SubStmt == 0) continue;
- // FIXME: diagnose jumps past initialization: required in C++, warning in C.
- // goto L; int X = 4; L: ;
+ bool isCPlusPlus = this->S.getLangOptions().CPlusPlus;
// If this is a declstmt with a VLA definition, it defines a scope from here
// to the end of the containing context.
if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) {
- // The decl statement creates a scope if any of the decls in it are VLAs or
- // have the cleanup attribute.
+ // The decl statement creates a scope if any of the decls in it are VLAs
+ // or have the cleanup attribute.
for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
I != E; ++I) {
// If this decl causes a new scope, push and switch to it.
- if (unsigned Diag = GetDiagForGotoScopeDecl(*I)) {
+ if (unsigned Diag = GetDiagForGotoScopeDecl(*I, isCPlusPlus)) {
Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation()));
ParentScope = Scopes.size()-1;
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 38c842e..3b4afef 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -26,7 +26,18 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
using namespace clang;
-
+
+FunctionScopeInfo::~FunctionScopeInfo() { }
+
+void FunctionScopeInfo::Clear(unsigned NumErrors) {
+ NeedsScopeChecking = false;
+ LabelMap.clear();
+ SwitchStack.clear();
+ NumErrorsAtStartOfFunction = NumErrors;
+}
+
+BlockScopeInfo::~BlockScopeInfo() { }
+
static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
if (C.getLangOptions().CPlusPlus)
return CXXRecordDecl::Create(C, TagDecl::TK_struct,
@@ -116,7 +127,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
- CurBlock(0), PackContext(0), ParsingDeclDepth(0),
+ PackContext(0), TopFunctionScope(0), ParsingDeclDepth(0),
IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
@@ -138,6 +149,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
Sema::~Sema() {
if (PackContext) FreePackedContext();
delete TheTargetAttributesSema;
+ while (!FunctionScopes.empty())
+ PopFunctionOrBlockScope();
}
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
@@ -342,6 +355,51 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
return Builder;
}
+
+/// \brief Enter a new function scope
+void Sema::PushFunctionScope() {
+ if (FunctionScopes.empty()) {
+ // Use the "top" function scope rather than having to allocate memory for
+ // a new scope.
+ TopFunctionScope.Clear(getDiagnostics().getNumErrors());
+ FunctionScopes.push_back(&TopFunctionScope);
+ return;
+ }
+
+ FunctionScopes.push_back(
+ new FunctionScopeInfo(getDiagnostics().getNumErrors()));
+}
+
+void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
+ FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics().getNumErrors(),
+ BlockScope, Block));
+}
+
+void Sema::PopFunctionOrBlockScope() {
+ if (FunctionScopes.back() != &TopFunctionScope)
+ delete FunctionScopes.back();
+ else
+ TopFunctionScope.Clear(getDiagnostics().getNumErrors());
+
+ FunctionScopes.pop_back();
+}
+
+/// \brief Determine whether any errors occurred within this function/method/
+/// block.
+bool Sema::hasAnyErrorsInThisFunction() const {
+ unsigned NumErrors = TopFunctionScope.NumErrorsAtStartOfFunction;
+ if (!FunctionScopes.empty())
+ NumErrors = FunctionScopes.back()->NumErrorsAtStartOfFunction;
+ return NumErrors != getDiagnostics().getNumErrors();
+}
+
+BlockScopeInfo *Sema::getCurBlock() {
+ if (FunctionScopes.empty())
+ return 0;
+
+ return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
+}
+
void Sema::ActOnComment(SourceRange Comment) {
Context.Comments.push_back(Comment);
}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3c7492a..efd04e8 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -95,6 +95,7 @@ namespace clang {
class ObjCMethodDecl;
class ObjCPropertyDecl;
class ObjCContainerDecl;
+ class PseudoDestructorTypeStorage;
class FunctionProtoType;
class CXXBasePath;
class CXXBasePaths;
@@ -107,9 +108,47 @@ namespace clang {
class TargetAttributesSema;
class ADLResult;
-/// BlockSemaInfo - When a block is being parsed, this contains information
-/// about the block. It is pointed to from Sema::CurBlock.
-struct BlockSemaInfo {
+/// \brief Retains information about a function, method, or block that is
+/// currently being parsed.
+struct FunctionScopeInfo {
+ /// \brief Whether this scope information structure defined information for
+ /// a block.
+ bool IsBlockInfo;
+
+ /// \brief Set true when a function, method contains a VLA or ObjC try block,
+ /// which introduce scopes that need to be checked for goto conditions. If a
+ /// function does not contain this, then it need not have the jump checker run on it.
+ bool NeedsScopeChecking;
+
+ /// \brief The number of errors that had occurred before starting this
+ /// function or block.
+ unsigned NumErrorsAtStartOfFunction;
+
+ /// LabelMap - This is a mapping from label identifiers to the LabelStmt for
+ /// it (which acts like the label decl in some ways). Forward referenced
+ /// labels have a LabelStmt created for them with a null location & SubStmt.
+ llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap;
+
+ /// SwitchStack - This is the current set of active switch statements in the
+ /// block.
+ llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
+
+ FunctionScopeInfo(unsigned NumErrors)
+ : IsBlockInfo(false), NeedsScopeChecking(false),
+ NumErrorsAtStartOfFunction(NumErrors) { }
+
+ virtual ~FunctionScopeInfo();
+
+ /// \brief Clear out the information in this function scope, making it
+ /// suitable for reuse.
+ void Clear(unsigned NumErrors);
+
+ static bool classof(const FunctionScopeInfo *FSI) { return true; }
+};
+
+
+/// \brief Retains information about a block that is currently being parsed.
+struct BlockScopeInfo : FunctionScopeInfo {
llvm::SmallVector<ParmVarDecl*, 8> Params;
bool hasPrototype;
bool isVariadic;
@@ -125,22 +164,17 @@ struct BlockSemaInfo {
/// return types, if any, in the block body.
QualType ReturnType;
- /// LabelMap - This is a mapping from label identifiers to the LabelStmt for
- /// it (which acts like the label decl in some ways). Forward referenced
- /// labels have a LabelStmt created for them with a null location & SubStmt.
- llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap;
-
- /// SwitchStack - This is the current set of active switch statements in the
- /// block.
- llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
+ BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block)
+ : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false),
+ hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope)
+ {
+ IsBlockInfo = true;
+ }
- /// SavedFunctionNeedsScopeChecking - This is the value of
- /// CurFunctionNeedsScopeChecking at the point when the block started.
- bool SavedFunctionNeedsScopeChecking;
+ virtual ~BlockScopeInfo();
- /// PrevBlockInfo - If this is nested inside another block, this points
- /// to the outer block.
- BlockSemaInfo *PrevBlockInfo;
+ static bool classof(const FunctionScopeInfo *FSI) { return FSI->IsBlockInfo; }
+ static bool classof(const BlockScopeInfo *BSI) { return true; }
};
/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator
@@ -199,38 +233,25 @@ public:
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;
- /// CurBlock - If inside of a block definition, this contains a pointer to
- /// the active block object that represents it.
- BlockSemaInfo *CurBlock;
-
/// PackContext - Manages the stack for #pragma pack. An alignment
/// of 0 indicates default alignment.
void *PackContext; // Really a "PragmaPackStack*"
- /// FunctionLabelMap - This is a mapping from label identifiers to the
- /// LabelStmt for it (which acts like the label decl in some ways). Forward
- /// referenced labels have a LabelStmt created for them with a null location &
- /// SubStmt.
+ /// \brief Stack containing information about each of the nested function,
+ /// block, and method scopes that are currently active.
+ llvm::SmallVector<FunctionScopeInfo *, 4> FunctionScopes;
+
+ /// \brief Cached function scope object used for the top function scope
+ /// and when there is no function scope (in error cases).
///
- /// Note that this should always be accessed through getLabelMap() in order
- /// to handle blocks properly.
- llvm::DenseMap<IdentifierInfo*, LabelStmt*> FunctionLabelMap;
-
- /// FunctionSwitchStack - This is the current set of active switch statements
- /// in the top level function. Clients should always use getSwitchStack() to
- /// handle the case when they are in a block.
- llvm::SmallVector<SwitchStmt*, 8> FunctionSwitchStack;
-
+ /// This should never be accessed directly; rather, it's address will be
+ /// pushed into \c FunctionScopes when we want to re-use it.
+ FunctionScopeInfo TopFunctionScope;
+
/// ExprTemporaries - This is the stack of temporaries that are created by
/// the current full expression.
llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries;
- /// CurFunctionNeedsScopeChecking - This is set to true when a function or
- /// ObjC method body contains a VLA or an ObjC try block, which introduce
- /// scopes that need to be checked for goto conditions. If a function does
- /// not contain this, then it need not have the jump checker run on it.
- bool CurFunctionNeedsScopeChecking;
-
/// ExtVectorDecls - This is a list all the extended vector types. This allows
/// us to associate a raw vector type with one of the ext_vector type names.
/// This is only necessary for issuing pretty diagnostics.
@@ -606,18 +627,42 @@ public:
virtual void ActOnEndOfTranslationUnit();
+ void PushFunctionScope();
+ void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
+ void PopFunctionOrBlockScope();
+
/// getLabelMap() - Return the current label map. If we're in a block, we
/// return it.
llvm::DenseMap<IdentifierInfo*, LabelStmt*> &getLabelMap() {
- return CurBlock ? CurBlock->LabelMap : FunctionLabelMap;
+ if (FunctionScopes.empty())
+ return TopFunctionScope.LabelMap;
+
+ return FunctionScopes.back()->LabelMap;
}
/// getSwitchStack - This is returns the switch stack for the current block or
/// function.
llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() {
- return CurBlock ? CurBlock->SwitchStack : FunctionSwitchStack;
+ if (FunctionScopes.empty())
+ return TopFunctionScope.SwitchStack;
+
+ return FunctionScopes.back()->SwitchStack;
}
+ /// \brief Determine whether the current function or block needs scope
+ /// checking.
+ bool &FunctionNeedsScopeChecking() {
+ if (FunctionScopes.empty())
+ return TopFunctionScope.NeedsScopeChecking;
+
+ return FunctionScopes.back()->NeedsScopeChecking;
+ }
+
+ bool hasAnyErrorsInThisFunction() const;
+
+ /// \brief Retrieve the current block, if any.
+ BlockScopeInfo *getCurBlock();
+
/// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls
llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
@@ -1440,6 +1485,8 @@ public:
void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl);
+ void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID);
+
/// MatchTwoMethodDeclarations - Checks if two methods' type match and returns
/// true, or false, accordingly.
bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
@@ -2056,6 +2103,12 @@ public:
SourceLocation Loc,
ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
+ virtual TypeTy *getDestructorName(SourceLocation TildeLoc,
+ IdentifierInfo &II, SourceLocation NameLoc,
+ Scope *S, const CXXScopeSpec &SS,
+ TypeTy *ObjectType,
+ bool EnteringContext);
+
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
tok::TokenKind Kind,
@@ -2167,8 +2220,32 @@ public:
ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- TypeTy *&ObjectType);
+ TypeTy *&ObjectType,
+ bool &MayBePseudoDestructor);
+ OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc,
+ ExprArg MemExpr);
+
+ OwningExprResult BuildPseudoDestructorExpr(ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ TypeSourceInfo *ScopeType,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
+ PseudoDestructorTypeStorage DestroyedType,
+ bool HasTrailingLParen);
+
+ virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ UnqualifiedId &FirstTypeName,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
+ UnqualifiedId &SecondTypeName,
+ bool HasTrailingLParen);
+
/// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
/// non-empty, will create a new CXXExprWithTemporaries expression.
/// Otherwise, just returs the passed in expression.
@@ -2195,7 +2272,11 @@ public:
bool isAcceptableNestedNameSpecifier(NamedDecl *SD);
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
-
+ virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
+ SourceLocation IdLoc,
+ IdentifierInfo &II,
+ TypeTy *ObjectType);
+
CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
SourceLocation IdLoc,
@@ -3376,7 +3457,8 @@ public:
Decl *getInstantiationOf(const Decl *D) {
Decl *Result = LocalDecls[D];
- assert(Result && "declaration was not instantiated in this scope!");
+ assert((Result || D->isInvalidDecl()) &&
+ "declaration was not instantiated in this scope!");
return Result;
}
@@ -3395,7 +3477,7 @@ public:
void InstantiatedLocal(const Decl *D, Decl *Inst) {
Decl *&Stored = LocalDecls[D];
- assert(!Stored && "Already instantiated this local");
+ assert((!Stored || Stored == Inst) && "Already instantiated this local");
Stored = Inst;
}
};
@@ -3502,9 +3584,9 @@ public:
const CXXConstructorDecl *Tmpl,
const MultiLevelTemplateArgumentList &TemplateArgs);
- NamedDecl *FindInstantiatedDecl(NamedDecl *D,
+ NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs);
- DeclContext *FindInstantiatedContext(DeclContext *DC,
+ DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
const MultiLevelTemplateArgumentList &TemplateArgs);
// Objective-C declarations.
@@ -3910,7 +3992,8 @@ public:
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
QualType CXXCheckConditionalOperands( // C++ 5.16
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
- QualType FindCompositePointerType(Expr *&E1, Expr *&E2); // C++ 5.9
+ QualType FindCompositePointerType(Expr *&E1, Expr *&E2,
+ bool *NonStandardCompositeType = 0);
QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
SourceLocation questionLoc);
@@ -4129,7 +4212,7 @@ private:
CallExpr *TheCall);
bool SemaBuiltinVAStart(CallExpr *TheCall);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
- bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned LastArg=1);
+ bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs);
bool SemaBuiltinStackAddress(CallExpr *TheCall);
public:
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 52e9e9b..971b78c 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -327,6 +327,54 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
return 0;
}
+bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
+ SourceLocation IdLoc,
+ IdentifierInfo &II,
+ TypeTy *ObjectTypePtr) {
+ QualType ObjectType = GetTypeFromParser(ObjectTypePtr);
+ LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName);
+
+ // Determine where to perform name lookup
+ DeclContext *LookupCtx = 0;
+ bool isDependent = false;
+ if (!ObjectType.isNull()) {
+ // This nested-name-specifier occurs in a member access expression, e.g.,
+ // x->B::f, and we are looking into the type of the object.
+ assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
+ LookupCtx = computeDeclContext(ObjectType);
+ isDependent = ObjectType->isDependentType();
+ } else if (SS.isSet()) {
+ // This nested-name-specifier occurs after another nested-name-specifier,
+ // so long into the context associated with the prior nested-name-specifier.
+ LookupCtx = computeDeclContext(SS, false);
+ isDependent = isDependentScopeSpecifier(SS);
+ Found.setContextRange(SS.getRange());
+ }
+
+ if (LookupCtx) {
+ // Perform "qualified" name lookup into the declaration context we
+ // computed, which is either the type of the base of a member access
+ // expression or the declaration context associated with a prior
+ // nested-name-specifier.
+
+ // The declaration context must be complete.
+ if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
+ return false;
+
+ LookupQualifiedName(Found, LookupCtx);
+ } else if (isDependent) {
+ return false;
+ } else {
+ LookupName(Found, S);
+ }
+ Found.suppressDiagnostics();
+
+ if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
+ return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
+
+ return false;
+}
+
/// \brief Build a new nested-name-specifier for "identifier::", as described
/// by ActOnCXXNestedNameSpecifier.
///
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index b62cd19..30a6ab4 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -13,8 +13,9 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "clang/Analysis/CFG.h"
#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/PrintfFormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
@@ -109,7 +110,8 @@ bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) {
}
if (format_idx < TheCall->getNumArgs()) {
Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts();
- if (!Format->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
+ if (!Format->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull))
return true;
}
}
@@ -150,7 +152,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__builtin_isinf_sign:
case Builtin::BI__builtin_isnan:
case Builtin::BI__builtin_isnormal:
- if (SemaBuiltinFPClassification(TheCall))
+ if (SemaBuiltinFPClassification(TheCall, 1))
return ExprError();
break;
case Builtin::BI__builtin_return_address:
@@ -504,6 +506,7 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
}
// Determine whether the current function is variadic or not.
+ BlockScopeInfo *CurBlock = getCurBlock();
bool isVariadic;
if (CurBlock)
isVariadic = CurBlock->isVariadic;
@@ -590,19 +593,20 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
/// SemaBuiltinSemaBuiltinFPClassification - Handle functions like
/// __builtin_isnan and friends. This is declared to take (...), so we have
-/// to check everything.
-bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned LastArg) {
- if (TheCall->getNumArgs() < LastArg)
+/// to check everything. We expect the last argument to be a floating point
+/// value.
+bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
+ if (TheCall->getNumArgs() < NumArgs)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 /*function call*/;
- if (TheCall->getNumArgs() > LastArg)
- return Diag(TheCall->getArg(LastArg)->getLocStart(),
+ if (TheCall->getNumArgs() > NumArgs)
+ return Diag(TheCall->getArg(NumArgs)->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/
- << SourceRange(TheCall->getArg(LastArg)->getLocStart(),
+ << SourceRange(TheCall->getArg(NumArgs)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
- Expr *OrigArg = TheCall->getArg(LastArg-1);
+ Expr *OrigArg = TheCall->getArg(NumArgs-1);
if (OrigArg->isTypeDependent())
return false;
@@ -953,6 +957,7 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
/// FormatGuard: Automatic Protection From printf Format String
/// Vulnerabilities, Proceedings of the 10th USENIX Security Symposium, 2001.
///
+/// TODO:
/// Functionality implemented:
///
/// We can statically check the following properties for string
@@ -963,7 +968,7 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
/// data arguments?
///
/// (2) Does each format conversion correctly match the type of the
-/// corresponding data argument? (TODO)
+/// corresponding data argument?
///
/// Moreover, for all printf functions we can:
///
@@ -982,7 +987,6 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
///
/// All of these checks can be done by parsing the format string.
///
-/// For now, we ONLY do (1), (3), (5), (6), (7), and (8).
void
Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg) {
@@ -1042,13 +1046,15 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler {
Sema &S;
const StringLiteral *FExpr;
const Expr *OrigFormatExpr;
- unsigned NumConversions;
const unsigned NumDataArgs;
const bool IsObjCLiteral;
const char *Beg; // Start of format string.
const bool HasVAListArg;
const CallExpr *TheCall;
unsigned FormatIdx;
+ llvm::BitVector CoveredArgs;
+ bool usesPositionalArgs;
+ bool atFirstArg;
public:
CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr,
@@ -1056,21 +1062,31 @@ public:
const char *beg, bool hasVAListArg,
const CallExpr *theCall, unsigned formatIdx)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
- NumConversions(0), NumDataArgs(numDataArgs),
+ NumDataArgs(numDataArgs),
IsObjCLiteral(isObjCLiteral), Beg(beg),
HasVAListArg(hasVAListArg),
- TheCall(theCall), FormatIdx(formatIdx) {}
+ TheCall(theCall), FormatIdx(formatIdx),
+ usesPositionalArgs(false), atFirstArg(true) {
+ CoveredArgs.resize(numDataArgs);
+ CoveredArgs.reset();
+ }
void DoneProcessing();
void HandleIncompleteFormatSpecifier(const char *startSpecifier,
unsigned specifierLen);
- void
+ bool
HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen);
+ virtual void HandleInvalidPosition(const char *startSpecifier,
+ unsigned specifierLen,
+ analyze_printf::PositionContext p);
+
+ virtual void HandleZeroPosition(const char *startPos, unsigned posLen);
+
void HandleNullChar(const char *nullCharacter);
bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
@@ -1082,9 +1098,8 @@ private:
unsigned specifierLen);
SourceLocation getLocationOfByte(const char *x);
- bool HandleAmount(const analyze_printf::OptionalAmount &Amt,
- unsigned MissingArgDiag, unsigned BadTypeDiag,
- const char *startSpecifier, unsigned specifierLen);
+ bool HandleAmount(const analyze_printf::OptionalAmount &Amt, unsigned k,
+ const char *startSpecifier, unsigned specifierLen);
void HandleFlags(const analyze_printf::FormatSpecifier &FS,
llvm::StringRef flag, llvm::StringRef cspec,
const char *startSpecifier, unsigned specifierLen);
@@ -1115,18 +1130,50 @@ HandleIncompleteFormatSpecifier(const char *startSpecifier,
<< getFormatSpecifierRange(startSpecifier, specifierLen);
}
-void CheckPrintfHandler::
+void
+CheckPrintfHandler::HandleInvalidPosition(const char *startPos, unsigned posLen,
+ analyze_printf::PositionContext p) {
+ SourceLocation Loc = getLocationOfByte(startPos);
+ S.Diag(Loc, diag::warn_printf_invalid_positional_specifier)
+ << (unsigned) p << getFormatSpecifierRange(startPos, posLen);
+}
+
+void CheckPrintfHandler::HandleZeroPosition(const char *startPos,
+ unsigned posLen) {
+ SourceLocation Loc = getLocationOfByte(startPos);
+ S.Diag(Loc, diag::warn_printf_zero_positional_specifier)
+ << getFormatSpecifierRange(startPos, posLen);
+}
+
+bool CheckPrintfHandler::
HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen) {
- ++NumConversions;
+ unsigned argIndex = FS.getArgIndex();
+ bool keepGoing = true;
+ if (argIndex < NumDataArgs) {
+ // Consider the argument coverered, even though the specifier doesn't
+ // make sense.
+ CoveredArgs.set(argIndex);
+ }
+ else {
+ // If argIndex exceeds the number of data arguments we
+ // don't issue a warning because that is just a cascade of warnings (and
+ // they may have intended '%%' anyway). We don't want to continue processing
+ // the format string after this point, however, as we will like just get
+ // gibberish when trying to match arguments.
+ keepGoing = false;
+ }
+
const analyze_printf::ConversionSpecifier &CS =
FS.getConversionSpecifier();
SourceLocation Loc = getLocationOfByte(CS.getStart());
S.Diag(Loc, diag::warn_printf_invalid_conversion)
<< llvm::StringRef(CS.getStart(), CS.getLength())
<< getFormatSpecifierRange(startSpecifier, specifierLen);
+
+ return keepGoing;
}
void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) {
@@ -1137,7 +1184,7 @@ void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) {
}
const Expr *CheckPrintfHandler::getDataArg(unsigned i) const {
- return TheCall->getArg(FormatIdx + i);
+ return TheCall->getArg(FormatIdx + i + 1);
}
@@ -1154,17 +1201,16 @@ void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS,
bool
CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt,
- unsigned MissingArgDiag,
- unsigned BadTypeDiag,
- const char *startSpecifier,
+ unsigned k, const char *startSpecifier,
unsigned specifierLen) {
if (Amt.hasDataArgument()) {
- ++NumConversions;
if (!HasVAListArg) {
- if (NumConversions > NumDataArgs) {
- S.Diag(getLocationOfByte(Amt.getStart()), MissingArgDiag)
- << getFormatSpecifierRange(startSpecifier, specifierLen);
+ unsigned argIndex = Amt.getArgIndex();
+ if (argIndex >= NumDataArgs) {
+ S.Diag(getLocationOfByte(Amt.getStart()),
+ diag::warn_printf_asterisk_missing_arg)
+ << k << getFormatSpecifierRange(startSpecifier, specifierLen);
// Don't do any more checking. We will just emit
// spurious errors.
return false;
@@ -1174,14 +1220,17 @@ CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt,
// Although not in conformance with C99, we also allow the argument to be
// an 'unsigned int' as that is a reasonably safe case. GCC also
// doesn't emit a warning for that case.
- const Expr *Arg = getDataArg(NumConversions);
+ CoveredArgs.set(argIndex);
+ const Expr *Arg = getDataArg(argIndex);
QualType T = Arg->getType();
const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context);
assert(ATR.isValid());
if (!ATR.matchesType(S.Context, T)) {
- S.Diag(getLocationOfByte(Amt.getStart()), BadTypeDiag)
+ S.Diag(getLocationOfByte(Amt.getStart()),
+ diag::warn_printf_asterisk_wrong_type)
+ << k
<< ATR.getRepresentativeType(S.Context) << T
<< getFormatSpecifierRange(startSpecifier, specifierLen)
<< Arg->getSourceRange();
@@ -1200,32 +1249,31 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
const char *startSpecifier,
unsigned specifierLen) {
- using namespace analyze_printf;
+ using namespace analyze_printf;
const ConversionSpecifier &CS = FS.getConversionSpecifier();
- // First check if the field width, precision, and conversion specifier
- // have matching data arguments.
- if (!HandleAmount(FS.getFieldWidth(),
- diag::warn_printf_asterisk_width_missing_arg,
- diag::warn_printf_asterisk_width_wrong_type,
- startSpecifier, specifierLen)) {
+ if (atFirstArg) {
+ atFirstArg = false;
+ usesPositionalArgs = FS.usesPositionalArg();
+ }
+ else if (usesPositionalArgs != FS.usesPositionalArg()) {
+ // Cannot mix-and-match positional and non-positional arguments.
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_mix_positional_nonpositional_args)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
return false;
}
- if (!HandleAmount(FS.getPrecision(),
- diag::warn_printf_asterisk_precision_missing_arg,
- diag::warn_printf_asterisk_precision_wrong_type,
- startSpecifier, specifierLen)) {
+ // First check if the field width, precision, and conversion specifier
+ // have matching data arguments.
+ if (!HandleAmount(FS.getFieldWidth(), /* field width */ 0,
+ startSpecifier, specifierLen)) {
return false;
}
- // Check for using an Objective-C specific conversion specifier
- // in a non-ObjC literal.
- if (!IsObjCLiteral && CS.isObjCArg()) {
- HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen);
-
- // Continue checking the other format specifiers.
- return true;
+ if (!HandleAmount(FS.getPrecision(), /* precision */ 1,
+ startSpecifier, specifierLen)) {
+ return false;
}
if (!CS.consumesDataArgument()) {
@@ -1234,7 +1282,20 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
return true;
}
- ++NumConversions;
+ // Consume the argument.
+ unsigned argIndex = FS.getArgIndex();
+ if (argIndex < NumDataArgs) {
+ // The check to see if the argIndex is valid will come later.
+ // We set the bit here because we may exit early from this
+ // function if we encounter some other error.
+ CoveredArgs.set(argIndex);
+ }
+
+ // Check for using an Objective-C specific conversion specifier
+ // in a non-ObjC literal.
+ if (!IsObjCLiteral && CS.isObjCArg()) {
+ return HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen);
+ }
// Are we using '%n'? Issue a warning about this being
// a possible security issue.
@@ -1268,7 +1329,7 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
if (HasVAListArg)
return true;
- if (NumConversions > NumDataArgs) {
+ if (argIndex >= NumDataArgs) {
S.Diag(getLocationOfByte(CS.getStart()),
diag::warn_printf_insufficient_data_args)
<< getFormatSpecifierRange(startSpecifier, specifierLen);
@@ -1278,7 +1339,7 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
// Now type check the data expression that matches the
// format specifier.
- const Expr *Ex = getDataArg(NumConversions);
+ const Expr *Ex = getDataArg(argIndex);
const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context);
if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
// Check if we didn't match because of an implicit cast from a 'char'
@@ -1302,10 +1363,17 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
void CheckPrintfHandler::DoneProcessing() {
// Does the number of data arguments exceed the number of
// format conversions in the format string?
- if (!HasVAListArg && NumConversions < NumDataArgs)
- S.Diag(getDataArg(NumConversions+1)->getLocStart(),
- diag::warn_printf_too_many_data_args)
- << getFormatStringRange();
+ if (!HasVAListArg) {
+ // Find any arguments that weren't covered.
+ CoveredArgs.flip();
+ signed notCoveredArg = CoveredArgs.find_first();
+ if (notCoveredArg >= 0) {
+ assert((unsigned)notCoveredArg < NumDataArgs);
+ S.Diag(getDataArg((unsigned) notCoveredArg)->getLocStart(),
+ diag::warn_printf_data_arg_not_used)
+ << getFormatStringRange();
+ }
+ }
}
void Sema::CheckPrintfString(const StringLiteral *FExpr,
@@ -1680,13 +1748,13 @@ struct IntRange {
}
// Returns the supremum of two ranges: i.e. their conservative merge.
- static IntRange join(const IntRange &L, const IntRange &R) {
+ static IntRange join(IntRange L, IntRange R) {
return IntRange(std::max(L.Width, R.Width),
L.NonNegative && R.NonNegative);
}
// Returns the infinum of two ranges: i.e. their aggressive merge.
- static IntRange meet(const IntRange &L, const IntRange &R) {
+ static IntRange meet(IntRange L, IntRange R) {
return IntRange(std::min(L.Width, R.Width),
L.NonNegative || R.NonNegative);
}
@@ -1804,6 +1872,15 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
case BinaryOperator::NE:
return IntRange::forBoolType();
+ // The type of these compound assignments is the type of the LHS,
+ // so the RHS is not necessarily an integer.
+ case BinaryOperator::MulAssign:
+ case BinaryOperator::DivAssign:
+ case BinaryOperator::RemAssign:
+ case BinaryOperator::AddAssign:
+ case BinaryOperator::SubAssign:
+ return IntRange::forType(C, E->getType());
+
// Operations with opaque sources are black-listed.
case BinaryOperator::PtrMemD:
case BinaryOperator::PtrMemI:
@@ -1811,15 +1888,18 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
// Bitwise-and uses the *infinum* of the two source ranges.
case BinaryOperator::And:
+ case BinaryOperator::AndAssign:
return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth),
GetExprRange(C, BO->getRHS(), MaxWidth));
// Left shift gets black-listed based on a judgement call.
case BinaryOperator::Shl:
+ case BinaryOperator::ShlAssign:
return IntRange::forType(C, E->getType());
// Right shift by a constant can narrow its left argument.
- case BinaryOperator::Shr: {
+ case BinaryOperator::Shr:
+ case BinaryOperator::ShrAssign: {
IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
// If the shift amount is a positive constant, drop the width by
@@ -2103,250 +2183,30 @@ 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) { }
- };
+class UnreachableCodeHandler : public reachable_code::Callback {
+ Sema &S;
+public:
+ UnreachableCodeHandler(Sema *s) : S(*s) {}
+
+ void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) {
+ S.Diag(L, diag::warn_unreachable) << R1 << 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)
+ if (getDiagnostics().hasErrorOccurred() ||
+ Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
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;
+ UnreachableCodeHandler UC(this);
+ reachable_code::FindUnreachableCode(AC, UC);
}
/// CheckFallThrough - Check that we don't fall off the end of a
@@ -2368,7 +2228,8 @@ Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) {
// confuse us, so we mark all live things first.
std::queue<CFGBlock*> workq;
llvm::BitVector live(cfg->getNumBlockIDs());
- unsigned count = MarkLive(&cfg->getEntry(), live);
+ unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(),
+ live);
bool AddEHEdges = AC.getAddEHEdges();
if (!AddEHEdges && count != cfg->getNumBlockIDs())
@@ -2382,7 +2243,7 @@ Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) {
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);
+ count += reachable_code::ScanReachableFromBlock(b, live);
continue;
}
}
@@ -2489,22 +2350,20 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
bool ReturnsVoid = false;
bool HasNoReturn = false;
+
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// For function templates, class templates and member function templates
// we'll do the analysis at instantiation time.
if (FD->isDependentContext())
return;
- if (FD->getResultType()->isVoidType())
- ReturnsVoid = true;
- if (FD->hasAttr<NoReturnAttr>() ||
- FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
- HasNoReturn = true;
+ ReturnsVoid = FD->getResultType()->isVoidType();
+ HasNoReturn = FD->hasAttr<NoReturnAttr>() ||
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
+
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (MD->getResultType()->isVoidType())
- ReturnsVoid = true;
- if (MD->hasAttr<NoReturnAttr>())
- HasNoReturn = true;
+ ReturnsVoid = MD->getResultType()->isVoidType();
+ HasNoReturn = MD->hasAttr<NoReturnAttr>();
}
// Short circuit for compilation speed.
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index a862949..edf1bc5 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1137,12 +1137,15 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
else if (ObjCMethodDecl *Method
= dyn_cast<ObjCMethodDecl>(SemaRef.CurContext))
isVoid = Method->getResultType()->isVoidType();
- else if (SemaRef.CurBlock && !SemaRef.CurBlock->ReturnType.isNull())
- isVoid = SemaRef.CurBlock->ReturnType->isVoidType();
+ else if (SemaRef.getCurBlock() &&
+ !SemaRef.getCurBlock()->ReturnType.isNull())
+ isVoid = SemaRef.getCurBlock()->ReturnType->isVoidType();
Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("return");
- if (!isVoid)
+ if (!isVoid) {
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("expression");
+ }
Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 1fc08ce..ec1939e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -436,14 +436,15 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
if (AddToContext)
CurContext->addDecl(D);
- // Out-of-line function and variable definitions should not be pushed into
- // scope.
- if ((isa<FunctionTemplateDecl>(D) &&
- cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->isOutOfLine()) ||
- (isa<FunctionDecl>(D) &&
- (cast<FunctionDecl>(D)->isFunctionTemplateSpecialization() ||
- cast<FunctionDecl>(D)->isOutOfLine())) ||
- (isa<VarDecl>(D) && cast<VarDecl>(D)->isOutOfLine()))
+ // Out-of-line definitions shouldn't be pushed into scope in C++.
+ // Out-of-line variable and function definitions shouldn't even in C.
+ if ((getLangOptions().CPlusPlus || isa<VarDecl>(D) || isa<FunctionDecl>(D)) &&
+ D->isOutOfLine())
+ return;
+
+ // Template instantiations should also not be pushed into scope.
+ if (isa<FunctionDecl>(D) &&
+ cast<FunctionDecl>(D)->isFunctionTemplateSpecialization())
return;
// If this replaces anything in the current scope,
@@ -552,7 +553,8 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (!D->getDeclName()) continue;
// Diagnose unused variables in this scope.
- if (ShouldDiagnoseUnusedDecl(D))
+ if (ShouldDiagnoseUnusedDecl(D) &&
+ S->getNumErrorsAtStart() == getDiagnostics().getNumErrors())
Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName();
// Remove this name from our lexical scope.
@@ -849,7 +851,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
// is normally mapped to an error, but can be controlled with
// -Wtypedef-redefinition. If either the original or the redefinition is
// in a system header, don't emit this for compatibility with GCC.
- if (PP.getDiagnostics().getSuppressSystemWarnings() &&
+ if (getDiagnostics().getSuppressSystemWarnings() &&
(Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
Context.getSourceManager().isInSystemHeader(New->getLocation())))
return;
@@ -908,6 +910,16 @@ static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx,
return Sema::CXXCopyAssignment;
}
+/// canREdefineFunction - checks if a function can be redefined. Currently,
+/// only extern inline functions can be redefined, and even then only in
+/// GNU89 mode.
+static bool canRedefineFunction(const FunctionDecl *FD,
+ const LangOptions& LangOpts) {
+ return (LangOpts.GNUMode && !LangOpts.C99 && !LangOpts.CPlusPlus &&
+ FD->isInlineSpecified() &&
+ FD->getStorageClass() == FunctionDecl::Extern);
+}
+
/// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation,
@@ -956,9 +968,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
QualType OldQType = Context.getCanonicalType(Old->getType());
QualType NewQType = Context.getCanonicalType(New->getType());
+ // Don't complain about this if we're in GNU89 mode and the old function
+ // is an extern inline function.
if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) &&
New->getStorageClass() == FunctionDecl::Static &&
- Old->getStorageClass() != FunctionDecl::Static) {
+ Old->getStorageClass() != FunctionDecl::Static &&
+ !canRedefineFunction(Old, getLangOptions())) {
Diag(New->getLocation(), diag::err_static_non_static)
<< New;
Diag(Old->getLocation(), PrevDiag);
@@ -1089,7 +1104,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
NewQType = Context.getFunctionType(NewFuncType->getResultType(),
ParamTypes.data(), ParamTypes.size(),
OldProto->isVariadic(),
- OldProto->getTypeQuals());
+ OldProto->getTypeQuals(),
+ false, false, 0, 0,
+ OldProto->getNoReturnAttr(),
+ OldProto->getCallConv());
New->setType(NewQType);
New->setHasInheritedPrototype();
@@ -1168,7 +1186,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0],
ArgTypes.size(),
- OldProto->isVariadic(), 0));
+ OldProto->isVariadic(), 0,
+ false, false, 0, 0,
+ OldProto->getNoReturnAttr(),
+ OldProto->getCallConv()));
return MergeCompatibleFunctionDecls(New, Old);
}
@@ -2159,7 +2180,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// then it shall have block scope.
QualType T = NewTD->getUnderlyingType();
if (T->isVariablyModifiedType()) {
- CurFunctionNeedsScopeChecking = true;
+ FunctionNeedsScopeChecking() = true;
if (S->getFnParent() == 0) {
bool SizeIsNegative;
@@ -2480,8 +2501,13 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
bool isVM = T->isVariablyModifiedType();
if (isVM || NewVD->hasAttr<CleanupAttr>() ||
- NewVD->hasAttr<BlocksAttr>())
- CurFunctionNeedsScopeChecking = true;
+ NewVD->hasAttr<BlocksAttr>() ||
+ // FIXME: We need to diagnose jumps passed initialized variables in C++.
+ // However, this turns on the scope checker for everything with a variable
+ // which may impact compile time. See if we can find a better solution
+ // to this, perhaps only checking functions that contain gotos in C++?
+ (LangOpts.CPlusPlus && NewVD->hasLocalStorage()))
+ FunctionNeedsScopeChecking() = true;
if ((isVM && NewVD->hasLinkage()) ||
(T->isVariableArrayType() && NewVD->hasGlobalStorage())) {
@@ -3135,7 +3161,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// FIXME: Also include static functions declared but not defined.
if (!NewFD->isInvalidDecl() && IsFunctionDefinition
&& !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage
- && !NewFD->isUsed())
+ && !NewFD->isUsed() && !NewFD->hasAttr<UnusedAttr>())
UnusedStaticFuncs.push_back(NewFD);
return NewFD;
@@ -3212,7 +3238,7 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// Turn this into a variadic function with no parameters.
QualType R = Context.getFunctionType(
NewFD->getType()->getAs<FunctionType>()->getResultType(),
- 0, 0, true, 0);
+ 0, 0, true, 0, false, false, 0, 0, false, CC_Default);
NewFD->setType(R);
return NewFD->setInvalidDecl();
}
@@ -3858,9 +3884,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
<< Context.getTypeDeclType(OwnedDecl);
}
- // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope.
- // Can this happen for params? We already checked that they don't conflict
- // among each other. Here they can only shadow globals, which is ok.
+ // Check for redeclaration of parameters, e.g. int foo(int x, int x);
IdentifierInfo *II = D.getIdentifier();
if (II) {
if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) {
@@ -3871,6 +3895,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
PrevDecl = 0;
} else if (S->isDeclScope(DeclPtrTy::make(PrevDecl))) {
Diag(D.getIdentifierLoc(), diag::err_param_redefinition) << II;
+ Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
// Recover by removing the name
II = 0;
@@ -4059,11 +4084,15 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
else
FD = cast<FunctionDecl>(D.getAs<Decl>());
- CurFunctionNeedsScopeChecking = false;
+ // Enter a new function scope
+ PushFunctionScope();
// See if this is a redefinition.
+ // But don't complain if we're in GNU89 mode and the previous definition
+ // was an extern inline function.
const FunctionDecl *Definition;
- if (FD->getBody(Definition)) {
+ if (FD->getBody(Definition) &&
+ !canRedefineFunction(Definition, getLangOptions())) {
Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
Diag(Definition->getLocation(), diag::note_previous_definition);
}
@@ -4120,7 +4149,11 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
<< "dllimport";
FD->setInvalidDecl();
return DeclPtrTy::make(FD);
- } else {
+ }
+
+ // Visual C++ appears to not think this is an issue, so only issue
+ // a warning when Microsoft extensions are disabled.
+ if (!LangOpts.Microsoft) {
// If a symbol previously declared dllimport is later defined, the
// attribute is ignored in subsequent references, and a warning is
// emitted.
@@ -4184,11 +4217,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
// Verify and clean out per-function state.
- assert(&getLabelMap() == &FunctionLabelMap && "Didn't pop block right?");
-
// Check goto/label use.
for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
- I = FunctionLabelMap.begin(), E = FunctionLabelMap.end(); I != E; ++I) {
+ I = getLabelMap().begin(), E = getLabelMap().end(); I != E; ++I) {
LabelStmt *L = I->second;
// Verify that we have no forward references left. If so, there was a goto
@@ -4224,32 +4255,41 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
Elements.push_back(L);
Compound->setStmts(Context, &Elements[0], Elements.size());
}
- FunctionLabelMap.clear();
- if (!Body) return D;
-
- CheckUnreachable(AC);
+ if (Body) {
+ CheckUnreachable(AC);
+ // C++ constructors that have function-try-blocks can't have return
+ // statements in the handlers of that block. (C++ [except.handle]p14)
+ // Verify this.
+ if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body))
+ DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
+
// Verify that that gotos and switch cases don't jump into scopes illegally.
- if (CurFunctionNeedsScopeChecking)
- DiagnoseInvalidJumps(Body);
-
- // C++ constructors that have function-try-blocks can't have return
- // statements in the handlers of that block. (C++ [except.handle]p14)
- // Verify this.
- if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body))
- DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
+ // Verify that that gotos and switch cases don't jump into scopes illegally.
+ if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction())
+ DiagnoseInvalidJumps(Body);
- if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
- MarkBaseAndMemberDestructorsReferenced(Destructor);
+ if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
+ MarkBaseAndMemberDestructorsReferenced(Destructor);
+
+ // If any errors have occurred, clear out any temporaries that may have
+ // been leftover. This ensures that these temporaries won't be picked up for
+ // deletion in some later function.
+ if (PP.getDiagnostics().hasErrorOccurred())
+ ExprTemporaries.clear();
+
+ assert(ExprTemporaries.empty() && "Leftover temporaries in function");
+ }
+
+ PopFunctionOrBlockScope();
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
- if (PP.getDiagnostics().hasErrorOccurred())
+ if (getDiagnostics().hasErrorOccurred())
ExprTemporaries.clear();
- assert(ExprTemporaries.empty() && "Leftover temporaries in function");
return D;
}
@@ -4501,8 +4541,9 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
bool isStdBadAlloc = false;
bool Invalid = false;
- RedeclarationKind Redecl = (TUK != TUK_Reference ? ForRedeclaration
- : NotForRedeclaration);
+ RedeclarationKind Redecl = ForRedeclaration;
+ if (TUK == TUK_Friend || TUK == TUK_Reference)
+ Redecl = NotForRedeclaration;
LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl);
@@ -4752,12 +4793,15 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// If a friend declaration in a non-local class first declares a
// class or function, the friend class or function is a member of
// the innermost enclosing namespace.
- while (!SearchDC->isFileContext())
- SearchDC = SearchDC->getParent();
+ SearchDC = SearchDC->getEnclosingNamespaceContext();
- // The entity of a decl scope is a DeclContext; see PushDeclContext.
- while (S->getEntity() != SearchDC)
+ // Look up through our scopes until we find one with an entity which
+ // matches our declaration context.
+ while (S->getEntity() &&
+ ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) {
S = S->getParent();
+ assert(S && "No enclosing scope matching the enclosing namespace.");
+ }
}
CreateNewDecl:
@@ -5625,7 +5669,6 @@ void Sema::ActOnFields(Scope* S,
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl)) {
- ID->setIVarList(ClsFields, RecFields.size(), Context);
ID->setLocEnd(RBrac);
// Add ivar's to class's DeclContext.
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
@@ -5634,21 +5677,8 @@ void Sema::ActOnFields(Scope* S,
}
// Must enforce the rule that ivars in the base classes may not be
// duplicates.
- if (ID->getSuperClass()) {
- for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(),
- IVE = ID->ivar_end(); IVI != IVE; ++IVI) {
- ObjCIvarDecl* Ivar = (*IVI);
-
- if (IdentifierInfo *II = Ivar->getIdentifier()) {
- ObjCIvarDecl* prevIvar =
- ID->getSuperClass()->lookupInstanceVariable(II);
- if (prevIvar) {
- Diag(Ivar->getLocation(), diag::err_duplicate_member) << II;
- Diag(prevIvar->getLocation(), diag::note_previous_declaration);
- }
- }
- }
- }
+ if (ID->getSuperClass())
+ DiagnoseDuplicateIvars(ID, ID->getSuperClass());
} else if (ObjCImplementationDecl *IMPDecl =
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl");
@@ -5657,6 +5687,19 @@ void Sema::ActOnFields(Scope* S,
// Only it is in implementation's lexical context.
ClsFields[I]->setLexicalDeclContext(IMPDecl);
CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac);
+ } else if (ObjCCategoryDecl *CDecl =
+ dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
+ if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension())
+ Diag(LBrac, diag::err_misplaced_ivar);
+ else {
+ // FIXME. Class extension does not have a LocEnd field.
+ // CDecl->setLocEnd(RBrac);
+ // Add ivar's to class extension's DeclContext.
+ for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
+ ClsFields[i]->setLexicalDeclContext(CDecl);
+ CDecl->addDecl(ClsFields[i]);
+ }
+ }
}
}
@@ -5714,12 +5757,13 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
llvm::APSInt EnumVal(IntWidth);
QualType EltTy;
if (Val) {
- if (Enum->isDependentType())
+ if (Enum->isDependentType() || Val->isTypeDependent())
EltTy = Context.DependentTy;
else {
// C99 6.7.2.2p2: Make sure we have an integer constant expression.
SourceLocation ExpLoc;
- if (VerifyIntegerConstantExpression(Val, &EnumVal)) {
+ if (!Val->isValueDependent() &&
+ VerifyIntegerConstantExpression(Val, &EnumVal)) {
Val = 0;
} else {
if (!getLangOptions().CPlusPlus) {
@@ -5732,7 +5776,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy))
Diag(IdLoc, diag::ext_enum_value_not_int)
<< EnumVal.toString(10) << Val->getSourceRange()
- << EnumVal.isNonNegative();
+ << (EnumVal.isUnsigned() || EnumVal.isNonNegative());
else if (!Context.hasSameType(Val->getType(), Context.IntTy)) {
// Force the type of the expression to 'int'.
ImpCastExprToType(Val, Context.IntTy, CastExpr::CK_IntegralCast);
@@ -5821,7 +5865,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
}
}
- if (!Enum->isDependentType()) {
+ if (!EltTy->isDependentType()) {
// Make the enumerator value match the signedness and size of the
// enumerator's type.
EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index cba1e9e..242d66f 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -225,19 +225,38 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
-static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void HandleIBAction(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() > 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- // The IBOutlet attribute only applies to instance variables of Objective-C
- // classes.
- if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))
+ // The IBAction attributes only apply to instance methods.
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
+ if (MD->isInstanceMethod()) {
+ d->addAttr(::new (S.Context) IBActionAttr());
+ return;
+ }
+
+ S.Diag(Attr.getLoc(), diag::err_attribute_ibaction) << Attr.getName();
+}
+
+static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() > 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // The IBOutlet attributes only apply to instance variables of
+ // Objective-C classes.
+ if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d)) {
d->addAttr(::new (S.Context) IBOutletAttr());
- else
- S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet);
+ return;
+ }
+
+ S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName();
}
static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -310,6 +329,86 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) NonNullAttr(S.Context, start, size));
}
+static bool isStaticVarOrStaticFunciton(Decl *D) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ return VD->getStorageClass() == VarDecl::Static;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getStorageClass() == FunctionDecl::Static;
+ return false;
+}
+
+static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() > 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ // gcc rejects
+ // class c {
+ // static int a __attribute__((weakref ("v2")));
+ // static int b() __attribute__((weakref ("f3")));
+ // };
+ // and ignores the attributes of
+ // void f(void) {
+ // static int a __attribute__((weakref ("v2")));
+ // }
+ // we reject them
+ if (const DeclContext *Ctx = d->getDeclContext()) {
+ Ctx = Ctx->getLookupContext();
+ if (!isa<TranslationUnitDecl>(Ctx) && !isa<NamespaceDecl>(Ctx) ) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) <<
+ dyn_cast<NamedDecl>(d)->getNameAsString();
+ return;
+ }
+ }
+
+ // The GCC manual says
+ //
+ // At present, a declaration to which `weakref' is attached can only
+ // be `static'.
+ //
+ // It also says
+ //
+ // Without a TARGET,
+ // given as an argument to `weakref' or to `alias', `weakref' is
+ // equivalent to `weak'.
+ //
+ // gcc 4.4.1 will accept
+ // int a7 __attribute__((weakref));
+ // as
+ // int a7 __attribute__((weak));
+ // This looks like a bug in gcc. We reject that for now. We should revisit
+ // it if this behaviour is actually used.
+
+ if (!isStaticVarOrStaticFunciton(d)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_static) <<
+ dyn_cast<NamedDecl>(d)->getNameAsString();
+ return;
+ }
+
+ // GCC rejects
+ // static ((alias ("y"), weakref)).
+ // Should we? How to check that weakref is before or after alias?
+
+ if (Attr.getNumArgs() == 1) {
+ Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
+ Arg = Arg->IgnoreParenCasts();
+ StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+
+ if (Str == 0 || Str->isWide()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "weakref" << 1;
+ return;
+ }
+ // GCC will accept anything as the argument of weakref. Should we
+ // check for an existing decl?
+ d->addAttr(::new (S.Context) AliasAttr(S.Context, Str->getString()));
+ }
+
+ d->addAttr(::new (S.Context) WeakRefAttr());
+}
+
static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 1) {
@@ -422,7 +521,7 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) {
+ if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
@@ -735,7 +834,7 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
return;
}
- if (!isFunctionOrMethod(D)) {
+ if (!isFunction(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
@@ -758,13 +857,7 @@ static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
/* weak only applies to non-static declarations */
- bool isStatic = false;
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- isStatic = VD->getStorageClass() == VarDecl::Static;
- } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- isStatic = FD->getStorageClass() == FunctionDecl::Static;
- }
- if (isStatic) {
+ if (isStaticVarOrStaticFunciton(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) <<
dyn_cast<NamedDecl>(D)->getNameAsString();
return;
@@ -813,82 +906,6 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
D->addAttr(::new (S.Context) WeakImportAttr());
}
-static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
- // Attribute can be applied only to functions or variables.
- if (isa<VarDecl>(D)) {
- D->addAttr(::new (S.Context) DLLImportAttr());
- return;
- }
-
- FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
- return;
- }
-
- // Currently, the dllimport attribute is ignored for inlined functions.
- // Warning is emitted.
- if (FD->isInlineSpecified()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
- return;
- }
-
- // The attribute is also overridden by a subsequent declaration as dllexport.
- // Warning is emitted.
- for (AttributeList *nextAttr = Attr.getNext(); nextAttr;
- nextAttr = nextAttr->getNext()) {
- if (nextAttr->getKind() == AttributeList::AT_dllexport) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
- return;
- }
- }
-
- if (D->getAttr<DLLExportAttr>()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
- return;
- }
-
- D->addAttr(::new (S.Context) DLLImportAttr());
-}
-
-static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
- // Attribute can be applied only to functions or variables.
- if (isa<VarDecl>(D)) {
- D->addAttr(::new (S.Context) DLLExportAttr());
- return;
- }
-
- FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
- return;
- }
-
- // Currently, the dllexport attribute is ignored for inlined functions, unless
- // the -fkeep-inline-functions flag has been used. Warning is emitted;
- if (FD->isInlineSpecified()) {
- // FIXME: ... unless the -fkeep-inline-functions flag has been used.
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
- return;
- }
-
- D->addAttr(::new (S.Context) DLLExportAttr());
-}
-
static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
Sema &S) {
// Attribute has 3 arguments.
@@ -1777,6 +1794,12 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
default:
assert(0 && "invalid ownership attribute");
return;
+ case AttributeList::AT_cf_returns_not_retained:
+ d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr());
+ return;
+ case AttributeList::AT_ns_returns_not_retained:
+ d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr());
+ return;
case AttributeList::AT_cf_returns_retained:
d->addAttr(::new (S.Context) CFReturnsRetainedAttr());
return;
@@ -1786,6 +1809,11 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
};
}
+static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
+ return Attr.getKind() == AttributeList::AT_dllimport ||
+ Attr.getKind() == AttributeList::AT_dllexport;
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -1796,11 +1824,12 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
static void ProcessDeclAttribute(Scope *scope, Decl *D,
const AttributeList &Attr, Sema &S) {
- if (Attr.isDeclspecAttribute())
- // FIXME: Try to deal with __declspec attributes!
+ if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr))
+ // FIXME: Try to deal with other __declspec attributes!
return;
switch (Attr.getKind()) {
- case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break;
+ case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break;
+ case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break;
case AttributeList::AT_address_space:
case AttributeList::AT_objc_gc:
case AttributeList::AT_vector_size:
@@ -1820,8 +1849,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break;
case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break;
case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break;
- case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break;
- case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break;
case AttributeList::AT_ext_vector_type:
HandleExtVectorTypeAttr(scope, D, Attr, S);
break;
@@ -1838,6 +1865,8 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_override: HandleOverrideAttr (D, Attr, S); break;
// Checker-specific.
+ case AttributeList::AT_ns_returns_not_retained:
+ case AttributeList::AT_cf_returns_not_retained:
case AttributeList::AT_ns_returns_retained:
case AttributeList::AT_cf_returns_retained:
HandleNSReturnsRetainedAttr(D, Attr, S); break;
@@ -1854,6 +1883,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S);
break;
case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break;
+ case AttributeList::AT_weakref: HandleWeakRefAttr (D, Attr, S); break;
case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break;
case AttributeList::AT_transparent_union:
HandleTransparentUnionAttr(D, Attr, S);
@@ -1892,9 +1922,17 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
/// ProcessDeclAttributeList - Apply all the decl attributes in the specified
/// attribute list to the specified decl, ignoring any type attributes.
void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList) {
- while (AttrList) {
- ProcessDeclAttribute(S, D, *AttrList, *this);
- AttrList = AttrList->getNext();
+ for (const AttributeList* l = AttrList; l; l = l->getNext()) {
+ ProcessDeclAttribute(S, D, *l, *this);
+ }
+
+ // GCC accepts
+ // static int a9 __attribute__((weakref));
+ // but that looks really pointless. We reject it.
+ if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) {
+ Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) <<
+ dyn_cast<NamedDecl>(D)->getNameAsString();
+ return;
}
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9defcca..574b225 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -586,7 +586,10 @@ Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange,
return true;
AdjustDeclIfTemplate(classdecl);
- CXXRecordDecl *Class = cast<CXXRecordDecl>(classdecl.getAs<Decl>());
+ CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(classdecl.getAs<Decl>());
+ if (!Class)
+ return true;
+
QualType BaseType = GetTypeFromParser(basetype);
if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
Virtual, Access,
@@ -1635,8 +1638,22 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
- for (unsigned Idx = 0; Idx < NumInitializers; ++Idx)
- baseOrMemberInitializers[Idx] = AllToInit[Idx];
+ for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) {
+ CXXBaseOrMemberInitializer *Member = AllToInit[Idx];
+ baseOrMemberInitializers[Idx] = Member;
+ if (!Member->isBaseInitializer())
+ continue;
+ const Type *BaseType = Member->getBaseClass();
+ const RecordType *RT = BaseType->getAs<RecordType>();
+ if (!RT)
+ continue;
+ CXXRecordDecl *BaseClassDecl =
+ cast<CXXRecordDecl>(RT->getDecl());
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ CXXDestructorDecl *DD = BaseClassDecl->getDestructor(Context);
+ MarkDeclarationReferenced(Constructor->getLocation(), DD);
+ }
}
return HadError;
@@ -2174,7 +2191,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
CXXConstructorDecl::Create(Context, ClassDecl,
ClassDecl->getLocation(), Name,
Context.getFunctionType(Context.VoidTy,
- 0, 0, false, 0),
+ 0, 0, false, 0,
+ /*FIXME*/false, false,
+ 0, 0, false,
+ CC_Default),
/*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
@@ -2246,7 +2266,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ClassDecl->getLocation(), Name,
Context.getFunctionType(Context.VoidTy,
&ArgType, 1,
- false, 0),
+ false, 0,
+ /*FIXME:*/false,
+ false, 0, 0, false,
+ CC_Default),
/*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
@@ -2332,7 +2355,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
CXXMethodDecl *CopyAssignment =
CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name,
Context.getFunctionType(RetType, &ArgType, 1,
- false, 0),
+ false, 0,
+ /*FIXME:*/false,
+ false, 0, 0, false,
+ CC_Default),
/*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
@@ -2364,7 +2390,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
= CXXDestructorDecl::Create(Context, ClassDecl,
ClassDecl->getLocation(), Name,
Context.getFunctionType(Context.VoidTy,
- 0, 0, false, 0),
+ 0, 0, false, 0,
+ /*FIXME:*/false,
+ false, 0, 0, false,
+ CC_Default),
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
@@ -2523,7 +2552,13 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
Proto->getNumArgs(),
- Proto->isVariadic(), 0);
+ Proto->isVariadic(), 0,
+ Proto->hasExceptionSpec(),
+ Proto->hasAnyExceptionSpec(),
+ Proto->getNumExceptions(),
+ Proto->exception_begin(),
+ Proto->getNoReturnAttr(),
+ Proto->getCallConv());
}
/// CheckConstructor - Checks a fully-formed constructor for
@@ -2680,7 +2715,9 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D,
// "void" as the return type, since destructors don't have return
// types. We *always* have to do this, because GetTypeForDeclarator
// will put in a result type of "int" when none was specified.
- return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0);
+ // FIXME: Exceptions!
+ return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0,
+ false, false, 0, 0, false, CC_Default);
}
/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
@@ -2749,8 +2786,15 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// Rebuild the function type "R" without any parameters (in case any
// of the errors above fired) and with the conversion type as the
// return type.
+ const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
R = Context.getFunctionType(ConvType, 0, 0, false,
- R->getAs<FunctionProtoType>()->getTypeQuals());
+ Proto->getTypeQuals(),
+ Proto->hasExceptionSpec(),
+ Proto->hasAnyExceptionSpec(),
+ Proto->getNumExceptions(),
+ Proto->exception_begin(),
+ Proto->getNoReturnAttr(),
+ Proto->getCallConv());
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
@@ -3996,7 +4040,8 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl());
- if (!ClassDecl->hasTrivialDestructor()) {
+ if (!ClassDecl->isInvalidDecl() && !VD->isInvalidDecl() &&
+ !ClassDecl->hasTrivialDestructor()) {
CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
MarkDeclarationReferenced(VD->getLocation(), Destructor);
CheckDestructorAccess(VD->getLocation(), Record);
@@ -4368,8 +4413,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// Most paths end in a failed conversion.
if (ICS) {
- ICS->setBad();
- ICS->Bad.init(BadConversionSequence::no_conversion, Init, DeclType);
+ ICS->setBad(BadConversionSequence::no_conversion, Init, DeclType);
}
// C++ [dcl.init.ref]p5:
@@ -5761,55 +5805,74 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
return Dcl;
}
-void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
- CXXMethodDecl *MD) {
+static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) {
// Ignore dependent types.
if (MD->isDependentContext())
- return;
-
+ return false;
+
+ // Ignore declarations that are not definitions.
+ if (!MD->isThisDeclarationADefinition())
+ return false;
+
CXXRecordDecl *RD = MD->getParent();
-
+
// Ignore classes without a vtable.
if (!RD->isDynamicClass())
- return;
+ return false;
- // Ignore declarations that are not definitions.
- if (!MD->isThisDeclarationADefinition())
- return;
-
- if (isa<CXXConstructorDecl>(MD)) {
- switch (MD->getParent()->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- // Classes that aren't instantiations of templates don't need their
- // virtual methods marked until we see the definition of the key
- // function.
- return;
-
- case TSK_ImplicitInstantiation:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- // This is a constructor of a class template; mark all of the virtual
- // members as referenced to ensure that they get instantiatied.
- break;
- }
- } else if (!MD->isOutOfLine()) {
- // Consider only out-of-line definitions of member functions. When we see
- // an inline definition, it's too early to compute the key function.
- return;
- } else if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD)) {
- // If this is not the key function, we don't need to mark virtual members.
- if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
- return;
- } else {
- // The class has no key function, so we've already noted that we need to
- // mark the virtual members of this class.
- return;
+ switch (MD->getParent()->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ // Classes that aren't instantiations of templates don't need their
+ // virtual methods marked until we see the definition of the key
+ // function.
+ break;
+
+ case TSK_ImplicitInstantiation:
+ // This is a constructor of a class template; mark all of the virtual
+ // members as referenced to ensure that they get instantiatied.
+ if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
+ return true;
+ break;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ return true; //FIXME: This looks wrong.
+
+ case TSK_ExplicitInstantiationDefinition:
+ // This is method of a explicit instantiation; mark all of the virtual
+ // members as referenced to ensure that they get instantiatied.
+ return true;
}
-
+
+ // Consider only out-of-line definitions of member functions. When we see
+ // an inline definition, it's too early to compute the key function.
+ if (!MD->isOutOfLine())
+ return false;
+
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
+
+ // If there is no key function, we will need a copy of the vtable.
+ if (!KeyFunction)
+ return true;
+
+ // If this is the key function, we need to mark virtual members.
+ if (KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl())
+ return true;
+
+ return false;
+}
+
+void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
+ CXXMethodDecl *MD) {
+ CXXRecordDecl *RD = MD->getParent();
+
// We will need to mark all of the virtual members as referenced to build the
// vtable.
- ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc));
+ // We actually call MarkVirtualMembersReferenced instead of adding to
+ // ClassesWithUnmarkedVirtualMembers because this marking is needed by
+ // codegen that will happend before we finish parsing the file.
+ if (needsVtable(MD, Context))
+ MarkVirtualMembersReferenced(Loc, RD);
}
bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
@@ -5837,4 +5900,3 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) {
MarkDeclarationReferenced(Loc, MD);
}
}
-
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 1e9b56a..149fe15 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -49,8 +49,6 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
if (!MDecl)
return;
- CurFunctionNeedsScopeChecking = false;
-
// Allow the rest of sema to find private method decl implementations.
if (MDecl->isInstanceMethod())
AddInstanceMethodToGlobalPool(MDecl);
@@ -59,7 +57,8 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
// Allow all of Sema to see that we are entering a method definition.
PushDeclContext(FnBodyScope, MDecl);
-
+ PushFunctionScope();
+
// Create Decl objects for each parameter, entrring them in the scope for
// binding to their use.
@@ -599,26 +598,31 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
SourceLocation EndProtoLoc) {
ObjCCategoryDecl *CDecl = 0;
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
+
+ /// Check that class of this category is already completely declared.
+ if (!IDecl || IDecl->isForwardDecl()) {
+ // Create an invalid ObjCCategoryDecl to serve as context for
+ // the enclosing method declarations. We mark the decl invalid
+ // to make it clear that this isn't a valid AST.
+ CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
+ ClassLoc, CategoryLoc, CategoryName);
+ CDecl->setInvalidDecl();
+ Diag(ClassLoc, diag::err_undef_interface) << ClassName;
+ return DeclPtrTy::make(CDecl);
+ }
+
if (!CategoryName) {
// Class extensions require a special treatment. Use an existing one.
- for (CDecl = IDecl->getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->IsClassExtension())
- break;
+ // Note that 'getClassExtension()' can return NULL.
+ CDecl = IDecl->getClassExtension();
}
+
if (!CDecl) {
- CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc,
- CategoryLoc, CategoryName);
+ CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
+ ClassLoc, CategoryLoc, CategoryName);
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
- /// Check that class of this category is already completely declared.
- if (!IDecl || IDecl->isForwardDecl()) {
- CDecl->setInvalidDecl();
- Diag(ClassLoc, diag::err_undef_interface) << ClassName;
- return DeclPtrTy::make(CDecl);
- }
-
CDecl->setClassInterface(IDecl);
// Insert first use of class extension to the list of class's categories.
if (!CategoryName)
@@ -821,8 +825,14 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
/// (legacy objective-c @implementation decl without an @interface decl).
/// Add implementations's ivar to the synthesize class's ivar list.
if (IDecl->isImplicitInterfaceDecl()) {
- IDecl->setIVarList(ivars, numIvars, Context);
IDecl->setLocEnd(RBrace);
+ // Add ivar's to class's DeclContext.
+ for (unsigned i = 0, e = numIvars; i != e; ++i) {
+ ivars[i]->setLexicalDeclContext(ImpDecl);
+ IDecl->makeDeclVisibleInContext(ivars[i], false);
+ ImpDecl->addDecl(ivars[i]);
+ }
+
return;
}
// If implementation has empty ivar list, just return.
@@ -830,7 +840,26 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
return;
assert(ivars && "missing @implementation ivars");
-
+ if (LangOpts.ObjCNonFragileABI2) {
+ if (ImpDecl->getSuperClass())
+ Diag(ImpDecl->getLocation(), diag::warn_on_superclass_use);
+ for (unsigned i = 0; i < numIvars; i++) {
+ ObjCIvarDecl* ImplIvar = ivars[i];
+ if (const ObjCIvarDecl *ClsIvar =
+ IDecl->getIvarDecl(ImplIvar->getIdentifier())) {
+ Diag(ImplIvar->getLocation(), diag::err_duplicate_ivar_declaration);
+ Diag(ClsIvar->getLocation(), diag::note_previous_definition);
+ continue;
+ }
+ if (ImplIvar->getAccessControl() != ObjCIvarDecl::Private)
+ Diag(ImplIvar->getLocation(), diag::err_non_private_ivar_declaration);
+ // Instance ivar to Implementation's DeclContext.
+ ImplIvar->setLexicalDeclContext(ImpDecl);
+ IDecl->makeDeclVisibleInContext(ImplIvar, false);
+ ImpDecl->addDecl(ImplIvar);
+ }
+ return;
+ }
// Check interface's Ivar list against those in the implementation.
// names and types must match.
//
@@ -1751,6 +1780,29 @@ void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl,
}
}
+/// DiagnoseDuplicateIvars -
+/// Check for duplicate ivars in the entire class at the start of
+/// @implementation. This becomes necesssary because class extension can
+/// add ivars to a class in random order which will not be known until
+/// class's @implementation is seen.
+void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
+ ObjCInterfaceDecl *SID) {
+ for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(),
+ IVE = ID->ivar_end(); IVI != IVE; ++IVI) {
+ ObjCIvarDecl* Ivar = (*IVI);
+ if (Ivar->isInvalidDecl())
+ continue;
+ if (IdentifierInfo *II = Ivar->getIdentifier()) {
+ ObjCIvarDecl* prevIvar = SID->lookupInstanceVariable(II);
+ if (prevIvar) {
+ Diag(Ivar->getLocation(), diag::err_duplicate_member) << II;
+ Diag(prevIvar->getLocation(), diag::note_previous_declaration);
+ Ivar->setInvalidDecl();
+ }
+ }
+ }
+}
+
// Note: For class/category implemenations, allMethods/allProperties is
// always null.
void Sema::ActOnAtEnd(SourceRange AtEnd,
@@ -1862,6 +1914,11 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) {
ImplMethodsVsClassMethods(IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
+ if (LangOpts.ObjCNonFragileABI2)
+ while (IDecl->getSuperClass()) {
+ DiagnoseDuplicateIvars(IDecl, IDecl->getSuperClass());
+ IDecl = IDecl->getSuperClass();
+ }
}
} else if (ObjCCategoryImplDecl* CatImplClass =
dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
@@ -1930,7 +1987,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
// Make sure we can establish a context for the method.
if (!ClassDecl) {
Diag(MethodLoc, diag::error_missing_method_context);
- FunctionLabelMap.clear();
+ getLabelMap().clear();
return DeclPtrTy();
}
QualType resultDeclType;
@@ -2440,8 +2497,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
PropertyIvar, PropType, /*Dinfo=*/0,
ObjCIvarDecl::Public,
(Expr *)0);
- Ivar->setLexicalDeclContext(IDecl);
- IDecl->addDecl(Ivar);
+ IDecl->makeDeclVisibleInContext(Ivar, false);
property->setPropertyIvarDecl(Ivar);
if (!getLangOptions().ObjCNonFragileABI)
Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 633884f..d9464ad 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -393,10 +393,10 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
/// variables defined outside the block) or false if this is not needed (e.g.
/// for values inside the block or for globals).
///
-/// This also keeps the 'hasBlockDeclRefExprs' in the BlockSemaInfo records
+/// This also keeps the 'hasBlockDeclRefExprs' in the BlockScopeInfo records
/// up-to-date.
///
-static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
+static bool ShouldSnapshotBlockValueReference(Sema &S, BlockScopeInfo *CurBlock,
ValueDecl *VD) {
// If the value is defined inside the block, we couldn't snapshot it even if
// we wanted to.
@@ -421,8 +421,12 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
// which case that outer block doesn't get "hasBlockDeclRefExprs") or it may
// be defined outside all of the current blocks (in which case the blocks do
// all get the bit). Walk the nesting chain.
- for (BlockSemaInfo *NextBlock = CurBlock->PrevBlockInfo; NextBlock;
- NextBlock = NextBlock->PrevBlockInfo) {
+ for (unsigned I = S.FunctionScopes.size() - 1; I; --I) {
+ BlockScopeInfo *NextBlock = dyn_cast<BlockScopeInfo>(S.FunctionScopes[I]);
+
+ if (!NextBlock)
+ continue;
+
// If we found the defining block for the variable, don't mark the block as
// having a reference outside it.
if (NextBlock->TheDecl == VD->getDeclContext())
@@ -1597,7 +1601,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// We do not do this for things like enum constants, global variables, etc,
// as they do not get snapshotted.
//
- if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) {
+ if (getCurBlock() &&
+ ShouldSnapshotBlockValueReference(*this, getCurBlock(), VD)) {
if (VD->getType().getTypePtr()->isVariablyModifiedType()) {
Diag(Loc, diag::err_ref_vm_type);
Diag(D->getLocation(), diag::note_declared_at);
@@ -1664,12 +1669,10 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
llvm::SmallString<16> CharBuffer;
- CharBuffer.resize(Tok.getLength());
- const char *ThisTokBegin = &CharBuffer[0];
- unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
+ llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer);
- CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
- Tok.getLocation(), PP);
+ CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), Tok.getLocation(),
+ PP);
if (Literal.hadError())
return ExprError();
@@ -1736,10 +1739,10 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
unsigned diagnostic;
llvm::SmallVector<char, 20> buffer;
if (result & APFloat::opOverflow) {
- diagnostic = diag::err_float_overflow;
+ diagnostic = diag::warn_float_overflow;
APFloat::getLargest(Format).toString(buffer);
} else {
- diagnostic = diag::err_float_underflow;
+ diagnostic = diag::warn_float_underflow;
APFloat::getSmallest(Format).toString(buffer);
}
@@ -2900,46 +2903,6 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
return Owned((Expr*) 0);
}
- // Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring
- // into a record type was handled above, any destructor we see here is a
- // pseudo-destructor.
- if (MemberName.getNameKind() == DeclarationName::CXXDestructorName) {
- // C++ [expr.pseudo]p2:
- // The left hand side of the dot operator shall be of scalar type. The
- // left hand side of the arrow operator shall be of pointer to scalar
- // type.
- if (!BaseType->isScalarType())
- return Owned(Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
- << BaseType << BaseExpr->getSourceRange());
-
- // [...] The type designated by the pseudo-destructor-name shall be the
- // same as the object type.
- if (!MemberName.getCXXNameType()->isDependentType() &&
- !Context.hasSameUnqualifiedType(BaseType, MemberName.getCXXNameType()))
- return Owned(Diag(OpLoc, diag::err_pseudo_dtor_type_mismatch)
- << BaseType << MemberName.getCXXNameType()
- << BaseExpr->getSourceRange() << SourceRange(MemberLoc));
-
- // [...] Furthermore, the two type-names in a pseudo-destructor-name of
- // the form
- //
- // ::[opt] nested-name-specifier[opt] type-name :: ̃ type-name
- //
- // shall designate the same scalar type.
- //
- // FIXME: DPG can't see any way to trigger this particular clause, so it
- // isn't checked here.
-
- // FIXME: We've lost the precise spelling of the type by going through
- // DeclarationName. Can we do better?
- return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr,
- IsArrow, OpLoc,
- (NestedNameSpecifier *) SS.getScopeRep(),
- SS.getRange(),
- MemberName.getCXXNameType(),
- MemberLoc));
- }
-
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
// (*Obj).ivar.
if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
@@ -3147,9 +3110,12 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl);
}
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType);
+ Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType;
+ if (Setter && !Getter)
+ Diag(Setter->getLocation(), diag::note_getter_unavailable)
+ << MemberName << BaseExpr->getSourceRange();
+ return ExprError();
}
// Handle the following exceptional case (*Obj).isa.
@@ -3168,30 +3134,13 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, *Member,
MemberLoc));
}
-
+
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr->getSourceRange();
return ExprError();
}
-static Sema::OwningExprResult DiagnoseDtorReference(Sema &SemaRef,
- SourceLocation NameLoc,
- Sema::ExprArg MemExpr) {
- Expr *E = (Expr *) MemExpr.get();
- SourceLocation ExpectedLParenLoc = SemaRef.PP.getLocForEndOfToken(NameLoc);
- SemaRef.Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
- << isa<CXXPseudoDestructorExpr>(E)
- << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
-
- return SemaRef.ActOnCallExpr(/*Scope*/ 0,
- move(MemExpr),
- /*LPLoc*/ ExpectedLParenLoc,
- Sema::MultiExprArg(SemaRef, 0, 0),
- /*CommaLocs*/ 0,
- /*RPLoc*/ ExpectedLParenLoc);
-}
-
/// The main callback when the parser finds something like
/// expression . [nested-name-specifier] identifier
/// expression -> [nested-name-specifier] identifier
@@ -3262,7 +3211,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
// call now.
if (!HasTrailingLParen &&
Id.getKind() == UnqualifiedId::IK_DestructorName)
- return DiagnoseDtorReference(*this, NameLoc, move(Result));
+ return DiagnoseDtorReference(NameLoc, move(Result));
return move(Result);
}
@@ -5378,11 +5327,18 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
//
// C++ [expr.eq]p1 uses the same notion for (in)equality
// comparisons of pointers.
- QualType T = FindCompositePointerType(lex, rex);
+ bool NonStandardCompositeType = false;
+ QualType T = FindCompositePointerType(lex, rex,
+ isSFINAEContext()? 0 : &NonStandardCompositeType);
if (T.isNull()) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
return QualType();
+ } else if (NonStandardCompositeType) {
+ Diag(Loc,
+ diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
+ << lType << rType << T
+ << lex->getSourceRange() << rex->getSourceRange();
}
ImpCastExprToType(lex, T, CastExpr::CK_BitCast);
@@ -5444,11 +5400,18 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// of one of the operands, with a cv-qualification signature (4.4)
// that is the union of the cv-qualification signatures of the operand
// types.
- QualType T = FindCompositePointerType(lex, rex);
+ bool NonStandardCompositeType = false;
+ QualType T = FindCompositePointerType(lex, rex,
+ isSFINAEContext()? 0 : &NonStandardCompositeType);
if (T.isNull()) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
return QualType();
+ } else if (NonStandardCompositeType) {
+ Diag(Loc,
+ diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
+ << lType << rType << T
+ << lex->getSourceRange() << rex->getSourceRange();
}
ImpCastExprToType(lex, T, CastExpr::CK_BitCast);
@@ -5697,7 +5660,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
unsigned Diag = 0;
bool NeedType = false;
switch (IsLV) { // C99 6.5.16p2
- default: assert(0 && "Unknown result from isModifiableLvalue!");
case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break;
case Expr::MLV_ArrayType:
Diag = diag::err_typecheck_array_not_modifiable_lvalue;
@@ -5710,7 +5672,11 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_LValueCast:
Diag = diag::err_typecheck_lvalue_casts_not_supported;
break;
+ case Expr::MLV_Valid:
+ llvm_unreachable("did not take early return for MLV_Valid");
case Expr::MLV_InvalidExpression:
+ case Expr::MLV_MemberFunction:
+ case Expr::MLV_ClassTemporary:
Diag = diag::err_typecheck_expression_not_modifiable_lvalue;
break;
case Expr::MLV_IncompleteType:
@@ -5995,6 +5961,12 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
return Context.getMemberPointerType(op->getType(),
Context.getTypeDeclType(cast<RecordDecl>(dcl->getDeclContext()))
.getTypePtr());
+ } else if (lval == Expr::LV_ClassTemporary) {
+ Diag(OpLoc, isSFINAEContext()? diag::err_typecheck_addrof_class_temporary
+ : diag::ext_typecheck_addrof_class_temporary)
+ << op->getType() << op->getSourceRange();
+ if (isSFINAEContext())
+ return QualType();
} else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
// C99 6.5.3.2p1
// The operand must be either an l-value or a function designator
@@ -6755,28 +6727,16 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
/// ActOnBlockStart - This callback is invoked when a block literal is started.
void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
- // Analyze block parameters.
- BlockSemaInfo *BSI = new BlockSemaInfo();
-
- // Add BSI to CurBlock.
- BSI->PrevBlockInfo = CurBlock;
- CurBlock = BSI;
-
- BSI->ReturnType = QualType();
- BSI->TheScope = BlockScope;
- BSI->hasBlockDeclRefExprs = false;
- BSI->hasPrototype = false;
- BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking;
- CurFunctionNeedsScopeChecking = false;
-
- BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc);
- CurContext->addDecl(BSI->TheDecl);
- PushDeclContext(BlockScope, BSI->TheDecl);
+ BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc);
+ PushBlockScope(BlockScope, Block);
+ CurContext->addDecl(Block);
+ PushDeclContext(BlockScope, Block);
}
void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!");
-
+ BlockScopeInfo *CurBlock = getCurBlock();
+
if (ParamInfo.getNumTypeObjects() == 0
|| ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) {
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
@@ -6790,7 +6750,8 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// The parameter list is optional, if there was none, assume ().
if (!T->isFunctionType())
- T = Context.getFunctionType(T, NULL, 0, 0, 0);
+ T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0, false,
+ CC_Default);
CurBlock->hasPrototype = true;
CurBlock->isVariadic = false;
@@ -6877,14 +6838,9 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
/// ActOnBlockError - If there is an error parsing a block, this callback
/// is invoked to pop the information about the block from the action impl.
void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
- // Ensure that CurBlock is deleted.
- llvm::OwningPtr<BlockSemaInfo> CC(CurBlock);
-
- CurFunctionNeedsScopeChecking = CurBlock->SavedFunctionNeedsScopeChecking;
-
// Pop off CurBlock, handle nested blocks.
PopDeclContext();
- CurBlock = CurBlock->PrevBlockInfo;
+ PopFunctionOrBlockScope();
// FIXME: Delete the ParmVarDecl objects as well???
}
@@ -6896,14 +6852,10 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (!LangOpts.Blocks)
Diag(CaretLoc, diag::err_blocks_disable);
- // Ensure that CurBlock is deleted.
- llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
+ BlockScopeInfo *BSI = cast<BlockScopeInfo>(FunctionScopes.back());
PopDeclContext();
- // Pop off CurBlock, handle nested blocks.
- CurBlock = CurBlock->PrevBlockInfo;
-
QualType RetTy = Context.VoidTy;
if (!BSI->ReturnType.isNull())
RetTy = BSI->ReturnType;
@@ -6916,20 +6868,19 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
QualType BlockTy;
if (!BSI->hasPrototype)
BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0,
- NoReturn);
+ NoReturn, CC_Default);
else
BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
BSI->isVariadic, 0, false, false, 0, 0,
- NoReturn);
+ NoReturn, CC_Default);
// FIXME: Check that return/parameter types are complete/non-abstract
DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
BlockTy = Context.getBlockPointerType(BlockTy);
// If needed, diagnose invalid gotos and switches in the block.
- if (CurFunctionNeedsScopeChecking)
+ if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction())
DiagnoseInvalidJumps(static_cast<CompoundStmt*>(body.get()));
- CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
@@ -6948,15 +6899,18 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName();
Good = false;
}
- BSI->LabelMap.clear();
- if (!Good)
+ if (!Good) {
+ PopFunctionOrBlockScope();
return ExprError();
-
+ }
+
AnalysisContext AC(BSI->TheDecl);
CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC);
CheckUnreachable(AC);
- return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
- BSI->hasBlockDeclRefExprs));
+ Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy,
+ BSI->hasBlockDeclRefExprs);
+ PopFunctionOrBlockScope();
+ return Owned(Result);
}
Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 9eeda54..5f46019 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -17,13 +17,278 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Template.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
+Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
+ IdentifierInfo &II,
+ SourceLocation NameLoc,
+ Scope *S, const CXXScopeSpec &SS,
+ TypeTy *ObjectTypePtr,
+ bool EnteringContext) {
+ // Determine where to perform name lookup.
+
+ // FIXME: This area of the standard is very messy, and the current
+ // wording is rather unclear about which scopes we search for the
+ // destructor name; see core issues 399 and 555. Issue 399 in
+ // particular shows where the current description of destructor name
+ // lookup is completely out of line with existing practice, e.g.,
+ // this appears to be ill-formed:
+ //
+ // namespace N {
+ // template <typename T> struct S {
+ // ~S();
+ // };
+ // }
+ //
+ // void f(N::S<int>* s) {
+ // s->N::S<int>::~S();
+ // }
+ //
+ // See also PR6358 and PR6359.
+ QualType SearchType;
+ DeclContext *LookupCtx = 0;
+ bool isDependent = false;
+ bool LookInScope = false;
+
+ // If we have an object type, it's because we are in a
+ // pseudo-destructor-expression or a member access expression, and
+ // we know what type we're looking for.
+ if (ObjectTypePtr)
+ SearchType = GetTypeFromParser(ObjectTypePtr);
+
+ if (SS.isSet()) {
+ NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
+
+ bool AlreadySearched = false;
+ bool LookAtPrefix = true;
+ if (!getLangOptions().CPlusPlus0x) {
+ // C++ [basic.lookup.qual]p6:
+ // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier,
+ // the type-names are looked up as types in the scope designated by the
+ // nested-name-specifier. In a qualified-id of the form:
+ //
+ // ::[opt] nested-name-specifier ̃ class-name
+ //
+ // where the nested-name-specifier designates a namespace scope, and in
+ // a qualified-id of the form:
+ //
+ // ::opt nested-name-specifier class-name :: ̃ class-name
+ //
+ // the class-names are looked up as types in the scope designated by
+ // the nested-name-specifier.
+ //
+ // Here, we check the first case (completely) and determine whether the
+ // code below is permitted to look at the prefix of the
+ // nested-name-specifier (as we do in C++0x).
+ DeclContext *DC = computeDeclContext(SS, EnteringContext);
+ if (DC && DC->isFileContext()) {
+ AlreadySearched = true;
+ LookupCtx = DC;
+ isDependent = false;
+ } else if (DC && isa<CXXRecordDecl>(DC))
+ LookAtPrefix = false;
+ }
+
+ // C++0x [basic.lookup.qual]p6:
+ // If a pseudo-destructor-name (5.2.4) contains a
+ // nested-name-specifier, the type-names are looked up as types
+ // in the scope designated by the nested-name-specifier. Similarly, in
+ // a qualified-id of the form:
+ //
+ // :: [opt] nested-name-specifier[opt] class-name :: ~class-name
+ //
+ // the second class-name is looked up in the same scope as the first.
+ //
+ // To implement this, we look at the prefix of the
+ // nested-name-specifier we were given, and determine the lookup
+ // context from that.
+ //
+ // We also fold in the second case from the C++03 rules quoted further
+ // above.
+ NestedNameSpecifier *Prefix = 0;
+ if (AlreadySearched) {
+ // Nothing left to do.
+ } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) {
+ CXXScopeSpec PrefixSS;
+ PrefixSS.setScopeRep(Prefix);
+ LookupCtx = computeDeclContext(PrefixSS, EnteringContext);
+ isDependent = isDependentScopeSpecifier(PrefixSS);
+ } else if (getLangOptions().CPlusPlus0x &&
+ (LookupCtx = computeDeclContext(SS, EnteringContext))) {
+ if (!LookupCtx->isTranslationUnit())
+ LookupCtx = LookupCtx->getParent();
+ isDependent = LookupCtx && LookupCtx->isDependentContext();
+ } else if (ObjectTypePtr) {
+ LookupCtx = computeDeclContext(SearchType);
+ isDependent = SearchType->isDependentType();
+ } else {
+ LookupCtx = computeDeclContext(SS, EnteringContext);
+ isDependent = LookupCtx && LookupCtx->isDependentContext();
+ }
+
+ LookInScope = false;
+ } else if (ObjectTypePtr) {
+ // C++ [basic.lookup.classref]p3:
+ // If the unqualified-id is ~type-name, the type-name is looked up
+ // in the context of the entire postfix-expression. If the type T
+ // of the object expression is of a class type C, the type-name is
+ // also looked up in the scope of class C. At least one of the
+ // lookups shall find a name that refers to (possibly
+ // cv-qualified) T.
+ LookupCtx = computeDeclContext(SearchType);
+ isDependent = SearchType->isDependentType();
+ assert((isDependent || !SearchType->isIncompleteType()) &&
+ "Caller should have completed object type");
+
+ LookInScope = true;
+ } else {
+ // Perform lookup into the current scope (only).
+ LookInScope = true;
+ }
+
+ LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName);
+ for (unsigned Step = 0; Step != 2; ++Step) {
+ // Look for the name first in the computed lookup context (if we
+ // have one) and, if that fails to find a match, in the sope (if
+ // we're allowed to look there).
+ Found.clear();
+ if (Step == 0 && LookupCtx)
+ LookupQualifiedName(Found, LookupCtx);
+ else if (Step == 1 && LookInScope && S)
+ LookupName(Found, S);
+ else
+ continue;
+
+ // FIXME: Should we be suppressing ambiguities here?
+ if (Found.isAmbiguous())
+ return 0;
+
+ if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) {
+ QualType T = Context.getTypeDeclType(Type);
+ // If we found the injected-class-name of a class template, retrieve the
+ // type of that template.
+ // FIXME: We really shouldn't need to do this.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Type))
+ if (Record->isInjectedClassName())
+ if (Record->getDescribedClassTemplate())
+ T = Record->getDescribedClassTemplate()
+ ->getInjectedClassNameType(Context);
+
+ if (SearchType.isNull() || SearchType->isDependentType() ||
+ Context.hasSameUnqualifiedType(T, SearchType)) {
+ // We found our type!
+
+ return T.getAsOpaquePtr();
+ }
+ }
+
+ // If the name that we found is a class template name, and it is
+ // the same name as the template name in the last part of the
+ // nested-name-specifier (if present) or the object type, then
+ // this is the destructor for that class.
+ // FIXME: This is a workaround until we get real drafting for core
+ // issue 399, for which there isn't even an obvious direction.
+ if (ClassTemplateDecl *Template = Found.getAsSingle<ClassTemplateDecl>()) {
+ QualType MemberOfType;
+ if (SS.isSet()) {
+ if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) {
+ // Figure out the type of the context, if it has one.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Ctx))
+ MemberOfType = Context.getTypeDeclType(Spec);
+ else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+ if (Record->getDescribedClassTemplate())
+ MemberOfType = Record->getDescribedClassTemplate()
+ ->getInjectedClassNameType(Context);
+ else
+ MemberOfType = Context.getTypeDeclType(Record);
+ }
+ }
+ }
+ if (MemberOfType.isNull())
+ MemberOfType = SearchType;
+
+ if (MemberOfType.isNull())
+ continue;
+
+ // We're referring into a class template specialization. If the
+ // class template we found is the same as the template being
+ // specialized, we found what we are looking for.
+ if (const RecordType *Record = MemberOfType->getAs<RecordType>()) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
+ if (Spec->getSpecializedTemplate()->getCanonicalDecl() ==
+ Template->getCanonicalDecl())
+ return MemberOfType.getAsOpaquePtr();
+ }
+
+ continue;
+ }
+
+ // We're referring to an unresolved class template
+ // specialization. Determine whether we class template we found
+ // is the same as the template being specialized or, if we don't
+ // know which template is being specialized, that it at least
+ // has the same name.
+ if (const TemplateSpecializationType *SpecType
+ = MemberOfType->getAs<TemplateSpecializationType>()) {
+ TemplateName SpecName = SpecType->getTemplateName();
+
+ // The class template we found is the same template being
+ // specialized.
+ if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) {
+ if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl())
+ return MemberOfType.getAsOpaquePtr();
+
+ continue;
+ }
+
+ // The class template we found has the same name as the
+ // (dependent) template name being specialized.
+ if (DependentTemplateName *DepTemplate
+ = SpecName.getAsDependentTemplateName()) {
+ if (DepTemplate->isIdentifier() &&
+ DepTemplate->getIdentifier() == Template->getIdentifier())
+ return MemberOfType.getAsOpaquePtr();
+
+ continue;
+ }
+ }
+ }
+ }
+
+ if (isDependent) {
+ // We didn't find our type, but that's okay: it's dependent
+ // anyway.
+ NestedNameSpecifier *NNS = 0;
+ SourceRange Range;
+ if (SS.isSet()) {
+ NNS = (NestedNameSpecifier *)SS.getScopeRep();
+ Range = SourceRange(SS.getRange().getBegin(), NameLoc);
+ } else {
+ NNS = NestedNameSpecifier::Create(Context, &II);
+ Range = SourceRange(NameLoc);
+ }
+
+ return CheckTypenameType(NNS, II, Range).getAsOpaquePtr();
+ }
+
+ if (ObjectTypePtr)
+ Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
+ << &II;
+ else
+ Diag(NameLoc, diag::err_destructor_class_name);
+
+ return 0;
+}
+
/// ActOnCXXTypeidOfType - Parse typeid( type-id ).
Action::OwningExprResult
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
@@ -161,6 +426,18 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
: diag::err_throw_incomplete)
<< E->getSourceRange()))
return true;
+
+ // FIXME: This is just a hack to mark the copy constructor referenced.
+ // This should go away when the next FIXME is fixed.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->hasTrivialCopyConstructor())
+ return false;
+ CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(Context, 0);
+ MarkDeclarationReferenced(ThrowLoc, CopyCtor);
}
// FIXME: Construct a temporary here.
@@ -515,6 +792,12 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
ConsArgs = (Expr **)ConvertedConstructorArgs.take();
}
+ // Mark the new and delete operators as referenced.
+ if (OperatorNew)
+ MarkDeclarationReferenced(StartLoc, OperatorNew);
+ if (OperatorDelete)
+ MarkDeclarationReferenced(StartLoc, OperatorDelete);
+
// FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
PlacementArgs.release();
@@ -554,6 +837,20 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
return false;
}
+/// \brief Determine whether the given function is a non-placement
+/// deallocation function.
+static bool isNonPlacementDeallocationFunction(FunctionDecl *FD) {
+ if (FD->isInvalidDecl())
+ return false;
+
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
+ return Method->isUsualDeallocationFunction();
+
+ return ((FD->getOverloadedOperator() == OO_Delete ||
+ FD->getOverloadedOperator() == OO_Array_Delete) &&
+ FD->getNumParams() == 1);
+}
+
/// FindAllocationFunctions - Finds the overloads of operator new and delete
/// that are appropriate for the allocation.
bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
@@ -570,7 +867,6 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// operator new.
// 3) The first argument is always size_t. Append the arguments from the
// placement form.
- // FIXME: Also find the appropriate delete operator.
llvm::SmallVector<Expr*, 8> AllocArgs(1 + NumPlaceArgs);
// We don't care about the actual value of this argument.
@@ -583,12 +879,20 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
AllocArgs[0] = &Size;
std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1);
+ // C++ [expr.new]p8:
+ // If the allocated type is a non-array type, the allocation
+ // function’s name is operator new and the deallocation function’s
+ // name is operator delete. If the allocated type is an array
+ // type, the allocation function’s name is operator new[] and the
+ // deallocation function’s name is operator delete[].
DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName(
IsArray ? OO_Array_New : OO_New);
+ DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
+ IsArray ? OO_Array_Delete : OO_Delete);
+
if (AllocType->isRecordType() && !UseGlobal) {
CXXRecordDecl *Record
= cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl());
- // FIXME: We fail to find inherited overloads.
if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0],
AllocArgs.size(), Record, /*AllowMissing=*/true,
OperatorNew))
@@ -609,6 +913,110 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
if (NumPlaceArgs > 0)
std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs);
+ // C++ [expr.new]p19:
+ //
+ // If the new-expression begins with a unary :: operator, the
+ // deallocation function’s name is looked up in the global
+ // scope. Otherwise, if the allocated type is a class type T or an
+ // array thereof, the deallocation function’s name is looked up in
+ // the scope of T. If this lookup fails to find the name, or if
+ // the allocated type is not a class type or array thereof, the
+ // deallocation function’s name is looked up in the global scope.
+ LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName);
+ if (AllocType->isRecordType() && !UseGlobal) {
+ CXXRecordDecl *RD
+ = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl());
+ LookupQualifiedName(FoundDelete, RD);
+ }
+
+ if (FoundDelete.empty()) {
+ DeclareGlobalNewDelete();
+ LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl());
+ }
+
+ FoundDelete.suppressDiagnostics();
+ llvm::SmallVector<NamedDecl *, 4> Matches;
+ if (NumPlaceArgs > 1) {
+ // C++ [expr.new]p20:
+ // A declaration of a placement deallocation function matches the
+ // declaration of a placement allocation function if it has the
+ // same number of parameters and, after parameter transformations
+ // (8.3.5), all parameter types except the first are
+ // identical. [...]
+ //
+ // To perform this comparison, we compute the function type that
+ // the deallocation function should have, and use that type both
+ // for template argument deduction and for comparison purposes.
+ QualType ExpectedFunctionType;
+ {
+ const FunctionProtoType *Proto
+ = OperatorNew->getType()->getAs<FunctionProtoType>();
+ llvm::SmallVector<QualType, 4> ArgTypes;
+ ArgTypes.push_back(Context.VoidPtrTy);
+ for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I)
+ ArgTypes.push_back(Proto->getArgType(I));
+
+ ExpectedFunctionType
+ = Context.getFunctionType(Context.VoidTy, ArgTypes.data(),
+ ArgTypes.size(),
+ Proto->isVariadic(),
+ 0, false, false, 0, 0, false, CC_Default);
+ }
+
+ for (LookupResult::iterator D = FoundDelete.begin(),
+ DEnd = FoundDelete.end();
+ D != DEnd; ++D) {
+ FunctionDecl *Fn = 0;
+ if (FunctionTemplateDecl *FnTmpl
+ = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) {
+ // Perform template argument deduction to try to match the
+ // expected function type.
+ TemplateDeductionInfo Info(Context, StartLoc);
+ if (DeduceTemplateArguments(FnTmpl, 0, ExpectedFunctionType, Fn, Info))
+ continue;
+ } else
+ Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl());
+
+ if (Context.hasSameType(Fn->getType(), ExpectedFunctionType))
+ Matches.push_back(Fn);
+ }
+ } else {
+ // C++ [expr.new]p20:
+ // [...] Any non-placement deallocation function matches a
+ // non-placement allocation function. [...]
+ for (LookupResult::iterator D = FoundDelete.begin(),
+ DEnd = FoundDelete.end();
+ D != DEnd; ++D) {
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl()))
+ if (isNonPlacementDeallocationFunction(Fn))
+ Matches.push_back(*D);
+ }
+ }
+
+ // C++ [expr.new]p20:
+ // [...] If the lookup finds a single matching deallocation
+ // function, that function will be called; otherwise, no
+ // deallocation function will be called.
+ if (Matches.size() == 1) {
+ // FIXME: Drops access, using-declaration info!
+ OperatorDelete = cast<FunctionDecl>(Matches[0]->getUnderlyingDecl());
+
+ // C++0x [expr.new]p20:
+ // If the lookup finds the two-parameter form of a usual
+ // deallocation function (3.7.4.2) and that function, considered
+ // as a placement deallocation function, would have been
+ // selected as a match for the allocation function, the program
+ // is ill-formed.
+ if (NumPlaceArgs && getLangOptions().CPlusPlus0x &&
+ isNonPlacementDeallocationFunction(OperatorDelete)) {
+ Diag(StartLoc, diag::err_placement_new_non_placement_delete)
+ << SourceRange(PlaceArgs[0]->getLocStart(),
+ PlaceArgs[NumPlaceArgs - 1]->getLocEnd());
+ Diag(OperatorDelete->getLocation(), diag::note_previous_decl)
+ << DeleteName;
+ }
+ }
+
return false;
}
@@ -802,7 +1210,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0,
true, false,
HasBadAllocExceptionSpec? 1 : 0,
- &BadAllocType);
+ &BadAllocType, false, CC_Default);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
FnType, /*TInfo=*/0, FunctionDecl::None, false, true);
@@ -1079,8 +1487,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
AssignmentAction Action, bool AllowExplicit,
bool Elidable,
ImplicitConversionSequence& ICS) {
- ICS.setBad();
- ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
if (Elidable && getLangOptions().CPlusPlus0x) {
ICS = TryImplicitConversion(From, ToType,
/*SuppressUserConversions=*/false,
@@ -1379,6 +1786,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
ImpCastExprToType(From, ToType.getNonReferenceType(),
CastExpr::CK_NoOp,
ToType->isLValueReferenceType());
+
+ if (SCS.DeprecatedStringLiteralToCharPtr)
+ Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion)
+ << ToType.getNonReferenceType();
+
break;
default:
@@ -1494,6 +1906,7 @@ static QualType TargetType(const ImplicitConversionSequence &ICS) {
return ICS.UserDefined.After.getToType(2);
case ImplicitConversionSequence::AmbiguousConversion:
return ICS.Ambiguous.getToType();
+
case ImplicitConversionSequence::EllipsisConversion:
case ImplicitConversionSequence::BadConversion:
llvm_unreachable("function not valid for ellipsis or bad conversions");
@@ -1537,7 +1950,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
return false;
}
}
- ICS.setBad();
+
// -- If E2 is an rvalue, or if the conversion above cannot be done:
// -- if E1 and E2 have class type, and the underlying class types are
// the same or one is a base class of the other:
@@ -1551,14 +1964,22 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// E1 can be converted to match E2 if the class of T2 is the
// same type as, or a base class of, the class of T1, and
// [cv2 > cv1].
- if ((FRec == TRec || FDerivedFromT) && TTy.isAtLeastAsQualifiedAs(FTy)) {
- // Could still fail if there's no copy constructor.
- // FIXME: Is this a hard error then, or just a conversion failure? The
- // standard doesn't say.
- ICS = Self.TryCopyInitialization(From, TTy,
- /*SuppressUserConversions=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
+ if (FRec == TRec || FDerivedFromT) {
+ if (TTy.isAtLeastAsQualifiedAs(FTy)) {
+ // Could still fail if there's no copy constructor.
+ // FIXME: Is this a hard error then, or just a conversion failure? The
+ // standard doesn't say.
+ ICS = Self.TryCopyInitialization(From, TTy,
+ /*SuppressUserConversions=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+ } else {
+ ICS.setBad(BadConversionSequence::bad_qualifiers, From, TTy);
+ }
+ } else {
+ // Can't implicitly convert FTy to a derived class TTy.
+ // TODO: more specific error for this.
+ ICS.setBad(BadConversionSequence::no_conversion, From, TTy);
}
} else {
// -- Otherwise: E1 can be converted to match E2 if E1 can be
@@ -1807,9 +2228,18 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// performed to bring them to a common type, whose cv-qualification
// shall match the cv-qualification of either the second or the third
// operand. The result is of the common type.
- QualType Composite = FindCompositePointerType(LHS, RHS);
- if (!Composite.isNull())
+ bool NonStandardCompositeType = false;
+ QualType Composite = FindCompositePointerType(LHS, RHS,
+ isSFINAEContext()? 0 : &NonStandardCompositeType);
+ if (!Composite.isNull()) {
+ if (NonStandardCompositeType)
+ Diag(QuestionLoc,
+ diag::ext_typecheck_cond_incompatible_operands_nonstandard)
+ << LTy << RTy << Composite
+ << LHS->getSourceRange() << RHS->getSourceRange();
+
return Composite;
+ }
// Similarly, attempt to find composite type of twp objective-c pointers.
Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc);
@@ -1828,7 +2258,16 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
/// and @p E2 according to C++0x 5.9p2. It converts both expressions to this
/// type and returns it.
/// It does not emit diagnostics.
-QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
+///
+/// If \p NonStandardCompositeType is non-NULL, then we are permitted to find
+/// a non-standard (but still sane) composite type to which both expressions
+/// can be converted. When such a type is chosen, \c *NonStandardCompositeType
+/// will be set true.
+QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2,
+ bool *NonStandardCompositeType) {
+ if (NonStandardCompositeType)
+ *NonStandardCompositeType = false;
+
assert(getLangOptions().CPlusPlus && "This function assumes C++");
QualType T1 = E1->getType(), T2 = E2->getType();
@@ -1879,12 +2318,20 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
ContainingClassVector MemberOfClass;
QualType Composite1 = Context.getCanonicalType(T1),
Composite2 = Context.getCanonicalType(T2);
+ unsigned NeedConstBefore = 0;
do {
const PointerType *Ptr1, *Ptr2;
if ((Ptr1 = Composite1->getAs<PointerType>()) &&
(Ptr2 = Composite2->getAs<PointerType>())) {
Composite1 = Ptr1->getPointeeType();
Composite2 = Ptr2->getPointeeType();
+
+ // If we're allowed to create a non-standard composite type, keep track
+ // of where we need to fill in additional 'const' qualifiers.
+ if (NonStandardCompositeType &&
+ Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
+ NeedConstBefore = QualifierUnion.size();
+
QualifierUnion.push_back(
Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0));
@@ -1896,6 +2343,13 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
(MemPtr2 = Composite2->getAs<MemberPointerType>())) {
Composite1 = MemPtr1->getPointeeType();
Composite2 = MemPtr2->getPointeeType();
+
+ // If we're allowed to create a non-standard composite type, keep track
+ // of where we need to fill in additional 'const' qualifiers.
+ if (NonStandardCompositeType &&
+ Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
+ NeedConstBefore = QualifierUnion.size();
+
QualifierUnion.push_back(
Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(),
@@ -1909,6 +2363,18 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
break;
} while (true);
+ if (NeedConstBefore && NonStandardCompositeType) {
+ // Extension: Add 'const' to qualifiers that come before the first qualifier
+ // mismatch, so that our (non-standard!) composite type meets the
+ // requirements of C++ [conv.qual]p4 bullet 3.
+ for (unsigned I = 0; I != NeedConstBefore; ++I) {
+ if ((QualifierUnion[I] & Qualifiers::Const) == 0) {
+ QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const;
+ *NonStandardCompositeType = true;
+ }
+ }
+ }
+
// Rewrap the composites as pointers or member pointers with the union CVRs.
ContainingClassVector::reverse_iterator MOC
= MemberOfClass.rbegin();
@@ -1947,9 +2413,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
+ bool ToC2Viable = false;
ImplicitConversionSequence E1ToC2, E2ToC2;
- E1ToC2.setBad();
- E2ToC2.setBad();
if (Context.getCanonicalType(Composite1) !=
Context.getCanonicalType(Composite2)) {
E1ToC2 = TryImplicitConversion(E1, Composite2,
@@ -1962,10 +2427,10 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
/*AllowExplicit=*/false,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
+ ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad();
}
bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad();
- bool ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad();
if (ToC1Viable && !ToC2Viable) {
if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) &&
!PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting))
@@ -1995,7 +2460,9 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
QualType Ty = CE->getCallee()->getType();
if (const PointerType *PT = Ty->getAs<PointerType>())
Ty = PT->getPointeeType();
-
+ else if (const BlockPointerType *BPT = Ty->getAs<BlockPointerType>())
+ Ty = BPT->getPointeeType();
+
const FunctionType *FTy = Ty->getAs<FunctionType>();
if (FTy->getResultType()->isReferenceType())
return Owned(E);
@@ -2060,7 +2527,8 @@ FullExpr Sema::CreateFullExpr(Expr *SubExpr) {
Sema::OwningExprResult
Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
- tok::TokenKind OpKind, TypeTy *&ObjectType) {
+ tok::TokenKind OpKind, TypeTy *&ObjectType,
+ bool &MayBePseudoDestructor) {
// Since this might be a postfix expression, get rid of ParenListExprs.
Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
@@ -2068,6 +2536,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
assert(BaseExpr && "no record expansion");
QualType BaseType = BaseExpr->getType();
+ MayBePseudoDestructor = false;
if (BaseType->isDependentType()) {
// If we have a pointer to a dependent type and are using the -> operator,
// the object type is the type that the pointer points to. We might still
@@ -2077,6 +2546,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
BaseType = Ptr->getPointeeType();
ObjectType = BaseType.getAsOpaquePtr();
+ MayBePseudoDestructor = true;
return move(Base);
}
@@ -2118,7 +2588,11 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
// [...] If the type of the object expression is of pointer to scalar
// type, the unqualified-id is looked up in the context of the complete
// postfix-expression.
+ //
+ // This also indicates that we should be parsing a
+ // pseudo-destructor-name.
ObjectType = 0;
+ MayBePseudoDestructor = true;
return move(Base);
}
@@ -2134,10 +2608,277 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
// type C (or of pointer to a class type C), the unqualified-id is looked
// up in the scope of class C. [...]
ObjectType = BaseType.getAsOpaquePtr();
-
return move(Base);
}
+Sema::OwningExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
+ ExprArg MemExpr) {
+ Expr *E = (Expr *) MemExpr.get();
+ SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc);
+ Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
+ << isa<CXXPseudoDestructorExpr>(E)
+ << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
+
+ return ActOnCallExpr(/*Scope*/ 0,
+ move(MemExpr),
+ /*LPLoc*/ ExpectedLParenLoc,
+ Sema::MultiExprArg(*this, 0, 0),
+ /*CommaLocs*/ 0,
+ /*RPLoc*/ ExpectedLParenLoc);
+}
+
+Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ TypeSourceInfo *ScopeTypeInfo,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
+ PseudoDestructorTypeStorage Destructed,
+ bool HasTrailingLParen) {
+ TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
+
+ // C++ [expr.pseudo]p2:
+ // The left-hand side of the dot operator shall be of scalar type. The
+ // left-hand side of the arrow operator shall be of pointer to scalar type.
+ // This scalar type is the object type.
+ Expr *BaseE = (Expr *)Base.get();
+ QualType ObjectType = BaseE->getType();
+ if (OpKind == tok::arrow) {
+ if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
+ ObjectType = Ptr->getPointeeType();
+ } else if (!BaseE->isTypeDependent()) {
+ // The user wrote "p->" when she probably meant "p."; fix it.
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << ObjectType << true
+ << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ if (isSFINAEContext())
+ return ExprError();
+
+ OpKind = tok::period;
+ }
+ }
+
+ if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) {
+ Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
+ << ObjectType << BaseE->getSourceRange();
+ return ExprError();
+ }
+
+ // C++ [expr.pseudo]p2:
+ // [...] The cv-unqualified versions of the object type and of the type
+ // designated by the pseudo-destructor-name shall be the same type.
+ if (DestructedTypeInfo) {
+ QualType DestructedType = DestructedTypeInfo->getType();
+ SourceLocation DestructedTypeStart
+ = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin();
+ if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
+ !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
+ Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
+ << ObjectType << DestructedType << BaseE->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getSourceRange();
+
+ // Recover by setting the destructed type to the object type.
+ DestructedType = ObjectType;
+ DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+ DestructedTypeStart);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ }
+ }
+
+ // C++ [expr.pseudo]p2:
+ // [...] Furthermore, the two type-names in a pseudo-destructor-name of the
+ // form
+ //
+ // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name
+ //
+ // shall designate the same scalar type.
+ if (ScopeTypeInfo) {
+ QualType ScopeType = ScopeTypeInfo->getType();
+ if (!ScopeType->isDependentType() && !ObjectType->isDependentType() &&
+ !Context.hasSameType(ScopeType, ObjectType)) {
+
+ Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(),
+ diag::err_pseudo_dtor_type_mismatch)
+ << ObjectType << ScopeType << BaseE->getSourceRange()
+ << ScopeTypeInfo->getTypeLoc().getSourceRange();
+
+ ScopeType = QualType();
+ ScopeTypeInfo = 0;
+ }
+ }
+
+ OwningExprResult Result
+ = Owned(new (Context) CXXPseudoDestructorExpr(Context,
+ Base.takeAs<Expr>(),
+ OpKind == tok::arrow,
+ OpLoc,
+ (NestedNameSpecifier *) SS.getScopeRep(),
+ SS.getRange(),
+ ScopeTypeInfo,
+ CCLoc,
+ TildeLoc,
+ Destructed));
+
+ if (HasTrailingLParen)
+ return move(Result);
+
+ return DiagnoseDtorReference(Destructed.getLocation(), move(Result));
+}
+
+Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ UnqualifiedId &FirstTypeName,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
+ UnqualifiedId &SecondTypeName,
+ bool HasTrailingLParen) {
+ assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
+ FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
+ "Invalid first type name in pseudo-destructor");
+ assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
+ SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
+ "Invalid second type name in pseudo-destructor");
+
+ Expr *BaseE = (Expr *)Base.get();
+
+ // C++ [expr.pseudo]p2:
+ // The left-hand side of the dot operator shall be of scalar type. The
+ // left-hand side of the arrow operator shall be of pointer to scalar type.
+ // This scalar type is the object type.
+ QualType ObjectType = BaseE->getType();
+ if (OpKind == tok::arrow) {
+ if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
+ ObjectType = Ptr->getPointeeType();
+ } else if (!ObjectType->isDependentType()) {
+ // The user wrote "p->" when she probably meant "p."; fix it.
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << ObjectType << true
+ << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ if (isSFINAEContext())
+ return ExprError();
+
+ OpKind = tok::period;
+ }
+ }
+
+ // Compute the object type that we should use for name lookup purposes. Only
+ // record types and dependent types matter.
+ void *ObjectTypePtrForLookup = 0;
+ if (!SS.isSet()) {
+ ObjectTypePtrForLookup = (void *)ObjectType->getAs<RecordType>();
+ if (!ObjectTypePtrForLookup && ObjectType->isDependentType())
+ ObjectTypePtrForLookup = Context.DependentTy.getAsOpaquePtr();
+ }
+
+ // Convert the name of the type being destructed (following the ~) into a
+ // type (with source-location information).
+ QualType DestructedType;
+ TypeSourceInfo *DestructedTypeInfo = 0;
+ PseudoDestructorTypeStorage Destructed;
+ if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
+ TypeTy *T = getTypeName(*SecondTypeName.Identifier,
+ SecondTypeName.StartLocation,
+ S, &SS, true, ObjectTypePtrForLookup);
+ if (!T &&
+ ((SS.isSet() && !computeDeclContext(SS, false)) ||
+ (!SS.isSet() && ObjectType->isDependentType()))) {
+ // The name of the type being destroyed is a dependent name, and we
+ // couldn't find anything useful in scope. Just store the identifier and
+ // it's location, and we'll perform (qualified) name lookup again at
+ // template instantiation time.
+ Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier,
+ SecondTypeName.StartLocation);
+ } else if (!T) {
+ Diag(SecondTypeName.StartLocation,
+ diag::err_pseudo_dtor_destructor_non_type)
+ << SecondTypeName.Identifier << ObjectType;
+ if (isSFINAEContext())
+ return ExprError();
+
+ // Recover by assuming we had the right type all along.
+ DestructedType = ObjectType;
+ } else
+ DestructedType = GetTypeFromParser(T, &DestructedTypeInfo);
+ } else {
+ // Resolve the template-id to a type.
+ TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
+ TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->RAngleLoc);
+ if (T.isInvalid() || !T.get()) {
+ // Recover by assuming we had the right type all along.
+ DestructedType = ObjectType;
+ } else
+ DestructedType = GetTypeFromParser(T.get(), &DestructedTypeInfo);
+ }
+
+ // If we've performed some kind of recovery, (re-)build the type source
+ // information.
+ if (!DestructedType.isNull()) {
+ if (!DestructedTypeInfo)
+ DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType,
+ SecondTypeName.StartLocation);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ }
+
+ // Convert the name of the scope type (the type prior to '::') into a type.
+ TypeSourceInfo *ScopeTypeInfo = 0;
+ QualType ScopeType;
+ if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
+ FirstTypeName.Identifier) {
+ if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
+ TypeTy *T = getTypeName(*FirstTypeName.Identifier,
+ FirstTypeName.StartLocation,
+ S, &SS, false, ObjectTypePtrForLookup);
+ if (!T) {
+ Diag(FirstTypeName.StartLocation,
+ diag::err_pseudo_dtor_destructor_non_type)
+ << FirstTypeName.Identifier << ObjectType;
+
+ if (isSFINAEContext())
+ return ExprError();
+
+ // Just drop this type. It's unnecessary anyway.
+ ScopeType = QualType();
+ } else
+ ScopeType = GetTypeFromParser(T, &ScopeTypeInfo);
+ } else {
+ // Resolve the template-id to a type.
+ TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
+ TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->RAngleLoc);
+ if (T.isInvalid() || !T.get()) {
+ // Recover by dropping this type.
+ ScopeType = QualType();
+ } else
+ ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo);
+ }
+ }
+
+ if (!ScopeType.isNull() && !ScopeTypeInfo)
+ ScopeTypeInfo = Context.getTrivialTypeSourceInfo(ScopeType,
+ FirstTypeName.StartLocation);
+
+
+ return BuildPseudoDestructorExpr(move(Base), OpLoc, OpKind, SS,
+ ScopeTypeInfo, CCLoc, TildeLoc,
+ Destructed, HasTrailingLParen);
+}
+
CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
CXXMethodDecl *Method) {
if (PerformObjectArgumentInitialization(Exp, Method))
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 0c5d8ef..3a05241 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -426,14 +426,14 @@ Sema::ExprResult Sema::ActOnClassMessage(
if (!ClassDecl) {
NamedDecl *IDecl
= LookupSingleName(TUScope, receiverName, LookupOrdinaryName);
- if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) {
- const ObjCInterfaceType *OCIT;
- OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>();
- if (!OCIT) {
- Diag(receiverLoc, diag::err_invalid_receiver_to_message);
- return true;
- }
- ClassDecl = OCIT->getDecl();
+ if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl))
+ if (const ObjCInterfaceType *OCIT
+ = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>())
+ ClassDecl = OCIT->getDecl();
+
+ if (!ClassDecl) {
+ Diag(receiverLoc, diag::err_invalid_receiver_to_message);
+ return true;
}
}
assert(ClassDecl && "missing interface declaration");
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 7b4a417..0f8107a 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2227,7 +2227,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
ToType, CandidateSet);
else
S.AddConversionCandidate(Conv, I.getAccess(), ActingDC,
- Initializer, cv1T1, CandidateSet);
+ Initializer, ToType, CandidateSet);
}
}
}
@@ -3439,10 +3439,25 @@ InitializationSequence::Perform(Sema &S,
return S.ExprError();
// Build the an expression that constructs a temporary.
- CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
- Constructor,
- move_arg(ConstructorArgs),
- ConstructorInitRequiresZeroInit,
+ if (Entity.getKind() == InitializedEntity::EK_Temporary &&
+ (Kind.getKind() == InitializationKind::IK_Direct ||
+ Kind.getKind() == InitializationKind::IK_Value)) {
+ // An explicitly-constructed temporary, e.g., X(1, 2).
+ unsigned NumExprs = ConstructorArgs.size();
+ Expr **Exprs = (Expr **)ConstructorArgs.take();
+ S.MarkDeclarationReferenced(Kind.getLocation(), Constructor);
+ CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context,
+ Constructor,
+ Entity.getType(),
+ Kind.getLocation(),
+ Exprs,
+ NumExprs,
+ Kind.getParenRange().getEnd()));
+ } else
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor,
+ move_arg(ConstructorArgs),
+ ConstructorInitRequiresZeroInit,
Entity.getKind() == InitializedEntity::EK_Base);
if (CurInit.isInvalid())
return S.ExprError();
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index c7569d6..744b806 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -544,7 +544,8 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
0, 0, ConvProto->isVariadic(),
ConvProto->getTypeQuals(),
false, false, 0, 0,
- ConvProto->getNoReturnAttr());
+ ConvProto->getNoReturnAttr(),
+ CC_Default);
// Perform template argument deduction against the type that we would
// expect the function to have.
@@ -644,14 +645,37 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
DeclContext *OuterCtx = findOuterContext(S);
for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
Ctx = Ctx->getLookupParent()) {
- // We do not directly look into function or method contexts
- // (since all local variables are found via the identifier
- // changes) or in transparent contexts (since those entities
- // will be found in the nearest enclosing non-transparent
- // context).
- if (Ctx->isFunctionOrMethod() || Ctx->isTransparentContext())
+ // We do not directly look into transparent contexts, since
+ // those entities will be found in the nearest enclosing
+ // non-transparent context.
+ if (Ctx->isTransparentContext())
continue;
-
+
+ // We do not look directly into function or method contexts,
+ // since all of the local variables and parameters of the
+ // function/method are present within the Scope.
+ if (Ctx->isFunctionOrMethod()) {
+ // If we have an Objective-C instance method, look for ivars
+ // in the corresponding interface.
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) {
+ if (Method->isInstanceMethod() && Name.getAsIdentifierInfo())
+ if (ObjCInterfaceDecl *Class = Method->getClassInterface()) {
+ ObjCInterfaceDecl *ClassDeclared;
+ if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(
+ Name.getAsIdentifierInfo(),
+ ClassDeclared)) {
+ if (R.isAcceptableDecl(Ivar)) {
+ R.addDecl(Ivar);
+ R.resolveKind();
+ return true;
+ }
+ }
+ }
+ }
+
+ continue;
+ }
+
// Perform qualified name lookup into this context.
// FIXME: In some cases, we know that every name that could be found by
// this qualified name lookup will also be on the identifier chain. For
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index b79b1cc..ed0d137 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -80,7 +80,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
- ICR_Conversion
+ ICR_Complex_Real_Conversion
};
return Rank[(int)Kind];
}
@@ -118,7 +118,7 @@ void StandardConversionSequence::setAsIdentityConversion() {
First = ICK_Identity;
Second = ICK_Identity;
Third = ICK_Identity;
- Deprecated = false;
+ DeprecatedStringLiteralToCharPtr = false;
ReferenceBinding = false;
DirectBinding = false;
RRefBinding = false;
@@ -453,8 +453,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
}
if (!getLangOptions().CPlusPlus) {
- ICS.setBad();
- ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
return ICS;
}
@@ -500,8 +499,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
// 13.3.1.6 in all cases, only standard conversion sequences and
// ellipsis conversion sequences are allowed.
if (SuppressUserConversions && ICS.isUserDefined()) {
- ICS.setBad();
- ICS.Bad.init(BadConversionSequence::suppressed_user, From, ToType);
+ ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
}
} else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
ICS.setAmbiguous();
@@ -512,8 +510,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
if (Cand->Viable)
ICS.Ambiguous.addConversion(Cand->Function);
} else {
- ICS.setBad();
- ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
}
return ICS;
@@ -552,7 +549,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// Standard conversions (C++ [conv])
SCS.setAsIdentityConversion();
- SCS.Deprecated = false;
+ SCS.DeprecatedStringLiteralToCharPtr = false;
SCS.IncompatibleObjC = false;
SCS.setFromType(FromType);
SCS.CopyConstructor = 0;
@@ -595,7 +592,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
if (IsStringLiteralToNonConstPointerConversion(From, ToType)) {
// This conversion is deprecated. (C++ D.4).
- SCS.Deprecated = true;
+ SCS.DeprecatedStringLiteralToCharPtr = true;
// For the purpose of ranking in overload resolution
// (13.3.3.1.1), this conversion is considered an
@@ -672,14 +669,19 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// Integral conversions (C++ 4.7).
SCS.Second = ICK_Integral_Conversion;
FromType = ToType.getUnqualifiedType();
- } else if (FromType->isFloatingType() && ToType->isFloatingType()) {
- // Floating point conversions (C++ 4.8).
- SCS.Second = ICK_Floating_Conversion;
- FromType = ToType.getUnqualifiedType();
} else if (FromType->isComplexType() && ToType->isComplexType()) {
// Complex conversions (C99 6.3.1.6)
SCS.Second = ICK_Complex_Conversion;
FromType = ToType.getUnqualifiedType();
+ } else if ((FromType->isComplexType() && ToType->isArithmeticType()) ||
+ (ToType->isComplexType() && FromType->isArithmeticType())) {
+ // Complex-real conversions (C99 6.3.1.7)
+ SCS.Second = ICK_Complex_Real;
+ FromType = ToType.getUnqualifiedType();
+ } else if (FromType->isFloatingType() && ToType->isFloatingType()) {
+ // Floating point conversions (C++ 4.8).
+ SCS.Second = ICK_Floating_Conversion;
+ FromType = ToType.getUnqualifiedType();
} else if ((FromType->isFloatingType() &&
ToType->isIntegralType() && (!ToType->isBooleanType() &&
!ToType->isEnumeralType())) ||
@@ -688,11 +690,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// Floating-integral conversions (C++ 4.9).
SCS.Second = ICK_Floating_Integral;
FromType = ToType.getUnqualifiedType();
- } else if ((FromType->isComplexType() && ToType->isArithmeticType()) ||
- (ToType->isComplexType() && FromType->isArithmeticType())) {
- // Complex-real conversions (C99 6.3.1.7)
- SCS.Second = ICK_Complex_Real;
- FromType = ToType.getUnqualifiedType();
} else if (IsPointerConversion(From, FromType, ToType, InOverloadResolution,
FromType, IncompatibleObjC)) {
// Pointer conversions (C++ 4.10).
@@ -1094,6 +1091,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// here. That is handled by CheckPointerConversion.
if (getLangOptions().CPlusPlus &&
FromPointeeType->isRecordType() && ToPointeeType->isRecordType() &&
+ !Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType) &&
!RequireCompleteType(From->getLocStart(), FromPointeeType, PDiag()) &&
IsDerivedFrom(FromPointeeType, ToPointeeType)) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
@@ -1995,7 +1993,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
// the deprecated string literal array to pointer conversion.
switch (Result) {
case ImplicitConversionSequence::Better:
- if (SCS1.Deprecated)
+ if (SCS1.DeprecatedStringLiteralToCharPtr)
Result = ImplicitConversionSequence::Indistinguishable;
break;
@@ -2003,7 +2001,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
break;
case ImplicitConversionSequence::Worse:
- if (SCS2.Deprecated)
+ if (SCS2.DeprecatedStringLiteralToCharPtr)
Result = ImplicitConversionSequence::Indistinguishable;
break;
}
@@ -2096,32 +2094,6 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
}
}
- // Compare based on reference bindings.
- if (SCS1.ReferenceBinding && SCS2.ReferenceBinding &&
- SCS1.Second == ICK_Derived_To_Base) {
- // -- binding of an expression of type C to a reference of type
- // B& is better than binding an expression of type C to a
- // reference of type A&,
- if (Context.hasSameUnqualifiedType(FromType1, FromType2) &&
- !Context.hasSameUnqualifiedType(ToType1, ToType2)) {
- if (IsDerivedFrom(ToType1, ToType2))
- return ImplicitConversionSequence::Better;
- else if (IsDerivedFrom(ToType2, ToType1))
- return ImplicitConversionSequence::Worse;
- }
-
- // -- binding of an expression of type B to a reference of type
- // A& is better than binding an expression of type C to a
- // reference of type A&,
- if (!Context.hasSameUnqualifiedType(FromType1, FromType2) &&
- Context.hasSameUnqualifiedType(ToType1, ToType2)) {
- if (IsDerivedFrom(FromType2, FromType1))
- return ImplicitConversionSequence::Better;
- else if (IsDerivedFrom(FromType1, FromType2))
- return ImplicitConversionSequence::Worse;
- }
- }
-
// Ranking of member-pointer types.
if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member &&
FromType1->isMemberPointerType() && FromType2->isMemberPointerType() &&
@@ -2158,9 +2130,13 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
}
}
- if (SCS1.CopyConstructor && SCS2.CopyConstructor &&
+ if ((SCS1.ReferenceBinding || SCS1.CopyConstructor) &&
+ (SCS2.ReferenceBinding || SCS2.CopyConstructor) &&
SCS1.Second == ICK_Derived_To_Base) {
// -- conversion of C to B is better than conversion of C to A,
+ // -- binding of an expression of type C to a reference of type
+ // B& is better than binding an expression of type C to a
+ // reference of type A&,
if (Context.hasSameUnqualifiedType(FromType1, FromType2) &&
!Context.hasSameUnqualifiedType(ToType1, ToType2)) {
if (IsDerivedFrom(ToType1, ToType2))
@@ -2170,6 +2146,9 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
}
// -- conversion of B to A is better than conversion of C to A.
+ // -- binding of an expression of type B to a reference of type
+ // A& is better than binding an expression of type C to a
+ // reference of type A&,
if (!Context.hasSameUnqualifiedType(FromType1, FromType2) &&
Context.hasSameUnqualifiedType(ToType1, ToType2)) {
if (IsDerivedFrom(FromType2, FromType1))
@@ -2195,7 +2174,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType,
bool InOverloadResolution) {
if (ToType->isReferenceType()) {
ImplicitConversionSequence ICS;
- ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
CheckReferenceInit(From, ToType,
/*FIXME:*/From->getLocStart(),
SuppressUserConversions,
@@ -2267,8 +2246,6 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType,
// Set up the conversion sequence as a "bad" conversion, to allow us
// to exit early.
ImplicitConversionSequence ICS;
- ICS.Standard.setAsIdentityConversion();
- ICS.setBad();
// We need to have an object of class type.
QualType FromType = OrigFromType;
@@ -2292,25 +2269,29 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType,
if (ImplicitParamType.getCVRQualifiers()
!= FromTypeCanon.getLocalCVRQualifiers() &&
!ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) {
- ICS.Bad.init(BadConversionSequence::bad_qualifiers,
- OrigFromType, ImplicitParamType);
+ ICS.setBad(BadConversionSequence::bad_qualifiers,
+ OrigFromType, ImplicitParamType);
return ICS;
}
// Check that we have either the same type or a derived type. It
// affects the conversion rank.
QualType ClassTypeCanon = Context.getCanonicalType(ClassType);
- if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType())
- ICS.Standard.Second = ICK_Identity;
- else if (IsDerivedFrom(FromType, ClassType))
- ICS.Standard.Second = ICK_Derived_To_Base;
+ ImplicitConversionKind SecondKind;
+ if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) {
+ SecondKind = ICK_Identity;
+ } else if (IsDerivedFrom(FromType, ClassType))
+ SecondKind = ICK_Derived_To_Base;
else {
- ICS.Bad.init(BadConversionSequence::unrelated_class, FromType, ImplicitParamType);
+ ICS.setBad(BadConversionSequence::unrelated_class,
+ FromType, ImplicitParamType);
return ICS;
}
// Success. Mark this as a reference binding.
ICS.setStandard();
+ ICS.Standard.setAsIdentityConversion();
+ ICS.Standard.Second = SecondKind;
ICS.Standard.setFromType(FromType);
ICS.Standard.setAllToTypes(ImplicitParamType);
ICS.Standard.ReferenceBinding = true;
@@ -2439,7 +2420,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
QualType ClassType = Context.getTypeDeclType(Constructor->getParent());
if (NumArgs == 1 &&
Constructor->isCopyConstructorLikeSpecialization() &&
- Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()))
+ (Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) ||
+ IsDerivedFrom(Args[0]->getType(), ClassType)))
return;
}
@@ -4462,7 +4444,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
QualType ToTy = Conv.Bad.getToType();
if (FromTy == S.Context.OverloadTy) {
- assert(FromExpr);
+ assert(FromExpr && "overload set argument came from implicit argument?");
Expr *E = FromExpr->IgnoreParens();
if (isa<UnaryOperator>(E))
E = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
@@ -4665,8 +4647,9 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_bad_final_conversion:
return S.NoteOverloadCandidate(Fn);
- case ovl_fail_bad_conversion:
- for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I)
+ case ovl_fail_bad_conversion: {
+ unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
+ for (unsigned N = Cand->Conversions.size(); I != N; ++I)
if (Cand->Conversions[I].isBad())
return DiagnoseBadConversion(S, Cand, I);
@@ -4675,6 +4658,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
// those conditions and diagnose them well.
return S.NoteOverloadCandidate(Fn);
}
+ }
}
void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
@@ -4794,7 +4778,8 @@ struct CompareOverloadCandidatesForDisplay {
assert(L->Conversions.size() == R->Conversions.size());
int leftBetter = 0;
- for (unsigned I = 0, E = L->Conversions.size(); I != E; ++I) {
+ unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument);
+ for (unsigned E = L->Conversions.size(); I != E; ++I) {
switch (S.CompareImplicitConversionSequences(L->Conversions[I],
R->Conversions[I])) {
case ImplicitConversionSequence::Better:
@@ -4840,7 +4825,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
if (Cand->FailureKind != ovl_fail_bad_conversion) return;
// Skip forward to the first bad conversion.
- unsigned ConvIdx = 0;
+ unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
unsigned ConvCount = Cand->Conversions.size();
while (true) {
assert(ConvIdx != ConvCount && "no bad conversion in candidate");
@@ -4852,6 +4837,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
if (ConvIdx == ConvCount)
return;
+ assert(!Cand->Conversions[ConvIdx].isInitialized() &&
+ "remaining conversion is initialized?");
+
// FIXME: these should probably be preserved from the overload
// operation somehow.
bool SuppressUserConversions = false;
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index e6dfa74..58e416c 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -54,12 +54,12 @@ namespace clang {
ICK_Floating_Conversion, ///< Floating point conversions (C++ 4.8)
ICK_Complex_Conversion, ///< Complex conversions (C99 6.3.1.6)
ICK_Floating_Integral, ///< Floating-integral conversions (C++ 4.9)
- ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7)
ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10)
ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11)
ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12)
ICK_Compatible_Conversion, ///< Conversions between compatible types in C99
ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics])
+ ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7)
ICK_Num_Conversion_Kinds ///< The number of conversion kinds
};
@@ -83,9 +83,10 @@ namespace clang {
/// 13.3.3.1.1) and are listed such that better conversion ranks
/// have smaller values.
enum ImplicitConversionRank {
- ICR_Exact_Match = 0, ///< Exact Match
- ICR_Promotion, ///< Promotion
- ICR_Conversion ///< Conversion
+ ICR_Exact_Match = 0, ///< Exact Match
+ ICR_Promotion, ///< Promotion
+ ICR_Conversion, ///< Conversion
+ ICR_Complex_Real_Conversion ///< Complex <-> Real conversion
};
ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
@@ -116,7 +117,7 @@ namespace clang {
/// Deprecated - Whether this the deprecated conversion of a
/// string literal to a pointer to non-const character data
/// (C++ 4.2p2).
- bool Deprecated : 1;
+ bool DeprecatedStringLiteralToCharPtr : 1;
/// IncompatibleObjC - Whether this is an Objective-C conversion
/// that we should warn about (if we actually use it).
@@ -316,14 +317,22 @@ namespace clang {
};
private:
+ enum {
+ Uninitialized = BadConversion + 1
+ };
+
/// ConversionKind - The kind of implicit conversion sequence.
- Kind ConversionKind;
+ unsigned ConversionKind;
void setKind(Kind K) {
- if (isAmbiguous()) Ambiguous.destruct();
+ destruct();
ConversionKind = K;
}
+ void destruct() {
+ if (ConversionKind == AmbiguousConversion) Ambiguous.destruct();
+ }
+
public:
union {
/// When ConversionKind == StandardConversion, provides the
@@ -343,14 +352,15 @@ namespace clang {
BadConversionSequence Bad;
};
- ImplicitConversionSequence() : ConversionKind(BadConversion) {}
+ ImplicitConversionSequence() : ConversionKind(Uninitialized) {}
~ImplicitConversionSequence() {
- if (isAmbiguous()) Ambiguous.destruct();
+ destruct();
}
ImplicitConversionSequence(const ImplicitConversionSequence &Other)
: ConversionKind(Other.ConversionKind)
{
switch (ConversionKind) {
+ case Uninitialized: break;
case StandardConversion: Standard = Other.Standard; break;
case UserDefinedConversion: UserDefined = Other.UserDefined; break;
case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break;
@@ -361,26 +371,45 @@ namespace clang {
ImplicitConversionSequence &
operator=(const ImplicitConversionSequence &Other) {
- if (isAmbiguous()) Ambiguous.destruct();
+ destruct();
new (this) ImplicitConversionSequence(Other);
return *this;
}
- Kind getKind() const { return ConversionKind; }
- bool isBad() const { return ConversionKind == BadConversion; }
- bool isStandard() const { return ConversionKind == StandardConversion; }
- bool isEllipsis() const { return ConversionKind == EllipsisConversion; }
- bool isAmbiguous() const { return ConversionKind == AmbiguousConversion; }
- bool isUserDefined() const {
- return ConversionKind == UserDefinedConversion;
+ Kind getKind() const {
+ assert(isInitialized() && "querying uninitialized conversion");
+ return Kind(ConversionKind);
+ }
+ bool isBad() const { return getKind() == BadConversion; }
+ bool isStandard() const { return getKind() == StandardConversion; }
+ bool isEllipsis() const { return getKind() == EllipsisConversion; }
+ bool isAmbiguous() const { return getKind() == AmbiguousConversion; }
+ bool isUserDefined() const { return getKind() == UserDefinedConversion; }
+
+ /// Determines whether this conversion sequence has been
+ /// initialized. Most operations should never need to query
+ /// uninitialized conversions and should assert as above.
+ bool isInitialized() const { return ConversionKind != Uninitialized; }
+
+ /// Sets this sequence as a bad conversion for an explicit argument.
+ void setBad(BadConversionSequence::FailureKind Failure,
+ Expr *FromExpr, QualType ToType) {
+ setKind(BadConversion);
+ Bad.init(Failure, FromExpr, ToType);
+ }
+
+ /// Sets this sequence as a bad conversion for an implicit argument.
+ void setBad(BadConversionSequence::FailureKind Failure,
+ QualType FromType, QualType ToType) {
+ setKind(BadConversion);
+ Bad.init(Failure, FromType, ToType);
}
- void setBad() { setKind(BadConversion); }
void setStandard() { setKind(StandardConversion); }
void setEllipsis() { setKind(EllipsisConversion); }
void setUserDefined() { setKind(UserDefinedConversion); }
void setAmbiguous() {
- if (isAmbiguous()) return;
+ if (ConversionKind == AmbiguousConversion) return;
ConversionKind = AmbiguousConversion;
Ambiguous.construct();
}
@@ -490,6 +519,7 @@ namespace clang {
bool hasAmbiguousConversion() const {
for (llvm::SmallVectorImpl<ImplicitConversionSequence>::const_iterator
I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
+ if (!I->isInitialized()) return false;
if (I->isAmbiguous()) return true;
}
return false;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index fa42634..75d9f67 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -314,15 +314,13 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
// Perform a conversion to the promoted condition type if needed.
if (NewWidth > Val.getBitWidth()) {
// If this is an extension, just do it.
- llvm::APSInt OldVal(Val);
Val.extend(NewWidth);
-
- // If the input was signed and negative and the output is unsigned,
- // warn.
- if (!NewSign && OldVal.isSigned() && OldVal.isNegative())
- Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10);
-
Val.setIsSigned(NewSign);
+
+ // If the input was signed and negative and the output is
+ // unsigned, don't bother to warn: this is implementation-defined
+ // behavior.
+ // FIXME: Introduce a second, default-ignored warning for this case?
} else if (NewWidth < Val.getBitWidth()) {
// If this is a truncation, check for overflow.
llvm::APSInt ConvVal(Val);
@@ -340,11 +338,11 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
} else if (NewSign != Val.isSigned()) {
// Convert the sign to match the sign of the condition. This can cause
// overflow as well: unsigned(INTMIN)
+ // We don't diagnose this overflow, because it is implementation-defined
+ // behavior.
+ // FIXME: Introduce a second, default-ignored warning for this case?
llvm::APSInt OldVal(Val);
Val.setIsSigned(NewSign);
-
- if (Val.isNegative()) // Sign bit changes meaning.
- Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10);
}
}
@@ -752,7 +750,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
// Check to see if switch is over an Enum and handles all of its
// values
- const EnumType* ET = dyn_cast<EnumType>(CondTypeBeforePromotion);
+ const EnumType* ET = CondTypeBeforePromotion->getAs<EnumType>();
// If switch has default case, then ignore it.
if (!CaseListIsErroneous && !TheDefaultStmt && ET) {
const EnumDecl *ED = ET->getDecl();
@@ -1038,6 +1036,7 @@ Action::OwningStmtResult
Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// If this is the first return we've seen in the block, infer the type of
// the block from it.
+ BlockScopeInfo *CurBlock = getCurBlock();
if (CurBlock->ReturnType.isNull()) {
if (RetValExp) {
// Don't call UsualUnaryConversions(), since we don't want to do
@@ -1132,7 +1131,7 @@ static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
Action::OwningStmtResult
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
Expr *RetValExp = rex.takeAs<Expr>();
- if (CurBlock)
+ if (getCurBlock())
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
QualType FnRetType;
@@ -1502,7 +1501,7 @@ Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) {
Action::OwningStmtResult
Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
StmtArg Try, StmtArg Catch, StmtArg Finally) {
- CurFunctionNeedsScopeChecking = true;
+ FunctionNeedsScopeChecking() = true;
return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(),
Catch.takeAs<Stmt>(),
Finally.takeAs<Stmt>()));
@@ -1535,7 +1534,7 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
Action::OwningStmtResult
Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr,
StmtArg SynchBody) {
- CurFunctionNeedsScopeChecking = true;
+ FunctionNeedsScopeChecking() = true;
// Make sure the expression type is an ObjC pointer or "void *".
Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get());
@@ -1645,7 +1644,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock,
// Neither of these are explicitly forbidden, but every compiler detects them
// and warns.
- CurFunctionNeedsScopeChecking = true;
+ FunctionNeedsScopeChecking() = true;
RawHandlers.release();
return Owned(CXXTryStmt::Create(Context, TryLoc,
static_cast<Stmt*>(TryBlock.release()),
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 10e411f..0321958 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3242,6 +3242,23 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
return false;
}
+/// \brief Retrieve the previous declaration of the given declaration.
+static NamedDecl *getPreviousDecl(NamedDecl *ND) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(ND))
+ return VD->getPreviousDeclaration();
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+ return FD->getPreviousDeclaration();
+ if (TagDecl *TD = dyn_cast<TagDecl>(ND))
+ return TD->getPreviousDeclaration();
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(ND))
+ return TD->getPreviousDeclaration();
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+ return FTD->getPreviousDeclaration();
+ if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(ND))
+ return CTD->getPreviousDeclaration();
+ return 0;
+}
+
Sema::DeclResult
Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TagUseKind TUK,
@@ -3547,15 +3564,26 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// instantiation to take place, in every translation unit in which such a
// use occurs; no diagnostic is required.
if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) {
- SourceRange Range(TemplateNameLoc, RAngleLoc);
- Diag(TemplateNameLoc, diag::err_specialization_after_instantiation)
- << Context.getTypeDeclType(Specialization) << Range;
+ bool Okay = false;
+ for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) {
+ // Is there any previous explicit specialization declaration?
+ if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) {
+ Okay = true;
+ break;
+ }
+ }
- Diag(PrevDecl->getPointOfInstantiation(),
- diag::note_instantiation_required_here)
- << (PrevDecl->getTemplateSpecializationKind()
+ if (!Okay) {
+ SourceRange Range(TemplateNameLoc, RAngleLoc);
+ Diag(TemplateNameLoc, diag::err_specialization_after_instantiation)
+ << Context.getTypeDeclType(Specialization) << Range;
+
+ Diag(PrevDecl->getPointOfInstantiation(),
+ diag::note_instantiation_required_here)
+ << (PrevDecl->getTemplateSpecializationKind()
!= TSK_ImplicitInstantiation);
- return true;
+ return true;
+ }
}
// If this is not a friend, note that this is an explicit specialization.
@@ -3728,6 +3756,12 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// before the first use of that specialization that would cause an
// implicit instantiation to take place, in every translation unit in
// which such a use occurs; no diagnostic is required.
+ for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) {
+ // Is there any previous explicit specialization declaration?
+ if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization)
+ return false;
+ }
+
Diag(NewLoc, diag::err_specialization_after_instantiation)
<< PrevDecl;
Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here)
@@ -3756,6 +3790,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// of a template appears after a declaration of an explicit
// specialization for that template, the explicit instantiation has no
// effect.
+ SuppressNew = true;
return false;
case TSK_ExplicitInstantiationDefinition:
@@ -4911,18 +4946,21 @@ namespace {
/// \brief Transforms a typename type by determining whether the type now
/// refers to a member of the current instantiation, and then
/// type-checking and building a QualifiedNameType (when possible).
- QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL);
+ QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL,
+ QualType ObjectType);
};
}
QualType
CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB,
- TypenameTypeLoc TL) {
+ TypenameTypeLoc TL,
+ QualType ObjectType) {
TypenameType *T = TL.getTypePtr();
NestedNameSpecifier *NNS
= TransformNestedNameSpecifier(T->getQualifier(),
- /*FIXME:*/SourceRange(getBaseLocation()));
+ /*FIXME:*/SourceRange(getBaseLocation()),
+ ObjectType);
if (!NNS)
return QualType();
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index df4d4a8..7f16400 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2419,6 +2419,27 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
OnlyDeduced, Depth, Used);
break;
+ case Type::TypeOf:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<TypeOfType>(T)->getUnderlyingType(),
+ OnlyDeduced, Depth, Used);
+ break;
+
+ case Type::TypeOfExpr:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<TypeOfExprType>(T)->getUnderlyingExpr(),
+ OnlyDeduced, Depth, Used);
+ break;
+
+ case Type::Decltype:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<DecltypeType>(T)->getUnderlyingExpr(),
+ OnlyDeduced, Depth, Used);
+ break;
+
// None of these types have any template parameters in them.
case Type::Builtin:
case Type::VariableArray:
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 51e17fe..8f73337 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -540,11 +540,11 @@ namespace {
/// \brief Transform the given declaration by instantiating a reference to
/// this declaration.
- Decl *TransformDecl(Decl *D);
+ Decl *TransformDecl(SourceLocation Loc, Decl *D);
/// \brief Transform the definition of the given declaration by
/// instantiating it.
- Decl *TransformDefinition(Decl *D);
+ Decl *TransformDefinition(SourceLocation Loc, Decl *D);
/// \bried Transform the first qualifier within a scope by instantiating the
/// declaration.
@@ -570,11 +570,12 @@ namespace {
/// \brief Transforms a template type parameter type by performing
/// substitution of the corresponding template type argument.
QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL);
+ TemplateTypeParmTypeLoc TL,
+ QualType ObjectType);
};
}
-Decl *TemplateInstantiator::TransformDecl(Decl *D) {
+Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
if (!D)
return 0;
@@ -599,10 +600,10 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) {
// template parameter.
}
- return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D), TemplateArgs);
+ return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D), TemplateArgs);
}
-Decl *TemplateInstantiator::TransformDefinition(Decl *D) {
+Decl *TemplateInstantiator::TransformDefinition(SourceLocation Loc, Decl *D) {
Decl *Inst = getSema().SubstDecl(D, getSema().CurContext, TemplateArgs);
if (!Inst)
return 0;
@@ -622,7 +623,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
QualType T = TemplateArgs(TTP->getDepth(), TTP->getIndex()).getAsType();
if (T.isNull())
- return cast_or_null<NamedDecl>(TransformDecl(D));
+ return cast_or_null<NamedDecl>(TransformDecl(Loc, D));
if (const TagType *Tag = T->getAs<TagType>())
return Tag->getDecl();
@@ -633,7 +634,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
}
}
- return cast_or_null<NamedDecl>(TransformDecl(D));
+ return cast_or_null<NamedDecl>(TransformDecl(Loc, D));
}
VarDecl *
@@ -723,7 +724,8 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
// Find the instantiation of the template argument. This is
// required for nested templates.
VD = cast_or_null<ValueDecl>(
- getSema().FindInstantiatedDecl(VD, TemplateArgs));
+ getSema().FindInstantiatedDecl(E->getLocation(),
+ VD, TemplateArgs));
if (!VD)
return SemaRef.ExprError();
@@ -859,7 +861,8 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
QualType
TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL) {
+ TemplateTypeParmTypeLoc TL,
+ QualType ObjectType) {
TemplateTypeParmType *T = TL.getTypePtr();
if (T->getDepth() < TemplateArgs.getNumLevels()) {
// Replace the template type parameter with its corresponding
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 0b0efcb..3a6b4cb 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -162,7 +162,8 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
Typedef->setInvalidDecl();
if (TypedefDecl *Prev = D->getPreviousDeclaration()) {
- NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(Prev, TemplateArgs);
+ NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev,
+ TemplateArgs);
Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev));
}
@@ -201,6 +202,72 @@ static bool InstantiateInitializationArguments(Sema &SemaRef,
return false;
}
+/// \brief Instantiate an initializer, breaking it into separate
+/// initialization arguments.
+///
+/// \param S The semantic analysis object.
+///
+/// \param Init The initializer to instantiate.
+///
+/// \param TemplateArgs Template arguments to be substituted into the
+/// initializer.
+///
+/// \param NewArgs Will be filled in with the instantiation arguments.
+///
+/// \returns true if an error occurred, false otherwise
+static bool InstantiateInitializer(Sema &S, Expr *Init,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation &LParenLoc,
+ llvm::SmallVector<SourceLocation, 4> &CommaLocs,
+ ASTOwningVector<&ActionBase::DeleteExpr> &NewArgs,
+ SourceLocation &RParenLoc) {
+ NewArgs.clear();
+ LParenLoc = SourceLocation();
+ RParenLoc = SourceLocation();
+
+ if (!Init)
+ return false;
+
+ if (CXXExprWithTemporaries *ExprTemp = dyn_cast<CXXExprWithTemporaries>(Init))
+ Init = ExprTemp->getSubExpr();
+
+ while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
+ Init = Binder->getSubExpr();
+
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
+ Init = ICE->getSubExprAsWritten();
+
+ if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
+ LParenLoc = ParenList->getLParenLoc();
+ RParenLoc = ParenList->getRParenLoc();
+ return InstantiateInitializationArguments(S, ParenList->getExprs(),
+ ParenList->getNumExprs(),
+ TemplateArgs, CommaLocs,
+ NewArgs);
+ }
+
+ if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) {
+ if (InstantiateInitializationArguments(S,
+ Construct->getArgs(),
+ Construct->getNumArgs(),
+ TemplateArgs,
+ CommaLocs, NewArgs))
+ return true;
+
+ // FIXME: Fake locations!
+ LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart());
+ RParenLoc = CommaLocs.empty()? LParenLoc : CommaLocs.back();
+ return false;
+ }
+
+ Sema::OwningExprResult Result = S.SubstExpr(Init, TemplateArgs);
+ if (Result.isInvalid())
+ return true;
+
+ NewArgs.push_back(Result.takeAs<Expr>());
+ return false;
+}
+
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// Do substitution on the type of the declaration
TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
@@ -232,7 +299,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
bool Redeclaration = false;
// FIXME: having to fake up a LookupResult is dumb.
LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(),
- Sema::LookupOrdinaryName);
+ Sema::LookupOrdinaryName, Sema::ForRedeclaration);
if (D->isStaticDataMember())
SemaRef.LookupQualifiedName(Previous, Owner, false);
SemaRef.CheckVariableDeclaration(Var, Previous, Redeclaration);
@@ -258,77 +325,33 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
else
SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
- // Extract the initializer, skipping through any temporary-binding
- // expressions and look at the subexpression as it was written.
- Expr *DInit = D->getInit();
- if (CXXExprWithTemporaries *ExprTemp
- = dyn_cast<CXXExprWithTemporaries>(DInit))
- DInit = ExprTemp->getSubExpr();
- while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(DInit))
- DInit = Binder->getSubExpr();
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(DInit))
- DInit = ICE->getSubExprAsWritten();
-
- if (ParenListExpr *PLE = dyn_cast<ParenListExpr>(DInit)) {
- // The initializer is a parenthesized list of expressions that is
- // type-dependent. Instantiate each of the expressions; we'll be
- // performing direct initialization with them.
- llvm::SmallVector<SourceLocation, 4> CommaLocs;
- ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef);
- if (!InstantiateInitializationArguments(SemaRef,
- PLE->getExprs(),
- PLE->getNumExprs(),
- TemplateArgs,
- CommaLocs, InitArgs)) {
+ // Instantiate the initializer.
+ SourceLocation LParenLoc, RParenLoc;
+ llvm::SmallVector<SourceLocation, 4> CommaLocs;
+ ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef);
+ if (!InstantiateInitializer(SemaRef, D->getInit(), TemplateArgs, LParenLoc,
+ CommaLocs, InitArgs, RParenLoc)) {
+ // Attach the initializer to the declaration.
+ if (D->hasCXXDirectInitializer()) {
// Add the direct initializer to the declaration.
SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
- PLE->getLParenLoc(),
+ LParenLoc,
move_arg(InitArgs),
CommaLocs.data(),
- PLE->getRParenLoc());
+ RParenLoc);
+ } else if (InitArgs.size() == 1) {
+ Expr *Init = (Expr*)(InitArgs.take()[0]);
+ SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var),
+ SemaRef.Owned(Init),
+ false);
+ } else {
+ assert(InitArgs.size() == 0);
+ SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
}
- } else if (CXXConstructExpr *Construct =dyn_cast<CXXConstructExpr>(DInit)) {
- // The initializer resolved to a constructor. Instantiate the constructor
- // arguments.
- llvm::SmallVector<SourceLocation, 4> CommaLocs;
- ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef);
-
- if (!InstantiateInitializationArguments(SemaRef,
- Construct->getArgs(),
- Construct->getNumArgs(),
- TemplateArgs,
- CommaLocs, InitArgs)) {
- if (D->hasCXXDirectInitializer()) {
- SourceLocation FakeLParenLoc =
- SemaRef.PP.getLocForEndOfToken(D->getLocation());
- SourceLocation FakeRParenLoc = CommaLocs.empty()? FakeLParenLoc
- : CommaLocs.back();
- SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
- FakeLParenLoc,
- move_arg(InitArgs),
- CommaLocs.data(),
- FakeRParenLoc);
- } else if (InitArgs.size() == 1) {
- Expr *Init = (Expr*)(InitArgs.take()[0]);
- SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var),
- SemaRef.Owned(Init),
- false);
- } else {
- assert(InitArgs.size() == 0);
- SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
- }
- }
} else {
- OwningExprResult Init
- = SemaRef.SubstExpr(D->getInit(), TemplateArgs);
-
- // FIXME: Not happy about invalidating decls just because of a bad
- // initializer, unless it affects the type.
- if (Init.isInvalid())
- Var->setInvalidDecl();
- else
- SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
- D->hasCXXDirectInitializer());
+ // FIXME: Not too happy about invalidating the declaration
+ // because of a bogus initializer.
+ Var->setInvalidDecl();
}
SemaRef.PopExpressionEvaluationContext();
@@ -433,7 +456,8 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
// Hack to make this work almost well pending a rewrite.
if (ND->getDeclContext()->isRecord()) {
if (!ND->getDeclContext()->isDependentContext()) {
- NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs);
+ NewND = SemaRef.FindInstantiatedDecl(D->getLocation(), ND,
+ TemplateArgs);
} else {
// FIXME: Hack to avoid crashing when incorrectly trying to instantiate
// templated friend declarations. This doesn't produce a correct AST;
@@ -489,6 +513,9 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
Owner->addDecl(Enum);
Enum->startDefinition();
+ if (D->getDeclContext()->isFunctionOrMethod())
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
+
llvm::SmallVector<Sema::DeclPtrTy, 4> Enumerators;
EnumConstantDecl *LastEnumConst = 0;
@@ -528,6 +555,12 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
Enum->addDecl(EnumConst);
Enumerators.push_back(Sema::DeclPtrTy::make(EnumConst));
LastEnumConst = EnumConst;
+
+ if (D->getDeclContext()->isFunctionOrMethod()) {
+ // If the enumeration is within a function or method, record the enum
+ // constant as a local.
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(*EC, EnumConst);
+ }
}
}
@@ -699,7 +732,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (D->isInjectedClassName())
PrevDecl = cast<CXXRecordDecl>(Owner);
else if (D->getPreviousDeclaration()) {
- NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getPreviousDeclaration(),
+ NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
+ D->getPreviousDeclaration(),
TemplateArgs);
if (!Prev) return 0;
PrevDecl = cast<CXXRecordDecl>(Prev);
@@ -772,7 +806,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (D->getDeclContext()->isFunctionOrMethod())
DC = Owner;
else
- DC = SemaRef.FindInstantiatedContext(D->getDeclContext(), TemplateArgs);
+ DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(),
+ TemplateArgs);
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
@@ -1228,7 +1263,8 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
I != E; ++I) {
UsingShadowDecl *Shadow = *I;
NamedDecl *InstTarget =
- cast<NamedDecl>(SemaRef.FindInstantiatedDecl(Shadow->getTargetDecl(),
+ cast<NamedDecl>(SemaRef.FindInstantiatedDecl(Shadow->getLocation(),
+ Shadow->getTargetDecl(),
TemplateArgs));
if (CheckRedeclaration &&
@@ -1304,6 +1340,9 @@ Decl * TemplateDeclInstantiator
Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
+ if (D->isInvalidDecl())
+ return 0;
+
return Instantiator.Visit(D);
}
@@ -1871,29 +1910,15 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
Inits != InitsEnd; ++Inits) {
CXXBaseOrMemberInitializer *Init = *Inits;
+ SourceLocation LParenLoc, RParenLoc;
ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this);
llvm::SmallVector<SourceLocation, 4> CommaLocs;
- // Instantiate all the arguments.
- Expr *InitE = Init->getInit();
- if (!InitE) {
- // Nothing to instantiate;
- } else if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(InitE)) {
- if (InstantiateInitializationArguments(*this, ParenList->getExprs(),
- ParenList->getNumExprs(),
- TemplateArgs, CommaLocs,
- NewArgs)) {
- AnyErrors = true;
- continue;
- }
- } else {
- OwningExprResult InitArg = SubstExpr(InitE, TemplateArgs);
- if (InitArg.isInvalid()) {
- AnyErrors = true;
- continue;
- }
-
- NewArgs.push_back(InitArg.release());
+ // Instantiate the initializer.
+ if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs,
+ LParenLoc, CommaLocs, NewArgs, RParenLoc)) {
+ AnyErrors = true;
+ continue;
}
MemInitResult NewInit;
@@ -1919,9 +1944,11 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
// Is this an anonymous union?
if (FieldDecl *UnionInit = Init->getAnonUnionMember())
- Member = cast<FieldDecl>(FindInstantiatedDecl(UnionInit, TemplateArgs));
+ Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMemberLocation(),
+ UnionInit, TemplateArgs));
else
- Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMember(),
+ Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMemberLocation(),
+ Init->getMember(),
TemplateArgs));
NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(),
@@ -2151,10 +2178,10 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
/// within the current instantiation.
///
/// \returns NULL if there was an error
-DeclContext *Sema::FindInstantiatedContext(DeclContext* DC,
+DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
const MultiLevelTemplateArgumentList &TemplateArgs) {
if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) {
- Decl* ID = FindInstantiatedDecl(D, TemplateArgs);
+ Decl* ID = FindInstantiatedDecl(Loc, D, TemplateArgs);
return cast_or_null<DeclContext>(ID);
} else return DC;
}
@@ -2185,7 +2212,7 @@ DeclContext *Sema::FindInstantiatedContext(DeclContext* DC,
/// X<T>::<Kind>::KnownValue) to its instantiation
/// (X<int>::<Kind>::KnownValue). InstantiateCurrentDeclRef() performs
/// this mapping from within the instantiation of X<int>.
-NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
+NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs) {
DeclContext *ParentDC = D->getDeclContext();
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
@@ -2272,7 +2299,7 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
if (!ParentDC->isDependentContext())
return D;
- ParentDC = FindInstantiatedContext(ParentDC, TemplateArgs);
+ ParentDC = FindInstantiatedContext(Loc, ParentDC, TemplateArgs);
if (!ParentDC)
return 0;
@@ -2280,6 +2307,20 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
// We performed some kind of instantiation in the parent context,
// so now we need to look into the instantiated parent context to
// find the instantiation of the declaration D.
+
+ // If our context is a class template specialization, we may need
+ // to instantiate it before performing lookup into that context.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(ParentDC)) {
+ if (!Spec->isDependentContext()) {
+ QualType T = Context.getTypeDeclType(Spec);
+ if (const TagType *Tag = T->getAs<TagType>())
+ if (!Tag->isBeingDefined() &&
+ RequireCompleteType(Loc, T, diag::err_incomplete_type))
+ return 0;
+ }
+ }
+
NamedDecl *Result = 0;
if (D->getDeclName()) {
DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName());
@@ -2299,7 +2340,8 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
}
// UsingShadowDecls can instantiate to nothing because of using hiding.
- assert((Result || isa<UsingShadowDecl>(D))
+ assert((Result || isa<UsingShadowDecl>(D) || D->isInvalidDecl() ||
+ cast<Decl>(ParentDC)->isInvalidDecl())
&& "Unable to find instantiation of declaration!");
D = Result;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 7911e76..2fb5c84 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -72,6 +72,7 @@ typedef std::pair<const AttributeList*,QualType> DelayedAttribute;
typedef llvm::SmallVectorImpl<DelayedAttribute> DelayedAttributeSet;
static void ProcessTypeAttributeList(Sema &S, QualType &Type,
+ bool IsDeclSpec,
const AttributeList *Attrs,
DelayedAttributeSet &DelayedFnAttrs);
static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr);
@@ -385,7 +386,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
// See if there are any attributes on the declspec that apply to the type (as
// opposed to the decl).
if (const AttributeList *AL = DS.getAttributes())
- ProcessTypeAttributeList(TheSema, Result, AL, Delayed);
+ ProcessTypeAttributeList(TheSema, Result, true, AL, Delayed);
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
@@ -797,7 +798,7 @@ QualType Sema::BuildFunctionType(QualType T,
return QualType();
return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic,
- Quals);
+ Quals, false, false, 0, 0, false, CC_Default);
}
/// \brief Build a member pointer type \c T Class::*.
@@ -1132,7 +1133,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, FTI.TypeQuals,
FTI.hasExceptionSpec,
FTI.hasAnyExceptionSpec,
- Exceptions.size(), Exceptions.data());
+ Exceptions.size(), Exceptions.data(),
+ false, CC_Default);
} else if (FTI.isVariadic) {
// We allow a zero-parameter variadic function in C if the
// function is marked with the "overloadable"
@@ -1148,7 +1150,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (!Overloadable)
Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg);
- T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0);
+ T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0,
+ false, false, 0, 0, false, CC_Default);
} else {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T);
@@ -1223,7 +1226,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FTI.isVariadic, FTI.TypeQuals,
FTI.hasExceptionSpec,
FTI.hasAnyExceptionSpec,
- Exceptions.size(), Exceptions.data());
+ Exceptions.size(), Exceptions.data(),
+ false, CC_Default);
}
// For GCC compatibility, we allow attributes that apply only to
@@ -1294,7 +1298,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// See if there are any attributes on this declarator chunk.
if (const AttributeList *AL = DeclType.getAttrs())
- ProcessTypeAttributeList(*this, T, AL, FnAttrsFromPreviousChunk);
+ ProcessTypeAttributeList(*this, T, false, AL, FnAttrsFromPreviousChunk);
}
if (getLangOptions().CPlusPlus && T->isFunctionType()) {
@@ -1320,7 +1324,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Strip the cv-quals from the type.
T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(),
- FnTy->getNumArgs(), FnTy->isVariadic(), 0);
+ FnTy->getNumArgs(), FnTy->isVariadic(), 0,
+ false, false, 0, 0, false, CC_Default);
}
}
@@ -1333,7 +1338,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// block-literal expressions, which are parsed wierdly.
if (D.getContext() != Declarator::BlockLiteralContext)
if (const AttributeList *Attrs = D.getAttributes())
- ProcessTypeAttributeList(*this, T, Attrs, FnAttrsFromPreviousChunk);
+ ProcessTypeAttributeList(*this, T, false, Attrs,
+ FnAttrsFromPreviousChunk);
DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk);
@@ -1751,7 +1757,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
}
CallingConv CCOld = Fn->getCallConv();
- if (CC == CCOld) return false;
+ if (S.Context.getCanonicalCallConv(CC) ==
+ S.Context.getCanonicalCallConv(CCOld)) return false;
if (CCOld != CC_Default) {
// Should we diagnose reapplications of the same convention?
@@ -1829,7 +1836,7 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
}
void ProcessTypeAttributeList(Sema &S, QualType &Result,
- const AttributeList *AL,
+ bool IsDeclSpec, const AttributeList *AL,
DelayedAttributeSet &FnAttrs) {
// Scan through and apply attributes to this type where it makes sense. Some
// attributes (such as __address_space__, __vector_size__, etc) apply to the
@@ -1855,7 +1862,9 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result,
case AttributeList::AT_cdecl:
case AttributeList::AT_fastcall:
case AttributeList::AT_stdcall:
- if (ProcessFnAttr(S, Result, *AL))
+ // Don't process these on the DeclSpec.
+ if (IsDeclSpec ||
+ ProcessFnAttr(S, Result, *AL))
FnAttrs.push_back(DelayedAttribute(AL, Result));
break;
}
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
index d45d010..87e7b9d 100644
--- a/lib/Sema/TargetAttributesSema.cpp
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -79,14 +79,17 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D,
return;
}
- // If we try to apply it to a function pointer, warn. This is a special
- // instance of the warn_attribute_ignored warning that can be turned
- // off with -Wno-force-align-arg-pointer.
- ValueDecl* VD = dyn_cast<ValueDecl>(D);
- if (VD && VD->getType()->isFunctionPointerType()) {
- S.Diag(Attr.getLoc(), diag::warn_faap_attribute_ignored);
+ // If we try to apply it to a function pointer, don't warn, but don't
+ // do anything, either. It doesn't matter anyway, because there's nothing
+ // special about calling a force_align_arg_pointer function.
+ ValueDecl *VD = dyn_cast<ValueDecl>(D);
+ if (VD && VD->getType()->isFunctionPointerType())
+ return;
+ // Also don't warn on function pointer typedefs.
+ TypedefDecl *TD = dyn_cast<TypedefDecl>(D);
+ if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
+ TD->getUnderlyingType()->isFunctionType()))
return;
- }
// Attribute can only be applied to function types.
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -97,13 +100,106 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D,
D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr());
}
+static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // Attribute can be applied only to functions or variables.
+ if (isa<VarDecl>(D)) {
+ D->addAttr(::new (S.Context) DLLImportAttr());
+ return;
+ }
+
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) {
+ // Apparently Visual C++ thinks it is okay to not emit a warning
+ // in this case, so only emit a warning when -fms-extensions is not
+ // specified.
+ if (!S.getLangOptions().Microsoft)
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
+ }
+
+ // Currently, the dllimport attribute is ignored for inlined functions.
+ // Warning is emitted.
+ if (FD->isInlineSpecified()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
+ return;
+ }
+
+ // The attribute is also overridden by a subsequent declaration as dllexport.
+ // Warning is emitted.
+ for (AttributeList *nextAttr = Attr.getNext(); nextAttr;
+ nextAttr = nextAttr->getNext()) {
+ if (nextAttr->getKind() == AttributeList::AT_dllexport) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
+ return;
+ }
+ }
+
+ if (D->getAttr<DLLExportAttr>()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) DLLImportAttr());
+}
+
+static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // Attribute can be applied only to functions or variables.
+ if (isa<VarDecl>(D)) {
+ D->addAttr(::new (S.Context) DLLExportAttr());
+ return;
+ }
+
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
+ }
+
+ // Currently, the dllexport attribute is ignored for inlined functions, unless
+ // the -fkeep-inline-functions flag has been used. Warning is emitted;
+ if (FD->isInlineSpecified()) {
+ // FIXME: ... unless the -fkeep-inline-functions flag has been used.
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) DLLExportAttr());
+}
+
namespace {
class X86AttributesSema : public TargetAttributesSema {
public:
X86AttributesSema() { }
bool ProcessDeclAttribute(Scope *scope, Decl *D,
const AttributeList &Attr, Sema &S) const {
- if (Attr.getName()->getName() == "force_align_arg_pointer") {
+ const llvm::Triple &Triple(S.Context.Target.getTriple());
+ if (Triple.getOS() == llvm::Triple::Win32 ||
+ Triple.getOS() == llvm::Triple::MinGW32 ||
+ Triple.getOS() == llvm::Triple::MinGW64) {
+ switch (Attr.getKind()) {
+ case AttributeList::AT_dllimport: HandleDLLImportAttr(D, Attr, S);
+ return true;
+ case AttributeList::AT_dllexport: HandleDLLExportAttr(D, Attr, S);
+ return true;
+ default: break;
+ }
+ }
+ if (Attr.getName()->getName() == "force_align_arg_pointer" ||
+ Attr.getName()->getName() == "__force_align_arg_pointer__") {
HandleX86ForceAlignArgPointerAttr(D, Attr, S);
return true;
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index fc069f7..2f3c482 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -191,7 +191,7 @@ public:
/// switched to storing TypeSourceInfos.
///
/// \returns the transformed type.
- QualType TransformType(QualType T);
+ QualType TransformType(QualType T, QualType ObjectType = QualType());
/// \brief Transforms the given type-with-location into a new
/// type-with-location.
@@ -201,13 +201,15 @@ public:
/// may override this function (to take over all type
/// transformations) or some set of the TransformXXXType functions
/// to alter the transformation.
- TypeSourceInfo *TransformType(TypeSourceInfo *DI);
+ TypeSourceInfo *TransformType(TypeSourceInfo *DI,
+ QualType ObjectType = QualType());
/// \brief Transform the given type-with-location into a new
/// type, collecting location information in the given builder
/// as necessary.
///
- QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL);
+ QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL,
+ QualType ObjectType = QualType());
/// \brief Transform the given statement.
///
@@ -235,13 +237,15 @@ public:
///
/// By default, acts as the identity function on declarations. Subclasses
/// may override this function to provide alternate behavior.
- Decl *TransformDecl(Decl *D) { return D; }
+ Decl *TransformDecl(SourceLocation Loc, Decl *D) { return D; }
/// \brief Transform the definition of the given declaration.
///
/// By default, invokes TransformDecl() to transform the declaration.
/// Subclasses may override this function to provide alternate behavior.
- Decl *TransformDefinition(Decl *D) { return getDerived().TransformDecl(D); }
+ Decl *TransformDefinition(SourceLocation Loc, Decl *D) {
+ return getDerived().TransformDecl(Loc, D);
+ }
/// \brief Transform the given declaration, which was the first part of a
/// nested-name-specifier in a member access expression.
@@ -253,7 +257,7 @@ public:
/// By default, invokes TransformDecl() to transform the declaration.
/// Subclasses may override this function to provide alternate behavior.
NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc) {
- return cast_or_null<NamedDecl>(getDerived().TransformDecl(D));
+ return cast_or_null<NamedDecl>(getDerived().TransformDecl(Loc, D));
}
/// \brief Transform the given nested-name-specifier.
@@ -307,20 +311,17 @@ public:
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
- QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
+ QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T, \
+ QualType ObjectType = QualType());
#include "clang/AST/TypeLocNodes.def"
- QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
+ QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL,
+ QualType ObjectType);
QualType
TransformTemplateSpecializationType(const TemplateSpecializationType *T,
QualType ObjectType);
- QualType
- TransformTemplateSpecializationType(TypeLocBuilder &TLB,
- TemplateSpecializationTypeLoc TL,
- QualType ObjectType);
-
OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
#define STMT(Node, Parent) \
@@ -882,28 +883,12 @@ public:
OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base,
SourceLocation OperatorLoc,
bool isArrow,
- SourceLocation DestroyedTypeLoc,
- QualType DestroyedType,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange) {
- CXXScopeSpec SS;
- if (Qualifier) {
- SS.setRange(QualifierRange);
- SS.setScopeRep(Qualifier);
- }
-
- QualType BaseType = ((Expr*) Base.get())->getType();
-
- DeclarationName Name
- = SemaRef.Context.DeclarationNames.getCXXDestructorName(
- SemaRef.Context.getCanonicalType(DestroyedType));
-
- return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
- OperatorLoc, isArrow,
- SS, /*FIXME: FirstQualifier*/ 0,
- Name, DestroyedTypeLoc,
- /*TemplateArgs*/ 0);
- }
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ TypeSourceInfo *ScopeType,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
+ PseudoDestructorTypeStorage Destroyed);
/// \brief Build a new unary operator expression.
///
@@ -1762,7 +1747,8 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
case NestedNameSpecifier::Namespace: {
NamespaceDecl *NS
= cast_or_null<NamespaceDecl>(
- getDerived().TransformDecl(NNS->getAsNamespace()));
+ getDerived().TransformDecl(Range.getBegin(),
+ NNS->getAsNamespace()));
if (!getDerived().AlwaysRebuild() &&
Prefix == NNS->getPrefix() &&
NS == NNS->getAsNamespace())
@@ -1779,7 +1765,8 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec: {
TemporaryBase Rebase(*this, Range.getBegin(), DeclarationName());
- QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0));
+ QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0),
+ ObjectType);
if (T.isNull())
return 0;
@@ -1820,14 +1807,8 @@ TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name,
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName: {
TemporaryBase Rebase(*this, Loc, Name);
- QualType T;
- if (!ObjectType.isNull() &&
- isa<TemplateSpecializationType>(Name.getCXXNameType())) {
- TemplateSpecializationType *SpecType
- = cast<TemplateSpecializationType>(Name.getCXXNameType());
- T = TransformTemplateSpecializationType(SpecType, ObjectType);
- } else
- T = getDerived().TransformType(Name.getCXXNameType());
+ QualType T = getDerived().TransformType(Name.getCXXNameType(),
+ ObjectType);
if (T.isNull())
return DeclarationName();
@@ -1844,16 +1825,19 @@ template<typename Derived>
TemplateName
TreeTransform<Derived>::TransformTemplateName(TemplateName Name,
QualType ObjectType) {
+ SourceLocation Loc = getDerived().getBaseLocation();
+
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(QTN->getQualifier(),
- /*FIXME:*/SourceRange(getDerived().getBaseLocation()));
+ /*FIXME:*/SourceRange(getDerived().getBaseLocation()),
+ ObjectType);
if (!NNS)
return TemplateName();
if (TemplateDecl *Template = QTN->getTemplateDecl()) {
TemplateDecl *TransTemplate
- = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template));
+ = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Loc, Template));
if (!TransTemplate)
return TemplateName();
@@ -1873,7 +1857,8 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name,
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(DTN->getQualifier(),
- /*FIXME:*/SourceRange(getDerived().getBaseLocation()));
+ /*FIXME:*/SourceRange(getDerived().getBaseLocation()),
+ ObjectType);
if (!NNS && DTN->getQualifier())
return TemplateName();
@@ -1892,7 +1877,7 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name,
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
TemplateDecl *TransTemplate
- = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template));
+ = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Loc, Template));
if (!TransTemplate)
return TemplateName();
@@ -1969,7 +1954,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl()))
Name = ND->getDeclName();
TemporaryBase Rebase(*this, Input.getLocation(), Name);
- Decl *D = getDerived().TransformDecl(Arg.getAsDecl());
+ Decl *D = getDerived().TransformDecl(Input.getLocation(), Arg.getAsDecl());
if (!D) return true;
Expr *SourceExpr = Input.getSourceDeclExpression();
@@ -2055,7 +2040,8 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
//===----------------------------------------------------------------------===//
template<typename Derived>
-QualType TreeTransform<Derived>::TransformType(QualType T) {
+QualType TreeTransform<Derived>::TransformType(QualType T,
+ QualType ObjectType) {
if (getDerived().AlreadyTransformed(T))
return T;
@@ -2064,7 +2050,7 @@ QualType TreeTransform<Derived>::TransformType(QualType T) {
TypeSourceInfo *DI = getSema().Context.CreateTypeSourceInfo(T);
DI->getTypeLoc().initialize(getDerived().getBaseLocation());
- TypeSourceInfo *NewDI = getDerived().TransformType(DI);
+ TypeSourceInfo *NewDI = getDerived().TransformType(DI, ObjectType);
if (!NewDI)
return QualType();
@@ -2073,7 +2059,8 @@ QualType TreeTransform<Derived>::TransformType(QualType T) {
}
template<typename Derived>
-TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) {
+TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI,
+ QualType ObjectType) {
if (getDerived().AlreadyTransformed(DI->getType()))
return DI;
@@ -2082,7 +2069,7 @@ TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) {
TypeLoc TL = DI->getTypeLoc();
TLB.reserve(TL.getFullDataSize());
- QualType Result = getDerived().TransformType(TLB, TL);
+ QualType Result = getDerived().TransformType(TLB, TL, ObjectType);
if (Result.isNull())
return 0;
@@ -2091,12 +2078,14 @@ TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) {
template<typename Derived>
QualType
-TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) {
+TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T,
+ QualType ObjectType) {
switch (T.getTypeLocClass()) {
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
case TypeLoc::CLASS: \
- return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T));
+ return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T), \
+ ObjectType);
#include "clang/AST/TypeLocNodes.def"
}
@@ -2112,10 +2101,12 @@ TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) {
template<typename Derived>
QualType
TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
- QualifiedTypeLoc T) {
+ QualifiedTypeLoc T,
+ QualType ObjectType) {
Qualifiers Quals = T.getType().getLocalQualifiers();
- QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc());
+ QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc(),
+ ObjectType);
if (Result.isNull())
return QualType();
@@ -2166,7 +2157,8 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) {
template<typename Derived>
QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB,
- BuiltinTypeLoc T) {
+ BuiltinTypeLoc T,
+ QualType ObjectType) {
BuiltinTypeLoc NewT = TLB.push<BuiltinTypeLoc>(T.getType());
NewT.setBuiltinLoc(T.getBuiltinLoc());
if (T.needsExtraLocalData())
@@ -2176,21 +2168,24 @@ QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB,
- ComplexTypeLoc T) {
+ ComplexTypeLoc T,
+ QualType ObjectType) {
// FIXME: recurse?
return TransformTypeSpecType(TLB, T);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
- PointerTypeLoc TL) {
+ PointerTypeLoc TL,
+ QualType ObjectType) {
TransformPointerLikeType(PointerType);
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB,
- BlockPointerTypeLoc TL) {
+ BlockPointerTypeLoc TL,
+ QualType ObjectType) {
TransformPointerLikeType(BlockPointerType);
}
@@ -2201,7 +2196,8 @@ TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB,
template<typename Derived>
QualType
TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
- ReferenceTypeLoc TL) {
+ ReferenceTypeLoc TL,
+ QualType ObjectType) {
const ReferenceType *T = TL.getTypePtr();
// Note that this works with the pointee-as-written.
@@ -2233,21 +2229,24 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
template<typename Derived>
QualType
TreeTransform<Derived>::TransformLValueReferenceType(TypeLocBuilder &TLB,
- LValueReferenceTypeLoc TL) {
- return TransformReferenceType(TLB, TL);
+ LValueReferenceTypeLoc TL,
+ QualType ObjectType) {
+ return TransformReferenceType(TLB, TL, ObjectType);
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformRValueReferenceType(TypeLocBuilder &TLB,
- RValueReferenceTypeLoc TL) {
- return TransformReferenceType(TLB, TL);
+ RValueReferenceTypeLoc TL,
+ QualType ObjectType) {
+ return TransformReferenceType(TLB, TL, ObjectType);
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
- MemberPointerTypeLoc TL) {
+ MemberPointerTypeLoc TL,
+ QualType ObjectType) {
MemberPointerType *T = TL.getTypePtr();
QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc());
@@ -2279,7 +2278,8 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
template<typename Derived>
QualType
TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
- ConstantArrayTypeLoc TL) {
+ ConstantArrayTypeLoc TL,
+ QualType ObjectType) {
ConstantArrayType *T = TL.getTypePtr();
QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc());
if (ElementType.isNull())
@@ -2314,7 +2314,8 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformIncompleteArrayType(
TypeLocBuilder &TLB,
- IncompleteArrayTypeLoc TL) {
+ IncompleteArrayTypeLoc TL,
+ QualType ObjectType) {
IncompleteArrayType *T = TL.getTypePtr();
QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc());
if (ElementType.isNull())
@@ -2342,7 +2343,8 @@ QualType TreeTransform<Derived>::TransformIncompleteArrayType(
template<typename Derived>
QualType
TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB,
- VariableArrayTypeLoc TL) {
+ VariableArrayTypeLoc TL,
+ QualType ObjectType) {
VariableArrayType *T = TL.getTypePtr();
QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc());
if (ElementType.isNull())
@@ -2383,7 +2385,8 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB,
template<typename Derived>
QualType
TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB,
- DependentSizedArrayTypeLoc TL) {
+ DependentSizedArrayTypeLoc TL,
+ QualType ObjectType) {
DependentSizedArrayType *T = TL.getTypePtr();
QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc());
if (ElementType.isNull())
@@ -2426,7 +2429,8 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
TypeLocBuilder &TLB,
- DependentSizedExtVectorTypeLoc TL) {
+ DependentSizedExtVectorTypeLoc TL,
+ QualType ObjectType) {
DependentSizedExtVectorType *T = TL.getTypePtr();
// FIXME: ext vector locs should be nested
@@ -2468,7 +2472,8 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
template<typename Derived>
QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB,
- VectorTypeLoc TL) {
+ VectorTypeLoc TL,
+ QualType ObjectType) {
VectorType *T = TL.getTypePtr();
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
@@ -2491,7 +2496,8 @@ QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB,
- ExtVectorTypeLoc TL) {
+ ExtVectorTypeLoc TL,
+ QualType ObjectType) {
VectorType *T = TL.getTypePtr();
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
@@ -2516,7 +2522,8 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB,
template<typename Derived>
QualType
TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
- FunctionProtoTypeLoc TL) {
+ FunctionProtoTypeLoc TL,
+ QualType ObjectType) {
FunctionProtoType *T = TL.getTypePtr();
QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
if (ResultType.isNull())
@@ -2592,7 +2599,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
TypeLocBuilder &TLB,
- FunctionNoProtoTypeLoc TL) {
+ FunctionNoProtoTypeLoc TL,
+ QualType ObjectType) {
FunctionNoProtoType *T = TL.getTypePtr();
QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
if (ResultType.isNull())
@@ -2612,9 +2620,10 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
template<typename Derived> QualType
TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB,
- UnresolvedUsingTypeLoc TL) {
+ UnresolvedUsingTypeLoc TL,
+ QualType ObjectType) {
UnresolvedUsingType *T = TL.getTypePtr();
- Decl *D = getDerived().TransformDecl(T->getDecl());
+ Decl *D = getDerived().TransformDecl(TL.getNameLoc(), T->getDecl());
if (!D)
return QualType();
@@ -2635,10 +2644,12 @@ TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB,
- TypedefTypeLoc TL) {
+ TypedefTypeLoc TL,
+ QualType ObjectType) {
TypedefType *T = TL.getTypePtr();
TypedefDecl *Typedef
- = cast_or_null<TypedefDecl>(getDerived().TransformDecl(T->getDecl()));
+ = cast_or_null<TypedefDecl>(getDerived().TransformDecl(TL.getNameLoc(),
+ T->getDecl()));
if (!Typedef)
return QualType();
@@ -2658,7 +2669,8 @@ QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
- TypeOfExprTypeLoc TL) {
+ TypeOfExprTypeLoc TL,
+ QualType ObjectType) {
// typeof expressions are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
@@ -2685,7 +2697,8 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
- TypeOfTypeLoc TL) {
+ TypeOfTypeLoc TL,
+ QualType ObjectType) {
TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo();
TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI);
if (!New_Under_TI)
@@ -2709,7 +2722,8 @@ QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
- DecltypeTypeLoc TL) {
+ DecltypeTypeLoc TL,
+ QualType ObjectType) {
DecltypeType *T = TL.getTypePtr();
// decltype expressions are not potentially evaluated contexts
@@ -2736,10 +2750,12 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB,
- RecordTypeLoc TL) {
+ RecordTypeLoc TL,
+ QualType ObjectType) {
RecordType *T = TL.getTypePtr();
RecordDecl *Record
- = cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl()));
+ = cast_or_null<RecordDecl>(getDerived().TransformDecl(TL.getNameLoc(),
+ T->getDecl()));
if (!Record)
return QualType();
@@ -2759,10 +2775,12 @@ QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB,
- EnumTypeLoc TL) {
+ EnumTypeLoc TL,
+ QualType ObjectType) {
EnumType *T = TL.getTypePtr();
EnumDecl *Enum
- = cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl()));
+ = cast_or_null<EnumDecl>(getDerived().TransformDecl(TL.getNameLoc(),
+ T->getDecl()));
if (!Enum)
return QualType();
@@ -2782,7 +2800,8 @@ QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB,
template <typename Derived>
QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
- ElaboratedTypeLoc TL) {
+ ElaboratedTypeLoc TL,
+ QualType ObjectType) {
ElaboratedType *T = TL.getTypePtr();
// FIXME: this should be a nested type.
@@ -2808,26 +2827,20 @@ QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL) {
+ TemplateTypeParmTypeLoc TL,
+ QualType ObjectType) {
return TransformTypeSpecType(TLB, TL);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
TypeLocBuilder &TLB,
- SubstTemplateTypeParmTypeLoc TL) {
+ SubstTemplateTypeParmTypeLoc TL,
+ QualType ObjectType) {
return TransformTypeSpecType(TLB, TL);
}
template<typename Derived>
-inline QualType
-TreeTransform<Derived>::TransformTemplateSpecializationType(
- TypeLocBuilder &TLB,
- TemplateSpecializationTypeLoc TL) {
- return TransformTemplateSpecializationType(TLB, TL, QualType());
-}
-
-template<typename Derived>
QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
const TemplateSpecializationType *TST,
QualType ObjectType) {
@@ -2901,11 +2914,13 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
template<typename Derived>
QualType
TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB,
- QualifiedNameTypeLoc TL) {
+ QualifiedNameTypeLoc TL,
+ QualType ObjectType) {
QualifiedNameType *T = TL.getTypePtr();
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(T->getQualifier(),
- SourceRange());
+ SourceRange(),
+ ObjectType);
if (!NNS)
return QualType();
@@ -2930,14 +2945,16 @@ TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB,
- TypenameTypeLoc TL) {
+ TypenameTypeLoc TL,
+ QualType ObjectType) {
TypenameType *T = TL.getTypePtr();
/* FIXME: preserve source information better than this */
SourceRange SR(TL.getNameLoc());
NestedNameSpecifier *NNS
- = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR);
+ = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR,
+ ObjectType);
if (!NNS)
return QualType();
@@ -2970,7 +2987,8 @@ QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB,
template<typename Derived>
QualType
TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB,
- ObjCInterfaceTypeLoc TL) {
+ ObjCInterfaceTypeLoc TL,
+ QualType ObjectType) {
assert(false && "TransformObjCInterfaceType unimplemented");
return QualType();
}
@@ -2978,7 +2996,8 @@ TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB,
template<typename Derived>
QualType
TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
- ObjCObjectPointerTypeLoc TL) {
+ ObjCObjectPointerTypeLoc TL,
+ QualType ObjectType) {
assert(false && "TransformObjCObjectPointerType unimplemented");
return QualType();
}
@@ -3098,7 +3117,9 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
if (S->getConditionVariable()) {
ConditionVar
= cast_or_null<VarDecl>(
- getDerived().TransformDefinition(S->getConditionVariable()));
+ getDerived().TransformDefinition(
+ S->getConditionVariable()->getLocation(),
+ S->getConditionVariable()));
if (!ConditionVar)
return SemaRef.StmtError();
} else {
@@ -3141,7 +3162,9 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
if (S->getConditionVariable()) {
ConditionVar
= cast_or_null<VarDecl>(
- getDerived().TransformDefinition(S->getConditionVariable()));
+ getDerived().TransformDefinition(
+ S->getConditionVariable()->getLocation(),
+ S->getConditionVariable()));
if (!ConditionVar)
return SemaRef.StmtError();
} else {
@@ -3178,7 +3201,9 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
if (S->getConditionVariable()) {
ConditionVar
= cast_or_null<VarDecl>(
- getDerived().TransformDefinition(S->getConditionVariable()));
+ getDerived().TransformDefinition(
+ S->getConditionVariable()->getLocation(),
+ S->getConditionVariable()));
if (!ConditionVar)
return SemaRef.StmtError();
} else {
@@ -3242,7 +3267,9 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
if (S->getConditionVariable()) {
ConditionVar
= cast_or_null<VarDecl>(
- getDerived().TransformDefinition(S->getConditionVariable()));
+ getDerived().TransformDefinition(
+ S->getConditionVariable()->getLocation(),
+ S->getConditionVariable()));
if (!ConditionVar)
return SemaRef.StmtError();
} else {
@@ -3330,7 +3357,8 @@ TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) {
llvm::SmallVector<Decl *, 4> Decls;
for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D) {
- Decl *Transformed = getDerived().TransformDefinition(*D);
+ Decl *Transformed = getDerived().TransformDefinition((*D)->getLocation(),
+ *D);
if (!Transformed)
return SemaRef.StmtError();
@@ -3577,7 +3605,8 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
}
ValueDecl *ND
- = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getDecl()));
+ = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getLocation(),
+ E->getDecl()));
if (!ND)
return SemaRef.ExprError();
@@ -3786,7 +3815,8 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
}
ValueDecl *Member
- = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getMemberDecl()));
+ = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getMemberLoc(),
+ E->getMemberDecl()));
if (!Member)
return SemaRef.ExprError();
@@ -4510,7 +4540,8 @@ template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
ParmVarDecl *Param
- = cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getParam()));
+ = cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getLocStart(),
+ E->getParam()));
if (!Param)
return SemaRef.ExprError();
@@ -4577,11 +4608,51 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
ConstructorArgs.push_back(Arg.take());
}
+ // Transform constructor, new operator, and delete operator.
+ CXXConstructorDecl *Constructor = 0;
+ if (E->getConstructor()) {
+ Constructor = cast_or_null<CXXConstructorDecl>(
+ getDerived().TransformDecl(E->getLocStart(),
+ E->getConstructor()));
+ if (!Constructor)
+ return SemaRef.ExprError();
+ }
+
+ FunctionDecl *OperatorNew = 0;
+ if (E->getOperatorNew()) {
+ OperatorNew = cast_or_null<FunctionDecl>(
+ getDerived().TransformDecl(E->getLocStart(),
+ E->getOperatorNew()));
+ if (!OperatorNew)
+ return SemaRef.ExprError();
+ }
+
+ FunctionDecl *OperatorDelete = 0;
+ if (E->getOperatorDelete()) {
+ OperatorDelete = cast_or_null<FunctionDecl>(
+ getDerived().TransformDecl(E->getLocStart(),
+ E->getOperatorDelete()));
+ if (!OperatorDelete)
+ return SemaRef.ExprError();
+ }
+
if (!getDerived().AlwaysRebuild() &&
AllocType == E->getAllocatedType() &&
ArraySize.get() == E->getArraySize() &&
- !ArgumentChanged)
+ Constructor == E->getConstructor() &&
+ OperatorNew == E->getOperatorNew() &&
+ OperatorDelete == E->getOperatorDelete() &&
+ !ArgumentChanged) {
+ // Mark any declarations we need as referenced.
+ // FIXME: instantiation-specific.
+ if (Constructor)
+ SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
+ if (OperatorNew)
+ SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorNew);
+ if (OperatorDelete)
+ SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete);
return SemaRef.Owned(E->Retain());
+ }
if (!ArraySize.get()) {
// If no array size was specified, but the new expression was
@@ -4630,9 +4701,25 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
if (Operand.isInvalid())
return SemaRef.ExprError();
+ // Transform the delete operator, if known.
+ FunctionDecl *OperatorDelete = 0;
+ if (E->getOperatorDelete()) {
+ OperatorDelete = cast_or_null<FunctionDecl>(
+ getDerived().TransformDecl(E->getLocStart(),
+ E->getOperatorDelete()));
+ if (!OperatorDelete)
+ return SemaRef.ExprError();
+ }
+
if (!getDerived().AlwaysRebuild() &&
- Operand.get() == E->getArgument())
+ Operand.get() == E->getArgument() &&
+ OperatorDelete == E->getOperatorDelete()) {
+ // Mark any declarations we need as referenced.
+ // FIXME: instantiation-specific.
+ if (OperatorDelete)
+ SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete);
return SemaRef.Owned(E->Retain());
+ }
return getDerived().RebuildCXXDeleteExpr(E->getLocStart(),
E->isGlobalDelete(),
@@ -4648,33 +4735,75 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
if (Base.isInvalid())
return SemaRef.ExprError();
+ Sema::TypeTy *ObjectTypePtr = 0;
+ bool MayBePseudoDestructor = false;
+ Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
+ E->getOperatorLoc(),
+ E->isArrow()? tok::arrow : tok::period,
+ ObjectTypePtr,
+ MayBePseudoDestructor);
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
NestedNameSpecifier *Qualifier
= getDerived().TransformNestedNameSpecifier(E->getQualifier(),
- E->getQualifierRange());
+ E->getQualifierRange(),
+ ObjectType);
if (E->getQualifier() && !Qualifier)
return SemaRef.ExprError();
- QualType DestroyedType;
- {
- TemporaryBase Rebase(*this, E->getDestroyedTypeLoc(), DeclarationName());
- DestroyedType = getDerived().TransformType(E->getDestroyedType());
- if (DestroyedType.isNull())
+ PseudoDestructorTypeStorage Destroyed;
+ if (E->getDestroyedTypeInfo()) {
+ TypeSourceInfo *DestroyedTypeInfo
+ = getDerived().TransformType(E->getDestroyedTypeInfo(), ObjectType);
+ if (!DestroyedTypeInfo)
return SemaRef.ExprError();
+ Destroyed = DestroyedTypeInfo;
+ } else if (ObjectType->isDependentType()) {
+ // We aren't likely to be able to resolve the identifier down to a type
+ // now anyway, so just retain the identifier.
+ Destroyed = PseudoDestructorTypeStorage(E->getDestroyedTypeIdentifier(),
+ E->getDestroyedTypeLoc());
+ } else {
+ // Look for a destructor known with the given name.
+ CXXScopeSpec SS;
+ if (Qualifier) {
+ SS.setScopeRep(Qualifier);
+ SS.setRange(E->getQualifierRange());
+ }
+
+ Sema::TypeTy *T = SemaRef.getDestructorName(E->getTildeLoc(),
+ *E->getDestroyedTypeIdentifier(),
+ E->getDestroyedTypeLoc(),
+ /*Scope=*/0,
+ SS, ObjectTypePtr,
+ false);
+ if (!T)
+ return SemaRef.ExprError();
+
+ Destroyed
+ = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.GetTypeFromParser(T),
+ E->getDestroyedTypeLoc());
}
- if (!getDerived().AlwaysRebuild() &&
- Base.get() == E->getBase() &&
- Qualifier == E->getQualifier() &&
- DestroyedType == E->getDestroyedType())
- return SemaRef.Owned(E->Retain());
-
+ TypeSourceInfo *ScopeTypeInfo = 0;
+ if (E->getScopeTypeInfo()) {
+ ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo(),
+ ObjectType);
+ if (!ScopeTypeInfo)
+ return SemaRef.ExprError();
+ }
+
return getDerived().RebuildCXXPseudoDestructorExpr(move(Base),
E->getOperatorLoc(),
E->isArrow(),
- E->getDestroyedTypeLoc(),
- DestroyedType,
Qualifier,
- E->getQualifierRange());
+ E->getQualifierRange(),
+ ScopeTypeInfo,
+ E->getColonColonLoc(),
+ E->getTildeLoc(),
+ Destroyed);
}
template<typename Derived>
@@ -4689,7 +4818,9 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
// Transform all the decls.
for (UnresolvedLookupExpr::decls_iterator I = Old->decls_begin(),
E = Old->decls_end(); I != E; ++I) {
- NamedDecl *InstD = static_cast<NamedDecl*>(getDerived().TransformDecl(*I));
+ NamedDecl *InstD = static_cast<NamedDecl*>(
+ getDerived().TransformDecl(Old->getNameLoc(),
+ *I));
if (!InstD) {
// Silently ignore these if a UsingShadowDecl instantiated to nothing.
// This can happen because of dependent hiding.
@@ -4828,7 +4959,8 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
CXXConstructorDecl *Constructor
= cast_or_null<CXXConstructorDecl>(
- getDerived().TransformDecl(E->getConstructor()));
+ getDerived().TransformDecl(E->getLocStart(),
+ E->getConstructor()));
if (!Constructor)
return SemaRef.ExprError();
@@ -4853,8 +4985,12 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
if (!getDerived().AlwaysRebuild() &&
T == E->getType() &&
Constructor == E->getConstructor() &&
- !ArgumentChanged)
+ !ArgumentChanged) {
+ // Mark the constructor as referenced.
+ // FIXME: Instantiation-specific
+ SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
return SemaRef.Owned(E->Retain());
+ }
return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(),
Constructor, E->isElidable(),
@@ -4904,7 +5040,8 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
CXXConstructorDecl *Constructor
= cast_or_null<CXXConstructorDecl>(
- getDerived().TransformDecl(E->getConstructor()));
+ getDerived().TransformDecl(E->getLocStart(),
+ E->getConstructor()));
if (!Constructor)
return SemaRef.ExprError();
@@ -4914,6 +5051,11 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
for (CXXTemporaryObjectExpr::arg_iterator Arg = E->arg_begin(),
ArgEnd = E->arg_end();
Arg != ArgEnd; ++Arg) {
+ if (getDerived().DropCallArgument(*Arg)) {
+ ArgumentChanged = true;
+ break;
+ }
+
OwningExprResult TransArg = getDerived().TransformExpr(*Arg);
if (TransArg.isInvalid())
return SemaRef.ExprError();
@@ -4925,8 +5067,11 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
if (!getDerived().AlwaysRebuild() &&
T == E->getType() &&
Constructor == E->getConstructor() &&
- !ArgumentChanged)
+ !ArgumentChanged) {
+ // FIXME: Instantiation-specific
+ SemaRef.MarkDeclarationReferenced(E->getTypeBeginLoc(), Constructor);
return SemaRef.Owned(E->Retain());
+ }
// FIXME: Bogus location information
SourceLocation CommaLoc;
@@ -4999,10 +5144,12 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
// Start the member reference and compute the object's type.
Sema::TypeTy *ObjectTy = 0;
+ bool MayBePseudoDestructor = false;
Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
E->getOperatorLoc(),
E->isArrow()? tok::arrow : tok::period,
- ObjectTy);
+ ObjectTy,
+ MayBePseudoDestructor);
if (Base.isInvalid())
return SemaRef.ExprError();
@@ -5110,7 +5257,9 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
// Transform all the decls.
for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(),
E = Old->decls_end(); I != E; ++I) {
- NamedDecl *InstD = static_cast<NamedDecl*>(getDerived().TransformDecl(*I));
+ NamedDecl *InstD = static_cast<NamedDecl*>(
+ getDerived().TransformDecl(Old->getMemberLoc(),
+ *I));
if (!InstD) {
// Silently ignore these if a UsingShadowDecl instantiated to nothing.
// This can happen because of dependent hiding.
@@ -5208,7 +5357,8 @@ Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) {
ObjCProtocolDecl *Protocol
= cast_or_null<ObjCProtocolDecl>(
- getDerived().TransformDecl(E->getProtocol()));
+ getDerived().TransformDecl(E->getLocStart(),
+ E->getProtocol()));
if (!Protocol)
return SemaRef.ExprError();
@@ -5704,6 +5854,52 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
return move(Result);
}
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(ExprArg Base,
+ SourceLocation OperatorLoc,
+ bool isArrow,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ TypeSourceInfo *ScopeType,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
+ PseudoDestructorTypeStorage Destroyed) {
+ CXXScopeSpec SS;
+ if (Qualifier) {
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(Qualifier);
+ }
+
+ Expr *BaseE = (Expr *)Base.get();
+ QualType BaseType = BaseE->getType();
+ if (BaseE->isTypeDependent() || Destroyed.getIdentifier() ||
+ (!isArrow && !BaseType->getAs<RecordType>()) ||
+ (isArrow && BaseType->getAs<PointerType>() &&
+ !BaseType->getAs<PointerType>()->getPointeeType()
+ ->template getAs<RecordType>())){
+ // This pseudo-destructor expression is still a pseudo-destructor.
+ return SemaRef.BuildPseudoDestructorExpr(move(Base), OperatorLoc,
+ isArrow? tok::arrow : tok::period,
+ SS, ScopeType, CCLoc, TildeLoc,
+ Destroyed,
+ /*FIXME?*/true);
+ }
+
+ TypeSourceInfo *DestroyedType = Destroyed.getTypeSourceInfo();
+ DeclarationName Name
+ = SemaRef.Context.DeclarationNames.getCXXDestructorName(
+ SemaRef.Context.getCanonicalType(DestroyedType->getType()));
+
+ // FIXME: the ScopeType should be tacked onto SS.
+
+ return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
+ OperatorLoc, isArrow,
+ SS, /*FIXME: FirstQualifier*/ 0,
+ Name, Destroyed.getLocation(),
+ /*TemplateArgs*/ 0);
+}
+
} // end namespace clang
#endif // LLVM_CLANG_SEMA_TREETRANSFORM_H
OpenPOWER on IntegriCloud