summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp52
-rw-r--r--lib/AST/CFG.cpp6
-rw-r--r--lib/AST/Decl.cpp39
-rw-r--r--lib/AST/DeclBase.cpp7
-rw-r--r--lib/AST/DeclCXX.cpp9
-rw-r--r--lib/AST/Expr.cpp4
-rw-r--r--lib/AST/ExprConstant.cpp22
-rw-r--r--lib/AST/StmtViz.cpp3
-rw-r--r--lib/AST/Type.cpp20
-rw-r--r--lib/Analysis/BasicConstraintManager.cpp12
-rw-r--r--lib/Analysis/BasicStore.cpp14
-rw-r--r--lib/Analysis/BugReporter.cpp2
-rw-r--r--lib/Analysis/CFRefCount.cpp33
-rw-r--r--lib/Analysis/CMakeLists.txt3
-rw-r--r--lib/Analysis/CheckObjCUnusedIVars.cpp5
-rw-r--r--lib/Analysis/GRExprEngine.cpp101
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp3
-rw-r--r--lib/Analysis/GRSimpleVals.cpp415
-rw-r--r--lib/Analysis/GRSimpleVals.h86
-rw-r--r--lib/Analysis/GRState.cpp79
-rw-r--r--lib/Analysis/GRTransferFuncs.cpp27
-rw-r--r--lib/Analysis/PathDiagnostic.cpp2
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp8
-rw-r--r--lib/Analysis/RegionStore.cpp219
-rw-r--r--lib/Analysis/SVals.cpp29
-rw-r--r--lib/Analysis/SimpleSValuator.cpp346
-rw-r--r--lib/Analysis/SymbolManager.cpp6
-rw-r--r--lib/Basic/IdentifierTable.cpp4
-rw-r--r--lib/Basic/SourceManager.cpp103
-rw-r--r--lib/Basic/Targets.cpp2
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp63
-rw-r--r--lib/CodeGen/CGDebugInfo.h4
-rw-r--r--lib/CodeGen/CGDecl.cpp2
-rw-r--r--lib/CodeGen/CGExpr.cpp7
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp5
-rw-r--r--lib/CodeGen/CGObjCMac.cpp63
-rw-r--r--lib/CodeGen/CGObjCRuntime.h3
-rw-r--r--lib/CodeGen/CodeGenModule.cpp11
-rw-r--r--lib/CodeGen/Mangle.cpp3
-rw-r--r--lib/Frontend/ASTUnit.cpp6
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp4
-rw-r--r--lib/Frontend/CMakeLists.txt7
-rw-r--r--lib/Frontend/PCHReader.cpp9
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp8
-rw-r--r--lib/Frontend/PCHWriter.cpp16
-rw-r--r--lib/Frontend/ResolveLocation.cpp322
-rw-r--r--lib/Headers/CMakeLists.txt2
-rw-r--r--lib/Parse/AttributeList.cpp3
-rw-r--r--lib/Parse/DeclSpec.cpp1
-rw-r--r--lib/Parse/MinimalAction.cpp1
-rw-r--r--lib/Parse/ParseDecl.cpp60
-rw-r--r--lib/Parse/ParseDeclCXX.cpp77
-rw-r--r--lib/Parse/ParseExprCXX.cpp154
-rw-r--r--lib/Parse/ParseObjc.cpp4
-rw-r--r--lib/Parse/ParseTemplate.cpp32
-rw-r--r--lib/Parse/ParseTentative.cpp7
-rw-r--r--lib/Parse/Parser.cpp26
-rw-r--r--lib/Sema/Sema.h72
-rw-r--r--lib/Sema/SemaChecking.cpp21
-rw-r--r--lib/Sema/SemaDecl.cpp97
-rw-r--r--lib/Sema/SemaDeclAttr.cpp27
-rw-r--r--lib/Sema/SemaDeclCXX.cpp195
-rw-r--r--lib/Sema/SemaExpr.cpp135
-rw-r--r--lib/Sema/SemaExprCXX.cpp4
-rw-r--r--lib/Sema/SemaInit.cpp9
-rw-r--r--lib/Sema/SemaLookup.cpp119
-rw-r--r--lib/Sema/SemaOverload.cpp106
-rw-r--r--lib/Sema/SemaTemplate.cpp61
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp424
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp176
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp74
-rw-r--r--lib/Sema/SemaTemplateInstantiateExpr.cpp10
-rw-r--r--lib/Sema/SemaType.cpp79
73 files changed, 2882 insertions, 1288 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index b80142f..12f75ae 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -179,6 +179,10 @@ void ASTContext::InitBuiltinTypes() {
// expressions.
InitBuiltinType(DependentTy, BuiltinType::Dependent);
+ // Placeholder type for C++0x auto declarations whose real type has
+ // not yet been deduced.
+ InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto);
+
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
@@ -460,6 +464,10 @@ ASTContext::getTypeInfo(const Type *T) {
case Type::TypeOf:
return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr());
+ case Type::Decltype:
+ return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
+ .getTypePtr());
+
case Type::QualifiedName:
return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
@@ -1659,6 +1667,50 @@ QualType ASTContext::getTypeOfType(QualType tofType) {
return QualType(tot, 0);
}
+/// getDecltypeForExpr - Given an expr, will return the decltype for that
+/// expression, according to the rules in C++0x [dcl.type.simple]p4
+static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) {
+ if (e->isTypeDependent())
+ return Context.DependentTy;
+
+ // If e is an id expression or a class member access, decltype(e) is defined
+ // as the type of the entity named by e.
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(e)) {
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
+ return VD->getType();
+ }
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(e)) {
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ return FD->getType();
+ }
+ // If e is a function call or an invocation of an overloaded operator,
+ // (parentheses around e are ignored), decltype(e) is defined as the
+ // return type of that function.
+ if (const CallExpr *CE = dyn_cast<CallExpr>(e->IgnoreParens()))
+ return CE->getCallReturnType();
+
+ QualType T = e->getType();
+
+ // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is
+ // defined as T&, otherwise decltype(e) is defined as T.
+ if (e->isLvalue(Context) == Expr::LV_Valid)
+ T = Context.getLValueReferenceType(T);
+
+ return T;
+}
+
+/// getDecltypeType - Unlike many "get<Type>" functions, we don't unique
+/// DecltypeType AST's. The only motivation to unique these nodes would be
+/// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be
+/// an issue. This doesn't effect the type checker, since it operates
+/// on canonical type's (which are always unique).
+QualType ASTContext::getDecltypeType(Expr *e) {
+ QualType T = getDecltypeForExpr(e, *this);
+ DecltypeType *dt = new (*this, 8) DecltypeType(e, getCanonicalType(T));
+ Types.push_back(dt);
+ return QualType(dt, 0);
+}
+
/// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl.
QualType ASTContext::getTagDeclType(TagDecl *Decl) {
diff --git a/lib/AST/CFG.cpp b/lib/AST/CFG.cpp
index 9f2f207..d7a8307 100644
--- a/lib/AST/CFG.cpp
+++ b/lib/AST/CFG.cpp
@@ -22,9 +22,6 @@
#include "llvm/Support/Compiler.h"
#include <llvm/Support/Allocator.h>
#include <llvm/Support/Format.h>
-#include <iomanip>
-#include <algorithm>
-#include <sstream>
using namespace clang;
@@ -1887,7 +1884,8 @@ void CFG::viewCFG() const {
namespace llvm {
template<>
struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
- static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) {
+ static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph,
+ bool ShortNames) {
#ifndef NDEBUG
std::string OutSStr;
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 71e88a9..5382ab5 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -269,6 +269,14 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
// For function declarations, we keep track of redeclarations.
return FD->getPreviousDeclaration() == OldD;
+ // For function templates, the underlying function declarations are linked.
+ if (const FunctionTemplateDecl *FunctionTemplate
+ = dyn_cast<FunctionTemplateDecl>(this))
+ if (const FunctionTemplateDecl *OldFunctionTemplate
+ = dyn_cast<FunctionTemplateDecl>(OldD))
+ return FunctionTemplate->getTemplatedDecl()
+ ->declarationReplaces(OldFunctionTemplate->getTemplatedDecl());
+
// For method declarations, we keep track of redeclarations.
if (isa<ObjCMethodDecl>(this))
return false;
@@ -289,6 +297,19 @@ bool NamedDecl::hasLinkage() const {
return false;
}
+NamedDecl *NamedDecl::getUnderlyingDecl() {
+ NamedDecl *ND = this;
+ while (true) {
+ if (UsingDecl *UD = dyn_cast<UsingDecl>(ND))
+ ND = UD->getTargetDecl();
+ else if (ObjCCompatibleAliasDecl *AD
+ = dyn_cast<ObjCCompatibleAliasDecl>(ND))
+ return AD->getClassInterface();
+ else
+ return ND;
+ }
+}
+
//===----------------------------------------------------------------------===//
// VarDecl Implementation
//===----------------------------------------------------------------------===//
@@ -351,6 +372,10 @@ void FunctionDecl::Destroy(ASTContext& C) {
C.Deallocate(ParamInfo);
+ if (TemplateSpecializationInfo *Info
+ = TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>())
+ C.Deallocate(Info);
+
Decl::Destroy(C);
}
@@ -547,6 +572,20 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
return OO_None;
}
+void
+FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
+ FunctionTemplateDecl *Template,
+ const TemplateArgumentList *TemplateArgs) {
+ TemplateSpecializationInfo *Info
+ = TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>();
+ if (!Info)
+ Info = new (Context) TemplateSpecializationInfo;
+
+ Info->Template = Template;
+ Info->TemplateArguments = TemplateArgs;
+ TemplateOrSpecialization = Info;
+}
+
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 02e71d7..5815d82 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -96,6 +96,13 @@ bool Decl::isTemplateParameterPack() const {
return false;
}
+bool Decl::isFunctionOrFunctionTemplate() const {
+ if (const UsingDecl *UD = dyn_cast<UsingDecl>(this))
+ return UD->getTargetDecl()->isFunctionOrFunctionTemplate();
+
+ return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
+}
+
//===----------------------------------------------------------------------===//
// PrettyStackTraceDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 25e4d19..752218d 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -420,6 +420,15 @@ OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) OverloadedFunctionDecl(DC, N);
}
+void OverloadedFunctionDecl::addOverload(FunctionTemplateDecl *FTD) {
+ Functions.push_back(FTD);
+
+ // An overloaded function declaration always has the location of
+ // the most-recently-added function declaration.
+ if (FTD->getLocation().isValid())
+ this->setLocation(FTD->getLocation());
+}
+
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 4a3ad26..fce88cc 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1496,7 +1496,7 @@ bool ExtVectorElementExpr::containsDuplicateElements() const {
return false;
// Advance past s-char prefix on hex swizzles.
- if (*compStr == 's') {
+ if (*compStr == 's' || *compStr == 'S') {
compStr++;
length--;
}
@@ -1514,7 +1514,7 @@ bool ExtVectorElementExpr::containsDuplicateElements() const {
void ExtVectorElementExpr::getEncodedElementAccess(
llvm::SmallVectorImpl<unsigned> &Elts) const {
const char *compStr = Accessor->getName();
- if (*compStr == 's')
+ if (*compStr == 's' || *compStr == 'S')
compStr++;
bool isHi = !strcmp(compStr, "hi");
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 4815ae5..9d76592 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -486,12 +486,28 @@ static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
const Expr* SE = E->getSubExpr();
+ QualType SETy = SE->getType();
+ APValue Result = APValue();
- // Check for vector->vector bitcast.
- if (SE->getType()->isVectorType())
+ // Check for vector->vector bitcast and scalar->vector splat.
+ if (SETy->isVectorType()) {
return this->Visit(const_cast<Expr*>(SE));
+ } else if (SETy->isIntegerType()) {
+ APSInt IntResult;
+ if (EvaluateInteger(SE, IntResult, Info))
+ Result = APValue(IntResult);
+ } else if (SETy->isRealFloatingType()) {
+ APFloat F(0.0);
+ if (EvaluateFloat(SE, F, Info))
+ Result = APValue(F);
+ }
- return APValue();
+ if (Result.isInt() || Result.isFloat()) {
+ unsigned NumElts = E->getType()->getAsVectorType()->getNumElements();
+ llvm::SmallVector<APValue, 4> Elts(NumElts, Result);
+ Result = APValue(&Elts[0], Elts.size());
+ }
+ return Result;
}
APValue
diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp
index 1316d35..96b5218 100644
--- a/lib/AST/StmtViz.cpp
+++ b/lib/AST/StmtViz.cpp
@@ -31,7 +31,8 @@ void Stmt::viewAST() const {
namespace llvm {
template<>
struct DOTGraphTraits<const Stmt*> : public DefaultDOTGraphTraits {
- static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) {
+ static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph,
+ bool ShortNames) {
#ifndef NDEBUG
std::string OutSStr;
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 7b45b21..4153661 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -112,6 +112,8 @@ QualType Type::getDesugaredType(bool ForDisplay) const {
return TOE->getUnderlyingExpr()->getType().getDesugaredType();
if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this))
return TOT->getUnderlyingType().getDesugaredType();
+ if (const DecltypeType *DTT = dyn_cast<DecltypeType>(this))
+ return DTT->getUnderlyingExpr()->getType().getDesugaredType();
if (const TemplateSpecializationType *Spec
= dyn_cast<TemplateSpecializationType>(this)) {
if (ForDisplay)
@@ -962,6 +964,7 @@ const char *BuiltinType::getName(bool CPlusPlus) const {
case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>";
case Dependent: return "<dependent type>";
+ case UndeducedAuto: return "<undeduced auto type>";
}
}
@@ -1052,6 +1055,13 @@ TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
assert(!isa<TypedefType>(can) && "Invalid canonical type");
}
+DecltypeType::DecltypeType(Expr *E, QualType can)
+ : Type(Decltype, can, E->isTypeDependent()), E(E) {
+ assert(can->isDependentType() == E->isTypeDependent() &&
+ "type dependency mismatch!");
+ assert(!isa<TypedefType>(can) && "Invalid canonical type");
+}
+
TagType::TagType(TypeClass TC, TagDecl *D, QualType can)
: Type(TC, can, D->isDependentType()), decl(D, 0) {}
@@ -1421,6 +1431,16 @@ void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPol
InnerString = "typeof(" + Tmp + ")" + InnerString;
}
+void DecltypeType::getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'decltype(t) X'.
+ InnerString = ' ' + InnerString;
+ std::string Str;
+ llvm::raw_string_ostream s(Str);
+ getUnderlyingExpr()->printPretty(s, 0, Policy);
+ InnerString = "decltype(" + s.str() + ")" + InnerString;
+}
+
void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
// If needed for precedence reasons, wrap the inner part in grouping parens.
if (!S.empty())
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp
index ffa8a86..cb89d30 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Analysis/BasicConstraintManager.cpp
@@ -83,7 +83,7 @@ public:
const GRState* RemoveDeadBindings(const GRState* state, SymbolReaper& SymReaper);
- void print(const GRState* state, std::ostream& Out,
+ void print(const GRState* state, llvm::raw_ostream& Out,
const char* nl, const char *sep);
};
@@ -280,7 +280,7 @@ BasicConstraintManager::RemoveDeadBindings(const GRState* state,
return state->set<ConstNotEq>(CNE);
}
-void BasicConstraintManager::print(const GRState* state, std::ostream& Out,
+void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out,
const char* nl, const char *sep) {
// Print equality constraints.
@@ -288,12 +288,8 @@ void BasicConstraintManager::print(const GRState* state, std::ostream& Out,
if (!CE.isEmpty()) {
Out << nl << sep << "'==' constraints:";
-
- for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
- Out << nl << " $" << I.getKey();
- llvm::raw_os_ostream OS(Out);
- OS << " : " << *I.getData();
- }
+ for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I)
+ Out << nl << " $" << I.getKey() << " : " << *I.getData();
}
// Print != constraints.
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index 6b346cd..8fbce52 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -112,7 +112,8 @@ public:
return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store));
}
- void print(Store store, std::ostream& Out, const char* nl, const char *sep);
+ void print(Store store, llvm::raw_ostream& Out, const char* nl,
+ const char *sep);
private:
ASTContext& getContext() { return StateMgr.getContext(); }
@@ -535,7 +536,7 @@ Store BasicStoreManager::getInitialStore() {
// Initialize globals and parameters to symbolic values.
// Initialize local variables to undefined.
- const MemRegion *R = StateMgr.getRegion(VD);
+ const MemRegion *R = ValMgr.getRegionManager().getVarRegion(VD);
SVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
isa<ImplicitParamDecl>(VD))
? ValMgr.getRegionValueSymbolVal(R)
@@ -602,18 +603,19 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
return store;
}
-void BasicStoreManager::print(Store store, std::ostream& O,
+void BasicStoreManager::print(Store store, llvm::raw_ostream& Out,
const char* nl, const char *sep) {
- llvm::raw_os_ostream Out(O);
BindingsTy B = GetBindings(store);
Out << "Variables:" << nl;
bool isFirst = true;
for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
- if (isFirst) isFirst = false;
- else Out << nl;
+ if (isFirst)
+ isFirst = false;
+ else
+ Out << nl;
Out << ' ' << I.getKey() << " : ";
I.getData().print(Out);
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 9c9029c..38ea458 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines BugReporter, a utility class for generating
-// PathDiagnostics for analyses based on GRSimpleVals.
+// PathDiagnostics.
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 46333a7..f4a28e0 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#include "GRSimpleVals.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
@@ -22,6 +21,7 @@
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
@@ -30,7 +30,6 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/STLExtras.h"
-#include <ostream>
#include <stdarg.h>
using namespace clang;
@@ -1674,10 +1673,10 @@ public:
ID.Add(T);
}
- void print(std::ostream& Out) const;
+ void print(llvm::raw_ostream& Out) const;
};
-void RefVal::print(std::ostream& Out) const {
+void RefVal::print(llvm::raw_ostream& Out) const {
if (!T.isNull())
Out << "Tracked Type:" << T.getAsString() << '\n';
@@ -1827,11 +1826,11 @@ static const GRState * SendAutorelease(const GRState *state,
namespace {
-class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
+class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs {
public:
class BindingsPrinter : public GRState::Printer {
public:
- virtual void Print(std::ostream& Out, const GRState* state,
+ virtual void Print(llvm::raw_ostream& Out, const GRState* state,
const char* nl, const char* sep);
};
@@ -1959,7 +1958,8 @@ public:
} // end anonymous namespace
-static void PrintPool(std::ostream &Out, SymbolRef Sym, const GRState *state) {
+static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym,
+ const GRState *state) {
Out << ' ';
if (Sym)
Out << Sym->getSymbolID();
@@ -1975,10 +1975,9 @@ static void PrintPool(std::ostream &Out, SymbolRef Sym, const GRState *state) {
Out << '}';
}
-void CFRefCount::BindingsPrinter::Print(std::ostream& Out, const GRState* state,
+void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out,
+ const GRState* state,
const char* nl, const char* sep) {
-
-
RefBindings B = state->get<RefBindings>();
@@ -2790,10 +2789,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
if (Summ.getArg(idx) == DoNothingByRef)
continue;
- // Invalidate the value of the variable passed by reference.
-
- // FIXME: Either this logic should also be replicated in GRSimpleVals
- // or should be pulled into a separate "constraint engine."
+ // Invalidate the value of the variable passed by reference.
// FIXME: We can have collisions on the conjured symbol if the
// expression *I also creates conjured symbols. We probably want
@@ -2942,11 +2938,10 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
default:
assert (false && "Unhandled RetEffect."); break;
- case RetEffect::NoRet: {
-
+ case RetEffect::NoRet: {
// Make up a symbol for the return value (not reference counted).
- // FIXME: This is basically copy-and-paste from GRSimpleVals. We
- // should compose behavior, not copy it.
+ // FIXME: Most of this logic is not specific to the retain/release
+ // checker.
// FIXME: We eventually should handle structs and other compound types
// that are returned by value.
@@ -3091,7 +3086,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
if (Expr* Receiver = ME->getReceiver()) {
SVal X = St->getSValAsScalarOrLoc(Receiver);
if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X))
- if (L->getRegion() == Eng.getStateManager().getSelfRegion(St)) {
+ if (L->getRegion() == St->getSelfRegion()) {
// Update the summary to make the default argument effect
// 'StopTracking'.
Summ = Summaries.copySummary(Summ);
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index e064e3c..7d6a619 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -18,15 +18,14 @@ add_clang_library(clangAnalysis
GRCoreEngine.cpp
GRExprEngine.cpp
GRExprEngineInternalChecks.cpp
- GRSimpleVals.cpp
GRState.cpp
- GRTransferFuncs.cpp
LiveVariables.cpp
MemRegion.cpp
PathDiagnostic.cpp
RangeConstraintManager.cpp
RegionStore.cpp
SimpleConstraintManager.cpp
+ SimpleSValuator.cpp
Store.cpp
SVals.cpp
SymbolManager.cpp
diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp
index 92c50e2..21dc658 100644
--- a/lib/Analysis/CheckObjCUnusedIVars.cpp
+++ b/lib/Analysis/CheckObjCUnusedIVars.cpp
@@ -20,7 +20,6 @@
#include "clang/AST/Expr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/LangOptions.h"
-#include <sstream>
using namespace clang;
@@ -97,8 +96,8 @@ void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) {
// Find ivars that are unused.
for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
if (I->second == Unused) {
-
- std::ostringstream os;
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
os << "Instance variable '" << I->first->getNameAsString()
<< "' in class '" << ID->getNameAsString()
<< "' is never used by the methods in its @implementation "
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 7d56d10..8b4f5c8 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -15,7 +15,6 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.h"
@@ -29,7 +28,6 @@
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
-#include <sstream>
#endif
using namespace clang;
@@ -126,6 +124,7 @@ GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx,
StateMgr(G.getContext(), SMC, CMC, G.getAllocator(), cfg, CD, L),
SymMgr(StateMgr.getSymbolManager()),
ValMgr(StateMgr.getValueManager()),
+ SVator(clang::CreateSimpleSValuator(ValMgr)), // FIXME: Generalize later.
CurrentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", G.getContext())),
@@ -176,7 +175,7 @@ const GRState* GRExprEngine::getInitialState() {
const ParmVarDecl *PD = FD->getParamDecl(0);
QualType T = PD->getType();
if (T->isIntegerType())
- if (const MemRegion *R = StateMgr.getRegion(PD)) {
+ if (const MemRegion *R = state->getRegion(PD)) {
SVal V = state->getSVal(loc::MemRegionVal(R));
SVal Constraint = EvalBinOp(state, BinaryOperator::GT, V,
ValMgr.makeZeroVal(T),
@@ -1046,7 +1045,7 @@ void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
else {
// We are binding to a value other than 'unknown'. Perform the binding
// using the StoreManager.
- newState = StateMgr.BindLoc(state, cast<Loc>(location), Val);
+ newState = state->bindLoc(cast<Loc>(location), Val);
}
// The next thing to do is check if the GRTransferFuncs object wants to
@@ -1296,9 +1295,8 @@ static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet<GRState>& Dst,
SVal oldValueVal = stateLoad->getSVal(oldValueExpr);
// Perform the comparison.
- SVal Cmp = Engine.EvalBinOp(stateLoad,
- BinaryOperator::EQ, theValueVal, oldValueVal,
- Engine.getContext().IntTy);
+ SVal Cmp = Engine.EvalBinOp(stateLoad, BinaryOperator::EQ, theValueVal,
+ oldValueVal, Engine.getContext().IntTy);
const GRState *stateEqual = stateLoad->assume(Cmp, true);
@@ -2247,17 +2245,17 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
InitVal = ValMgr.getConjuredSymbolVal(InitEx, Count);
}
- state = StateMgr.BindDecl(state, VD, InitVal);
+ state = state->bindDecl(VD, InitVal);
// The next thing to do is check if the GRTransferFuncs object wants to
// update the state based on the new binding. If the GRTransferFunc
// object doesn't do anything, just auto-propagate the current state.
GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, state, DS,true);
- getTF().EvalBind(BuilderRef, loc::MemRegionVal(StateMgr.getRegion(VD)),
+ getTF().EvalBind(BuilderRef, loc::MemRegionVal(state->getRegion(VD)),
InitVal);
}
else {
- state = StateMgr.BindDeclWithNoInit(state, VD);
+ state = state->bindDeclWithNoInit(VD);
MakeNode(Dst, DS, *I, state);
}
}
@@ -2562,7 +2560,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
case UnaryOperator::Minus:
// FIXME: Do we need to handle promotions?
- state = state->bindExpr(U, EvalMinus(U, cast<NonLoc>(V)));
+ state = state->bindExpr(U, EvalMinus(cast<NonLoc>(V)));
break;
case UnaryOperator::LNot:
@@ -2571,25 +2569,21 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
//
// Note: technically we do "E == 0", but this is the same in the
// transfer functions as "0 == E".
+ SVal Result;
if (isa<Loc>(V)) {
Loc X = ValMgr.makeNull();
- SVal Result = EvalBinOp(state,BinaryOperator::EQ, cast<Loc>(V), X,
- U->getType());
- state = state->bindExpr(U, Result);
+ Result = EvalBinOp(state, BinaryOperator::EQ, cast<Loc>(V), X,
+ U->getType());
}
else {
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
-#if 0
- SVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X);
- state = SetSVal(state, U, Result);
-#else
- EvalBinOp(Dst, U, BinaryOperator::EQ, cast<NonLoc>(V), X, *I,
- U->getType());
- continue;
-#endif
+ Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X,
+ U->getType());
}
+ state = state->bindExpr(U, Result);
+
break;
}
@@ -2640,8 +2634,8 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
Builder->getCurrentBlockCount());
// If the value is a location, ++/-- should always preserve
- // non-nullness. Check if the original value was non-null, and if so propagate
- // that constraint.
+ // non-nullness. Check if the original value was non-null, and if so
+ // propagate that constraint.
if (Loc::IsLocType(U->getType())) {
SVal Constraint = EvalBinOp(state, BinaryOperator::EQ, V2,
ValMgr.makeZeroVal(U->getType()),
@@ -2907,9 +2901,8 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
if (B->isAssignmentOp())
break;
- // Process non-assignements except commas or short-circuited
- // logical expressions (LAnd and LOr).
-
+ // Process non-assignments except commas or short-circuited
+ // logical expressions (LAnd and LOr).
SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType());
if (Result.isUnknown()) {
@@ -3024,7 +3017,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
}
// Compute the result of the operation.
- SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
+ SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
B->getType());
if (Result.isUndef()) {
@@ -3073,26 +3066,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
// Transfer-function Helpers.
//===----------------------------------------------------------------------===//
-void GRExprEngine::EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
- BinaryOperator::Opcode Op,
- NonLoc L, NonLoc R,
- ExplodedNode<GRState>* Pred, QualType T) {
-
- GRStateSet OStates;
- EvalBinOp(OStates, GetState(Pred), Ex, Op, L, R, T);
-
- for (GRStateSet::iterator I=OStates.begin(), E=OStates.end(); I!=E; ++I)
- MakeNode(Dst, Ex, Pred, *I);
-}
-
-void GRExprEngine::EvalBinOp(GRStateSet& OStates, const GRState* state,
- Expr* Ex, BinaryOperator::Opcode Op,
- NonLoc L, NonLoc R, QualType T) {
-
- GRStateSet::AutoPopulate AP(OStates, state);
- if (R.isValid()) getTF().EvalBinOpNN(OStates, *this, state, Ex, Op, L, R, T);
-}
-
SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op,
SVal L, SVal R, QualType T) {
@@ -3104,9 +3077,9 @@ SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op,
if (isa<Loc>(L)) {
if (isa<Loc>(R))
- return getTF().EvalBinOp(*this, Op, cast<Loc>(L), cast<Loc>(R));
+ return SVator->EvalBinOpLL(Op, cast<Loc>(L), cast<Loc>(R), T);
else
- return getTF().EvalBinOp(*this, state, Op, cast<Loc>(L), cast<NonLoc>(R));
+ return SVator->EvalBinOpLN(state, Op, cast<Loc>(L), cast<NonLoc>(R), T);
}
if (isa<Loc>(R)) {
@@ -3116,11 +3089,10 @@ SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op,
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub);
// Commute the operands.
- return getTF().EvalBinOp(*this, state, Op, cast<Loc>(R), cast<NonLoc>(L));
+ return SVator->EvalBinOpLN(state, Op, cast<Loc>(R), cast<NonLoc>(L), T);
}
else
- return getTF().DetermEvalBinOpNN(*this, Op, cast<NonLoc>(L),
- cast<NonLoc>(R), T);
+ return SVator->EvalBinOpNN(Op, cast<NonLoc>(L), cast<NonLoc>(R), T);
}
//===----------------------------------------------------------------------===//
@@ -3156,8 +3128,11 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
return "";
}
- static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*) {
- std::ostringstream Out;
+ static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*,
+ bool ShortNames) {
+
+ std::string sbuf;
+ llvm::raw_string_ostream Out(sbuf);
// Program Location.
ProgramPoint Loc = N->getLocation();
@@ -3179,9 +3154,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
SourceLocation SLoc = S->getLocStart();
Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
- llvm::raw_os_ostream OutS(Out);
- S->printPretty(OutS);
- OutS.flush();
+ S->printPretty(Out);
if (SLoc.isFileID()) {
Out << "\\lline="
@@ -3235,10 +3208,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
SourceLocation SLoc = T->getLocStart();
Out << "\\|Terminator: ";
-
- llvm::raw_os_ostream OutS(Out);
- E.getSrc()->printTerminator(OutS);
- OutS.flush();
+ E.getSrc()->printTerminator(Out);
if (SLoc.isFileID()) {
Out << "\\lline="
@@ -3253,14 +3223,11 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
if (Label) {
if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
Out << "\\lcase ";
- llvm::raw_os_ostream OutS(Out);
- C->getLHS()->printPretty(OutS);
- OutS.flush();
+ C->getLHS()->printPretty(Out);
if (Stmt* RHS = C->getRHS()) {
Out << " .. ";
- RHS->printPretty(OutS);
- OutS.flush();
+ RHS->printPretty(Out);
}
Out << ":";
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
index 13df89e..76d26dd 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -672,7 +672,6 @@ public:
return NULL;
if (!StoreSite) {
- GRStateManager &StateMgr = BRC.getStateManager();
const ExplodedNode<GRState> *Node = N, *Last = NULL;
for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
@@ -686,7 +685,7 @@ public:
}
}
- if (StateMgr.GetSVal(Node->getState(), R) != V)
+ if (Node->getState()->getSVal(R) != V)
break;
}
diff --git a/lib/Analysis/GRSimpleVals.cpp b/lib/Analysis/GRSimpleVals.cpp
deleted file mode 100644
index 4806121..0000000
--- a/lib/Analysis/GRSimpleVals.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-// GRSimpleVals.cpp - Transfer functions for tracking simple values -*- C++ -*--
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines GRSimpleVals, a sub-class of GRTransferFuncs that
-// provides transfer functions for performing simple value tracking with
-// limited support for symbolics.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRSimpleVals.h"
-#include "BasicObjCFoundationChecks.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "llvm/Support/Compiler.h"
-#include <sstream>
-
-using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// Transfer Function creation for External clients.
-//===----------------------------------------------------------------------===//
-
-GRTransferFuncs* clang::MakeGRSimpleValsTF() { return new GRSimpleVals(); }
-
-//===----------------------------------------------------------------------===//
-// Transfer function for Casts.
-//===----------------------------------------------------------------------===//
-
-SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLoc X, QualType T) {
-
- if (!isa<nonloc::ConcreteInt>(X))
- return UnknownVal();
-
- bool isLocType = Loc::IsLocType(T);
-
- // Only handle casts from integers to integers.
- if (!isLocType && !T->isIntegerType())
- return UnknownVal();
-
- BasicValueFactory& BasicVals = Eng.getBasicVals();
-
- llvm::APSInt V = cast<nonloc::ConcreteInt>(X).getValue();
- V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
- V.extOrTrunc(Eng.getContext().getTypeSize(T));
-
- if (isLocType)
- return loc::ConcreteInt(BasicVals.getValue(V));
- else
- return nonloc::ConcreteInt(BasicVals.getValue(V));
-}
-
-// Casts.
-
-SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, Loc X, QualType T) {
-
- // Casts from pointers -> pointers, just return the lval.
- //
- // Casts from pointers -> references, just return the lval. These
- // can be introduced by the frontend for corner cases, e.g
- // casting from va_list* to __builtin_va_list&.
- //
- assert (!X.isUnknownOrUndef());
-
- if (Loc::IsLocType(T) || T->isReferenceType())
- return X;
-
- // FIXME: Handle transparent unions where a value can be "transparently"
- // lifted into a union type.
- if (T->isUnionType())
- return UnknownVal();
-
- assert (T->isIntegerType());
- BasicValueFactory& BasicVals = Eng.getBasicVals();
- unsigned BitWidth = Eng.getContext().getTypeSize(T);
-
- if (!isa<loc::ConcreteInt>(X))
- return Eng.getValueManager().makeLocAsInteger(X, BitWidth);
-
- llvm::APSInt V = cast<loc::ConcreteInt>(X).getValue();
- V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
- V.extOrTrunc(BitWidth);
- return nonloc::ConcreteInt(BasicVals.getValue(V));
-}
-
-// Unary operators.
-
-SVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLoc X){
-
- switch (X.getSubKind()) {
-
- case nonloc::ConcreteIntKind:
- return cast<nonloc::ConcreteInt>(X).EvalMinus(Eng.getBasicVals(), U);
-
- default:
- return UnknownVal();
- }
-}
-
-SVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLoc X) {
-
- switch (X.getSubKind()) {
-
- case nonloc::ConcreteIntKind:
- return cast<nonloc::ConcreteInt>(X).EvalComplement(Eng.getBasicVals());
-
- default:
- return UnknownVal();
- }
-}
-
-// Binary operators.
-
-static unsigned char LNotOpMap[] = {
- (unsigned char) BinaryOperator::GE, /* LT => GE */
- (unsigned char) BinaryOperator::LE, /* GT => LE */
- (unsigned char) BinaryOperator::GT, /* LE => GT */
- (unsigned char) BinaryOperator::LT, /* GE => LT */
- (unsigned char) BinaryOperator::NE, /* EQ => NE */
- (unsigned char) BinaryOperator::EQ /* NE => EQ */
-};
-
-SVal GRSimpleVals::DetermEvalBinOpNN(GRExprEngine& Eng,
- BinaryOperator::Opcode Op,
- NonLoc L, NonLoc R,
- QualType T) {
- BasicValueFactory& BasicVals = Eng.getBasicVals();
- ValueManager& ValMgr = Eng.getValueManager();
- unsigned subkind = L.getSubKind();
-
- while (1) {
-
- switch (subkind) {
- default:
- return UnknownVal();
-
- case nonloc::LocAsIntegerKind: {
- Loc LL = cast<nonloc::LocAsInteger>(L).getLoc();
-
- switch (R.getSubKind()) {
- case nonloc::LocAsIntegerKind:
- return EvalBinOp(Eng, Op, LL,
- cast<nonloc::LocAsInteger>(R).getLoc());
-
- case nonloc::ConcreteIntKind: {
- // Transform the integer into a location and compare.
- ASTContext& Ctx = Eng.getContext();
- llvm::APSInt V = cast<nonloc::ConcreteInt>(R).getValue();
- V.setIsUnsigned(true);
- V.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
- return EvalBinOp(Eng, Op, LL, ValMgr.makeLoc(V));
- }
-
- default:
- switch (Op) {
- case BinaryOperator::EQ:
- return ValMgr.makeTruthVal(false);
- case BinaryOperator::NE:
- return ValMgr.makeTruthVal(true);
- default:
- // This case also handles pointer arithmetic.
- return UnknownVal();
- }
- }
- }
-
- case nonloc::SymExprValKind: {
- // Logical not?
- if (!(Op == BinaryOperator::EQ && R.isZeroConstant()))
- return UnknownVal();
-
- const SymExpr &SE=*cast<nonloc::SymExprVal>(L).getSymbolicExpression();
-
- // Only handle ($sym op constant) for now.
- if (const SymIntExpr *E = dyn_cast<SymIntExpr>(&SE)) {
- BinaryOperator::Opcode Opc = E->getOpcode();
-
- if (Opc < BinaryOperator::LT || Opc > BinaryOperator::NE)
- return UnknownVal();
-
- // For comparison operators, translate the constraint by
- // changing the opcode.
- int idx = (unsigned) Opc - (unsigned) BinaryOperator::LT;
-
- assert (idx >= 0 &&
- (unsigned) idx < sizeof(LNotOpMap)/sizeof(unsigned char));
-
- Opc = (BinaryOperator::Opcode) LNotOpMap[idx];
- assert(E->getType(Eng.getContext()) == T);
- E = Eng.getSymbolManager().getSymIntExpr(E->getLHS(), Opc,
- E->getRHS(), T);
- return nonloc::SymExprVal(E);
- }
-
- return UnknownVal();
- }
-
- case nonloc::ConcreteIntKind:
-
- if (isa<nonloc::ConcreteInt>(R)) {
- const nonloc::ConcreteInt& L_CI = cast<nonloc::ConcreteInt>(L);
- const nonloc::ConcreteInt& R_CI = cast<nonloc::ConcreteInt>(R);
- return L_CI.EvalBinOp(BasicVals, Op, R_CI);
- }
- else {
- subkind = R.getSubKind();
- NonLoc tmp = R;
- R = L;
- L = tmp;
-
- // Swap the operators.
- switch (Op) {
- case BinaryOperator::LT: Op = BinaryOperator::GT; break;
- case BinaryOperator::GT: Op = BinaryOperator::LT; break;
- case BinaryOperator::LE: Op = BinaryOperator::GE; break;
- case BinaryOperator::GE: Op = BinaryOperator::LE; break;
- default: break;
- }
-
- continue;
- }
-
- case nonloc::SymbolValKind:
- if (isa<nonloc::ConcreteInt>(R)) {
- ValueManager &ValMgr = Eng.getValueManager();
- return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(L).getSymbol(), Op,
- cast<nonloc::ConcreteInt>(R).getValue(), T);
- }
- else
- return UnknownVal();
- }
- }
-}
-
-
-// Binary Operators (except assignments and comma).
-
-SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
- Loc L, Loc R) {
-
- switch (Op) {
- default:
- return UnknownVal();
- case BinaryOperator::EQ:
- case BinaryOperator::NE:
- return EvalEquality(Eng, L, R, Op == BinaryOperator::EQ);
- }
-}
-
-SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, const GRState *state,
- BinaryOperator::Opcode Op, Loc L, NonLoc R) {
-
- // Special case: 'R' is an integer that has the same width as a pointer and
- // we are using the integer location in a comparison. Normally this cannot be
- // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
- // can generate comparisons that trigger this code.
- // FIXME: Are all locations guaranteed to have pointer width?
- if (BinaryOperator::isEqualityOp(Op)) {
- if (nonloc::ConcreteInt *RInt = dyn_cast<nonloc::ConcreteInt>(&R)) {
- const llvm::APSInt *X = &RInt->getValue();
- ASTContext &C = Eng.getContext();
- if (C.getTypeSize(C.VoidPtrTy) == X->getBitWidth()) {
- // Convert the signedness of the integer (if necessary).
- if (X->isSigned())
- X = &Eng.getBasicVals().getValue(*X, true);
-
- return EvalBinOp(Eng, Op, L, loc::ConcreteInt(*X));
- }
- }
- }
-
- // Delegate pointer arithmetic to store manager.
- return Eng.getStoreManager().EvalBinOp(state, Op, L, R);
-}
-
-// Equality operators for Locs.
-// FIXME: All this logic will be revamped when we have MemRegion::getLocation()
-// implemented.
-
-SVal GRSimpleVals::EvalEquality(GRExprEngine& Eng, Loc L, Loc R, bool isEqual) {
-
- ValueManager& ValMgr = Eng.getValueManager();
-
- switch (L.getSubKind()) {
-
- default:
- assert(false && "EQ/NE not implemented for this Loc.");
- return UnknownVal();
-
- case loc::ConcreteIntKind:
-
- if (isa<loc::ConcreteInt>(R)) {
- bool b = cast<loc::ConcreteInt>(L).getValue() ==
- cast<loc::ConcreteInt>(R).getValue();
-
- // Are we computing '!='? Flip the result.
- if (!isEqual)
- b = !b;
-
- return ValMgr.makeTruthVal(b);
- }
- else if (SymbolRef Sym = R.getAsSymbol()) {
- const SymIntExpr * SE =
- Eng.getSymbolManager().getSymIntExpr(Sym,
- isEqual ? BinaryOperator::EQ
- : BinaryOperator::NE,
- cast<loc::ConcreteInt>(L).getValue(),
- Eng.getContext().IntTy);
- return nonloc::SymExprVal(SE);
- }
-
- break;
-
- case loc::MemRegionKind: {
- if (SymbolRef LSym = L.getAsLocSymbol()) {
- if (isa<loc::ConcreteInt>(R)) {
- const SymIntExpr *SE =
- Eng.getSymbolManager().getSymIntExpr(LSym,
- isEqual ? BinaryOperator::EQ
- : BinaryOperator::NE,
- cast<loc::ConcreteInt>(R).getValue(),
- Eng.getContext().IntTy);
-
- return nonloc::SymExprVal(SE);
- }
- }
- }
-
- // Fall-through.
-
- case loc::GotoLabelKind:
- return ValMgr.makeTruthVal(isEqual ? L == R : L != R);
- }
-
- return ValMgr.makeTruthVal(isEqual ? false : true);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function for function calls.
-//===----------------------------------------------------------------------===//
-
-void GRSimpleVals::EvalCall(ExplodedNodeSet<GRState>& Dst,
- GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
- CallExpr* CE, SVal L,
- ExplodedNode<GRState>* Pred) {
-
- GRStateManager& StateMgr = Eng.getStateManager();
- const GRState* St = Builder.GetState(Pred);
-
- // Invalidate all arguments passed in by reference (Locs).
-
- for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I) {
-
- SVal V = St->getSVal(*I);
-
- if (isa<loc::MemRegionVal>(V)) {
- const MemRegion *R = cast<loc::MemRegionVal>(V).getRegion();
- if (R->isBoundable())
- St = StateMgr.BindLoc(St, cast<Loc>(V), UnknownVal());
- } else if (isa<nonloc::LocAsInteger>(V))
- St = StateMgr.BindLoc(St, cast<nonloc::LocAsInteger>(V).getLoc(),
- UnknownVal());
-
- }
-
- // Make up a symbol for the return value of this function.
- // FIXME: We eventually should handle structs and other compound types
- // that are returned by value.
- QualType T = CE->getType();
- if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
- unsigned Count = Builder.getCurrentBlockCount();
- SVal X = Eng.getValueManager().getConjuredSymbolVal(CE, Count);
- St = St->bindExpr(CE, X, Eng.getCFG().isBlkExpr(CE), false);
- }
-
- Builder.MakeNode(Dst, CE, Pred, St);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function for Objective-C message expressions.
-//===----------------------------------------------------------------------===//
-
-void GRSimpleVals::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
- GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
- ObjCMessageExpr* ME,
- ExplodedNode<GRState>* Pred) {
-
-
- // The basic transfer function logic for message expressions does nothing.
- // We just invalidate all arguments passed in by references.
- const GRState *St = Builder.GetState(Pred);
-
- for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
- I != E; ++I) {
-
- SVal V = St->getSVal(*I);
-
- if (isa<Loc>(V))
- St = St->bindLoc(cast<Loc>(V), UnknownVal());
- }
-
- Builder.MakeNode(Dst, ME, Pred, St);
-}
diff --git a/lib/Analysis/GRSimpleVals.h b/lib/Analysis/GRSimpleVals.h
deleted file mode 100644
index 6ef49dc..0000000
--- a/lib/Analysis/GRSimpleVals.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// GRSimpleVals.h - Transfer functions for tracking simple values -*- C++ -*--//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines GRSimpleVals, a sub-class of GRTransferFuncs that
-// provides transfer functions for performing simple value tracking with
-// limited support for symbolics.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_ANALYSIS_GRSIMPLEVALS
-#define LLVM_CLANG_ANALYSIS_GRSIMPLEVALS
-
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-
-namespace clang {
-
-class PathDiagnostic;
-class ASTContext;
-
-class GRSimpleVals : public GRTransferFuncs {
-protected:
-
- virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng,
- BinaryOperator::Opcode Op,
- NonLoc L, NonLoc R, QualType T);
-
-public:
- GRSimpleVals() {}
- virtual ~GRSimpleVals() {}
-
- // Casts.
-
- virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT);
- virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT);
-
- // Unary Operators.
-
- virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X);
-
- virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X);
-
- // Binary Operators.
-
- virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
- Loc L, Loc R);
-
- // Pointer arithmetic.
-
- virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state,
- BinaryOperator::Opcode Op, Loc L, NonLoc R);
-
- // Calls.
-
- virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
- GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
- CallExpr* CE, SVal L,
- ExplodedNode<GRState>* Pred);
-
- virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
- GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
- ObjCMessageExpr* ME,
- ExplodedNode<GRState>* Pred);
-
-
-
- static void GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
- ExplodedNode<GRState>* N);
-
-protected:
-
- // Equality (==, !=) operators for Locs.
- SVal EvalEquality(GRExprEngine& Engine, Loc L, Loc R, bool isEqual);
-};
-
-} // end clang namespace
-
-#endif
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index a64b2d7..493edc3 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -1,4 +1,4 @@
-//= GRState*cpp - Path-Sens. "State" for tracking valuues -----*- C++ -*--=//
+//= GRState.cpp - Path-Sensitive "State" for tracking values -----*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines SymbolRef, ExprBindKey, and GRState*
+// This file implements GRState and GRStateManager.
//
//===----------------------------------------------------------------------===//
@@ -20,6 +20,7 @@
using namespace clang;
// Give the vtable for ConstraintManager somewhere to live.
+// FIXME: Move this elsewhere.
ConstraintManager::~ConstraintManager() {}
GRStateManager::~GRStateManager() {
@@ -56,16 +57,63 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
SymReaper);
}
-const GRState* GRStateManager::Unbind(const GRState* St, Loc LV) {
- Store OldStore = St->getStore();
- Store NewStore = StoreMgr->Remove(OldStore, LV);
+const GRState *GRState::unbindLoc(Loc LV) const {
+ Store OldStore = getStore();
+ Store NewStore = Mgr->StoreMgr->Remove(OldStore, LV);
if (NewStore == OldStore)
- return St;
+ return this;
- GRState NewSt = *St;
+ GRState NewSt = *this;
NewSt.St = NewStore;
- return getPersistentState(NewSt);
+ return Mgr->getPersistentState(NewSt);
+}
+
+SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const {
+ // We only want to do fetches from regions that we can actually bind
+ // values. For example, SymbolicRegions of type 'id<...>' cannot
+ // have direct bindings (but their can be bindings on their subregions).
+ if (!R->isBoundable())
+ return UnknownVal();
+
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ QualType T = TR->getValueType(Mgr->getContext());
+ if (Loc::IsLocType(T) || T->isIntegerType())
+ return getSVal(R);
+ }
+
+ return UnknownVal();
+}
+
+
+const GRState *GRState::bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr,
+ bool Invalidate) const {
+
+ Environment NewEnv = Mgr->EnvMgr.BindExpr(Env, Ex, V, isBlkExpr, Invalidate);
+
+ if (NewEnv == Env)
+ return this;
+
+ GRState NewSt = *this;
+ NewSt.Env = NewEnv;
+ return Mgr->getPersistentState(NewSt);
+}
+
+const GRState *GRState::bindExpr(const Stmt* Ex, SVal V,
+ bool Invalidate) const {
+
+ bool isBlkExpr = false;
+
+ if (Ex == Mgr->CurrentStmt) {
+ // FIXME: Should this just be an assertion? When would we want to set
+ // the value of a block-level expression if it wasn't CurrentStmt?
+ isBlkExpr = Mgr->cfg.isBlkExpr(Ex);
+
+ if (!isBlkExpr)
+ return this;
+ }
+
+ return bindExpr(Ex, V, isBlkExpr, Invalidate);
}
const GRState* GRStateManager::getInitialState() {
@@ -101,7 +149,8 @@ const GRState* GRState::makeWithStore(Store store) const {
// State pretty-printing.
//===----------------------------------------------------------------------===//
-void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
+void GRState::print(llvm::raw_ostream& Out, const char* nl,
+ const char* sep) const {
// Print the store.
Mgr->getStoreManager().print(getStore(), Out, nl, sep);
@@ -117,9 +166,7 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
else { Out << nl; }
Out << " (" << (void*) I.getKey() << ") ";
- llvm::raw_os_ostream OutS(Out);
- I.getKey()->printPretty(OutS);
- OutS.flush();
+ I.getKey()->printPretty(Out);
Out << " : ";
I.getData().print(Out);
}
@@ -136,9 +183,7 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
else { Out << nl; }
Out << " (" << (void*) I.getKey() << ") ";
- llvm::raw_os_ostream OutS(Out);
- I.getKey()->printPretty(OutS);
- OutS.flush();
+ I.getKey()->printPretty(Out);
Out << " : ";
I.getData().print(Out);
}
@@ -152,12 +197,12 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
}
}
-void GRState::printDOT(std::ostream& Out) const {
+void GRState::printDOT(llvm::raw_ostream& Out) const {
print(Out, "\\l", "\\|");
}
void GRState::printStdErr() const {
- print(*llvm::cerr);
+ print(llvm::errs());
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/GRTransferFuncs.cpp b/lib/Analysis/GRTransferFuncs.cpp
deleted file mode 100644
index 3c14ee9..0000000
--- a/lib/Analysis/GRTransferFuncs.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-//== GRTransferFuncs.cpp - Path-Sens. Transfer Functions Interface -*- C++ -*--=
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines GRTransferFuncs, which provides a base-class that
-// defines an interface for transfer functions used by GRExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-
-using namespace clang;
-
-void GRTransferFuncs::EvalBinOpNN(GRStateSet& OStates,
- GRExprEngine& Eng,
- const GRState *St, Expr* Ex,
- BinaryOperator::Opcode Op,
- NonLoc L, NonLoc R, QualType T) {
-
- OStates.Add(St->bindExpr(Ex, DetermEvalBinOpNN(Eng, Op, L, R, T)));
-}
diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp
index ec96329..a608ce0 100644
--- a/lib/Analysis/PathDiagnostic.cpp
+++ b/lib/Analysis/PathDiagnostic.cpp
@@ -18,7 +18,7 @@
#include "clang/AST/StmtCXX.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Casting.h"
-#include <sstream>
+
using namespace clang;
using llvm::dyn_cast;
using llvm::isa;
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index 73c68bc..079462e 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -200,7 +200,7 @@ public:
return newRanges;
}
- void Print(std::ostream &os) const {
+ void print(llvm::raw_ostream &os) const {
bool isFirst = true;
os << "{ ";
for (iterator i = begin(), e = end(); i != e; ++i) {
@@ -265,7 +265,7 @@ public:
const GRState* RemoveDeadBindings(const GRState* St, SymbolReaper& SymReaper);
- void print(const GRState* St, std::ostream& Out,
+ void print(const GRState* St, llvm::raw_ostream& Out,
const char* nl, const char *sep);
private:
@@ -341,7 +341,7 @@ AssumeX(GE)
// Pretty-printing.
//===------------------------------------------------------------------------===/
-void RangeConstraintManager::print(const GRState* St, std::ostream& Out,
+void RangeConstraintManager::print(const GRState* St, llvm::raw_ostream& Out,
const char* nl, const char *sep) {
ConstraintRangeTy Ranges = St->get<ConstraintRange>();
@@ -353,6 +353,6 @@ void RangeConstraintManager::print(const GRState* St, std::ostream& Out,
for (ConstraintRangeTy::iterator I=Ranges.begin(), E=Ranges.end(); I!=E; ++I){
Out << nl << ' ' << I.getKey() << " : ";
- I.getData().Print(Out);
+ I.getData().print(Out);
}
}
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 77f5b7c..d45048d 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -103,25 +103,6 @@ namespace clang {
}
//===----------------------------------------------------------------------===//
-// Region "killsets".
-//===----------------------------------------------------------------------===//
-//
-// RegionStore lazily adds value bindings to regions when the analyzer handles
-// assignment statements. Killsets track which default values have been
-// killed, thus distinguishing between "unknown" values and default
-// values. Regions are added to killset only when they are assigned "unknown"
-// directly, otherwise we should have their value in the region bindings.
-//
-namespace { class VISIBILITY_HIDDEN RegionKills {}; }
-static int RegionKillsIndex = 0;
-namespace clang {
- template<> struct GRStateTrait<RegionKills>
- : public GRStatePartialTrait< llvm::ImmutableSet<const MemRegion*> > {
- static void* GDMIndex() { return &RegionKillsIndex; }
- };
-}
-
-//===----------------------------------------------------------------------===//
// Regions with default values.
//===----------------------------------------------------------------------===//
//
@@ -238,10 +219,8 @@ public:
CastResult CastRegion(const GRState *state, const MemRegion* R,
QualType CastToTy);
- SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L,NonLoc R);
-
-
-
+ SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L,
+ NonLoc R, QualType resultTy);
Store getInitialStore() { return RBFactory.GetEmptyMap().getRoot(); }
@@ -260,8 +239,6 @@ public:
return SelfRegion;
}
-
-
//===-------------------------------------------------------------------===//
// Binding values to regions.
@@ -306,7 +283,11 @@ public:
/// else
/// return symbolic
SVal Retrieve(const GRState *state, Loc L, QualType T = QualType());
-
+
+ SVal RetrieveElement(const GRState* state, const ElementRegion* R);
+
+ SVal RetrieveField(const GRState* state, const FieldRegion* R);
+
/// Retrieve the values in a struct and return a CompoundVal, used when doing
/// struct copy:
/// struct s x, y;
@@ -352,7 +333,8 @@ public:
return RegionBindingsTy(static_cast<const RegionBindingsTy::TreeTy*>(store));
}
- void print(Store store, std::ostream& Out, const char* nl, const char *sep);
+ void print(Store store, llvm::raw_ostream& Out, const char* nl,
+ const char *sep);
void iterBindings(Store store, BindingsHandler& f) {
// FIXME: Implement.
@@ -740,7 +722,8 @@ RegionStoreManager::CastRegion(const GRState *state, const MemRegion* R,
//===----------------------------------------------------------------------===//
SVal RegionStoreManager::EvalBinOp(const GRState *state,
- BinaryOperator::Opcode Op, Loc L, NonLoc R) {
+ BinaryOperator::Opcode Op, Loc L, NonLoc R,
+ QualType resultTy) {
// Assume the base location is MemRegionVal.
if (!isa<loc::MemRegionVal>(L))
return UnknownVal();
@@ -798,7 +781,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
//
nonloc::ConcreteInt OffConverted(getBasicVals().Convert(Base->getValue(),
Offset->getValue()));
- SVal NewIdx = Base->EvalBinOp(getBasicVals(), Op, OffConverted);
+ SVal NewIdx = Base->evalBinOp(ValMgr, Op, OffConverted);
const MemRegion* NewER =
MRMgr.getElementRegion(ER->getElementType(), NewIdx,ER->getSuperRegion(),
getContext());
@@ -839,6 +822,12 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
const TypedRegion *R = cast<TypedRegion>(MR);
assert(R && "bad region");
+ if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
+ return RetrieveField(state, FR);
+
+ if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
+ return RetrieveElement(state, ER);
+
// FIXME: We should eventually handle funny addressing. e.g.:
//
// int x = ...;
@@ -867,42 +856,6 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
if (V)
return *V;
- // Check if the region is in killset.
- if (state->contains<RegionKills>(R))
- return UnknownVal();
-
- // Check if the region is an element region of a string literal.
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- if (const StringRegion *StrR=dyn_cast<StringRegion>(ER->getSuperRegion())) {
- const StringLiteral *Str = StrR->getStringLiteral();
- SVal Idx = ER->getIndex();
- if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
- int64_t i = CI->getValue().getSExtValue();
- char c;
- if (i == Str->getByteLength())
- c = '\0';
- else
- c = Str->getStrData()[i];
- const llvm::APSInt &V = getBasicVals().getValue(c, getContext().CharTy);
- return nonloc::ConcreteInt(V);
- }
- }
- }
-
- // If the region is an element or field, it may have a default value.
- if (isa<ElementRegion>(R) || isa<FieldRegion>(R)) {
- const MemRegion* SuperR = cast<SubRegion>(R)->getSuperRegion();
- GRStateTrait<RegionDefaultValue>::lookup_type D =
- state->get<RegionDefaultValue>(SuperR);
- if (D) {
- // If the default value is symbolic, we need to create a new symbol.
- if (D->hasConjuredSymbol())
- return ValMgr.getRegionValueSymbolVal(R);
- else
- return *D;
- }
- }
-
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
const MemRegion *SR = IVR->getSuperRegion();
@@ -961,6 +914,97 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
return UnknownVal();
}
+SVal RegionStoreManager::RetrieveElement(const GRState* state,
+ const ElementRegion* R) {
+ // Check if the region has a binding.
+ RegionBindingsTy B = GetRegionBindings(state->getStore());
+ const SVal* V = B.lookup(R);
+ if (V)
+ return *V;
+
+ // Check if the region is an element region of a string literal.
+ if (const StringRegion *StrR=dyn_cast<StringRegion>(R->getSuperRegion())) {
+ const StringLiteral *Str = StrR->getStringLiteral();
+ SVal Idx = R->getIndex();
+ if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
+ int64_t i = CI->getValue().getSExtValue();
+ char c;
+ if (i == Str->getByteLength())
+ c = '\0';
+ else
+ c = Str->getStrData()[i];
+ return ValMgr.makeIntVal(c, getContext().CharTy);
+ }
+ }
+
+ const MemRegion* SuperR = R->getSuperRegion();
+ const SVal* D = state->get<RegionDefaultValue>(SuperR);
+
+ if (D) {
+ if (D->hasConjuredSymbol())
+ return ValMgr.getRegionValueSymbolVal(R);
+ else
+ return *D;
+ }
+
+ if (R->hasHeapOrStackStorage())
+ return UndefinedVal();
+
+ QualType Ty = R->getValueType(getContext());
+
+ // If the region is already cast to another type, use that type to create the
+ // symbol value.
+ if (const QualType *p = state->get<RegionCasts>(R))
+ Ty = (*p)->getAsPointerType()->getPointeeType();
+
+ if (Loc::IsLocType(Ty) || Ty->isIntegerType())
+ return ValMgr.getRegionValueSymbolVal(R, Ty);
+ else
+ return UnknownVal();
+}
+
+SVal RegionStoreManager::RetrieveField(const GRState* state,
+ const FieldRegion* R) {
+ QualType Ty = R->getValueType(getContext());
+
+ // Check if the region has a binding.
+ RegionBindingsTy B = GetRegionBindings(state->getStore());
+ const SVal* V = B.lookup(R);
+ if (V)
+ return *V;
+
+ const MemRegion* SuperR = R->getSuperRegion();
+ const SVal* D = state->get<RegionDefaultValue>(SuperR);
+ if (D) {
+ if (D->hasConjuredSymbol())
+ return ValMgr.getRegionValueSymbolVal(R);
+
+ if (D->isZeroConstant())
+ return ValMgr.makeZeroVal(Ty);
+
+ if (D->isUnknown())
+ return *D;
+
+ assert(0 && "Unknown default value");
+ }
+
+ if (R->hasHeapOrStackStorage())
+ return UndefinedVal();
+
+ // If the region is already cast to another type, use that type to create the
+ // symbol value.
+ if (const QualType *p = state->get<RegionCasts>(R)) {
+ QualType tmp = *p;
+ Ty = tmp->getAsPointerType()->getPointeeType();
+ }
+
+ // All other integer values are symbolic.
+ if (Loc::IsLocType(Ty) || Ty->isIntegerType())
+ return ValMgr.getRegionValueSymbolVal(R, Ty);
+ else
+ return UnknownVal();
+}
+
SVal RegionStoreManager::RetrieveStruct(const GRState *state,
const TypedRegion* R){
QualType T = R->getValueType(getContext());
@@ -1040,12 +1084,7 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
RegionBindingsTy B = GetRegionBindings(state->getStore());
- if (V.isUnknown()) {
- B = RBFactory.Remove(B, R); // Remove the binding.
- state = state->add<RegionKills>(R); // Add the region to the killset.
- }
- else
- B = RBFactory.Add(B, R, V);
+ B = RBFactory.Add(B, R, V);
return state->makeWithStore(B.getRoot());
}
@@ -1127,15 +1166,12 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
state = Bind(state, ValMgr.makeLoc(ER), *VI);
}
- // If the init list is shorter than the array length, bind the rest elements
- // to 0.
- if (ElementTy->isIntegerType()) {
- while (i < Size) {
- SVal Idx = ValMgr.makeIntVal(i);
- ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx,R,getContext());
+ // If the init list is shorter than the array length, set the array default
+ // value.
+ if (i < Size) {
+ if (ElementTy->isIntegerType()) {
SVal V = ValMgr.makeZeroVal(ElementTy);
- state = Bind(state, ValMgr.makeLoc(ER), V);
- ++i;
+ state = setDefaultValue(state, R, V);
}
}
@@ -1186,15 +1222,8 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
}
// There may be fewer values in the initialize list than the fields of struct.
- while (FI != FE) {
- QualType FTy = (*FI)->getType();
- if (FTy->isIntegerType()) {
- FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
- state = Bind(state, ValMgr.makeLoc(FR), ValMgr.makeZeroVal(FTy));
- }
-
- ++FI;
- }
+ if (FI != FE)
+ state = setDefaultValue(state, R, ValMgr.makeIntVal(0, false));
return state;
}
@@ -1202,20 +1231,17 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
const GRState *RegionStoreManager::KillStruct(const GRState *state,
const TypedRegion* R){
- // (1) Kill the struct region because it is assigned "unknown".
- // (2) Set the default value of the struct region to "unknown".
- state = state->add<RegionKills>(R)->set<RegionDefaultValue>(R, UnknownVal());
- Store store = state->getStore();
- RegionBindingsTy B = GetRegionBindings(store);
+ // Set the default value of the struct region to "unknown".
+ state = state->set<RegionDefaultValue>(R, UnknownVal());
// Remove all bindings for the subregions of the struct.
+ Store store = state->getStore();
+ RegionBindingsTy B = GetRegionBindings(store);
for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion* R = I.getKey();
if (const SubRegion* subRegion = dyn_cast<SubRegion>(R))
if (subRegion->isSubRegionOf(R))
store = Remove(store, ValMgr.makeLoc(subRegion));
- // FIXME: Maybe we should also remove the bindings for the "views" of the
- // subregions.
}
return state->makeWithStore(store);
@@ -1427,9 +1453,8 @@ Store RegionStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
// Utility methods.
//===----------------------------------------------------------------------===//
-void RegionStoreManager::print(Store store, std::ostream& Out,
+void RegionStoreManager::print(Store store, llvm::raw_ostream& OS,
const char* nl, const char *sep) {
- llvm::raw_os_ostream OS(Out);
RegionBindingsTy B = GetRegionBindings(store);
OS << "Store:" << nl;
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
index dd9490b..7d1850d 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Analysis/SVals.cpp
@@ -188,12 +188,11 @@ bool SVal::isZeroConstant() const {
// Transfer function dispatch for Non-Locs.
//===----------------------------------------------------------------------===//
-SVal nonloc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
- BinaryOperator::Opcode Op,
- const nonloc::ConcreteInt& R) const {
-
+SVal nonloc::ConcreteInt::evalBinOp(ValueManager &ValMgr,
+ BinaryOperator::Opcode Op,
+ const nonloc::ConcreteInt& R) const {
const llvm::APSInt* X =
- BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue());
+ ValMgr.getBasicValueFactory().EvaluateAPSInt(Op, getValue(), R.getValue());
if (X)
return nonloc::ConcreteInt(*X);
@@ -201,20 +200,13 @@ SVal nonloc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
return UndefinedVal();
}
- // Bitwise-Complement.
-
nonloc::ConcreteInt
-nonloc::ConcreteInt::EvalComplement(BasicValueFactory& BasicVals) const {
- return BasicVals.getValue(~getValue());
+nonloc::ConcreteInt::evalComplement(ValueManager &ValMgr) const {
+ return ValMgr.makeIntVal(~getValue());
}
- // Unary Minus.
-
-nonloc::ConcreteInt
-nonloc::ConcreteInt::EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const {
- assert (U->getType() == U->getSubExpr()->getType());
- assert (U->getType()->isIntegerType());
- return BasicVals.getValue(-getValue());
+nonloc::ConcreteInt nonloc::ConcreteInt::evalMinus(ValueManager &ValMgr) const {
+ return ValMgr.makeIntVal(-getValue());
}
//===----------------------------------------------------------------------===//
@@ -242,11 +234,6 @@ SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
void SVal::printStdErr() const { print(llvm::errs()); }
-void SVal::print(std::ostream& Out) const {
- llvm::raw_os_ostream out(Out);
- print(out);
-}
-
void SVal::print(llvm::raw_ostream& Out) const {
switch (getBaseKind()) {
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
new file mode 100644
index 0000000..76a8bc7
--- /dev/null
+++ b/lib/Analysis/SimpleSValuator.cpp
@@ -0,0 +1,346 @@
+// SimpleSValuator.cpp - A basic SValuator ------------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SimpleSValuator, a basic implementation of SValuator.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/SValuator.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN SimpleSValuator : public SValuator {
+public:
+ SimpleSValuator(ValueManager &valMgr) : SValuator(valMgr) {}
+ virtual ~SimpleSValuator() {}
+
+ virtual SVal EvalCast(NonLoc val, QualType castTy);
+ virtual SVal EvalCast(Loc val, QualType castTy);
+ virtual SVal EvalMinus(NonLoc val);
+ virtual SVal EvalComplement(NonLoc val);
+ virtual SVal EvalBinOpNN(BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs,
+ QualType resultTy);
+ virtual SVal EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
+ QualType resultTy);
+ virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
+ Loc lhs, NonLoc rhs, QualType resultTy);
+};
+} // end anonymous namespace
+
+SValuator *clang::CreateSimpleSValuator(ValueManager &valMgr) {
+ return new SimpleSValuator(valMgr);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for Casts.
+//===----------------------------------------------------------------------===//
+
+SVal SimpleSValuator::EvalCast(NonLoc val, QualType castTy) {
+ if (!isa<nonloc::ConcreteInt>(val))
+ return UnknownVal();
+
+ bool isLocType = Loc::IsLocType(castTy);
+
+ // Only handle casts from integers to integers.
+ if (!isLocType && !castTy->isIntegerType())
+ return UnknownVal();
+
+ llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
+ i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
+ i.extOrTrunc(ValMgr.getContext().getTypeSize(castTy));
+
+ if (isLocType)
+ return ValMgr.makeIntLocVal(i);
+ else
+ return ValMgr.makeIntVal(i);
+}
+
+SVal SimpleSValuator::EvalCast(Loc val, QualType castTy) {
+
+ // Casts from pointers -> pointers, just return the lval.
+ //
+ // Casts from pointers -> references, just return the lval. These
+ // can be introduced by the frontend for corner cases, e.g
+ // casting from va_list* to __builtin_va_list&.
+ //
+ assert(!val.isUnknownOrUndef());
+
+ if (Loc::IsLocType(castTy) || castTy->isReferenceType())
+ return val;
+
+ // FIXME: Handle transparent unions where a value can be "transparently"
+ // lifted into a union type.
+ if (castTy->isUnionType())
+ return UnknownVal();
+
+ assert(castTy->isIntegerType());
+ unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
+
+ if (!isa<loc::ConcreteInt>(val))
+ return ValMgr.makeLocAsInteger(val, BitWidth);
+
+ llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
+ i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
+ i.extOrTrunc(BitWidth);
+ return ValMgr.makeIntVal(i);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for unary operators.
+//===----------------------------------------------------------------------===//
+
+SVal SimpleSValuator::EvalMinus(NonLoc val) {
+ switch (val.getSubKind()) {
+ case nonloc::ConcreteIntKind:
+ return cast<nonloc::ConcreteInt>(val).evalMinus(ValMgr);
+ default:
+ return UnknownVal();
+ }
+}
+
+SVal SimpleSValuator::EvalComplement(NonLoc X) {
+ switch (X.getSubKind()) {
+ case nonloc::ConcreteIntKind:
+ return cast<nonloc::ConcreteInt>(X).evalComplement(ValMgr);
+ default:
+ return UnknownVal();
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for binary operators.
+//===----------------------------------------------------------------------===//
+
+static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
+ switch (op) {
+ default:
+ assert(false && "Invalid opcode.");
+ case BinaryOperator::LT: return BinaryOperator::GE;
+ case BinaryOperator::GT: return BinaryOperator::LE;
+ case BinaryOperator::LE: return BinaryOperator::GT;
+ case BinaryOperator::GE: return BinaryOperator::LT;
+ case BinaryOperator::EQ: return BinaryOperator::NE;
+ case BinaryOperator::NE: return BinaryOperator::EQ;
+ }
+}
+
+// Equality operators for Locs.
+// FIXME: All this logic will be revamped when we have MemRegion::getLocation()
+// implemented.
+
+static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual,
+ QualType resultTy) {
+
+ switch (lhs.getSubKind()) {
+ default:
+ assert(false && "EQ/NE not implemented for this Loc.");
+ return UnknownVal();
+
+ case loc::ConcreteIntKind: {
+ if (SymbolRef rSym = rhs.getAsSymbol())
+ return ValMgr.makeNonLoc(rSym,
+ isEqual ? BinaryOperator::EQ
+ : BinaryOperator::NE,
+ cast<loc::ConcreteInt>(lhs).getValue(),
+ resultTy);
+ break;
+ }
+ case loc::MemRegionKind: {
+ if (SymbolRef lSym = lhs.getAsLocSymbol()) {
+ if (isa<loc::ConcreteInt>(rhs)) {
+ return ValMgr.makeNonLoc(lSym,
+ isEqual ? BinaryOperator::EQ
+ : BinaryOperator::NE,
+ cast<loc::ConcreteInt>(rhs).getValue(),
+ resultTy);
+ }
+ }
+ break;
+ }
+
+ case loc::GotoLabelKind:
+ break;
+ }
+
+ return ValMgr.makeTruthVal(isEqual ? lhs == rhs : lhs != rhs, resultTy);
+}
+
+SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
+ NonLoc lhs, NonLoc rhs,
+ QualType resultTy) {
+ while (1) {
+ switch (lhs.getSubKind()) {
+ default:
+ return UnknownVal();
+ case nonloc::LocAsIntegerKind: {
+ Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
+ switch (rhs.getSubKind()) {
+ case nonloc::LocAsIntegerKind:
+ return EvalBinOpLL(op, lhsL, cast<nonloc::LocAsInteger>(rhs).getLoc(),
+ resultTy);
+ case nonloc::ConcreteIntKind: {
+ // Transform the integer into a location and compare.
+ ASTContext& Ctx = ValMgr.getContext();
+ llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue();
+ i.setIsUnsigned(true);
+ i.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
+ return EvalBinOpLL(op, lhsL, ValMgr.makeLoc(i), resultTy);
+ }
+ default:
+ switch (op) {
+ case BinaryOperator::EQ:
+ return ValMgr.makeTruthVal(false, resultTy);
+ case BinaryOperator::NE:
+ return ValMgr.makeTruthVal(true, resultTy);
+ default:
+ // This case also handles pointer arithmetic.
+ return UnknownVal();
+ }
+ }
+ }
+ case nonloc::SymExprValKind: {
+ // Logical not?
+ if (!(op == BinaryOperator::EQ && rhs.isZeroConstant()))
+ return UnknownVal();
+
+ const SymExpr *symExpr =
+ cast<nonloc::SymExprVal>(lhs).getSymbolicExpression();
+
+ // Only handle ($sym op constant) for now.
+ if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(symExpr)) {
+ BinaryOperator::Opcode opc = symIntExpr->getOpcode();
+ switch (opc) {
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ assert(false && "Logical operators handled by branching logic.");
+ return UnknownVal();
+ case BinaryOperator::Assign:
+ case BinaryOperator::MulAssign:
+ case BinaryOperator::DivAssign:
+ case BinaryOperator::RemAssign:
+ case BinaryOperator::AddAssign:
+ case BinaryOperator::SubAssign:
+ case BinaryOperator::ShlAssign:
+ case BinaryOperator::ShrAssign:
+ case BinaryOperator::AndAssign:
+ case BinaryOperator::XorAssign:
+ case BinaryOperator::OrAssign:
+ case BinaryOperator::Comma:
+ assert(false && "'=' and ',' operators handled by GRExprEngine.");
+ return UnknownVal();
+ case BinaryOperator::PtrMemD:
+ case BinaryOperator::PtrMemI:
+ assert(false && "Pointer arithmetic not handled here.");
+ return UnknownVal();
+ case BinaryOperator::Mul:
+ case BinaryOperator::Div:
+ case BinaryOperator::Rem:
+ case BinaryOperator::Add:
+ case BinaryOperator::Sub:
+ case BinaryOperator::Shl:
+ case BinaryOperator::Shr:
+ case BinaryOperator::And:
+ case BinaryOperator::Xor:
+ case BinaryOperator::Or:
+ // Not handled yet.
+ return UnknownVal();
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ opc = NegateComparison(opc);
+ assert(symIntExpr->getType(ValMgr.getContext()) == resultTy);
+ return ValMgr.makeNonLoc(symIntExpr->getLHS(), opc,
+ symIntExpr->getRHS(), resultTy);
+ }
+ }
+ }
+ case nonloc::ConcreteIntKind: {
+ if (isa<nonloc::ConcreteInt>(rhs)) {
+ const nonloc::ConcreteInt& lhsInt = cast<nonloc::ConcreteInt>(lhs);
+ return lhsInt.evalBinOp(ValMgr, op, cast<nonloc::ConcreteInt>(rhs));
+ }
+ else {
+ // Swap the left and right sides and flip the operator if doing so
+ // allows us to better reason about the expression (this is a form
+ // of expression canonicalization).
+ NonLoc tmp = rhs;
+ rhs = lhs;
+ lhs = tmp;
+
+ switch (op) {
+ case BinaryOperator::LT: op = BinaryOperator::GT; continue;
+ case BinaryOperator::GT: op = BinaryOperator::LT; continue;
+ case BinaryOperator::LE: op = BinaryOperator::GE; continue;
+ case BinaryOperator::GE: op = BinaryOperator::LE; continue;
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ case BinaryOperator::Add:
+ case BinaryOperator::Mul:
+ continue;
+ default:
+ return UnknownVal();
+ }
+ }
+ }
+ case nonloc::SymbolValKind: {
+ if (isa<nonloc::ConcreteInt>(rhs)) {
+ return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(lhs).getSymbol(), op,
+ cast<nonloc::ConcreteInt>(rhs).getValue(),
+ resultTy);
+ }
+
+ return UnknownVal();
+ }
+ }
+ }
+}
+
+SVal SimpleSValuator::EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
+ QualType resultTy) {
+ switch (op) {
+ default:
+ return UnknownVal();
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ return EvalEquality(ValMgr, lhs, rhs, op == BinaryOperator::EQ, resultTy);
+ }
+}
+
+SVal SimpleSValuator::EvalBinOpLN(const GRState *state,
+ BinaryOperator::Opcode op,
+ Loc lhs, NonLoc rhs, QualType resultTy) {
+ // Special case: 'rhs' is an integer that has the same width as a pointer and
+ // we are using the integer location in a comparison. Normally this cannot be
+ // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
+ // can generate comparisons that trigger this code.
+ // FIXME: Are all locations guaranteed to have pointer width?
+ if (BinaryOperator::isEqualityOp(op)) {
+ if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
+ const llvm::APSInt *x = &rhsInt->getValue();
+ ASTContext &ctx = ValMgr.getContext();
+ if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) {
+ // Convert the signedness of the integer (if necessary).
+ if (x->isSigned())
+ x = &ValMgr.getBasicValueFactory().getValue(*x, true);
+
+ return EvalBinOpLL(op, lhs, loc::ConcreteInt(*x), resultTy);
+ }
+ }
+ }
+
+ // Delegate pointer arithmetic to the StoreManager.
+ return state->getStateManager().getStoreManager().EvalBinOp(state, op, lhs,
+ rhs, resultTy);
+}
diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp
index 4e38a34..275f30a 100644
--- a/lib/Analysis/SymbolManager.cpp
+++ b/lib/Analysis/SymbolManager.cpp
@@ -85,12 +85,6 @@ llvm::raw_ostream& llvm::operator<<(llvm::raw_ostream& os, const SymExpr *SE) {
return os;
}
-std::ostream& std::operator<<(std::ostream& os, const SymExpr *SE) {
- llvm::raw_os_ostream O(os);
- print(O, SE);
- return os;
-}
-
const SymbolRegionValue*
SymbolManager::getRegionValueSymbol(const MemRegion* R, QualType T) {
llvm::FoldingSetNodeID profile;
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index cf78da98..d13ffa3 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -66,7 +66,8 @@ namespace {
KEYCXX = 4,
KEYCXX0X = 8,
KEYGNU = 16,
- KEYMS = 32
+ KEYMS = 32,
+ BOOLSUPPORT = 64
};
}
@@ -88,6 +89,7 @@ static void AddKeyword(const char *Keyword, unsigned KWLen,
else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1;
else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1;
+ else if (LangOpts.OpenCL && (Flags & BOOLSUPPORT)) AddResult = 2;
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 23a01c9..6640c61 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -943,7 +943,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
return SourceLocation();
unsigned FilePos = Content->SourceLineCache[Line - 1];
- const char *Buf = Content->getBuffer()->getBufferStart();
+ const char *Buf = Content->getBuffer()->getBufferStart() + FilePos;
unsigned BufLength = Content->getBuffer()->getBufferEnd() - Buf;
unsigned i = 0;
@@ -957,6 +957,107 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
getFileLocWithOffset(FilePos + Col - 1);
}
+/// \brief Determines the order of 2 source locations in the translation unit.
+///
+/// \returns true if LHS source location comes before RHS, false otherwise.
+bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
+ SourceLocation RHS) const {
+ assert(LHS.isValid() && RHS.isValid() && "Passed invalid source location!");
+ if (LHS == RHS)
+ return false;
+
+ std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
+ std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
+
+ // If the source locations are in the same file, just compare offsets.
+ if (LOffs.first == ROffs.first)
+ return LOffs.second < ROffs.second;
+
+ // If we are comparing a source location with multiple locations in the same
+ // file, we get a big win by caching the result.
+
+ if (LastLFIDForBeforeTUCheck == LOffs.first &&
+ LastRFIDForBeforeTUCheck == ROffs.first)
+ return LastResForBeforeTUCheck;
+
+ LastLFIDForBeforeTUCheck = LOffs.first;
+ LastRFIDForBeforeTUCheck = ROffs.first;
+
+ // "Traverse" the include/instantiation stacks of both locations and try to
+ // find a common "ancestor".
+ //
+ // First we traverse the stack of the right location and check each level
+ // against the level of the left location, while collecting all levels in a
+ // "stack map".
+
+ std::map<FileID, unsigned> ROffsMap;
+ ROffsMap[ROffs.first] = ROffs.second;
+
+ while (1) {
+ SourceLocation UpperLoc;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(ROffs.first);
+ if (Entry.isInstantiation())
+ UpperLoc = Entry.getInstantiation().getInstantiationLocStart();
+ else
+ UpperLoc = Entry.getFile().getIncludeLoc();
+
+ if (UpperLoc.isInvalid())
+ break; // We reached the top.
+
+ ROffs = getDecomposedLoc(UpperLoc);
+
+ if (LOffs.first == ROffs.first)
+ return LastResForBeforeTUCheck = LOffs.second < ROffs.second;
+
+ ROffsMap[ROffs.first] = ROffs.second;
+ }
+
+ // We didn't find a common ancestor. Now traverse the stack of the left
+ // location, checking against the stack map of the right location.
+
+ while (1) {
+ SourceLocation UpperLoc;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(LOffs.first);
+ if (Entry.isInstantiation())
+ UpperLoc = Entry.getInstantiation().getInstantiationLocStart();
+ else
+ UpperLoc = Entry.getFile().getIncludeLoc();
+
+ if (UpperLoc.isInvalid())
+ break; // We reached the top.
+
+ LOffs = getDecomposedLoc(UpperLoc);
+
+ std::map<FileID, unsigned>::iterator I = ROffsMap.find(LOffs.first);
+ if (I != ROffsMap.end())
+ return LastResForBeforeTUCheck = LOffs.second < I->second;
+ }
+
+ // No common ancestor.
+ // Now we are getting into murky waters. Most probably this is because one
+ // location is in the predefines buffer.
+
+ const FileEntry *LEntry =
+ getSLocEntry(LOffs.first).getFile().getContentCache()->Entry;
+ const FileEntry *REntry =
+ getSLocEntry(ROffs.first).getFile().getContentCache()->Entry;
+
+ // If the locations are in two memory buffers we give up, we can't answer
+ // which one should be considered first.
+ // FIXME: Should there be a way to "include" memory buffers in the translation
+ // unit ?
+ assert((LEntry != 0 || REntry != 0) && "Locations in memory buffers.");
+ (void) REntry;
+
+ // Consider the memory buffer as coming before the file in the translation
+ // unit.
+ if (LEntry == 0)
+ return LastResForBeforeTUCheck = true;
+ else {
+ assert(REntry == 0 && "Locations in not #included files ?");
+ return LastResForBeforeTUCheck = false;
+ }
+}
/// PrintStats - Print statistics to stderr.
///
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 1d69e4e..9910e28 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -930,7 +930,7 @@ public:
WindowsX86_32TargetInfo(const std::string& triple)
: X86_32TargetInfo(triple) {
TLSSupported = false;
- WCharType = SignedShort;
+ WCharType = UnsignedShort;
WCharWidth = WCharAlign = 16;
DoubleAlign = LongLongAlign = 64;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index a2b8d13..5e872c2 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -50,24 +50,6 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
/// one if necessary. This returns null for invalid source locations.
llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
-
- // Each input file is encoded as a separate compile unit in LLVM
- // debugging information output. However, many target specific tool chains
- // prefer to encode only one compile unit in an object file. In this
- // situation, the LLVM code generator will include debugging information
- // entities in the compile unit that is marked as main compile unit. The
- // code generator accepts maximum one main compile unit per module. If a
- // module does not contain any main compile unit then the code generator
- // will emit multiple compile units in the output object file. Create main
- // compile unit if there is not one available.
- const LangOptions &LO = M->getLangOptions();
- if (isMainCompileUnitCreated == false) {
- if (LO.getMainFileName()) {
- createCompileUnit(LO.getMainFileName(), true /* isMain */);
- isMainCompileUnitCreated = true;
- }
- }
-
// Get source file information.
const char *FileName = "<unknown>";
SourceManager &SM = M->getContext().getSourceManager();
@@ -90,26 +72,25 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
AbsFileName = tmp;
}
- // There is only one main source file at a time whose compile unit
- // is already created.
- Unit = createCompileUnit(FileName, false /* isMain */);
- return Unit;
-}
-
-/// createCompileUnit - Create a new unit for the given file.
-llvm::DICompileUnit CGDebugInfo::createCompileUnit(const char *FileName,
- bool isMain) {
-
- // Get absolute path name.
- llvm::sys::Path AbsFileName(FileName);
- if (!AbsFileName.isAbsolute()) {
- llvm::sys::Path tmp = llvm::sys::Path::GetCurrentDirectory();
- tmp.appendComponent(FileName);
- AbsFileName = tmp;
+ // See if thie compile unit is representing main source file. Each source
+ // file has corresponding compile unit. There is only one main source
+ // file at a time.
+ bool isMain = false;
+ const LangOptions &LO = M->getLangOptions();
+ const char *MainFileName = LO.getMainFileName();
+ if (isMainCompileUnitCreated == false) {
+ if (MainFileName) {
+ if (!strcmp(AbsFileName.getLast().c_str(), MainFileName))
+ isMain = true;
+ } else {
+ if (Loc.isValid() && SM.isFromMainFile(Loc))
+ isMain = true;
+ }
+ if (isMain)
+ isMainCompileUnitCreated = true;
}
unsigned LangTag;
- const LangOptions &LO = M->getLangOptions();
if (LO.CPlusPlus) {
if (LO.ObjC1)
LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus;
@@ -133,13 +114,12 @@ llvm::DICompileUnit CGDebugInfo::createCompileUnit(const char *FileName,
RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1;
// Create new compile unit.
- return DebugFactory.CreateCompileUnit(LangTag, AbsFileName.getLast(),
- AbsFileName.getDirname(),
- Producer, isMain, isOptimized,
- Flags, RuntimeVers);
+ return Unit = DebugFactory.CreateCompileUnit(LangTag, AbsFileName.getLast(),
+ AbsFileName.getDirname(),
+ Producer, isMain, isOptimized,
+ Flags, RuntimeVers);
}
-
/// CreateType - Get the Basic type from the cache or create a new
/// one if necessary.
llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT,
@@ -810,6 +790,9 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
case Type::TypeOf:
return Slot = getOrCreateType(cast<TypeOfType>(Ty)->getUnderlyingType(),
Unit);
+ case Type::Decltype:
+ return Slot = getOrCreateType(cast<DecltypeType>(Ty)->getUnderlyingExpr()
+ ->getType(), Unit);
}
return Slot;
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 8f3368e..de65580 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -111,9 +111,7 @@ private:
void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
CGBuilderTy &Builder);
- /// createCompileUnit - Create a new unit for the given file.
- llvm::DICompileUnit createCompileUnit(const char *FileName, bool isMain);
-
+
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a
/// new one if necessary.
llvm::DICompileUnit getOrCreateCompileUnit(SourceLocation Loc);
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 4e603c3..f97c62f 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -234,7 +234,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(QualType Ty,
}
// FIXME: Align this on at least an Align boundary, assert if we can't.
assert((Align <= unsigned(Target.getPointerAlign(0))/8)
- && "Can't align more thqn pointer yet");
+ && "Can't align more than pointer yet");
Types[needsCopyDispose*2 + 4] = LTy;
return llvm::StructType::get(Types, false);
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 51c5b3d..a211407 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -606,11 +606,12 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
cast<llvm::VectorType>(Vec->getType())->getNumElements();
if (NumDstElts == NumSrcElts) {
// Use shuffle vector is the src and destination are the same number
- // of elements
- llvm::SmallVector<llvm::Constant*, 4> Mask;
+ // of elements and restore the vector mask since it is on the side
+ // it will be stored.
+ llvm::SmallVector<llvm::Constant*, 4> Mask(NumDstElts);
for (unsigned i = 0; i != NumSrcElts; ++i) {
unsigned InIdx = getAccessedFieldNo(i, Elts);
- Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx));
+ Mask[InIdx] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
}
llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 912479f..4f96b8b 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -139,6 +139,7 @@ public:
const ObjCProtocolDecl *PD);
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Function *ModuleInitFunction();
+ virtual void MergeMetadataGlobals(std::vector<llvm::Constant*> &UsedArray);
virtual llvm::Function *GetPropertyGetFunction();
virtual llvm::Function *GetPropertySetFunction();
virtual llvm::Function *EnumerationMutationFunction();
@@ -998,6 +999,10 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
Classes.push_back(ClassStruct);
}
+void CGObjCGNU::MergeMetadataGlobals(
+ std::vector<llvm::Constant*> &UsedArray) {
+}
+
llvm::Function *CGObjCGNU::ModuleInitFunction() {
// Only emit an ObjC load function if no Objective-C stuff has been called
if (Classes.empty() && Categories.empty() && ConstantStrings.empty() &&
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 6ffca81..865e8c2 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -911,6 +911,8 @@ protected:
const CallArgList &CallArgs,
const ObjCCommonTypesHelper &ObjCTypes);
+ virtual void MergeMetadataGlobals(std::vector<llvm::Constant*> &UsedArray);
+
public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm)
{ }
@@ -3426,6 +3428,16 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
NameOut += ']';
}
+void CGObjCCommonMac::MergeMetadataGlobals(
+ std::vector<llvm::Constant*> &UsedArray) {
+ llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(),
+ e = UsedGlobals.end(); i != e; ++i) {
+ UsedArray.push_back(llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(*i),
+ i8PTy));
+ }
+}
+
void CGObjCMac::FinishModule() {
EmitModuleInfo();
@@ -3447,22 +3459,6 @@ void CGObjCMac::FinishModule() {
Values));
}
- std::vector<llvm::Constant*> Used;
- for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(),
- e = UsedGlobals.end(); i != e; ++i) {
- Used.push_back(llvm::ConstantExpr::getBitCast(*i, ObjCTypes.Int8PtrTy));
- }
-
- llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy, Used.size());
- llvm::GlobalValue *GV =
- new llvm::GlobalVariable(AT, false,
- llvm::GlobalValue::AppendingLinkage,
- llvm::ConstantArray::get(AT, Used),
- "llvm.used",
- &CGM.getModule());
-
- GV->setSection("llvm.metadata");
-
// Add assembler directives to add lazy undefined symbol references
// for classes which are referenced but not defined. This is
// important for correct linker interaction.
@@ -4111,24 +4107,6 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
IMGV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip");
IMGV->setConstant(true);
UsedGlobals.push_back(IMGV);
-
- std::vector<llvm::Constant*> Used;
-
- for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(),
- e = UsedGlobals.end(); i != e; ++i) {
- Used.push_back(llvm::ConstantExpr::getBitCast(*i, ObjCTypes.Int8PtrTy));
- }
-
- llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy, Used.size());
- llvm::GlobalValue *GV =
- new llvm::GlobalVariable(AT, false,
- llvm::GlobalValue::AppendingLinkage,
- llvm::ConstantArray::get(AT, Used),
- "llvm.used",
- &CGM.getModule());
-
- GV->setSection("llvm.metadata");
-
}
/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
@@ -5036,16 +5014,13 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
}
}
else if (!IsSuper && ResultType->isFloatingType()) {
- if (const BuiltinType *BT = ResultType->getAsBuiltinType()) {
- BuiltinType::Kind k = BT->getKind();
- if (k == BuiltinType::LongDouble) {
- Fn = ObjCTypes.getMessageSendFpretFixupFn();
- Name += "objc_msgSend_fpret_fixup";
- }
- else {
- Fn = ObjCTypes.getMessageSendFixupFn();
- Name += "objc_msgSend_fixup";
- }
+ if (ResultType->isSpecificBuiltinType(BuiltinType::LongDouble)) {
+ Fn = ObjCTypes.getMessageSendFpretFixupFn();
+ Name += "objc_msgSend_fpret_fixup";
+ }
+ else {
+ Fn = ObjCTypes.getMessageSendFixupFn();
+ Name += "objc_msgSend_fixup";
}
}
else {
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index b8cf026..0f9cf06 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -95,6 +95,9 @@ public:
/// this compilation unit with the runtime library.
virtual llvm::Function *ModuleInitFunction() = 0;
+ /// Add metadata globals to the 'used' globals for final output.
+ virtual void MergeMetadataGlobals(std::vector<llvm::Constant*> &UsedArray) = 0;
+
/// Get a selector for the specified name and type values. The
/// return value should have the LLVM type for pointer-to
/// ASTContext::getObjCSelType().
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f926c05..0a531e9 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -406,11 +406,12 @@ void CodeGenModule::AddUsedGlobal(llvm::GlobalValue *GV) {
void CodeGenModule::EmitLLVMUsed() {
// Don't create llvm.used if there is no need.
- if (LLVMUsed.empty())
+ // FIXME. Runtime indicates that there might be more 'used' symbols; but not
+ // necessariy. So, this test is not accurate for emptiness.
+ if (LLVMUsed.empty() && !Runtime)
return;
llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
- llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, LLVMUsed.size());
// Convert LLVMUsed to what ConstantArray needs.
std::vector<llvm::Constant*> UsedArray;
@@ -420,6 +421,12 @@ void CodeGenModule::EmitLLVMUsed() {
llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(&*LLVMUsed[i]), i8PTy);
}
+ if (Runtime)
+ Runtime->MergeMetadataGlobals(UsedArray);
+ if (UsedArray.empty())
+ return;
+ llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, UsedArray.size());
+
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(ATy, false,
llvm::GlobalValue::AppendingLinkage,
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 24e441a..b5ad5ac 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -539,6 +539,9 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
assert(false &&
"Overloaded and dependent types shouldn't get to name mangling");
break;
+ case BuiltinType::UndeducedAuto:
+ assert(0 && "Should not see undeduced auto here");
+ break;
}
}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index a7fbcda..8143263 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -113,14 +113,10 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
break;
case PCHReader::Failure:
- // Unrecoverable failure: don't even try to process the input
- // file.
+ case PCHReader::IgnorePCH:
if (ErrMsg)
*ErrMsg = "Could not load PCH file";
return NULL;
-
- case PCHReader::IgnorePCH:
- assert(0 && "Is there a validation that should not have happened ?");
}
// PCH loaded successfully. Now create the preprocessor.
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index ae90594..d8fa141 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -469,10 +469,6 @@ static void ActionCheckerCFRef(AnalysisManager& mgr) {
}
}
-static void ActionCheckerSimple(AnalysisManager& mgr) {
- ActionGRExprEngine(mgr, MakeGRSimpleValsTF());
-}
-
static void ActionDisplayLiveVariables(AnalysisManager& mgr) {
if (LiveVariables* L = mgr.getLiveVariables()) {
mgr.DisplayFunction();
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 4ba39c9..f8d09db 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangFrontend
AnalysisConsumer.cpp
ASTConsumers.cpp
+ ASTUnit.cpp
Backend.cpp
CacheTokens.cpp
DeclXML.cpp
@@ -25,6 +26,7 @@ add_clang_library(clangFrontend
PlistDiagnostics.cpp
PrintParserCallbacks.cpp
PrintPreprocessedOutput.cpp
+ ResolveLocation.cpp
RewriteBlocks.cpp
RewriteMacros.cpp
RewriteObjC.cpp
@@ -36,4 +38,7 @@ add_clang_library(clangFrontend
Warnings.cpp
)
-add_dependencies(clangFrontend ClangDiagnosticFrontend)
+add_dependencies(clangFrontend
+ ClangDiagnosticFrontend
+ ClangDiagnosticLex
+ ClangDiagnosticSema)
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 96f21f1..765655b 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -71,6 +71,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_BENIGN(WritableStrings);
PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
diag::warn_pch_lax_vector_conversions);
+ PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec);
PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime);
PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding);
@@ -105,6 +106,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
}
PARSE_LANGOPT_BENIGN(getVisibilityMode());
PARSE_LANGOPT_BENIGN(InstantiationDepth);
+ PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl);
#undef PARSE_LANGOPT_IRRELEVANT
#undef PARSE_LANGOPT_BENIGN
@@ -1629,6 +1631,7 @@ bool PCHReader::ParseLanguageOptions(
PARSE_LANGOPT(PascalStrings);
PARSE_LANGOPT(WritableStrings);
PARSE_LANGOPT(LaxVectorConversions);
+ PARSE_LANGOPT(AltiVec);
PARSE_LANGOPT(Exceptions);
PARSE_LANGOPT(NeXTRuntime);
PARSE_LANGOPT(Freestanding);
@@ -1652,6 +1655,7 @@ bool PCHReader::ParseLanguageOptions(
LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx]);
++Idx;
PARSE_LANGOPT(InstantiationDepth);
+ PARSE_LANGOPT(OpenCL);
#undef PARSE_LANGOPT
return Listener->ReadLanguageOptions(LangOpts);
@@ -1822,7 +1826,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
QualType UnderlyingType = GetType(Record[0]);
return Context->getTypeOfType(UnderlyingType);
}
-
+
+ case pch::TYPE_DECLTYPE:
+ return Context->getDecltypeType(ReadTypeExpr());
+
case pch::TYPE_RECORD:
assert(Record.size() == 1 && "incorrect encoding of record type");
return Context->getTypeDeclType(cast<RecordDecl>(GetDecl(Record[0])));
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 3dd84c7..3f6ae35 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -489,6 +489,14 @@ Attr *PCHReader::ReadAttributes() {
New = ::new (*Context) NonNullAttr(ArgNums.data(), Size);
break;
}
+
+ case Attr::ReqdWorkGroupSize: {
+ unsigned X = Record[Idx++];
+ unsigned Y = Record[Idx++];
+ unsigned Z = Record[Idx++];
+ New = ::new (*Context) ReqdWorkGroupSizeAttr(X, Y, Z);
+ break;
+ }
SIMPLE_ATTR(ObjCException);
SIMPLE_ATTR(ObjCNSObject);
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 3b1eb08..e93219e 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -185,6 +185,11 @@ void PCHTypeWriter::VisitTypeOfType(const TypeOfType *T) {
Code = pch::TYPE_TYPEOF;
}
+void PCHTypeWriter::VisitDecltypeType(const DecltypeType *T) {
+ Writer.AddStmt(T->getUnderlyingExpr());
+ Code = pch::TYPE_DECLTYPE;
+}
+
void PCHTypeWriter::VisitTagType(const TagType *T) {
Writer.AddDeclRef(T->getDecl(), Record);
assert(!T->isBeingDefined() &&
@@ -526,6 +531,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
Record.push_back(LangOpts.WritableStrings); // Allow writable strings
Record.push_back(LangOpts.LaxVectorConversions);
+ Record.push_back(LangOpts.AltiVec);
Record.push_back(LangOpts.Exceptions); // Support exception handling.
Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime.
@@ -563,6 +569,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.getGCMode());
Record.push_back(LangOpts.getVisibilityMode());
Record.push_back(LangOpts.InstantiationDepth);
+ Record.push_back(LangOpts.OpenCL);
Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record);
}
@@ -1615,6 +1622,12 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
case Attr::Regparm:
Record.push_back(cast<RegparmAttr>(Attr)->getNumParams());
break;
+
+ case Attr::ReqdWorkGroupSize:
+ Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getXDim());
+ Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getYDim());
+ Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getZDim());
+ break;
case Attr::Section:
AddString(cast<SectionAttr>(Attr)->getName(), Record);
@@ -1896,6 +1909,9 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
case BuiltinType::NullPtr: ID = pch::PREDEF_TYPE_NULLPTR_ID; break;
case BuiltinType::Overload: ID = pch::PREDEF_TYPE_OVERLOAD_ID; break;
case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break;
+ case BuiltinType::UndeducedAuto:
+ assert(0 && "Should not see undeduced auto here");
+ break;
}
Record.push_back((ID << 3) | T.getCVRQualifiers());
diff --git a/lib/Frontend/ResolveLocation.cpp b/lib/Frontend/ResolveLocation.cpp
new file mode 100644
index 0000000..a5f0d1f
--- /dev/null
+++ b/lib/Frontend/ResolveLocation.cpp
@@ -0,0 +1,322 @@
+//===--- ResolveLocation.cpp - Source location resolver ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines the ResolveLocationInAST function, which resolves a
+// source location into a <Decl *, Stmt *> pair.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+
+namespace {
+
+/// \brief Base for the LocResolver classes. Mostly does source range checking.
+class VISIBILITY_HIDDEN LocResolverBase {
+protected:
+ ASTContext &Ctx;
+ SourceLocation Loc;
+
+ Decl *Dcl;
+ Stmt *Stm;
+ bool PassedLoc;
+
+ /// \brief Checks whether Loc is in the source range of 'D'.
+ ///
+ /// If it is, updates Dcl. If Loc is passed the source range, it sets
+ /// PassedLoc, otherwise it does nothing.
+ void CheckRange(Decl *D);
+
+ /// \brief Checks whether Loc is in the source range of 'Node'.
+ ///
+ /// If it is, updates Stm. If Loc is passed the source range, it sets
+ /// PassedLoc, otherwise it does nothing.
+ void CheckRange(Stmt *Node);
+
+ /// \brief Updates the end source range to cover the full length of the token
+ /// positioned at the end of the source range.
+ ///
+ /// e.g.,
+ /// @code
+ /// int foo
+ /// ^ ^
+ /// @endcode
+ /// will be updated to
+ /// @code
+ /// int foo
+ /// ^ ^
+ /// @endcode
+ void FixRange(SourceRange &Range);
+
+public:
+ LocResolverBase(ASTContext &ctx, SourceLocation loc)
+ : Ctx(ctx), Loc(loc), Dcl(0), Stm(0), PassedLoc(0) {}
+
+ /// \brief We found a AST node that corresponds to the source location.
+ bool FoundIt() const { return Dcl != 0 || Stm != 0; }
+
+ /// \brief We either found a AST node or we passed the source location while
+ /// searching.
+ bool Finished() const { return FoundIt() || PassedLoc; }
+
+ Decl *getDecl() const { return Dcl; }
+ Stmt *getStmt() const { return Stm; }
+
+ std::pair<Decl *, Stmt *> getResult() const {
+ return std::make_pair(getDecl(), getStmt());
+ }
+
+ /// \brief Debugging output.
+ void print(Decl *D);
+ /// \brief Debugging output.
+ void print(Stmt *Node);
+};
+
+/// \brief Searches a statement for the AST node that corresponds to a source
+/// location.
+class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
+ public StmtVisitor<StmtLocResolver> {
+public:
+ StmtLocResolver(ASTContext &ctx, SourceLocation loc)
+ : LocResolverBase(ctx, loc) {}
+
+ void VisitDeclStmt(DeclStmt *Node);
+ void VisitStmt(Stmt *Node);
+};
+
+/// \brief Searches a declaration for the AST node that corresponds to a source
+/// location.
+class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
+ public DeclVisitor<DeclLocResolver> {
+public:
+ DeclLocResolver(ASTContext &ctx, SourceLocation loc)
+ : LocResolverBase(ctx, loc) {}
+
+ void VisitDeclContext(DeclContext *DC);
+ void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
+ void VisitVarDecl(VarDecl *D);
+ void VisitFunctionDecl(FunctionDecl *D);
+ void VisitDecl(Decl *D);
+};
+
+} // anonymous namespace
+
+void StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
+ CheckRange(Node);
+ if (!FoundIt())
+ return;
+ assert(Stm == Node && "Result not updated ?");
+
+ // Search all declarations of this DeclStmt. If we found the one corresponding
+ // to the source location, update this StmtLocResolver's result.
+ DeclLocResolver DLR(Ctx, Loc);
+ for (DeclStmt::decl_iterator
+ I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
+ DLR.Visit(*I);
+ if (DLR.Finished()) {
+ if (DLR.FoundIt())
+ llvm::tie(Dcl, Stm) = DLR.getResult();
+ return;
+ }
+ }
+}
+
+void StmtLocResolver::VisitStmt(Stmt *Node) {
+ CheckRange(Node);
+ if (!FoundIt())
+ return;
+ assert(Stm == Node && "Result not updated ?");
+
+ // Search the child statements.
+ StmtLocResolver SLR(Ctx, Loc);
+ for (Stmt::child_iterator
+ I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
+ SLR.Visit(*I);
+ if (!SLR.Finished())
+ continue;
+
+ // We either found it or we passed the source location.
+
+ if (SLR.FoundIt()) {
+ // Only update Dcl if we found another more immediate 'parent' Decl for
+ // the statement.
+ if (SLR.getDecl())
+ Dcl = SLR.getDecl();
+ Stm = SLR.getStmt();
+ }
+
+ return;
+ }
+}
+
+void DeclLocResolver::VisitDeclContext(DeclContext *DC) {
+ DeclLocResolver DLR(Ctx, Loc);
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(Ctx), E = DC->decls_end(Ctx); I != E; ++I) {
+ DLR.Visit(*I);
+ if (DLR.Finished()) {
+ if (DLR.FoundIt())
+ llvm::tie(Dcl, Stm) = DLR.getResult();
+ return;
+ }
+ }
+}
+
+void DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+ VisitDeclContext(TU);
+}
+
+void DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
+ CheckRange(D);
+ if (!FoundIt())
+ return;
+ assert(Dcl == D && "Result not updated ?");
+
+ // First, search through the parameters of the function.
+ DeclLocResolver ParmRes(Ctx, Loc);
+ for (FunctionDecl::param_iterator
+ I = D->param_begin(), E = D->param_end(); I != E; ++I) {
+ ParmRes.Visit(*I);
+ if (ParmRes.Finished()) {
+ if (ParmRes.FoundIt())
+ llvm::tie(Dcl, Stm) = ParmRes.getResult();
+ return;
+ }
+ }
+
+ // We didn't found the location in the parameters and we didn't get passed it.
+
+ // Second, search through the declarations that are part of the function.
+ // If we find he location there, we won't have to search through its body.
+ DeclLocResolver DLR(Ctx, Loc);
+ DLR.VisitDeclContext(D);
+ if (DLR.FoundIt()) {
+ llvm::tie(Dcl, Stm) = DLR.getResult();
+ return;
+ }
+
+ // We didn't find a declaration that corresponds to the source location.
+
+ // Finally, search through the body of the function.
+ if (D->isThisDeclarationADefinition()) {
+ StmtLocResolver SLR(Ctx, Loc);
+ SLR.Visit(D->getBody(Ctx));
+ if (SLR.FoundIt()) {
+ llvm::tie(Dcl, Stm) = SLR.getResult();
+ // If we didn't find a more immediate 'parent' declaration for the
+ // statement, set the function as the parent.
+ if (Dcl == 0)
+ Dcl = D;
+ }
+ }
+}
+
+void DeclLocResolver::VisitVarDecl(VarDecl *D) {
+ CheckRange(D);
+ if (!FoundIt())
+ return;
+ assert(Dcl == D && "Result not updated ?");
+
+ // Check whether the location points to the init expression.
+ if (D->getInit()) {
+ StmtLocResolver SLR(Ctx, Loc);
+ SLR.Visit(D->getInit());
+ Stm = SLR.getStmt();
+ }
+}
+
+void DeclLocResolver::VisitDecl(Decl *D) {
+ CheckRange(D);
+}
+
+void LocResolverBase::CheckRange(Decl *D) {
+ SourceRange Range = D->getSourceRange();
+ if (!Range.isValid())
+ return;
+
+ FixRange(Range);
+
+ SourceManager &SourceMgr = Ctx.getSourceManager();
+ if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
+ return;
+
+ if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
+ PassedLoc = true;
+ else
+ Dcl = D;
+}
+
+void LocResolverBase::CheckRange(Stmt *Node) {
+ SourceRange Range = Node->getSourceRange();
+ if (!Range.isValid())
+ return;
+
+ FixRange(Range);
+
+ SourceManager &SourceMgr = Ctx.getSourceManager();
+ if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
+ return;
+
+ if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
+ PassedLoc = true;
+ else
+ Stm = Node;
+}
+
+void LocResolverBase::FixRange(SourceRange &Range) {
+ if (!Range.isValid())
+ return;
+
+ unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
+ Ctx.getSourceManager(),
+ Ctx.getLangOptions());
+ Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
+}
+
+void LocResolverBase::print(Decl *D) {
+ llvm::raw_ostream &OS = llvm::outs();
+ OS << "#### DECL ####\n";
+ D->print(OS, Ctx);
+ OS << " <";
+ D->getLocStart().print(OS, Ctx.getSourceManager());
+ OS << " > - <";
+ D->getLocEnd().print(OS, Ctx.getSourceManager());
+ OS << ">\n\n";
+ OS.flush();
+}
+
+void LocResolverBase::print(Stmt *Node) {
+ llvm::raw_ostream &OS = llvm::outs();
+ OS << "#### STMT ####\n";
+ Node->printPretty(OS, Ctx);
+ OS << " <";
+ Node->getLocStart().print(OS, Ctx.getSourceManager());
+ OS << " > - <";
+ Node->getLocEnd().print(OS, Ctx.getSourceManager());
+ OS << ">\n\n";
+ OS.flush();
+}
+
+
+/// \brief Returns the AST node that a source location points to.
+///
+std::pair<Decl *, Stmt *>
+clang::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
+ if (Loc.isInvalid())
+ return std::make_pair((Decl*)0, (Stmt*)0);
+
+ DeclLocResolver DLR(Ctx, Loc);
+ DLR.Visit(Ctx.getTranslationUnitDecl());
+ return DLR.getResult();
+}
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 318685a..57d7ee5 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -31,7 +31,7 @@ foreach( f ${files} )
COMMENT "Copying clang's ${f}...")
endforeach( f )
-add_custom_target(clang_headers ALL
+add_custom_target(clang-headers ALL
DEPENDS ${files})
install(FILES ${files}
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index 3fb6f95..5ee668a 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -118,6 +118,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
case 13:
if (!memcmp(Str, "address_space", 13)) return AT_address_space;
if (!memcmp(Str, "always_inline", 13)) return AT_always_inline;
+ if (!memcmp(Str, "vec_type_hint", 13)) return IgnoredAttribute;
break;
case 14:
if (!memcmp(Str, "objc_exception", 14)) return AT_objc_exception;
@@ -136,6 +137,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
if (!memcmp(Str, "ns_returns_retained", 19)) return AT_ns_returns_retained;
if (!memcmp(Str, "cf_returns_retained", 19)) return AT_cf_returns_retained;
break;
+ case 20:
+ if (!memcmp(Str, "reqd_work_group_size", 20)) return AT_reqd_wg_size;
case 22:
if (!memcmp(Str, "no_instrument_function", 22))
return AT_no_instrument_function;
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index d8c6986..8b3b285 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -173,6 +173,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_typename: return "type-name";
case DeclSpec::TST_typeofType:
case DeclSpec::TST_typeofExpr: return "typeof";
+ case DeclSpec::TST_auto: return "auto";
}
}
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 9ded366..648e2da 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -48,6 +48,7 @@ Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *TargetName,
+ OverloadedOperatorKind Op,
AttributeList *AttrList,
bool IsTypeName) {
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 426f56f..ff602e8 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -149,13 +149,35 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
}
}
} else { // not an identifier
+ switch (Tok.getKind()) {
+ case tok::r_paren:
// parse a possibly empty comma separated list of expressions
- if (Tok.is(tok::r_paren)) {
// __attribute__(( nonnull() ))
ConsumeParen(); // ignore the right paren loc for now
CurrAttr = new AttributeList(AttrName, AttrNameLoc,
0, SourceLocation(), 0, 0, CurrAttr);
- } else {
+ break;
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw_short:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_void:
+ case tok::kw_typeof:
+ // If it's a builtin type name, eat it and expect a rparen
+ // __attribute__(( vec_type_hint(char) ))
+ ConsumeToken();
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ 0, SourceLocation(), 0, 0, CurrAttr);
+ if (Tok.is(tok::r_paren))
+ ConsumeParen();
+ break;
+ default:
// __attribute__(( aligned(16) ))
ExprVector ArgExprs(Actions);
bool ArgExprsOk = true;
@@ -181,6 +203,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
SourceLocation(), ArgExprs.take(), ArgExprs.size(),
CurrAttr);
}
+ break;
}
}
} else {
@@ -371,7 +394,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
/// According to the standard grammar, =default and =delete are function
/// definitions, but that definitely doesn't fit with the parser here.
///
-Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D) {
+Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
+ const ParsedTemplateInfo &TemplateInfo) {
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
@@ -393,7 +417,13 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D) {
}
// Inform the current actions module that we just parsed this declarator.
- DeclPtrTy ThisDecl = Actions.ActOnDeclarator(CurScope, D);
+ DeclPtrTy ThisDecl = TemplateInfo.TemplateParams?
+ Actions.ActOnTemplateDeclarator(CurScope,
+ Action::MultiTemplateParamsArg(Actions,
+ TemplateInfo.TemplateParams->data(),
+ TemplateInfo.TemplateParams->size()),
+ D)
+ : Actions.ActOnDeclarator(CurScope, D);
// Parse declarator '=' initializer.
if (Tok.is(tok::equal)) {
@@ -896,7 +926,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec);
break;
case tok::kw_auto:
- isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec);
+ if (getLang().CPlusPlus0x)
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec);
+ else
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec);
break;
case tok::kw_register:
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec);
@@ -1018,6 +1051,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ParseTypeofSpecifier(DS);
continue;
+ case tok::kw_decltype:
+ ParseDecltypeSpecifier(DS);
+ continue;
+
case tok::less:
// GCC ObjC supports types like "<SomeProtocol>" as a synonym for
// "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
@@ -1095,6 +1132,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
/// [GNU] typeof-specifier
/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO]
+/// [C++0x] 'decltype' ( expression )
bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
const char *&PrevSpec,
const ParsedTemplateInfo &TemplateInfo) {
@@ -1235,6 +1273,18 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
ParseTypeofSpecifier(DS);
return true;
+ // C++0x decltype support.
+ case tok::kw_decltype:
+ ParseDecltypeSpecifier(DS);
+ return true;
+
+ // C++0x auto support.
+ case tok::kw_auto:
+ if (!getLang().CPlusPlus0x)
+ return false;
+
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec);
+ break;
case tok::kw___ptr64:
case tok::kw___w64:
case tok::kw___cdecl:
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 44f231a..225f926 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/OperatorKinds.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
@@ -274,8 +275,6 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
ParseOptionalCXXScopeSpecifier(SS);
AttributeList *AttrList = 0;
- IdentifierInfo *TargetName = 0;
- SourceLocation IdentLoc = SourceLocation();
// Check nested-name specifier.
if (SS.isInvalid()) {
@@ -287,17 +286,33 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
SkipUntil(tok::semi);
return DeclPtrTy();
}
- if (Tok.isNot(tok::identifier)) {
+
+ IdentifierInfo *TargetName = 0;
+ OverloadedOperatorKind Op = OO_None;
+ SourceLocation IdentLoc;
+
+ if (Tok.is(tok::kw_operator)) {
+ IdentLoc = Tok.getLocation();
+
+ Op = TryParseOperatorFunctionId();
+ if (!Op) {
+ // If there was an invalid operator, skip to end of decl, and eat ';'.
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+ } else if (Tok.is(tok::identifier)) {
+ // Parse identifier.
+ TargetName = Tok.getIdentifierInfo();
+ IdentLoc = ConsumeToken();
+ } else {
+ // FIXME: Use a better diagnostic here.
Diag(Tok, diag::err_expected_ident_in_using);
+
// If there was invalid identifier, skip to end of decl, and eat ';'.
SkipUntil(tok::semi);
return DeclPtrTy();
}
- // Parse identifier.
- TargetName = Tok.getIdentifierInfo();
- IdentLoc = ConsumeToken();
-
// Parse (optional) attributes (most likely GNU strong-using extension).
if (Tok.is(tok::kw___attribute))
AttrList = ParseAttributes();
@@ -308,7 +323,8 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
AttrList ? "attributes list" : "namespace name", tok::semi);
return Actions.ActOnUsingDeclaration(CurScope, UsingLoc, SS,
- IdentLoc, TargetName, AttrList, IsTypeName);
+ IdentLoc, TargetName, Op,
+ AttrList, IsTypeName);
}
/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion.
@@ -355,6 +371,51 @@ Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
move(AssertMessage));
}
+/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier.
+///
+/// 'decltype' ( expression )
+///
+void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
+ assert(Tok.is(tok::kw_decltype) && "Not a decltype specifier");
+
+ SourceLocation StartLoc = ConsumeToken();
+ SourceLocation LParenLoc = Tok.getLocation();
+
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "decltype")) {
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ // Parse the expression
+
+ // C++0x [dcl.type.simple]p4:
+ // The operand of the decltype specifier is an unevaluated operand.
+ EnterExpressionEvaluationContext Unevaluated(Actions,
+ Action::Unevaluated);
+ OwningExprResult Result = ParseExpression();
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ // Match the ')'
+ SourceLocation RParenLoc;
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (RParenLoc.isInvalid())
+ return;
+
+ const char *PrevSpec = 0;
+ // Check for duplicate type specifiers (e.g. "int decltype(a)").
+ if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
+ Result.release()))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+}
+
/// ParseClassName - Parse a C++ class-name, which names a class. Note
/// that we only check that the result names a type; semantic analysis
/// will need to verify that the type names a class. The result is
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 2be44a4..d89f1e1 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -59,81 +59,39 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
while (true) {
// nested-name-specifier:
- // type-name '::'
- // namespace-name '::'
- // nested-name-specifier identifier '::'
- if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
- // We have an identifier followed by a '::'. Lookup this name
- // as the name in a nested-name-specifier.
- IdentifierInfo *II = Tok.getIdentifierInfo();
- SourceLocation IdLoc = ConsumeToken();
- assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
- SourceLocation CCLoc = ConsumeToken();
+ // nested-name-specifier 'template'[opt] simple-template-id '::'
+
+ // Parse the optional 'template' keyword, then make sure we have
+ // 'identifier <' after it.
+ if (Tok.is(tok::kw_template)) {
+ SourceLocation TemplateKWLoc = ConsumeToken();
- if (!HasScopeSpecifier) {
- SS.setBeginLoc(IdLoc);
- HasScopeSpecifier = true;
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok.getLocation(),
+ diag::err_id_after_template_in_nested_name_spec)
+ << SourceRange(TemplateKWLoc);
+ break;
}
- if (SS.isInvalid())
- continue;
+ if (NextToken().isNot(tok::less)) {
+ Diag(NextToken().getLocation(),
+ diag::err_less_after_template_name_in_nested_name_spec)
+ << Tok.getIdentifierInfo()->getName()
+ << SourceRange(TemplateKWLoc, Tok.getLocation());
+ break;
+ }
+
+ TemplateTy Template
+ = Actions.ActOnDependentTemplateName(TemplateKWLoc,
+ *Tok.getIdentifierInfo(),
+ Tok.getLocation(), SS);
+ if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
+ &SS, TemplateKWLoc, false))
+ break;
- SS.setScopeRep(
- Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
- SS.setEndLoc(CCLoc);
continue;
}
-
- // nested-name-specifier:
- // type-name '::'
- // nested-name-specifier 'template'[opt] simple-template-id '::'
- if ((Tok.is(tok::identifier) && NextToken().is(tok::less)) ||
- Tok.is(tok::kw_template)) {
- // Parse the optional 'template' keyword, then make sure we have
- // 'identifier <' after it.
- if (Tok.is(tok::kw_template)) {
- SourceLocation TemplateKWLoc = ConsumeToken();
-
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok.getLocation(),
- diag::err_id_after_template_in_nested_name_spec)
- << SourceRange(TemplateKWLoc);
- break;
- }
-
- if (NextToken().isNot(tok::less)) {
- Diag(NextToken().getLocation(),
- diag::err_less_after_template_name_in_nested_name_spec)
- << Tok.getIdentifierInfo()->getName()
- << SourceRange(TemplateKWLoc, Tok.getLocation());
- break;
- }
-
- TemplateTy Template
- = Actions.ActOnDependentTemplateName(TemplateKWLoc,
- *Tok.getIdentifierInfo(),
- Tok.getLocation(),
- SS);
- AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
- &SS, TemplateKWLoc, false);
- continue;
- }
-
- TemplateTy Template;
- TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
- CurScope, Template, &SS);
- if (TNK) {
- // We have found a template name, so annotate this this token
- // with a template-id annotation. We do not permit the
- // template-id to be translated into a type annotation,
- // because some clients (e.g., the parsing of class template
- // specializations) still want to see the original template-id
- // token.
- AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), false);
- continue;
- }
- }
-
+
if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
// We have
//
@@ -172,8 +130,62 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
SS.setScopeRep(0);
SS.setEndLoc(CCLoc);
continue;
- } else
- assert(false && "FIXME: Only type template names supported here");
+ }
+
+ assert(false && "FIXME: Only type template names supported here");
+ }
+
+
+ // The rest of the nested-name-specifier possibilities start with
+ // tok::identifier.
+ if (Tok.isNot(tok::identifier))
+ break;
+
+ IdentifierInfo &II = *Tok.getIdentifierInfo();
+
+ // nested-name-specifier:
+ // type-name '::'
+ // namespace-name '::'
+ // nested-name-specifier identifier '::'
+ Token Next = NextToken();
+ if (Next.is(tok::coloncolon)) {
+ // We have an identifier followed by a '::'. Lookup this name
+ // as the name in a nested-name-specifier.
+ SourceLocation IdLoc = ConsumeToken();
+ assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+ SourceLocation CCLoc = ConsumeToken();
+
+ if (!HasScopeSpecifier) {
+ SS.setBeginLoc(IdLoc);
+ HasScopeSpecifier = true;
+ }
+
+ if (SS.isInvalid())
+ continue;
+
+ SS.setScopeRep(
+ Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II));
+ SS.setEndLoc(CCLoc);
+ continue;
+ }
+
+ // nested-name-specifier:
+ // type-name '<'
+ if (Next.is(tok::less)) {
+ TemplateTy Template;
+ if (TemplateNameKind TNK = Actions.isTemplateName(II, CurScope,
+ Template, &SS)) {
+ // We have found a template name, so annotate this this token
+ // with a template-id annotation. We do not permit the
+ // template-id to be translated into a type annotation,
+ // because some clients (e.g., the parsing of class template
+ // specializations) still want to see the original template-id
+ // token.
+ if (AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(),
+ false))
+ break;
+ continue;
+ }
}
// We don't have any tokens that form the beginning of a
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index cb7fe58..013e26b 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -771,10 +771,12 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
MethodAttrs = ParseAttributes();
+ if (KeyIdents.size() == 0)
+ return DeclPtrTy();
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
&KeyIdents[0]);
return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
- mType, IDecl, DSRet, ReturnType, Sel,
+ mType, IDecl, DSRet, ReturnType, Sel,
&ArgInfos[0], CargNames, MethodAttrs,
MethodImplKind, isVariadic);
}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index eabe10f..57a09fb 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -170,7 +170,8 @@ Parser::ParseSingleDeclarationAfterTemplate(
// If we have a declaration or declarator list, handle it.
if (isDeclarationAfterDeclarator()) {
// Parse this declaration.
- DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo);
+ DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
+ TemplateInfo);
if (Tok.is(tok::comma)) {
Diag(Tok, diag::err_multiple_template_declarators)
@@ -200,7 +201,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
}
return DeclPtrTy();
}
- return ParseFunctionDefinition(DeclaratorInfo);
+ return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo);
}
if (DeclaratorInfo.isFunctionDeclarator())
@@ -620,7 +621,11 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
/// replaced with a type annotation token. Otherwise, the
/// simple-template-id is always replaced with a template-id
/// annotation token.
-void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
+///
+/// If an unrecoverable parse error occurs and no annotation token can be
+/// formed, this function returns true.
+///
+bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
const CXXScopeSpec *SS,
SourceLocation TemplateKWLoc,
bool AllowTypeAnnotation) {
@@ -643,14 +648,19 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateArgIsType,
TemplateArgLocations,
RAngleLoc);
+
+ if (Invalid) {
+ // If we failed to parse the template ID but skipped ahead to a >, we're not
+ // going to be able to form a token annotation. Eat the '>' if present.
+ if (Tok.is(tok::greater))
+ ConsumeToken();
+ return true;
+ }
ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
TemplateArgIsType.data(),
TemplateArgs.size());
- if (Invalid) // FIXME: How to recover from a broken template-id?
- return;
-
// Build the annotation token.
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
Action::TypeResult Type
@@ -658,8 +668,13 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
LAngleLoc, TemplateArgsPtr,
&TemplateArgLocations[0],
RAngleLoc);
- if (Type.isInvalid()) // FIXME: better recovery?
- return;
+ if (Type.isInvalid()) {
+ // If we failed to parse the template ID but skipped ahead to a >, we're not
+ // going to be able to form a token annotation. Eat the '>' if present.
+ if (Tok.is(tok::greater))
+ ConsumeToken();
+ return true;
+ }
Tok.setKind(tok::annot_typename);
Tok.setAnnotationValue(Type.get());
@@ -704,6 +719,7 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// In case the tokens were cached, have Preprocessor replace them with the
// annotation token.
PP.AnnotateCachedTokens(Tok);
+ return false;
}
/// \brief Replaces a template-id annotation token with a type
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index f31855b..02687a2 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -543,6 +543,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
/// [GNU] typeof-specifier
/// [GNU] '_Complex'
/// [C++0x] 'auto' [TODO]
+/// [C++0x] 'decltype' ( expression )
///
/// type-name:
/// class-name
@@ -695,7 +696,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
return TPResult::True();
- // GNU typeof support.
+ // GNU typeof support.
case tok::kw_typeof: {
if (NextToken().isNot(tok::l_paren))
return TPResult::True();
@@ -716,6 +717,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
return TPResult::True();
}
+ // C++0x decltype support.
+ case tok::kw_decltype:
+ return TPResult::True();
+
default:
return TPResult::False();
}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index a2a66f9..29d1d87 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -590,7 +590,8 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
/// [C++] function-definition: [C++ 8.4]
/// decl-specifier-seq[opt] declarator function-try-block
///
-Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D) {
+Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D,
+ const ParsedTemplateInfo &TemplateInfo) {
const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
assert(FnTypeInfo.Kind == DeclaratorChunk::Function &&
"This isn't a function declarator!");
@@ -632,7 +633,13 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D) {
// Tell the actions module that we have entered a function definition with the
// specified Declarator for the function.
- DeclPtrTy Res = Actions.ActOnStartOfFunctionDef(CurScope, D);
+ DeclPtrTy Res = TemplateInfo.TemplateParams?
+ Actions.ActOnStartOfFunctionTemplateDef(CurScope,
+ Action::MultiTemplateParamsArg(Actions,
+ TemplateInfo.TemplateParams->data(),
+ TemplateInfo.TemplateParams->size()),
+ D)
+ : Actions.ActOnStartOfFunctionDef(CurScope, D);
if (Tok.is(tok::kw_try))
return ParseFunctionTryBlock(Res);
@@ -832,7 +839,8 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
/// specifier, and another one to get the actual type inside
/// ParseDeclarationSpecifiers).
///
-/// This returns true if the token was annotated.
+/// This returns true if the token was annotated or an unrecoverable error
+/// occurs.
///
/// Note that this routine emits an error if you call it with ::new or ::delete
/// as the current tokens, so only call it in contexts where these are invalid.
@@ -927,7 +935,12 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
if (TemplateNameKind TNK
= Actions.isTemplateName(*Tok.getIdentifierInfo(),
CurScope, Template, &SS))
- AnnotateTemplateIdToken(Template, TNK, &SS);
+ if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
+ // If an unrecoverable error occurred, we need to return true here,
+ // because the token stream is in a damaged state. We may not return
+ // a valid identifier.
+ return Tok.isNot(tok::identifier);
+ }
}
// The current token, which is either an identifier or a
@@ -950,7 +963,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
}
if (SS.isEmpty())
- return false;
+ return Tok.isNot(tok::identifier) && Tok.isNot(tok::coloncolon);
// A C++ scope specifier that isn't followed by a typename.
// Push the current token back into the token stream (or revert it if it is
@@ -971,7 +984,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
/// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only
/// annotates C++ scope specifiers and template-ids. This returns
-/// true if the token was annotated.
+/// true if the token was annotated or there was an error that could not be
+/// recovered from.
///
/// Note that this routine emits an error if you call it with ::new or ::delete
/// as the current tokens, so only call it in contexts where these are invalid.
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 8604fe5..2d27ccc 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -421,9 +421,12 @@ public:
virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S);
virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
- return ActOnDeclarator(S, D, false);
+ return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
}
- DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition);
+
+ DeclPtrTy HandleDeclarator(Scope *S, Declarator &D,
+ MultiTemplateParamsArg TemplateParameterLists,
+ bool IsFunctionDefinition);
void RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl,
Scope *S);
void DiagnoseFunctionSpecifiers(Declarator& D);
@@ -437,6 +440,7 @@ public:
bool &Redeclaration);
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, NamedDecl* PrevDecl,
+ MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition,
bool &Redeclaration);
void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
@@ -693,6 +697,11 @@ public:
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
+ void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions = false,
+ bool ForceRValue = false);
void AddConversionCandidate(CXXConversionDecl *Conversion,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet);
@@ -1137,7 +1146,8 @@ public:
void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
AssociatedNamespaceSet &AssociatedNamespaces,
- AssociatedClassSet &AssociatedClasses);
+ AssociatedClassSet &AssociatedClasses,
+ bool &GlobalScope);
bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
SourceLocation NameLoc,
@@ -1372,9 +1382,10 @@ public:
bool HasTrailingLParen,
const CXXScopeSpec &SS,
bool isAddressOfOperand);
- DeclRefExpr *BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
- bool TypeDependent, bool ValueDependent,
- const CXXScopeSpec *SS = 0);
+ OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty,
+ SourceLocation Loc, bool TypeDependent,
+ bool ValueDependent,
+ const CXXScopeSpec *SS = 0);
VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
llvm::SmallVectorImpl<FieldDecl *> &Path);
OwningExprResult
@@ -1563,6 +1574,7 @@ public:
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *TargetName,
+ OverloadedOperatorKind Op,
AttributeList *AttrList,
bool IsTypeName);
@@ -1581,17 +1593,36 @@ public:
CXXConstructorDecl *Constructor,
QualType DeclInitType,
Expr **Exprs, unsigned NumExprs);
+
+ /// MarcDestructorReferenced - Prepare for calling destructor on the
+ /// constructed decl.
+ void MarcDestructorReferenced(SourceLocation Loc, QualType DeclInitType);
/// DefineImplicitDefaultConstructor - Checks for feasibility of
/// defining this constructor as the default constructor.
void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor);
+ /// DefineImplicitDestructor - Checks for feasibility of
+ /// defining this destructor as the default destructor.
+ void DefineImplicitDestructor(SourceLocation CurrentLocation,
+ CXXDestructorDecl *Destructor);
+
/// DefineImplicitCopyConstructor - Checks for feasibility of
/// defining this constructor as the copy constructor.
void DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor,
unsigned TypeQuals);
+
+ /// DefineImplicitOverloadedAssign - Checks for feasibility of
+ /// defining implicit this overloaded assignment operator.
+ void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
+ CXXMethodDecl *MethodDecl);
+
+ /// getAssignOperatorMethod - Returns the default copy assignmment operator
+ /// for the class.
+ CXXMethodDecl *getAssignOperatorMethod(ParmVarDecl *Decl,
+ CXXRecordDecl *ClassDecl);
/// MaybeBindToTemporary - If the passed in expression has a record type with
/// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
@@ -2067,6 +2098,14 @@ public:
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists);
+ virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S,
+ MultiTemplateParamsArg TemplateParameterLists,
+ Declarator &D);
+
+ virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
+ MultiTemplateParamsArg TemplateParameterLists,
+ Declarator &D);
+
virtual DeclResult
ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
unsigned TagSpec,
@@ -2180,7 +2219,13 @@ public:
/// into a non-deduced context produced a type or value that
/// produces a type that does not match the original template
/// arguments provided.
- TDK_NonDeducedMismatch
+ TDK_NonDeducedMismatch,
+ /// \brief When performing template argument deduction for a function
+ /// template, there were too many call arguments.
+ TDK_TooManyArguments,
+ /// \brief When performing template argument deduction for a class
+ /// template, there were too few call arguments.
+ TDK_TooFewArguments
};
/// \brief Provides information about an attempted template argument
@@ -2260,6 +2305,12 @@ public:
const TemplateArgumentList &TemplateArgs,
TemplateDeductionInfo &Info);
+ TemplateDeductionResult
+ DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ Expr **Args, unsigned NumArgs,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info);
+
void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
llvm::SmallVectorImpl<bool> &Deduced);
@@ -3022,6 +3073,13 @@ public:
// returns true if the cast is invalid
bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
+ // CheckExtVectorCast - check type constraints for extended vectors.
+ // Since vectors are an extension, there are no C standard reference for this.
+ // We allow casting between vectors and integer datatypes of the same size,
+ // or vectors and the element type of that vector.
+ // returns true if the cast is invalid
+ bool CheckExtVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
+
/// CheckMessageArgumentTypes - Check types in an Obj-C message send.
/// \param Method - May be null.
/// \param [out] ReturnType - The return type of the send.
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index a2ceafa..f6d6623 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -717,6 +717,8 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
if (E->isTypeDependent() || E->isValueDependent())
return false;
+ E = E->IgnoreParenCasts();
+
switch (E->getStmtClass()) {
case Stmt::ConditionalOperatorClass: {
const ConditionalOperator *C = cast<ConditionalOperator>(E);
@@ -766,6 +768,25 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
return false;
}
+ case Stmt::CallExprClass: {
+ const CallExpr *CE = cast<CallExpr>(E);
+ if (const ImplicitCastExpr *ICE
+ = dyn_cast<ImplicitCastExpr>(CE->getCallee())) {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
+ if (const FormatArgAttr *FA = FD->getAttr<FormatArgAttr>(Context)) {
+ unsigned ArgIndex = FA->getFormatIdx();
+ const Expr *Arg = CE->getArg(ArgIndex - 1);
+
+ return SemaCheckStringLiteral(Arg, TheCall, HasVAListArg,
+ format_idx, firstDataArg);
+ }
+ }
+ }
+ }
+
+ return false;
+ }
case Stmt::ObjCStringLiteralClass:
case Stmt::StringLiteralClass: {
const StringLiteral *StrE = NULL;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index eba1d58..13162d8 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -319,16 +319,16 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
return;
}
}
- } else if (isa<FunctionDecl>(D) &&
- AllowOverloadingOfFunction(D, Context)) {
- // We are pushing the name of a function, which might be an
- // overloaded name.
- FunctionDecl *FD = cast<FunctionDecl>(D);
+ } else if ((isa<FunctionDecl>(D) &&
+ AllowOverloadingOfFunction(D, Context)) ||
+ isa<FunctionTemplateDecl>(D)) {
+ // We are pushing the name of a function or function template,
+ // which might be an overloaded name.
IdentifierResolver::iterator Redecl
- = std::find_if(IdResolver.begin(FD->getDeclName()),
+ = std::find_if(IdResolver.begin(D->getDeclName()),
IdResolver.end(),
std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
- FD));
+ D));
if (Redecl != IdResolver.end() &&
S->isDeclScope(DeclPtrTy::make(*Redecl))) {
// There is already a declaration of a function on our
@@ -655,7 +655,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
"Cannot merge with an overloaded function declaration");
// Verify the old decl was also a function.
- FunctionDecl *Old = dyn_cast<FunctionDecl>(OldD);
+ FunctionDecl *Old = 0;
+ if (FunctionTemplateDecl *OldFunctionTemplate
+ = dyn_cast<FunctionTemplateDecl>(OldD))
+ Old = OldFunctionTemplate->getTemplatedDecl();
+ else
+ Old = dyn_cast<FunctionDecl>(OldD);
if (!Old) {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
<< New->getDeclName();
@@ -1385,7 +1390,9 @@ static bool isNearlyMatchingFunction(ASTContext &Context,
}
Sema::DeclPtrTy
-Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) {
+Sema::HandleDeclarator(Scope *S, Declarator &D,
+ MultiTemplateParamsArg TemplateParamLists,
+ bool IsFunctionDefinition) {
DeclarationName Name = GetNameForDeclarator(D);
// All of these full declarators require an identifier. If it doesn't have
@@ -1500,9 +1507,15 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) {
bool Redeclaration = false;
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ if (TemplateParamLists.size()) {
+ Diag(D.getIdentifierLoc(), diag::err_template_typedef);
+ return DeclPtrTy();
+ }
+
New = ActOnTypedefDeclarator(S, D, DC, R, PrevDecl, Redeclaration);
} else if (R->isFunctionType()) {
New = ActOnFunctionDeclarator(S, D, DC, R, PrevDecl,
+ move(TemplateParamLists),
IsFunctionDefinition, Redeclaration);
} else {
New = ActOnVariableDeclarator(S, D, DC, R, PrevDecl, Redeclaration);
@@ -1799,6 +1812,15 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
} else if (SC == VarDecl::None)
SC = VarDecl::Static;
}
+ if (SC == VarDecl::Static) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
+ if (RD->isLocalClass())
+ Diag(D.getIdentifierLoc(),
+ diag::err_static_data_member_not_allowed_in_local_class)
+ << Name << RD->getDeclName();
+ }
+ }
+
// The variable can not
NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
@@ -1987,6 +2009,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, NamedDecl* PrevDecl,
+ MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition, bool &Redeclaration) {
assert(R.getTypePtr()->isFunctionType());
@@ -2044,6 +2067,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
<< R->getAsFunctionType()->getResultType();
D.setInvalidType();
}
+
+ // Check that we can declare a template here.
+ if (TemplateParamLists.size() &&
+ CheckTemplateDeclScope(S, TemplateParamLists))
+ return 0;
bool isVirtualOkay = false;
FunctionDecl *NewFD;
@@ -2143,6 +2171,26 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// from the semantic context.
NewFD->setLexicalDeclContext(CurContext);
+ // If there is a template parameter list, then we are dealing with a
+ // template declaration or specialization.
+ FunctionTemplateDecl *FunctionTemplate = 0;
+ if (TemplateParamLists.size()) {
+ // FIXME: member templates!
+ TemplateParameterList *TemplateParams
+ = static_cast<TemplateParameterList *>(*TemplateParamLists.release());
+
+ if (TemplateParams->size() > 0) {
+ // This is a function template
+ FunctionTemplate = FunctionTemplateDecl::Create(Context, CurContext,
+ NewFD->getLocation(),
+ Name, TemplateParams,
+ NewFD);
+ NewFD->setDescribedFunctionTemplate(FunctionTemplate);
+ } else {
+ // FIXME: Handle function template specializations
+ }
+ }
+
// C++ [dcl.fct.spec]p5:
// The virtual specifier shall only be used in declarations of
// nonstatic class member functions that appear within a
@@ -2261,8 +2309,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
// Finally, we know we have the right number of parameters, install them.
NewFD->setParams(Context, Params.data(), Params.size());
-
-
// If name lookup finds a previous declaration that is not in the
// same scope as the new declaration, this may still be an
@@ -2342,6 +2388,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
&& !NewFD->isInvalidDecl())
RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S);
+ // Set this FunctionDecl's range up to the right paren.
+ NewFD->setLocEnd(D.getSourceRange().getEnd());
+
+ if (FunctionTemplate && NewFD->isInvalidDecl())
+ FunctionTemplate->setInvalidDecl();
+
+ if (FunctionTemplate)
+ return FunctionTemplate;
+
return NewFD;
}
@@ -2470,7 +2525,11 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
if (MergeFunctionDecl(NewFD, OldDecl))
return NewFD->setInvalidDecl();
- NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
+ if (FunctionTemplateDecl *OldTemplateDecl
+ = dyn_cast<FunctionTemplateDecl>(OldDecl))
+ NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
+ else
+ NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
}
}
@@ -2733,9 +2792,13 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
IK_Default);
if (!Constructor)
Var->setInvalidDecl();
- else
+ else {
if (!RD->hasTrivialConstructor())
InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0);
+ // FIXME. Must do all that is needed to destroy the object
+ // on scope exit. For now, just mark the destructor as used.
+ MarcDestructorReferenced(Var->getLocation(), InitType);
+ }
}
}
@@ -2987,11 +3050,15 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
Scope *ParentScope = FnBodyScope->getParent();
- DeclPtrTy DP = ActOnDeclarator(ParentScope, D, /*IsFunctionDefinition=*/true);
+ DeclPtrTy DP = HandleDeclarator(ParentScope, D,
+ MultiTemplateParamsArg(*this),
+ /*IsFunctionDefinition=*/true);
return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
+ if (!D)
+ return D;
FunctionDecl *FD = cast<FunctionDecl>(D.getAs<Decl>());
CurFunctionNeedsScopeChecking = false;
@@ -3219,7 +3286,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
CurContext = Context.getTranslationUnitDecl();
FunctionDecl *FD =
- dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D, DeclPtrTy()).getAs<Decl>());
+ dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D).getAs<Decl>());
FD->setImplicit();
CurContext = PrevDC;
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index d57630e..f7dd930 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -915,6 +915,30 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
D->addAttr(S.Context, ::new (S.Context) DLLExportAttr());
}
+static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
+ Sema &S) {
+ // Attribute has 3 arguments.
+ if (Attr.getNumArgs() != 3) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ unsigned WGSize[3];
+ for (unsigned i = 0; i < 3; ++i) {
+ Expr *E = static_cast<Expr *>(Attr.getArg(i));
+ llvm::APSInt ArgNum(32);
+ if (!E->isIntegerConstantExpr(ArgNum, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "reqd_work_group_size" << E->getSourceRange();
+ return;
+ }
+ WGSize[i] = (unsigned) ArgNum.getZExtValue();
+ }
+ D->addAttr(S.Context,
+ ::new (S.Context) ReqdWorkGroupSizeAttr(WGSize[0], WGSize[1],
+ WGSize[2]));
+}
+
static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Attribute has no arguments.
if (Attr.getNumArgs() != 1) {
@@ -1736,6 +1760,9 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
case AttributeList::AT_cf_returns_retained:
HandleNSReturnsRetainedAttr(D, Attr, S); break;
+ case AttributeList::AT_reqd_wg_size:
+ HandleReqdWorkGroupSize(D, Attr, S); break;
+
case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index c9c6626..cf0dab5 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1625,7 +1625,8 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
Conv = Conversions->function_begin(),
ConvEnd = Conversions->function_end();
Conv != ConvEnd; ++Conv) {
- if (*Conv == Conversion->getPreviousDeclaration()) {
+ if (*Conv
+ == cast_or_null<NamedDecl>(Conversion->getPreviousDeclaration())) {
*Conv = Conversion;
return DeclPtrTy::make(Conversion);
}
@@ -1784,18 +1785,24 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *TargetName,
+ OverloadedOperatorKind Op,
AttributeList *AttrList,
bool IsTypeName) {
assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
- assert(TargetName && "Invalid TargetName.");
+ assert((TargetName || Op) && "Invalid TargetName.");
assert(IdentLoc.isValid() && "Invalid TargetName location.");
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
UsingDecl *UsingAlias = 0;
+ DeclarationName Name;
+ if (TargetName)
+ Name = TargetName;
+ else
+ Name = Context.DeclarationNames.getCXXOperatorName(Op);
+
// Lookup target name.
- LookupResult R = LookupParsedName(S, &SS, TargetName,
- LookupOrdinaryName, false);
+ LookupResult R = LookupParsedName(S, &SS, Name, LookupOrdinaryName, false);
if (NamedDecl *NS = R) {
if (IsTypeName && !isa<TypeDecl>(NS)) {
@@ -1890,10 +1897,8 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
= cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
if (!BaseClassDecl->hasTrivialConstructor()) {
if (CXXConstructorDecl *BaseCtor =
- BaseClassDecl->getDefaultConstructor(Context)) {
- if (BaseCtor->isImplicit() && !BaseCtor->isUsed())
- MarkDeclarationReferenced(CurrentLocation, BaseCtor);
- }
+ BaseClassDecl->getDefaultConstructor(Context))
+ MarkDeclarationReferenced(CurrentLocation, BaseCtor);
else {
Diag(CurrentLocation, diag::err_defining_default_ctor)
<< Context.getTagDeclType(ClassDecl) << 1
@@ -1913,12 +1918,10 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (!FieldClassDecl->hasTrivialConstructor())
+ if (!FieldClassDecl->hasTrivialConstructor()) {
if (CXXConstructorDecl *FieldCtor =
- FieldClassDecl->getDefaultConstructor(Context)) {
- if (FieldCtor->isImplicit() && !FieldCtor->isUsed())
- MarkDeclarationReferenced(CurrentLocation, FieldCtor);
- }
+ FieldClassDecl->getDefaultConstructor(Context))
+ MarkDeclarationReferenced(CurrentLocation, FieldCtor);
else {
Diag(CurrentLocation, diag::err_defining_default_ctor)
<< Context.getTagDeclType(ClassDecl) << 0 <<
@@ -1928,6 +1931,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
err = true;
}
}
+ }
else if (FieldType->isReferenceType()) {
Diag(CurrentLocation, diag::err_unintialized_member)
<< Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString();
@@ -1942,7 +1946,147 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
}
}
if (!err)
- Constructor->setUsed();
+ Constructor->setUsed();
+ else
+ Constructor->setInvalidDecl();
+}
+
+void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
+ CXXDestructorDecl *Destructor) {
+ assert((Destructor->isImplicit() && !Destructor->isUsed()) &&
+ "DefineImplicitDestructor - call it for implicit default dtor");
+
+ CXXRecordDecl *ClassDecl
+ = cast<CXXRecordDecl>(Destructor->getDeclContext());
+ assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
+ // C++ [class.dtor] p5
+ // Before the implicitly-declared default destructor for a class is
+ // implicitly defined, all the implicitly-declared default destructors
+ // for its base class and its non-static data members shall have been
+ // implicitly defined.
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
+ if (!BaseClassDecl->hasTrivialDestructor()) {
+ if (CXXDestructorDecl *BaseDtor =
+ const_cast<CXXDestructorDecl*>(BaseClassDecl->getDestructor(Context)))
+ MarkDeclarationReferenced(CurrentLocation, BaseDtor);
+ else
+ assert(false &&
+ "DefineImplicitDestructor - missing dtor in a base class");
+ }
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context);
+ Field != ClassDecl->field_end(Context);
+ ++Field) {
+ QualType FieldType = Context.getCanonicalType((*Field)->getType());
+ if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+ FieldType = Array->getElementType();
+ if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ if (!FieldClassDecl->hasTrivialDestructor()) {
+ if (CXXDestructorDecl *FieldDtor =
+ const_cast<CXXDestructorDecl*>(
+ FieldClassDecl->getDestructor(Context)))
+ MarkDeclarationReferenced(CurrentLocation, FieldDtor);
+ else
+ assert(false &&
+ "DefineImplicitDestructor - missing dtor in class of a data member");
+ }
+ }
+ }
+ Destructor->setUsed();
+}
+
+void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
+ CXXMethodDecl *MethodDecl) {
+ assert((MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
+ MethodDecl->getOverloadedOperator() == OO_Equal &&
+ !MethodDecl->isUsed()) &&
+ "DefineImplicitOverloadedAssign - call it for implicit assignment op");
+
+ CXXRecordDecl *ClassDecl
+ = cast<CXXRecordDecl>(MethodDecl->getDeclContext());
+ assert(ClassDecl && "DefineImplicitOverloadedAssign - invalid constructor");
+
+ // C++[class.copy] p12
+ // Before the implicitly-declared copy assignment operator for a class is
+ // implicitly defined, all implicitly-declared copy assignment operators
+ // for its direct base classes and its nonstatic data members shall have
+ // been implicitly defined.
+ bool err = false;
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
+ if (CXXMethodDecl *BaseAssignOpMethod =
+ getAssignOperatorMethod(MethodDecl->getParamDecl(0), BaseClassDecl))
+ MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
+ }
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context);
+ Field != ClassDecl->field_end(Context);
+ ++Field) {
+ QualType FieldType = Context.getCanonicalType((*Field)->getType());
+ if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+ FieldType = Array->getElementType();
+ if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ if (CXXMethodDecl *FieldAssignOpMethod =
+ getAssignOperatorMethod(MethodDecl->getParamDecl(0), FieldClassDecl))
+ MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
+ }
+ else if (FieldType->isReferenceType()) {
+ Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
+ << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ Diag(CurrentLocation, diag::note_first_required_here);
+ err = true;
+ }
+ else if (FieldType.isConstQualified()) {
+ Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
+ << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getNameAsCString();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ Diag(CurrentLocation, diag::note_first_required_here);
+ err = true;
+ }
+ }
+ if (!err)
+ MethodDecl->setUsed();
+}
+
+CXXMethodDecl *
+Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
+ CXXRecordDecl *ClassDecl) {
+ QualType LHSType = Context.getTypeDeclType(ClassDecl);
+ QualType RHSType(LHSType);
+ // If class's assignment operator argument is const/volatile qualified,
+ // look for operator = (const/volatile B&). Otherwise, look for
+ // operator = (B&).
+ if (ParmDecl->getType().isConstQualified())
+ RHSType.addConst();
+ if (ParmDecl->getType().isVolatileQualified())
+ RHSType.addVolatile();
+ ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
+ LHSType,
+ SourceLocation()));
+ ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
+ RHSType,
+ SourceLocation()));
+ Expr *Args[2] = { &*LHS, &*RHS };
+ OverloadCandidateSet CandidateSet;
+ AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
+ CandidateSet);
+ OverloadCandidateSet::iterator Best;
+ if (BestViableFunction(CandidateSet,
+ ClassDecl->getLocation(), Best) == OR_Success)
+ return cast<CXXMethodDecl>(Best->Function);
+ assert(false &&
+ "getAssignOperatorMethod - copy assignment operator method not found");
+ return 0;
}
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
@@ -1956,6 +2100,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
+ // C++ [class.copy] p209
// Before the implicitly-declared copy constructor for a class is
// implicitly defined, all the implicitly-declared copy constructors
// for its base class and its non-static data members shall have been
@@ -1966,8 +2111,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
= cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
if (CXXConstructorDecl *BaseCopyCtor =
BaseClassDecl->getCopyConstructor(Context, TypeQuals))
- if (BaseCopyCtor->isImplicit() && !BaseCopyCtor->isUsed())
- MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
+ MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context);
Field != ClassDecl->field_end(Context);
@@ -1980,8 +2124,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (CXXConstructorDecl *FieldCopyCtor =
FieldClassDecl->getCopyConstructor(Context, TypeQuals))
- if (FieldCopyCtor->isImplicit() && !FieldCopyCtor->isUsed())
- MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
+ MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
}
}
CopyConstructor->setUsed();
@@ -1997,6 +2140,16 @@ void Sema::InitializeVarWithConstructor(VarDecl *VD,
VD->setInit(Context, Temp);
}
+void Sema::MarcDestructorReferenced(SourceLocation Loc, QualType DeclInitType)
+{
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(
+ DeclInitType->getAsRecordType()->getDecl());
+ if (!ClassDecl->hasTrivialDestructor())
+ if (CXXDestructorDecl *Destructor =
+ const_cast<CXXDestructorDecl*>(ClassDecl->getDestructor(Context)))
+ MarkDeclarationReferenced(Loc, Destructor);
+}
+
/// AddCXXDirectInitializerToDecl - This action is called immediately after
/// ActOnDeclarator, when a C++ direct initializer is present.
/// e.g: "int x(1);"
@@ -2063,6 +2216,9 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
VDecl->setCXXDirectInitializer(true);
InitializeVarWithConstructor(VDecl, Constructor, DeclInitType,
(Expr**)Exprs.release(), NumExprs);
+ // FIXME. Must do all that is needed to destroy the object
+ // on scope exit. For now, just mark the destructor as used.
+ MarcDestructorReferenced(VDecl->getLocation(), DeclInitType);
}
return;
}
@@ -2590,7 +2746,8 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
ParamEnd = FnDecl->param_end();
Param != ParamEnd; ++Param) {
QualType ParamType = (*Param)->getType().getNonReferenceType();
- if (ParamType->isRecordType() || ParamType->isEnumeralType()) {
+ if (ParamType->isDependentType() || ParamType->isRecordType() ||
+ ParamType->isEnumeralType()) {
ClassOrEnumParam = true;
break;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 56d3bfe..383edec 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -623,17 +623,42 @@ Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
/// BuildDeclRefExpr - Build either a DeclRefExpr or a
/// QualifiedDeclRefExpr based on whether or not SS is a
/// nested-name-specifier.
-DeclRefExpr *
+Sema::OwningExprResult
Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
bool TypeDependent, bool ValueDependent,
const CXXScopeSpec *SS) {
+ if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) {
+ Diag(Loc,
+ diag::err_auto_variable_cannot_appear_in_own_initializer)
+ << D->getDeclName();
+ return ExprError();
+ }
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
+ if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) {
+ if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) {
+ Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
+ << D->getIdentifier() << FD->getDeclName();
+ Diag(D->getLocation(), diag::note_local_variable_declared_here)
+ << D->getIdentifier();
+ return ExprError();
+ }
+ }
+ }
+ }
+
MarkDeclarationReferenced(Loc, D);
+
+ Expr *E;
if (SS && !SS->isEmpty()) {
- return new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
- ValueDependent, SS->getRange(),
+ E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
+ ValueDependent, SS->getRange(),
static_cast<NestedNameSpecifier *>(SS->getScopeRep()));
} else
- return new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
+ E = new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
+
+ return Owned(E);
}
/// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or
@@ -968,7 +993,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// The pointer is type- and value-dependent if it points into something
// dependent.
bool Dependent = DC->isDependentContext();
- return Owned(BuildDeclRefExpr(D, DType, Loc, Dependent, Dependent, SS));
+ return BuildDeclRefExpr(D, DType, Loc, Dependent, Dependent, SS);
}
}
}
@@ -1061,11 +1086,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// Make the DeclRefExpr or BlockDeclRefExpr for the decl.
if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D))
- return Owned(BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
- false, false, SS));
+ return BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
+ false, false, SS);
else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
- return Owned(BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
- false, false, SS));
+ return BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
+ false, false, SS);
ValueDecl *VD = cast<ValueDecl>(D);
// Check whether this declaration can be used. Note that we suppress
@@ -1113,7 +1138,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
QualType NoProtoType = T;
if (const FunctionProtoType *Proto = T->getAsFunctionProtoType())
NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
- return Owned(BuildDeclRefExpr(VD, NoProtoType, Loc, false, false, SS));
+ return BuildDeclRefExpr(VD, NoProtoType, Loc, false, false, SS);
}
}
@@ -1194,8 +1219,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
}
}
- return Owned(BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
- TypeDependent, ValueDependent, SS));
+ return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
+ TypeDependent, ValueDependent, SS);
}
Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
@@ -1886,7 +1911,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
// This flag determines whether or not CompName has an 's' char prefix,
// indicating that it is a string of hex values to be used as vector indices.
- bool HexSwizzle = *compStr == 's';
+ bool HexSwizzle = *compStr == 's' || *compStr == 'S';
// Check that we've found one of the special components, or that the component
// names must come from the same set.
@@ -2586,11 +2611,16 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
CommaLocs, RParenLoc));
// Determine whether this is a call to a member function.
- if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens()))
- if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
- isa<CXXMethodDecl>(MemExpr->getMemberDecl()))
+ if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens())) {
+ NamedDecl *MemDecl = MemExpr->getMemberDecl();
+ if (isa<OverloadedFunctionDecl>(MemDecl) ||
+ isa<CXXMethodDecl>(MemDecl) ||
+ (isa<FunctionTemplateDecl>(MemDecl) &&
+ isa<CXXMethodDecl>(
+ cast<FunctionTemplateDecl>(MemDecl)->getTemplatedDecl())))
return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc));
+ }
}
// If we're directly calling a function, get the appropriate declaration.
@@ -2626,13 +2656,19 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
}
OverloadedFunctionDecl *Ovl = 0;
+ FunctionTemplateDecl *FunctionTemplate = 0;
if (DRExpr) {
FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
+ if ((FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DRExpr->getDecl())))
+ FDecl = FunctionTemplate->getTemplatedDecl();
+ else
+ FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
}
- if (Ovl || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
+ if (Ovl || FunctionTemplate ||
+ (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
// We don't perform ADL for implicit declarations of builtins.
if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit())
ADL = false;
@@ -2641,7 +2677,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
if (!getLangOptions().CPlusPlus)
ADL = false;
- if (Ovl || ADL) {
+ if (Ovl || FunctionTemplate || ADL) {
FDecl = ResolveOverloadedCallFn(Fn, DRExpr? DRExpr->getDecl() : 0,
UnqualifiedName, LParenLoc, Args,
NumArgs, CommaLocs, RParenLoc, ADL);
@@ -2846,12 +2882,15 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
return Diag(castExpr->getLocStart(),
diag::err_typecheck_expect_scalar_operand)
<< castExpr->getType() << castExpr->getSourceRange();
- } else if (castExpr->getType()->isVectorType()) {
- if (CheckVectorCast(TyR, castExpr->getType(), castType))
+ } else if (castType->isExtVectorType()) {
+ if (CheckExtVectorCast(TyR, castType, castExpr->getType()))
return true;
} else if (castType->isVectorType()) {
if (CheckVectorCast(TyR, castType, castExpr->getType()))
return true;
+ } else if (castExpr->getType()->isVectorType()) {
+ if (CheckVectorCast(TyR, castExpr->getType(), castType))
+ return true;
} else if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) {
return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR;
} else if (!castType->isArithmeticType()) {
@@ -2889,6 +2928,35 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) {
return false;
}
+bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) {
+ assert(DestTy->isExtVectorType() && "Not an extended vector type!");
+
+ // If SrcTy is also an ExtVectorType, the types must be identical unless
+ // lax vector conversions is enabled.
+ if (SrcTy->isExtVectorType()) {
+ if (getLangOptions().LaxVectorConversions &&
+ Context.getTypeSize(DestTy) == Context.getTypeSize(SrcTy))
+ return false;
+ if (DestTy != SrcTy)
+ return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
+ << DestTy << SrcTy << R;
+ return false;
+ }
+
+ // If SrcTy is a VectorType, then only the total size must match.
+ if (SrcTy->isVectorType()) {
+ if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy))
+ return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
+ << DestTy << SrcTy << R;
+ return false;
+ }
+
+ // All scalar -> ext vector "c-style" casts are legal; the appropriate
+ // conversion will take place first from scalar to elt type, and then
+ // splat from elt type to vector.
+ return false;
+}
+
Action::OwningExprResult
Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg Op) {
@@ -5525,18 +5593,27 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (!Constructor->isUsed())
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
}
- // FIXME: more checking for other implicits go here.
- else
- Constructor->setUsed(true);
- }
-
+ } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
+ if (Destructor->isImplicit() && !Destructor->isUsed())
+ DefineImplicitDestructor(Loc, Destructor);
+
+ } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
+ if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
+ MethodDecl->getOverloadedOperator() == OO_Equal) {
+ if (!MethodDecl->isUsed())
+ DefineImplicitOverloadedAssign(Loc, MethodDecl);
+ }
+ }
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- // Implicit instantiation of function templates
+ // Implicit instantiation of function templates and member functions of
+ // class templates.
if (!Function->getBody(Context)) {
- if (Function->getInstantiatedFromMemberFunction())
+ // FIXME: distinguish between implicit instantiations of function
+ // templates and explicit specializations (the latter don't get
+ // instantiated, naturally).
+ if (Function->getInstantiatedFromMemberFunction() ||
+ Function->getPrimaryTemplate())
PendingImplicitInstantiations.push(std::make_pair(Function, Loc));
-
- // FIXME: check for function template specializations.
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index a567218..bc8fc4e 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -771,7 +771,7 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
Diag(ED->getLocation(), diag::err_type_defined_in_condition);
}
- DeclPtrTy Dcl = ActOnDeclarator(S, D, DeclPtrTy());
+ DeclPtrTy Dcl = ActOnDeclarator(S, D);
if (!Dcl)
return ExprError();
AddInitializerToDecl(Dcl, move(AssignExprVal), /*DirectInit=*/false);
@@ -1567,7 +1567,7 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
CXXTemporary *Temp = CXXTemporary::Create(Context,
RD->getDestructor(Context));
ExprTemporaries.push_back(Temp);
-
+ MarcDestructorReferenced(E->getExprLoc(), E->getType());
// FIXME: Add the temporary to the temporaries vector.
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 4508596..6b812e1 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -200,10 +200,9 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
if (InitEntity)
return Diag(InitLoc, diag::err_cannot_initialize_decl)
- << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
- << Init->getType() << Init->getSourceRange();
- else
- return Diag(InitLoc, diag::err_cannot_initialize_decl_noname)
+ << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
+ << Init->getType() << Init->getSourceRange();
+ return Diag(InitLoc, diag::err_cannot_initialize_decl_noname)
<< DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
<< Init->getType() << Init->getSourceRange();
}
@@ -211,7 +210,7 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
// C99 6.7.8p16.
if (DeclType->isArrayType())
return Diag(Init->getLocStart(), diag::err_array_init_list_required)
- << Init->getSourceRange();
+ << Init->getSourceRange();
return CheckSingleInitializer(Init, DeclType, DirectInit, *this);
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 37e1df3..cc9e783 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -125,21 +125,32 @@ MaybeConstructOverloadSet(ASTContext &Context,
assert(!isa<OverloadedFunctionDecl>(*I) &&
"Cannot have an overloaded function");
- if (isa<FunctionDecl>(*I)) {
+ if ((*I)->isFunctionOrFunctionTemplate()) {
// If we found a function, there might be more functions. If
// so, collect them into an overload set.
DeclIterator Last = I;
OverloadedFunctionDecl *Ovl = 0;
- for (++Last; Last != IEnd && isa<FunctionDecl>(*Last); ++Last) {
+ for (++Last;
+ Last != IEnd && (*Last)->isFunctionOrFunctionTemplate();
+ ++Last) {
if (!Ovl) {
// FIXME: We leak this overload set. Eventually, we want to stop
// building the declarations for these overload sets, so there will be
// nothing to leak.
Ovl = OverloadedFunctionDecl::Create(Context, (*I)->getDeclContext(),
(*I)->getDeclName());
- Ovl->addOverload(cast<FunctionDecl>(*I));
+ NamedDecl *ND = (*I)->getUnderlyingDecl();
+ if (isa<FunctionDecl>(ND))
+ Ovl->addOverload(cast<FunctionDecl>(ND));
+ else
+ Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
}
- Ovl->addOverload(cast<FunctionDecl>(*Last));
+
+ NamedDecl *ND = (*Last)->getUnderlyingDecl();
+ if (isa<FunctionDecl>(ND))
+ Ovl->addOverload(cast<FunctionDecl>(ND));
+ else
+ Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
}
// If we had more than one function, we built an overload
@@ -202,11 +213,12 @@ MergeLookupResults(ASTContext &Context, LookupResultsTy &Results) {
break;
case LResult::Found: {
- NamedDecl *ND = I->getAsDecl();
+ NamedDecl *ND = I->getAsDecl()->getUnderlyingDecl();
+
if (TagDecl *TD = dyn_cast<TagDecl>(ND)) {
TagFound = Context.getCanonicalDecl(TD);
TagNames += FoundDecls.insert(TagFound)? 1 : 0;
- } else if (isa<FunctionDecl>(ND))
+ } else if (ND->isFunctionOrFunctionTemplate())
Functions += FoundDecls.insert(ND)? 1 : 0;
else
FoundDecls.insert(ND);
@@ -313,10 +325,9 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
Sema::LookupResult
Sema::LookupResult::CreateLookupResult(ASTContext &Context, NamedDecl *D) {
- if (ObjCCompatibleAliasDecl *Alias
- = dyn_cast_or_null<ObjCCompatibleAliasDecl>(D))
- D = Alias->getClassInterface();
-
+ if (D)
+ D = D->getUnderlyingDecl();
+
LookupResult Result;
Result.StoredKind = (D && isa<OverloadedFunctionDecl>(D))?
OverloadedDeclSingleDecl : SingleDecl;
@@ -334,10 +345,10 @@ Sema::LookupResult::CreateLookupResult(ASTContext &Context,
LookupResult Result;
Result.Context = &Context;
- if (F != L && isa<FunctionDecl>(*F)) {
+ if (F != L && (*F)->isFunctionOrFunctionTemplate()) {
IdentifierResolver::iterator Next = F;
++Next;
- if (Next != L && isa<FunctionDecl>(*Next)) {
+ if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) {
Result.StoredKind = OverloadedDeclFromIdResolver;
Result.First = F.getAsOpaqueValue();
Result.Last = L.getAsOpaqueValue();
@@ -345,11 +356,10 @@ Sema::LookupResult::CreateLookupResult(ASTContext &Context,
}
}
- Decl *D = *F;
- if (ObjCCompatibleAliasDecl *Alias
- = dyn_cast_or_null<ObjCCompatibleAliasDecl>(D))
- D = Alias->getClassInterface();
-
+ NamedDecl *D = *F;
+ if (D)
+ D = D->getUnderlyingDecl();
+
Result.StoredKind = SingleDecl;
Result.First = reinterpret_cast<uintptr_t>(D);
Result.Last = 0;
@@ -363,10 +373,10 @@ Sema::LookupResult::CreateLookupResult(ASTContext &Context,
LookupResult Result;
Result.Context = &Context;
- if (F != L && isa<FunctionDecl>(*F)) {
+ if (F != L && (*F)->isFunctionOrFunctionTemplate()) {
DeclContext::lookup_iterator Next = F;
++Next;
- if (Next != L && isa<FunctionDecl>(*Next)) {
+ if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) {
Result.StoredKind = OverloadedDeclFromDeclContext;
Result.First = reinterpret_cast<uintptr_t>(F);
Result.Last = reinterpret_cast<uintptr_t>(L);
@@ -374,10 +384,9 @@ Sema::LookupResult::CreateLookupResult(ASTContext &Context,
}
}
- Decl *D = *F;
- if (ObjCCompatibleAliasDecl *Alias
- = dyn_cast_or_null<ObjCCompatibleAliasDecl>(D))
- D = Alias->getClassInterface();
+ NamedDecl *D = *F;
+ if (D)
+ D = D->getUnderlyingDecl();
Result.StoredKind = SingleDecl;
Result.First = reinterpret_cast<uintptr_t>(D);
@@ -1083,7 +1092,7 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
// Lookup in a base class succeeded; return these results.
// If we found a function declaration, return an overload set.
- if (isa<FunctionDecl>(*Paths.front().Decls.first))
+ if ((*Paths.front().Decls.first)->isFunctionOrFunctionTemplate())
return LookupResult::CreateLookupResult(Context,
Paths.front().Decls.first, Paths.front().Decls.second);
@@ -1239,7 +1248,8 @@ static void
addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
ASTContext &Context,
Sema::AssociatedNamespaceSet &AssociatedNamespaces,
- Sema::AssociatedClassSet &AssociatedClasses) {
+ Sema::AssociatedClassSet &AssociatedClasses,
+ bool &GlobalScope) {
// C++ [basic.lookup.koenig]p2:
// [...]
// -- If T is a class type (including unions), its associated
@@ -1252,13 +1262,14 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
DeclContext *Ctx = Class->getDeclContext();
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
AssociatedClasses.insert(EnclosingClass);
-
// Add the associated namespace for this class.
while (Ctx->isRecord())
Ctx = Ctx->getParent();
if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
AssociatedNamespaces.insert(EnclosingNamespace);
-
+ else if (Ctx->isTranslationUnit())
+ GlobalScope = true;
+
// Add the class itself. If we've already seen this class, we don't
// need to visit base classes.
if (!AssociatedClasses.insert(Class))
@@ -1288,6 +1299,8 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
BaseCtx = BaseCtx->getParent();
if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(BaseCtx))
AssociatedNamespaces.insert(EnclosingNamespace);
+ else if (BaseCtx->isTranslationUnit())
+ GlobalScope = true;
// Make sure we visit the bases of this base class.
if (BaseDecl->bases_begin() != BaseDecl->bases_end())
@@ -1304,7 +1317,8 @@ static void
addAssociatedClassesAndNamespaces(QualType T,
ASTContext &Context,
Sema::AssociatedNamespaceSet &AssociatedNamespaces,
- Sema::AssociatedClassSet &AssociatedClasses) {
+ Sema::AssociatedClassSet &AssociatedClasses,
+ bool &GlobalScope) {
// C++ [basic.lookup.koenig]p2:
//
// For each argument type T in the function call, there is a set
@@ -1346,7 +1360,8 @@ addAssociatedClassesAndNamespaces(QualType T,
= dyn_cast<CXXRecordDecl>(ClassType->getDecl())) {
addAssociatedClassesAndNamespaces(ClassDecl, Context,
AssociatedNamespaces,
- AssociatedClasses);
+ AssociatedClasses,
+ GlobalScope);
return;
}
@@ -1366,6 +1381,8 @@ addAssociatedClassesAndNamespaces(QualType T,
Ctx = Ctx->getParent();
if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
AssociatedNamespaces.insert(EnclosingNamespace);
+ else if (Ctx->isTranslationUnit())
+ GlobalScope = true;
return;
}
@@ -1377,7 +1394,8 @@ addAssociatedClassesAndNamespaces(QualType T,
// Return type
addAssociatedClassesAndNamespaces(FunctionType->getResultType(),
Context,
- AssociatedNamespaces, AssociatedClasses);
+ AssociatedNamespaces, AssociatedClasses,
+ GlobalScope);
const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FunctionType);
if (!Proto)
@@ -1388,7 +1406,8 @@ addAssociatedClassesAndNamespaces(QualType T,
ArgEnd = Proto->arg_type_end();
Arg != ArgEnd; ++Arg)
addAssociatedClassesAndNamespaces(*Arg, Context,
- AssociatedNamespaces, AssociatedClasses);
+ AssociatedNamespaces, AssociatedClasses,
+ GlobalScope);
return;
}
@@ -1406,13 +1425,15 @@ addAssociatedClassesAndNamespaces(QualType T,
// Handle the type that the pointer to member points to.
addAssociatedClassesAndNamespaces(MemberPtr->getPointeeType(),
Context,
- AssociatedNamespaces, AssociatedClasses);
+ AssociatedNamespaces, AssociatedClasses,
+ GlobalScope);
// Handle the class type into which this points.
if (const RecordType *Class = MemberPtr->getClass()->getAsRecordType())
addAssociatedClassesAndNamespaces(cast<CXXRecordDecl>(Class->getDecl()),
Context,
- AssociatedNamespaces, AssociatedClasses);
+ AssociatedNamespaces, AssociatedClasses,
+ GlobalScope);
return;
}
@@ -1431,7 +1452,8 @@ addAssociatedClassesAndNamespaces(QualType T,
void
Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
AssociatedNamespaceSet &AssociatedNamespaces,
- AssociatedClassSet &AssociatedClasses) {
+ AssociatedClassSet &AssociatedClasses,
+ bool &GlobalScope) {
AssociatedNamespaces.clear();
AssociatedClasses.clear();
@@ -1447,7 +1469,8 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
if (Arg->getType() != Context.OverloadTy) {
addAssociatedClassesAndNamespaces(Arg->getType(), Context,
- AssociatedNamespaces, AssociatedClasses);
+ AssociatedNamespaces, AssociatedClasses,
+ GlobalScope);
continue;
}
@@ -1475,7 +1498,9 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
Func != FuncEnd; ++Func) {
- FunctionDecl *FDecl = cast<FunctionDecl>(*Func);
+ FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*Func);
+ if (!FDecl)
+ FDecl = cast<FunctionTemplateDecl>(*Func)->getTemplatedDecl();
// Add the namespace in which this function was defined. Note
// that, if this is a member function, we do *not* consider the
@@ -1483,11 +1508,14 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
DeclContext *Ctx = FDecl->getDeclContext();
if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
AssociatedNamespaces.insert(EnclosingNamespace);
+ else if (Ctx->isTranslationUnit())
+ GlobalScope = true;
// Add the classes and namespaces associated with the parameter
// types and return type of this function.
addAssociatedClassesAndNamespaces(FDecl->getType(), Context,
- AssociatedNamespaces, AssociatedClasses);
+ AssociatedNamespaces, AssociatedClasses,
+ GlobalScope);
}
}
}
@@ -1589,8 +1617,10 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
AssociatedClassSet AssociatedClasses;
+ bool GlobalScope = false;
FindAssociatedClassesAndNamespaces(Args, NumArgs,
- AssociatedNamespaces, AssociatedClasses);
+ AssociatedNamespaces, AssociatedClasses,
+ GlobalScope);
// C++ [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
@@ -1626,4 +1656,17 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
Functions.insert(Func);
}
}
+
+ if (GlobalScope) {
+ DeclContext::lookup_iterator I, E;
+ for (llvm::tie(I, E)
+ = Context.getTranslationUnitDecl()->lookup(Context, Name);
+ I != E; ++I) {
+ FunctionDecl *Func = dyn_cast<FunctionDecl>(*I);
+ if (!Func)
+ break;
+
+ Functions.insert(Func);
+ }
+ }
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 11cd510..fcc1557 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -300,7 +300,18 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
// This function overloads every function in the overload set.
return true;
- } else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) {
+ } else if (FunctionTemplateDecl *Old = dyn_cast<FunctionTemplateDecl>(OldD))
+ return IsOverload(New, Old->getTemplatedDecl(), MatchedDecl);
+ else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) {
+ FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
+
+ // C++ [temp.fct]p2:
+ // A function template can be overloaded with other function templates
+ // and with normal (non-template) functions.
+ if ((OldTemplate == 0) != (NewTemplate == 0))
+ return true;
+
// Is the function New an overload of the function Old?
QualType OldQType = Context.getCanonicalType(Old->getType());
QualType NewQType = Context.getCanonicalType(New->getType());
@@ -315,8 +326,8 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
isa<FunctionNoProtoType>(NewQType.getTypePtr()))
return false;
- FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType.getTypePtr());
- FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType.getTypePtr());
+ FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType);
+ FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType);
// The signature of a function includes the types of its
// parameters (C++ 1.3.10), which includes the presence or absence
@@ -328,6 +339,22 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
NewType->arg_type_begin())))
return true;
+ // C++ [temp.over.link]p4:
+ // The signature of a function template consists of its function
+ // signature, its return type and its template parameter list. The names
+ // of the template parameters are significant only for establishing the
+ // relationship between the template parameters and the rest of the
+ // signature.
+ //
+ // We check the return type and template parameter lists for function
+ // templates first; the remaining checks follow.
+ if (NewTemplate &&
+ (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
+ false, false, SourceLocation()) ||
+ OldType->getResultType() != NewType->getResultType()))
+ return true;
+
// If the function is a class member, its signature includes the
// cv-qualifiers (if any) on the function itself.
//
@@ -2048,7 +2075,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
assert(Proto && "Functions without a prototype cannot be overloaded");
assert(!isa<CXXConversionDecl>(Function) &&
"Use AddConversionCandidate for conversion functions");
-
+ assert(!Function->getDescribedFunctionTemplate() &&
+ "Use AddTemplateOverloadCandidate for function templates");
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
if (!isa<CXXConstructorDecl>(Method)) {
// If we get here, it's because we're calling a member function
@@ -2233,6 +2262,42 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
}
}
+/// \brief Add a C++ function template as a candidate in the candidate set,
+/// using template argument deduction to produce an appropriate function
+/// template specialization.
+void
+Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions,
+ bool ForceRValue) {
+ // C++ [over.match.funcs]p7:
+ // In each case where a candidate is a function template, candidate
+ // function template specializations are generated using template argument
+ // deduction (14.8.3, 14.8.2). Those candidates are then handled as
+ // candidate functions in the usual way.113) A given name can refer to one
+ // or more function templates and also to a set of overloaded non-template
+ // functions. In such a case, the candidate functions generated from each
+ // function template are combined with the set of non-template candidate
+ // functions.
+ TemplateDeductionInfo Info(Context);
+ FunctionDecl *Specialization = 0;
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArguments(FunctionTemplate, Args, NumArgs,
+ Specialization, Info)) {
+ // FIXME: Record what happened with template argument deduction, so
+ // that we can give the user a beautiful diagnostic.
+ (void)Result;
+ return;
+ }
+
+ // Add the function template specialization produced by template argument
+ // deduction as a candidate.
+ assert(Specialization && "Missing function template specialization?");
+ AddOverloadCandidate(Specialization, Args, NumArgs, CandidateSet,
+ SuppressUserConversions, ForceRValue);
+}
+
/// AddConversionCandidate - Add a C++ conversion function as a
/// candidate in the candidate set (C++ [over.match.conv],
/// C++ [over.match.copy]). From is the expression we're converting from,
@@ -3653,8 +3718,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
} else if (IsMember)
continue;
- if (FunctionType == Context.getCanonicalType((*Fun)->getType()))
- return *Fun;
+ if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Fun)) {
+ if (FunctionType == Context.getCanonicalType(FunDecl->getType()))
+ return FunDecl;
+ } else {
+ unsigned DiagID
+ = PP.getDiagnostics().getCustomDiagID(Diagnostic::Warning,
+ "Clang does not yet support templated conversion functions");
+ Diag(From->getLocStart(), DiagID);
+ }
}
return 0;
@@ -3699,10 +3771,18 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
Func != FuncEnd; ++Func) {
- AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet);
+ DeclContext *Ctx = 0;
+ if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Func)) {
+ AddOverloadCandidate(FunDecl, Args, NumArgs, CandidateSet);
+ Ctx = FunDecl->getDeclContext();
+ } else {
+ FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*Func);
+ AddTemplateOverloadCandidate(FunTmpl, Args, NumArgs, CandidateSet);
+ Ctx = FunTmpl->getDeclContext();
+ }
- if ((*Func)->getDeclContext()->isRecord() ||
- (*Func)->getDeclContext()->isFunctionOrMethod())
+
+ if (Ctx->isRecord() || Ctx->isFunctionOrMethod())
ArgumentDependentLookup = false;
}
} else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) {
@@ -3711,7 +3791,13 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
if (Func->getDeclContext()->isRecord() ||
Func->getDeclContext()->isFunctionOrMethod())
ArgumentDependentLookup = false;
- }
+ } else if (FunctionTemplateDecl *FuncTemplate
+ = dyn_cast_or_null<FunctionTemplateDecl>(Callee)) {
+ AddTemplateOverloadCandidate(FuncTemplate, Args, NumArgs, CandidateSet);
+
+ if (FuncTemplate->getDeclContext()->isRecord())
+ ArgumentDependentLookup = false;
+ }
if (Callee)
UnqualifiedName = Callee->getDeclName();
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index e98ebb1..cd985c5 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -67,9 +67,10 @@ TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
}
}
- // FIXME: What follows is a gross hack.
+ // FIXME: What follows is a slightly less gross hack than what used to
+ // follow.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) {
- if (FD->getType()->isDependentType()) {
+ if (FD->getDescribedFunctionTemplate()) {
TemplateResult = TemplateTy::make(FD);
return TNK_Function_template;
}
@@ -78,7 +79,7 @@ TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
FEnd = Ovl->function_end();
F != FEnd; ++F) {
- if ((*F)->getType()->isDependentType()) {
+ if (isa<FunctionTemplateDecl>(*F)) {
TemplateResult = TemplateTy::make(Ovl);
return TNK_Function_template;
}
@@ -1808,8 +1809,8 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
!isa<TemplateTemplateParmDecl>(Template)) {
assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
- Diag(Arg->getSourceRange().getBegin(),
- diag::note_template_arg_refers_here_func)
+ Diag(Arg->getLocStart(), diag::err_template_arg_not_class_template);
+ Diag(Template->getLocation(), diag::note_template_arg_refers_here_func)
<< Template;
}
@@ -1873,15 +1874,17 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
OldParmEnd = Old->end(), NewParm = New->begin();
OldParm != OldParmEnd; ++OldParm, ++NewParm) {
if ((*OldParm)->getKind() != (*NewParm)->getKind()) {
- unsigned NextDiag = diag::err_template_param_different_kind;
- if (TemplateArgLoc.isValid()) {
- Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch);
- NextDiag = diag::note_template_param_different_kind;
- }
- Diag((*NewParm)->getLocation(), NextDiag)
+ if (Complain) {
+ unsigned NextDiag = diag::err_template_param_different_kind;
+ if (TemplateArgLoc.isValid()) {
+ Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_param_different_kind;
+ }
+ Diag((*NewParm)->getLocation(), NextDiag)
<< IsTemplateTemplateParm;
- Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration)
+ Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration)
<< IsTemplateTemplateParm;
+ }
return false;
}
@@ -2499,6 +2502,40 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
return DeclPtrTy::make(Specialization);
}
+Sema::DeclPtrTy
+Sema::ActOnTemplateDeclarator(Scope *S,
+ MultiTemplateParamsArg TemplateParameterLists,
+ Declarator &D) {
+ return HandleDeclarator(S, D, move(TemplateParameterLists), false);
+}
+
+Sema::DeclPtrTy
+Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
+ MultiTemplateParamsArg TemplateParameterLists,
+ Declarator &D) {
+ assert(getCurFunctionDecl() == 0 && "Function parsing confused");
+ assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+ "Not a function declarator!");
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+
+ if (FTI.hasPrototype) {
+ // FIXME: Diagnose arguments without names in C.
+ }
+
+ Scope *ParentScope = FnBodyScope->getParent();
+
+ DeclPtrTy DP = HandleDeclarator(ParentScope, D,
+ move(TemplateParameterLists),
+ /*IsFunctionDefinition=*/true);
+ FunctionTemplateDecl *FunctionTemplate
+ = cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>());
+ if (FunctionTemplate)
+ return ActOnStartOfFunctionDef(FnBodyScope,
+ DeclPtrTy::make(FunctionTemplate->getTemplatedDecl()));
+
+ return DeclPtrTy();
+}
+
// Explicit instantiation of a class template specialization
Sema::DeclResult
Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index de3e52d..3d909bb 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -18,6 +18,30 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/Compiler.h"
+
+namespace clang {
+ /// \brief Various flags that control template argument deduction.
+ ///
+ /// These flags can be bitwise-OR'd together.
+ enum TemplateDeductionFlags {
+ /// \brief No template argument deduction flags, which indicates the
+ /// strictest results for template argument deduction (as used for, e.g.,
+ /// matching class template partial specializations).
+ TDF_None = 0,
+ /// \brief Within template argument deduction from a function call, we are
+ /// matching with a parameter type for which the original parameter was
+ /// a reference.
+ TDF_ParamWithReferenceType = 0x1,
+ /// \brief Within template argument deduction from a function call, we
+ /// are matching in a case where we ignore cv-qualifiers.
+ TDF_IgnoreQualifiers = 0x02,
+ /// \brief Within template argument deduction from a function call,
+ /// we are matching in a case where we can perform template argument
+ /// deduction from a template-id of a derived class of the argument type.
+ TDF_DerivedClass = 0x04
+ };
+}
+
using namespace clang;
static Sema::TemplateDeductionResult
@@ -156,27 +180,52 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_Success;
}
+/// \brief Deduce the template arguments by comparing the parameter type and
+/// the argument type (C++ [temp.deduct.type]).
+///
+/// \param Context the AST context in which this deduction occurs.
+///
+/// \param TemplateParams the template parameters that we are deducing
+///
+/// \param ParamIn the parameter type
+///
+/// \param ArgIn the argument type
+///
+/// \param Info information about the template argument deduction itself
+///
+/// \param Deduced the deduced template arguments
+///
+/// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe
+/// how template argument deduction is performed.
+///
+/// \returns the result of template argument deduction so far. Note that a
+/// "success" result means that template argument deduction has not yet failed,
+/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
DeduceTemplateArguments(ASTContext &Context,
TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ unsigned TDF) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
QualType Param = Context.getCanonicalType(ParamIn);
QualType Arg = Context.getCanonicalType(ArgIn);
- // If the parameter type is not dependent, just compare the types
- // directly.
- if (!Param->isDependentType()) {
- if (Param == Arg)
- return Sema::TDK_Success;
-
- Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
- Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
- return Sema::TDK_NonDeducedMismatch;
+ // C++0x [temp.deduct.call]p4 bullet 1:
+ // - If the original P is a reference type, the deduced A (i.e., the type
+ // referred to by the reference) can be more cv-qualified than the
+ // transformed A.
+ if (TDF & TDF_ParamWithReferenceType) {
+ unsigned ExtraQualsOnParam
+ = Param.getCVRQualifiers() & ~Arg.getCVRQualifiers();
+ Param.setCVRQualifiers(Param.getCVRQualifiers() & ~ExtraQualsOnParam);
}
+
+ // If the parameter type is not dependent, there is nothing to deduce.
+ if (!Param->isDependentType())
+ return Sema::TDK_Success;
// C++ [temp.deduct.type]p9:
// A template type argument T, a template template argument TT or a
@@ -191,7 +240,7 @@ DeduceTemplateArguments(ASTContext &Context,
// The argument type can not be less qualified than the parameter
// type.
- if (Param.isMoreQualifiedThan(Arg)) {
+ if (Param.isMoreQualifiedThan(Arg) && !(TDF & TDF_IgnoreQualifiers)) {
Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
Info.FirstArg = Deduced[Index];
Info.SecondArg = TemplateArgument(SourceLocation(), Arg);
@@ -227,8 +276,16 @@ DeduceTemplateArguments(ASTContext &Context,
Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
- if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
- return Sema::TDK_NonDeducedMismatch;
+ // Check the cv-qualifiers on the parameter and argument types.
+ if (!(TDF & TDF_IgnoreQualifiers)) {
+ if (TDF & TDF_ParamWithReferenceType) {
+ if (Param.isMoreQualifiedThan(Arg))
+ return Sema::TDK_NonDeducedMismatch;
+ } else {
+ if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
+ return Sema::TDK_NonDeducedMismatch;
+ }
+ }
switch (Param->getTypeClass()) {
// No deduction possible for these types
@@ -241,10 +298,11 @@ DeduceTemplateArguments(ASTContext &Context,
if (!PointerArg)
return Sema::TDK_NonDeducedMismatch;
+ unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
return DeduceTemplateArguments(Context, TemplateParams,
cast<PointerType>(Param)->getPointeeType(),
PointerArg->getPointeeType(),
- Info, Deduced);
+ Info, Deduced, SubTDF);
}
// T &
@@ -256,7 +314,7 @@ DeduceTemplateArguments(ASTContext &Context,
return DeduceTemplateArguments(Context, TemplateParams,
cast<LValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
- Info, Deduced);
+ Info, Deduced, 0);
}
// T && [C++0x]
@@ -268,7 +326,7 @@ DeduceTemplateArguments(ASTContext &Context,
return DeduceTemplateArguments(Context, TemplateParams,
cast<RValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
- Info, Deduced);
+ Info, Deduced, 0);
}
// T [] (implied, but not stated explicitly)
@@ -281,7 +339,7 @@ DeduceTemplateArguments(ASTContext &Context,
return DeduceTemplateArguments(Context, TemplateParams,
Context.getAsIncompleteArrayType(Param)->getElementType(),
IncompleteArrayArg->getElementType(),
- Info, Deduced);
+ Info, Deduced, 0);
}
// T [integer-constant]
@@ -299,7 +357,7 @@ DeduceTemplateArguments(ASTContext &Context,
return DeduceTemplateArguments(Context, TemplateParams,
ConstantArrayParm->getElementType(),
ConstantArrayArg->getElementType(),
- Info, Deduced);
+ Info, Deduced, 0);
}
// type [i]
@@ -315,7 +373,7 @@ DeduceTemplateArguments(ASTContext &Context,
= DeduceTemplateArguments(Context, TemplateParams,
DependentArrayParm->getElementType(),
ArrayArg->getElementType(),
- Info, Deduced))
+ Info, Deduced, 0))
return Result;
// Determine the array bound is something we can deduce.
@@ -371,7 +429,7 @@ DeduceTemplateArguments(ASTContext &Context,
= DeduceTemplateArguments(Context, TemplateParams,
FunctionProtoParam->getResultType(),
FunctionProtoArg->getResultType(),
- Info, Deduced))
+ Info, Deduced, 0))
return Result;
for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
@@ -380,14 +438,14 @@ DeduceTemplateArguments(ASTContext &Context,
= DeduceTemplateArguments(Context, TemplateParams,
FunctionProtoParam->getArgType(I),
FunctionProtoArg->getArgType(I),
- Info, Deduced))
+ Info, Deduced, 0))
return Result;
}
return Sema::TDK_Success;
}
- // template-name<T> (wheretemplate-name refers to a class template)
+ // template-name<T> (where template-name refers to a class template)
// template-name<i>
// TT<T> (TODO)
// TT<i> (TODO)
@@ -440,6 +498,11 @@ DeduceTemplateArguments(ASTContext &Context,
if (!RecordArg)
return Sema::TDK_NonDeducedMismatch;
+ // FIXME: Check TDF_DerivedClass here. When this flag is set, we need
+ // to troll through the base classes of the argument and try matching
+ // all of them. Failure to match does not mean that there is a problem,
+ // of course.
+
ClassTemplateSpecializationDecl *SpecArg
= dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
if (!SpecArg)
@@ -489,13 +552,14 @@ DeduceTemplateArguments(ASTContext &Context,
= DeduceTemplateArguments(Context, TemplateParams,
MemPtrParam->getPointeeType(),
MemPtrArg->getPointeeType(),
- Info, Deduced))
+ Info, Deduced,
+ TDF & TDF_IgnoreQualifiers))
return Result;
return DeduceTemplateArguments(Context, TemplateParams,
QualType(MemPtrParam->getClass(), 0),
QualType(MemPtrArg->getClass(), 0),
- Info, Deduced);
+ Info, Deduced, 0);
}
// (clang extension)
@@ -513,7 +577,7 @@ DeduceTemplateArguments(ASTContext &Context,
return DeduceTemplateArguments(Context, TemplateParams,
BlockPtrParam->getPointeeType(),
BlockPtrArg->getPointeeType(), Info,
- Deduced);
+ Deduced, 0);
}
case Type::TypeOfExpr:
@@ -527,7 +591,7 @@ DeduceTemplateArguments(ASTContext &Context,
}
// FIXME: Many more cases to go (to go).
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_Success;
}
static Sema::TemplateDeductionResult
@@ -544,9 +608,8 @@ DeduceTemplateArguments(ASTContext &Context,
case TemplateArgument::Type:
assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch");
- return DeduceTemplateArguments(Context, TemplateParams,
- Param.getAsType(),
- Arg.getAsType(), Info, Deduced);
+ return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(),
+ Arg.getAsType(), Info, Deduced, 0);
case TemplateArgument::Declaration:
// FIXME: Implement this check
@@ -624,6 +687,62 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_Success;
}
+/// \brief Determine whether two template arguments are the same.
+static bool isSameTemplateArg(ASTContext &Context,
+ const TemplateArgument &X,
+ const TemplateArgument &Y) {
+ if (X.getKind() != Y.getKind())
+ return false;
+
+ switch (X.getKind()) {
+ case TemplateArgument::Null:
+ assert(false && "Comparing NULL template argument");
+ break;
+
+ case TemplateArgument::Type:
+ return Context.getCanonicalType(X.getAsType()) ==
+ Context.getCanonicalType(Y.getAsType());
+
+ case TemplateArgument::Declaration:
+ return Context.getCanonicalDecl(X.getAsDecl()) ==
+ Context.getCanonicalDecl(Y.getAsDecl());
+
+ case TemplateArgument::Integral:
+ return *X.getAsIntegral() == *Y.getAsIntegral();
+
+ case TemplateArgument::Expression:
+ // FIXME: We assume that all expressions are distinct, but we should
+ // really check their canonical forms.
+ return false;
+
+ case TemplateArgument::Pack:
+ if (X.pack_size() != Y.pack_size())
+ return false;
+
+ for (TemplateArgument::pack_iterator XP = X.pack_begin(),
+ XPEnd = X.pack_end(),
+ YP = Y.pack_begin();
+ XP != XPEnd; ++XP, ++YP)
+ if (!isSameTemplateArg(Context, *XP, *YP))
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Helper function to build a TemplateParameter when we don't
+/// know its type statically.
+static TemplateParameter makeTemplateParameter(Decl *D) {
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D))
+ return TemplateParameter(TTP);
+ else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
+ return TemplateParameter(NTTP);
+
+ return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
+}
+
/// \brief Perform template argument deduction to determine whether
/// the given template arguments match the given class template
/// partial specialization per C++ [temp.class.spec.match].
@@ -688,32 +807,243 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
for (unsigned I = 0, N = PartialTemplateArgs.flat_size(); I != N; ++I) {
Decl *Param = const_cast<Decl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
- TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I],
- *DeducedArgumentList);
- if (InstArg.getKind() != TemplateArgument::Type) {
- Info.Param = TTP;
- Info.FirstArg = PartialTemplateArgs[I];
- return TDK_SubstitutionFailure;
+ TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I],
+ *DeducedArgumentList);
+ if (InstArg.isNull()) {
+ Info.Param = makeTemplateParameter(Param);
+ Info.FirstArg = PartialTemplateArgs[I];
+ return TDK_SubstitutionFailure;
+ }
+
+ if (InstArg.getKind() == TemplateArgument::Expression) {
+ // When the argument is an expression, check the expression result
+ // against the actual template parameter to get down to the canonical
+ // template argument.
+ Expr *InstExpr = InstArg.getAsExpr();
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
+ Info.Param = makeTemplateParameter(Param);
+ Info.FirstArg = PartialTemplateArgs[I];
+ return TDK_SubstitutionFailure;
+ }
+ } else if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+ // FIXME: template template arguments should really resolve to decls
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InstExpr);
+ if (!DRE || CheckTemplateArgument(TTP, DRE)) {
+ Info.Param = makeTemplateParameter(Param);
+ Info.FirstArg = PartialTemplateArgs[I];
+ return TDK_SubstitutionFailure;
+ }
}
+ }
+
+ if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) {
+ Info.Param = makeTemplateParameter(Param);
+ Info.FirstArg = TemplateArgs[I];
+ Info.SecondArg = InstArg;
+ return TDK_NonDeducedMismatch;
+ }
+ }
- if (Context.getCanonicalType(InstArg.getAsType())
- != Context.getCanonicalType(TemplateArgs[I].getAsType())) {
- Info.Param = TTP;
- Info.FirstArg = TemplateArgs[I];
- Info.SecondArg = InstArg;
- return TDK_NonDeducedMismatch;
- }
+ if (Trap.hasErrorOccurred())
+ return TDK_SubstitutionFailure;
- continue;
- }
+ return TDK_Success;
+}
- // FIXME: Check template template arguments?
+/// \brief Determine whether the given type T is a simple-template-id type.
+static bool isSimpleTemplateIdType(QualType T) {
+ if (const TemplateSpecializationType *Spec
+ = T->getAsTemplateSpecializationType())
+ return Spec->getTemplateName().getAsTemplateDecl() != 0;
+
+ return false;
+}
+
+/// \brief Perform template argument deduction from a function call
+/// (C++ [temp.deduct.call]).
+///
+/// \param FunctionTemplate the function template for which we are performing
+/// template argument deduction.
+///
+/// \param Args the function call arguments
+///
+/// \param NumArgs the number of arguments in Args
+///
+/// \param Specialization if template argument deduction was successful,
+/// this will be set to the function template specialization produced by
+/// template argument deduction.
+///
+/// \param Info the argument will be updated to provide additional information
+/// about template argument deduction.
+///
+/// \returns the result of template argument deduction.
+///
+/// FIXME: We will also need to pass in any explicitly-specified template
+/// arguments.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ Expr **Args, unsigned NumArgs,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info) {
+ FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+
+ // C++ [temp.deduct.call]p1:
+ // Template argument deduction is done by comparing each function template
+ // parameter type (call it P) with the type of the corresponding argument
+ // of the call (call it A) as described below.
+ unsigned CheckArgs = NumArgs;
+ if (NumArgs < Function->getNumParams())
+ return TDK_TooFewArguments;
+ else if (NumArgs > Function->getNumParams()) {
+ const FunctionProtoType *Proto
+ = Function->getType()->getAsFunctionProtoType();
+ if (!Proto->isVariadic())
+ return TDK_TooManyArguments;
+
+ CheckArgs = Function->getNumParams();
+ }
+
+ // Template argument deduction for function templates in a SFINAE context.
+ // Trap any errors that might occur.
+ SFINAETrap Trap(*this);
+
+ // Deduce template arguments from the function parameters.
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Deduced.resize(FunctionTemplate->getTemplateParameters()->size());
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ for (unsigned I = 0; I != CheckArgs; ++I) {
+ QualType ParamType = Function->getParamDecl(I)->getType();
+ QualType ArgType = Args[I]->getType();
+
+ // C++ [temp.deduct.call]p2:
+ // If P is not a reference type:
+ QualType CanonParamType = Context.getCanonicalType(ParamType);
+ bool ParamWasReference = isa<ReferenceType>(CanonParamType);
+ if (!ParamWasReference) {
+ // - If A is an array type, the pointer type produced by the
+ // array-to-pointer standard conversion (4.2) is used in place of
+ // A for type deduction; otherwise,
+ if (ArgType->isArrayType())
+ ArgType = Context.getArrayDecayedType(ArgType);
+ // - If A is a function type, the pointer type produced by the
+ // function-to-pointer standard conversion (4.3) is used in place
+ // of A for type deduction; otherwise,
+ else if (ArgType->isFunctionType())
+ ArgType = Context.getPointerType(ArgType);
+ else {
+ // - If A is a cv-qualified type, the top level cv-qualifiers of A’s
+ // type are ignored for type deduction.
+ QualType CanonArgType = Context.getCanonicalType(ArgType);
+ if (CanonArgType.getCVRQualifiers())
+ ArgType = CanonArgType.getUnqualifiedType();
+ }
+ }
+
+ // C++0x [temp.deduct.call]p3:
+ // If P is a cv-qualified type, the top level cv-qualifiers of P’s type
+ // are ignored for type deduction.
+ if (CanonParamType.getCVRQualifiers())
+ ParamType = CanonParamType.getUnqualifiedType();
+ if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
+ // [...] If P is a reference type, the type referred to by P is used
+ // for type deduction.
+ ParamType = ParamRefType->getPointeeType();
+
+ // [...] If P is of the form T&&, where T is a template parameter, and
+ // the argument is an lvalue, the type A& is used in place of A for
+ // type deduction.
+ if (isa<RValueReferenceType>(ParamRefType) &&
+ ParamRefType->getAsTemplateTypeParmType() &&
+ Args[I]->isLvalue(Context) == Expr::LV_Valid)
+ ArgType = Context.getLValueReferenceType(ArgType);
+ }
+
+ // C++0x [temp.deduct.call]p4:
+ // In general, the deduction process attempts to find template argument
+ // values that will make the deduced A identical to A (after the type A
+ // is transformed as described above). [...]
+ unsigned TDF = 0;
+
+ // - If the original P is a reference type, the deduced A (i.e., the
+ // type referred to by the reference) can be more cv-qualified than
+ // the transformed A.
+ if (ParamWasReference)
+ TDF |= TDF_ParamWithReferenceType;
+ // - The transformed A can be another pointer or pointer to member
+ // type that can be converted to the deduced A via a qualification
+ // conversion (4.4).
+ if (ArgType->isPointerType() || ArgType->isMemberPointerType())
+ TDF |= TDF_IgnoreQualifiers;
+ // - If P is a class and P has the form simple-template-id, then the
+ // transformed A can be a derived class of the deduced A. Likewise,
+ // if P is a pointer to a class of the form simple-template-id, the
+ // transformed A can be a pointer to a derived class pointed to by
+ // the deduced A.
+ if (isSimpleTemplateIdType(ParamType) ||
+ (isa<PointerType>(ParamType) &&
+ isSimpleTemplateIdType(
+ ParamType->getAsPointerType()->getPointeeType())))
+ TDF |= TDF_DerivedClass;
+
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(Context, TemplateParams,
+ ParamType, ArgType, Info, Deduced,
+ TDF))
+ return Result;
+
+ // FIXME: C++ [temp.deduct.call] paragraphs 6-9 deal with function
+ // pointer parameters.
}
- if (Trap.hasErrorOccurred())
+ InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
+ FunctionTemplate, Deduced.data(), Deduced.size());
+ if (Inst)
+ return TDK_InstantiationDepth;
+
+ // C++ [temp.deduct.type]p2:
+ // [...] or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size());
+ for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
+ if (Deduced[I].isNull()) {
+ Decl *Param
+ = const_cast<Decl *>(TemplateParams->getParam(I));
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ Info.Param = TTP;
+ else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param))
+ Info.Param = NTTP;
+ else
+ Info.Param = cast<TemplateTemplateParmDecl>(Param);
+ return TDK_Incomplete;
+ }
+
+ Builder.Append(Deduced[I]);
+ }
+
+ // Form the template argument list from the deduced template arguments.
+ TemplateArgumentList *DeducedArgumentList
+ = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
+ Info.reset(DeducedArgumentList);
+
+ // Substitute the deduced template arguments into the function template
+ // declaration to produce the function template specialization.
+ Specialization = cast_or_null<FunctionDecl>(
+ InstantiateDecl(FunctionTemplate->getTemplatedDecl(),
+ FunctionTemplate->getDeclContext(),
+ *DeducedArgumentList));
+
+ if (!Specialization || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
+ // Turn the specialization into an actual function template specialization.
+ Specialization->setFunctionTemplateSpecialization(Context,
+ FunctionTemplate,
+ Info.take());
return TDK_Success;
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 1c4e907..aed3489 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -29,10 +29,18 @@ using namespace clang;
/// instantiate the given declaration.
const TemplateArgumentList &
Sema::getTemplateInstantiationArgs(NamedDecl *D) {
+ // Template arguments for a class template specialization.
if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(D))
return Spec->getTemplateArgs();
+ // Template arguments for a function template specialization.
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
+ if (const TemplateArgumentList *TemplateArgs
+ = Function->getTemplateSpecializationArgs())
+ return *TemplateArgs;
+
+ // Template arguments for a member of a class template specialization.
DeclContext *EnclosingTemplateCtx = D->getDeclContext();
while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx)) {
assert(!EnclosingTemplateCtx->isFileContext() &&
@@ -158,8 +166,11 @@ void Sema::PrintInstantiationStack() {
<< Active->InstantiationRange;
} else {
FunctionDecl *Function = cast<FunctionDecl>(D);
- unsigned DiagID = diag::note_template_member_function_here;
- // FIXME: check for a function template
+ unsigned DiagID;
+ if (Function->getPrimaryTemplate())
+ DiagID = diag::note_function_template_spec_here;
+ else
+ DiagID = diag::note_template_member_function_here;
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
DiagID)
<< Function
@@ -251,88 +262,82 @@ namespace {
// Declare instantiate functions for each type.
#define TYPE(Class, Base) \
- QualType Instantiate##Class##Type(const Class##Type *T, \
- unsigned Quals) const;
+ QualType Instantiate##Class##Type(const Class##Type *T) const;
#define ABSTRACT_TYPE(Class, Base)
#include "clang/AST/TypeNodes.def"
};
}
QualType
-TemplateTypeInstantiator::InstantiateExtQualType(const ExtQualType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateExtQualType(const ExtQualType *T) const {
// FIXME: Implement this
assert(false && "Cannot instantiate ExtQualType yet");
return QualType();
}
QualType
-TemplateTypeInstantiator::InstantiateBuiltinType(const BuiltinType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateBuiltinType(const BuiltinType *T) const {
assert(false && "Builtin types are not dependent and cannot be instantiated");
- return QualType(T, Quals);
+ return QualType(T, 0);
}
QualType
TemplateTypeInstantiator::
-InstantiateFixedWidthIntType(const FixedWidthIntType *T, unsigned Quals) const {
+InstantiateFixedWidthIntType(const FixedWidthIntType *T) const {
// FIXME: Implement this
assert(false && "Cannot instantiate FixedWidthIntType yet");
return QualType();
}
QualType
-TemplateTypeInstantiator::InstantiateComplexType(const ComplexType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateComplexType(const ComplexType *T) const {
// FIXME: Implement this
assert(false && "Cannot instantiate ComplexType yet");
return QualType();
}
QualType
-TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T) const {
QualType PointeeType = Instantiate(T->getPointeeType());
if (PointeeType.isNull())
return QualType();
- return SemaRef.BuildPointerType(PointeeType, Quals, Loc, Entity);
+ return SemaRef.BuildPointerType(PointeeType, 0, Loc, Entity);
}
QualType
-TemplateTypeInstantiator::InstantiateBlockPointerType(const BlockPointerType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateBlockPointerType(
+ const BlockPointerType *T) const {
QualType PointeeType = Instantiate(T->getPointeeType());
if (PointeeType.isNull())
return QualType();
- return SemaRef.BuildBlockPointerType(PointeeType, Quals, Loc, Entity);
+ return SemaRef.BuildBlockPointerType(PointeeType, 0, Loc, Entity);
}
QualType
TemplateTypeInstantiator::InstantiateLValueReferenceType(
- const LValueReferenceType *T, unsigned Quals) const {
+ const LValueReferenceType *T) const {
QualType ReferentType = Instantiate(T->getPointeeType());
if (ReferentType.isNull())
return QualType();
- return SemaRef.BuildReferenceType(ReferentType, true, Quals, Loc, Entity);
+ return SemaRef.BuildReferenceType(ReferentType, true, 0, Loc, Entity);
}
QualType
TemplateTypeInstantiator::InstantiateRValueReferenceType(
- const RValueReferenceType *T, unsigned Quals) const {
+ const RValueReferenceType *T) const {
QualType ReferentType = Instantiate(T->getPointeeType());
if (ReferentType.isNull())
return QualType();
- return SemaRef.BuildReferenceType(ReferentType, false, Quals, Loc, Entity);
+ return SemaRef.BuildReferenceType(ReferentType, false, 0, Loc, Entity);
}
QualType
TemplateTypeInstantiator::
-InstantiateMemberPointerType(const MemberPointerType *T,
- unsigned Quals) const {
+InstantiateMemberPointerType(const MemberPointerType *T) const {
QualType PointeeType = Instantiate(T->getPointeeType());
if (PointeeType.isNull())
return QualType();
@@ -341,14 +346,13 @@ InstantiateMemberPointerType(const MemberPointerType *T,
if (ClassType.isNull())
return QualType();
- return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Quals, Loc,
+ return SemaRef.BuildMemberPointerType(PointeeType, ClassType, 0, Loc,
Entity);
}
QualType
TemplateTypeInstantiator::
-InstantiateConstantArrayType(const ConstantArrayType *T,
- unsigned Quals) const {
+InstantiateConstantArrayType(const ConstantArrayType *T) const {
QualType ElementType = Instantiate(T->getElementType());
if (ElementType.isNull())
return ElementType;
@@ -383,8 +387,7 @@ InstantiateConstantArrayType(const ConstantArrayType *T,
QualType
TemplateTypeInstantiator::
-InstantiateIncompleteArrayType(const IncompleteArrayType *T,
- unsigned Quals) const {
+InstantiateIncompleteArrayType(const IncompleteArrayType *T) const {
QualType ElementType = Instantiate(T->getElementType());
if (ElementType.isNull())
return ElementType;
@@ -396,8 +399,7 @@ InstantiateIncompleteArrayType(const IncompleteArrayType *T,
QualType
TemplateTypeInstantiator::
-InstantiateVariableArrayType(const VariableArrayType *T,
- unsigned Quals) const {
+InstantiateVariableArrayType(const VariableArrayType *T) const {
// FIXME: Implement this
assert(false && "Cannot instantiate VariableArrayType yet");
return QualType();
@@ -405,8 +407,7 @@ InstantiateVariableArrayType(const VariableArrayType *T,
QualType
TemplateTypeInstantiator::
-InstantiateDependentSizedArrayType(const DependentSizedArrayType *T,
- unsigned Quals) const {
+InstantiateDependentSizedArrayType(const DependentSizedArrayType *T) const {
Expr *ArraySize = T->getSizeExpr();
assert(ArraySize->isValueDependent() &&
"dependent sized array types must have value dependent size expr");
@@ -433,8 +434,8 @@ InstantiateDependentSizedArrayType(const DependentSizedArrayType *T,
QualType
TemplateTypeInstantiator::
-InstantiateDependentSizedExtVectorType(const DependentSizedExtVectorType *T,
- unsigned Quals) const {
+InstantiateDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) const {
// Instantiate the element type if needed.
QualType ElementType = T->getElementType();
@@ -462,16 +463,15 @@ InstantiateDependentSizedExtVectorType(const DependentSizedExtVectorType *T,
}
QualType
-TemplateTypeInstantiator::InstantiateVectorType(const VectorType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateVectorType(const VectorType *T) const {
// FIXME: Implement this
assert(false && "Cannot instantiate VectorType yet");
return QualType();
}
QualType
-TemplateTypeInstantiator::InstantiateExtVectorType(const ExtVectorType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateExtVectorType(
+ const ExtVectorType *T) const {
// FIXME: Implement this
assert(false && "Cannot instantiate ExtVectorType yet");
return QualType();
@@ -479,8 +479,7 @@ TemplateTypeInstantiator::InstantiateExtVectorType(const ExtVectorType *T,
QualType
TemplateTypeInstantiator::
-InstantiateFunctionProtoType(const FunctionProtoType *T,
- unsigned Quals) const {
+InstantiateFunctionProtoType(const FunctionProtoType *T) const {
QualType ResultType = Instantiate(T->getResultType());
if (ResultType.isNull())
return ResultType;
@@ -504,15 +503,13 @@ InstantiateFunctionProtoType(const FunctionProtoType *T,
QualType
TemplateTypeInstantiator::
-InstantiateFunctionNoProtoType(const FunctionNoProtoType *T,
- unsigned Quals) const {
+InstantiateFunctionNoProtoType(const FunctionNoProtoType *T) const {
assert(false && "Functions without prototypes cannot be dependent.");
return QualType();
}
QualType
-TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T) const {
TypedefDecl *Typedef
= cast_or_null<TypedefDecl>(
SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
@@ -523,8 +520,8 @@ TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T,
}
QualType
-TemplateTypeInstantiator::InstantiateTypeOfExprType(const TypeOfExprType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateTypeOfExprType(
+ const TypeOfExprType *T) const {
// The expression in a typeof is not potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
@@ -537,8 +534,7 @@ TemplateTypeInstantiator::InstantiateTypeOfExprType(const TypeOfExprType *T,
}
QualType
-TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T) const {
QualType Underlying = Instantiate(T->getUnderlyingType());
if (Underlying.isNull())
return QualType();
@@ -546,9 +542,24 @@ TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T,
return SemaRef.Context.getTypeOfType(Underlying);
}
+QualType
+TemplateTypeInstantiator::InstantiateDecltypeType(const DecltypeType *T) const {
+ // C++0x [dcl.type.simple]p4:
+ // The operand of the decltype specifier is an unevaluated operand.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Action::Unevaluated);
+
+ Sema::OwningExprResult E
+ = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs);
+
+ if (E.isInvalid())
+ return QualType();
+
+ return SemaRef.Context.getDecltypeType(E.takeAs<Expr>());
+}
+
QualType
-TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T) const {
RecordDecl *Record
= cast_or_null<RecordDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
if (!Record)
@@ -558,8 +569,7 @@ TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T,
}
QualType
-TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T,
- unsigned Quals) const {
+TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T) const {
EnumDecl *Enum
= cast_or_null<EnumDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
if (!Enum)
@@ -570,26 +580,13 @@ TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T,
QualType
TemplateTypeInstantiator::
-InstantiateTemplateTypeParmType(const TemplateTypeParmType *T,
- unsigned Quals) const {
+InstantiateTemplateTypeParmType(const TemplateTypeParmType *T) const {
if (T->getDepth() == 0) {
// Replace the template type parameter with its corresponding
// template argument.
assert(TemplateArgs[T->getIndex()].getKind() == TemplateArgument::Type &&
"Template argument kind mismatch");
- QualType Result = TemplateArgs[T->getIndex()].getAsType();
- if (Result.isNull() || !Quals)
- return Result;
-
- // C++ [dcl.ref]p1:
- // [...] Cv-qualified references are ill-formed except when
- // the cv-qualifiers are introduced through the use of a
- // typedef (7.1.3) or of a template type argument (14.3), in
- // which case the cv-qualifiers are ignored.
- if (Quals && Result->isReferenceType())
- Quals = 0;
-
- return QualType(Result.getTypePtr(), Quals | Result.getCVRQualifiers());
+ return TemplateArgs[T->getIndex()].getAsType();
}
// The template type parameter comes from an inner template (e.g.,
@@ -599,15 +596,13 @@ InstantiateTemplateTypeParmType(const TemplateTypeParmType *T,
return SemaRef.Context.getTemplateTypeParmType(T->getDepth() - 1,
T->getIndex(),
T->isParameterPack(),
- T->getName())
- .getQualifiedType(Quals);
+ T->getName());
}
QualType
TemplateTypeInstantiator::
InstantiateTemplateSpecializationType(
- const TemplateSpecializationType *T,
- unsigned Quals) const {
+ const TemplateSpecializationType *T) const {
llvm::SmallVector<TemplateArgument, 4> InstantiatedTemplateArgs;
InstantiatedTemplateArgs.reserve(T->getNumArgs());
for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
@@ -633,8 +628,7 @@ InstantiateTemplateSpecializationType(
QualType
TemplateTypeInstantiator::
-InstantiateQualifiedNameType(const QualifiedNameType *T,
- unsigned Quals) const {
+InstantiateQualifiedNameType(const QualifiedNameType *T) const {
// When we instantiated a qualified name type, there's no point in
// keeping the qualification around in the instantiated result. So,
// just instantiate the named type.
@@ -643,14 +637,14 @@ InstantiateQualifiedNameType(const QualifiedNameType *T,
QualType
TemplateTypeInstantiator::
-InstantiateTypenameType(const TypenameType *T, unsigned Quals) const {
+InstantiateTypenameType(const TypenameType *T) const {
if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
// When the typename type refers to a template-id, the template-id
// is dependent and has enough information to instantiate the
// result of the typename type. Since we don't care about keeping
// the spelling of the typename type in template instantiations,
// we just instantiate the template-id.
- return InstantiateTemplateSpecializationType(TemplateId, Quals);
+ return InstantiateTemplateSpecializationType(TemplateId);
}
NestedNameSpecifier *NNS
@@ -665,24 +659,22 @@ InstantiateTypenameType(const TypenameType *T, unsigned Quals) const {
QualType
TemplateTypeInstantiator::
-InstantiateObjCObjectPointerType(const ObjCObjectPointerType *T,
- unsigned Quals) const {
+InstantiateObjCObjectPointerType(const ObjCObjectPointerType *T) const {
assert(false && "Objective-C types cannot be dependent");
return QualType();
}
QualType
TemplateTypeInstantiator::
-InstantiateObjCInterfaceType(const ObjCInterfaceType *T,
- unsigned Quals) const {
+InstantiateObjCInterfaceType(const ObjCInterfaceType *T) const {
assert(false && "Objective-C types cannot be dependent");
return QualType();
}
QualType
TemplateTypeInstantiator::
-InstantiateObjCQualifiedInterfaceType(const ObjCQualifiedInterfaceType *T,
- unsigned Quals) const {
+InstantiateObjCQualifiedInterfaceType(
+ const ObjCQualifiedInterfaceType *T) const {
assert(false && "Objective-C types cannot be dependent");
return QualType();
}
@@ -693,17 +685,27 @@ QualType TemplateTypeInstantiator::Instantiate(QualType T) const {
if (!T->isDependentType())
return T;
+ QualType Result;
switch (T->getTypeClass()) {
#define TYPE(Class, Base) \
case Type::Class: \
- return Instantiate##Class##Type(cast<Class##Type>(T.getTypePtr()), \
- T.getCVRQualifiers());
+ Result = Instantiate##Class##Type(cast<Class##Type>(T.getTypePtr())); \
+ break;
#define ABSTRACT_TYPE(Class, Base)
#include "clang/AST/TypeNodes.def"
}
-
- assert(false && "Not all types have been decoded for instantiation");
- return QualType();
+
+ // C++ [dcl.ref]p1:
+ // [...] Cv-qualified references are ill-formed except when
+ // the cv-qualifiers are introduced through the use of a
+ // typedef (7.1.3) or of a template type argument (14.3), in
+ // which case the cv-qualifiers are ignored.
+ //
+ // The same rule applies to function types.
+ if (!Result.isNull() && T.getCVRQualifiers() &&
+ !Result->isFunctionType() && !Result->isReferenceType())
+ Result = Result.getWithAdditionalQualifiers(T.getCVRQualifiers());
+ return Result;
}
/// \brief Instantiate the type T with a given set of template arguments.
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ece71bc..a05095f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -44,6 +44,7 @@ namespace {
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
+ Decl *VisitFunctionDecl(FunctionDecl *D);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
@@ -61,6 +62,7 @@ namespace {
// Helper functions for instantiating methods.
QualType InstantiateFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
+ bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
};
}
@@ -291,12 +293,47 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
return Record;
}
-Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
- // Only handle actual methods; we'll deal with constructors,
- // destructors, etc. separately.
- if (D->getKind() != Decl::CXXMethod)
+Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
+ // FIXME: Look for existing specializations (explicit or otherwise).
+
+ Sema::LocalInstantiationScope Scope(SemaRef);
+
+ llvm::SmallVector<ParmVarDecl *, 4> Params;
+ QualType T = InstantiateFunctionType(D, Params);
+ if (T.isNull())
return 0;
+
+ // Build the instantiated method declaration.
+ FunctionDecl *Function
+ = FunctionDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getDeclName(), T, D->getStorageClass(),
+ D->isInline(), D->hasWrittenPrototype(),
+ D->getTypeSpecStartLoc());
+
+ // FIXME: friend functions
+
+ // Attach the parameters
+ for (unsigned P = 0; P < Params.size(); ++P)
+ Params[P]->setOwningFunction(Function);
+ Function->setParams(SemaRef.Context, Params.data(), Params.size());
+
+ if (InitFunctionInstantiation(Function, D))
+ Function->setInvalidDecl();
+
+ bool Redeclaration = false;
+ bool OverloadableAttrRequired = false;
+ NamedDecl *PrevDecl = 0;
+ SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration,
+ /*FIXME:*/OverloadableAttrRequired);
+
+
+ // FIXME: link this to the function template from which it was instantiated.
+
+ return Function;
+}
+Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ // FIXME: Look for existing, explicit specializations.
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
@@ -340,6 +377,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ // FIXME: Look for existing, explicit specializations.
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
@@ -387,6 +425,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+ // FIXME: Look for existing, explicit specializations.
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
@@ -418,6 +457,7 @@ Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
+ // FIXME: Look for existing, explicit specializations.
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
@@ -557,6 +597,18 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
D->getLocation(), D->getDeclName());
}
+/// \brief Initializes the common fields of an instantiation function
+/// declaration (New) from the corresponding fields of its template (Tmpl).
+///
+/// \returns true if there was an error
+bool
+TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
+ FunctionDecl *Tmpl) {
+ if (Tmpl->isDeleted())
+ New->setDeleted();
+ return false;
+}
+
/// \brief Initializes common fields of an instantiated method
/// declaration (New) from the corresponding fields of its template
/// (Tmpl).
@@ -565,6 +617,9 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
bool
TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
CXXMethodDecl *Tmpl) {
+ if (InitFunctionInstantiation(New, Tmpl))
+ return true;
+
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
New->setAccess(Tmpl->getAccess());
if (Tmpl->isVirtualAsWritten()) {
@@ -573,8 +628,6 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
Record->setPOD(false);
Record->setPolymorphic(true);
}
- if (Tmpl->isDeleted())
- New->setDeleted();
if (Tmpl->isPure()) {
New->setPure();
Record->setAbstract(true);
@@ -592,16 +645,17 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
/// function.
void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function) {
- // FIXME: make this work for function template specializations, too.
-
if (Function->isInvalidDecl())
return;
assert(!Function->getBody(Context) && "Already instantiated!");
// Find the function body that we'll be substituting.
- const FunctionDecl *PatternDecl
- = Function->getInstantiatedFromMemberFunction();
+ const FunctionDecl *PatternDecl = 0;
+ if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate())
+ PatternDecl = Primary->getTemplatedDecl();
+ else
+ PatternDecl = Function->getInstantiatedFromMemberFunction();
Stmt *Pattern = 0;
if (PatternDecl)
Pattern = PatternDecl->getBody(Context, PatternDecl);
diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp
index 749fb58..65a35f9 100644
--- a/lib/Sema/SemaTemplateInstantiateExpr.cpp
+++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp
@@ -119,6 +119,14 @@ TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) {
// FIXME: Clone the expression!
return SemaRef.Owned(Arg.getAsExpr());
+ if (Arg.getKind() == TemplateArgument::Declaration) {
+ ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
+
+ // FIXME: Can VD ever have a dependent type?
+ return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(),
+ false, false);
+ }
+
assert(Arg.getKind() == TemplateArgument::Integral);
QualType T = Arg.getIntegralType();
if (T->isCharType() || T->isWideCharType())
@@ -400,7 +408,7 @@ TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
F = Overloads->function_begin(),
FEnd = Overloads->function_end();
F != FEnd; ++F)
- Functions.insert(*F);
+ Functions.insert(cast<FunctionDecl>(*F));
// Add any functions found via argument-dependent lookup.
DeclarationName OpName
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 967f650..c6bcdc3 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -121,16 +121,18 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
if (DeclLoc.isInvalid())
DeclLoc = DS.getSourceRange().getBegin();
- if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft)
+ if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft) {
Diag(DeclLoc, diag::err_missing_type_specifier)
<< DS.getSourceRange();
- else
+
+ // When this occurs in C++ code, often something is very broken with the
+ // value being declared, poison it as invalid so we don't get chains of
+ // errors.
+ isInvalid = true;
+ } else {
Diag(DeclLoc, diag::ext_missing_type_specifier)
<< DS.getSourceRange();
-
- // FIXME: If we could guarantee that the result would be well-formed, it
- // would be useful to have a code insertion hint here. However, after
- // emitting this warning/error, we often emit other errors.
+ }
}
// FALL THROUGH.
@@ -236,6 +238,19 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
Result = Context.getTypeOfExprType(E);
break;
}
+ case DeclSpec::TST_decltype: {
+ Expr *E = static_cast<Expr *>(DS.getTypeRep());
+ assert(E && "Didn't get an expression for decltype?");
+ // TypeQuals handled by caller.
+ Result = Context.getDecltypeType(E);
+ break;
+ }
+ case DeclSpec::TST_auto: {
+ // TypeQuals handled by caller.
+ Result = Context.UndeducedAutoTy;
+ break;
+ }
+
case DeclSpec::TST_error:
Result = Context.IntTy;
isInvalid = true;
@@ -483,6 +498,12 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
return QualType();
}
+ if (Context.getCanonicalType(T) == Context.UndeducedAutoTy) {
+ Diag(Loc, diag::err_illegal_decl_array_of_auto)
+ << getPrintableNameForEntity(Entity);
+ return QualType();
+ }
+
if (const RecordType *EltTy = T->getAsRecordType()) {
// If the element type is a struct or union that contains a variadic
// array, accept it as a GNU extension: C99 6.7.2.1p2.
@@ -786,6 +807,52 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
break;
}
+ if (T == Context.UndeducedAutoTy) {
+ int Error = -1;
+
+ switch (D.getContext()) {
+ case Declarator::KNRTypeListContext:
+ assert(0 && "K&R type lists aren't allowed in C++");
+ break;
+ default:
+ printf("context: %d\n", D.getContext());
+ assert(0);
+ case Declarator::PrototypeContext:
+ Error = 0; // Function prototype
+ break;
+ case Declarator::MemberContext:
+ switch (cast<TagDecl>(CurContext)->getTagKind()) {
+ case TagDecl::TK_enum: assert(0 && "unhandled tag kind"); break;
+ case TagDecl::TK_struct: Error = 1; /* Struct member */ break;
+ case TagDecl::TK_union: Error = 2; /* Union member */ break;
+ case TagDecl::TK_class: Error = 3; /* Class member */ break;
+ }
+ break;
+ case Declarator::CXXCatchContext:
+ Error = 4; // Exception declaration
+ break;
+ case Declarator::TemplateParamContext:
+ Error = 5; // Template parameter
+ break;
+ case Declarator::BlockLiteralContext:
+ Error = 6; // Block literal
+ break;
+ case Declarator::FileContext:
+ case Declarator::BlockContext:
+ case Declarator::ForContext:
+ case Declarator::ConditionContext:
+ case Declarator::TypeNameContext:
+ break;
+ }
+
+ if (Error != -1) {
+ Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_not_allowed)
+ << Error;
+ T = Context.IntTy;
+ D.setInvalidType(true);
+ }
+ }
+
// The name we're declaring, if any.
DeclarationName Name;
if (D.getIdentifier())
OpenPOWER on IntegriCloud