diff options
Diffstat (limited to 'lib')
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()) |