diff options
Diffstat (limited to 'lib')
56 files changed, 2342 insertions, 796 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index fb28fd4..7ed9e45 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/RecordLayout.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/StringExtras.h" @@ -32,18 +33,15 @@ enum FloatingRank { ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, - bool FreeMem, unsigned size_reserve, - bool InitializeBuiltins) : + Builtin::Context &builtins, + bool FreeMem, unsigned size_reserve) : GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), - ExternalSource(0) { + BuiltinInfo(builtins), ExternalSource(0) { if (size_reserve > 0) Types.reserve(size_reserve); InitBuiltinTypes(); TUDecl = TranslationUnitDecl::Create(*this); - BuiltinInfo.InitializeTargetBuiltins(Target); - if (InitializeBuiltins) - this->InitializeBuiltins(idents); PrintingPolicy.CPlusPlus = LangOpts.CPlusPlus; } @@ -86,10 +84,6 @@ ASTContext::~ASTContext() { TUDecl->Destroy(*this); } -void ASTContext::InitializeBuiltins(IdentifierTable &idents) { - BuiltinInfo.InitializeBuiltins(idents, LangOpts.NoBuiltin); -} - void ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) { ExternalSource.reset(Source.take()); @@ -1979,9 +1973,8 @@ unsigned ASTContext::getIntegerRank(Type *T) { // There are two things which impact the integer rank: the width, and // the ordering of builtins. The builtin ordering is encoded in the // bottom three bits; the width is encoded in the bits above that. - if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) { + if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) return FWIT->getWidth() << 3; - } switch (cast<BuiltinType>(T)->getKind()) { default: assert(0 && "getIntegerRank(): not a built-in integer"); @@ -3375,3 +3368,203 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) { ExternalASTSource::~ExternalASTSource() { } void ExternalASTSource::PrintStats() { } + + +//===----------------------------------------------------------------------===// +// Builtin Type Computation +//===----------------------------------------------------------------------===// + +/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the +/// pointer over the consumed characters. This returns the resultant type. +static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, + ASTContext::GetBuiltinTypeError &Error, + bool AllowTypeModifiers = true) { + // Modifiers. + int HowLong = 0; + bool Signed = false, Unsigned = false; + + // Read the modifiers first. + bool Done = false; + while (!Done) { + switch (*Str++) { + default: Done = true; --Str; break; + case 'S': + assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); + assert(!Signed && "Can't use 'S' modifier multiple times!"); + Signed = true; + break; + case 'U': + assert(!Signed && "Can't use both 'S' and 'U' modifiers!"); + assert(!Unsigned && "Can't use 'S' modifier multiple times!"); + Unsigned = true; + break; + case 'L': + assert(HowLong <= 2 && "Can't have LLLL modifier"); + ++HowLong; + break; + } + } + + QualType Type; + + // Read the base type. + switch (*Str++) { + default: assert(0 && "Unknown builtin type letter!"); + case 'v': + assert(HowLong == 0 && !Signed && !Unsigned && + "Bad modifiers used with 'v'!"); + Type = Context.VoidTy; + break; + case 'f': + assert(HowLong == 0 && !Signed && !Unsigned && + "Bad modifiers used with 'f'!"); + Type = Context.FloatTy; + break; + case 'd': + assert(HowLong < 2 && !Signed && !Unsigned && + "Bad modifiers used with 'd'!"); + if (HowLong) + Type = Context.LongDoubleTy; + else + Type = Context.DoubleTy; + break; + case 's': + assert(HowLong == 0 && "Bad modifiers used with 's'!"); + if (Unsigned) + Type = Context.UnsignedShortTy; + else + Type = Context.ShortTy; + break; + case 'i': + if (HowLong == 3) + Type = Unsigned ? Context.UnsignedInt128Ty : Context.Int128Ty; + else if (HowLong == 2) + Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy; + else if (HowLong == 1) + Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy; + else + Type = Unsigned ? Context.UnsignedIntTy : Context.IntTy; + break; + case 'c': + assert(HowLong == 0 && "Bad modifiers used with 'c'!"); + if (Signed) + Type = Context.SignedCharTy; + else if (Unsigned) + Type = Context.UnsignedCharTy; + else + Type = Context.CharTy; + break; + case 'b': // boolean + assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'b'!"); + Type = Context.BoolTy; + break; + case 'z': // size_t. + assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'z'!"); + Type = Context.getSizeType(); + break; + case 'F': + Type = Context.getCFConstantStringType(); + break; + case 'a': + Type = Context.getBuiltinVaListType(); + assert(!Type.isNull() && "builtin va list type not initialized!"); + break; + case 'A': + // This is a "reference" to a va_list; however, what exactly + // this means depends on how va_list is defined. There are two + // different kinds of va_list: ones passed by value, and ones + // passed by reference. An example of a by-value va_list is + // x86, where va_list is a char*. An example of by-ref va_list + // is x86-64, where va_list is a __va_list_tag[1]. For x86, + // we want this argument to be a char*&; for x86-64, we want + // it to be a __va_list_tag*. + Type = Context.getBuiltinVaListType(); + assert(!Type.isNull() && "builtin va list type not initialized!"); + if (Type->isArrayType()) { + Type = Context.getArrayDecayedType(Type); + } else { + Type = Context.getLValueReferenceType(Type); + } + break; + case 'V': { + char *End; + + unsigned NumElements = strtoul(Str, &End, 10); + assert(End != Str && "Missing vector size"); + + Str = End; + + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); + Type = Context.getVectorType(ElementType, NumElements); + break; + } + case 'P': { + IdentifierInfo *II = &Context.Idents.get("FILE"); + DeclContext::lookup_result Lookup + = Context.getTranslationUnitDecl()->lookup(Context, II); + if (Lookup.first != Lookup.second && isa<TypeDecl>(*Lookup.first)) { + Type = Context.getTypeDeclType(cast<TypeDecl>(*Lookup.first)); + break; + } + else { + Error = ASTContext::GE_Missing_FILE; + return QualType(); + } + } + } + + if (!AllowTypeModifiers) + return Type; + + Done = false; + while (!Done) { + switch (*Str++) { + default: Done = true; --Str; break; + case '*': + Type = Context.getPointerType(Type); + break; + case '&': + Type = Context.getLValueReferenceType(Type); + break; + // FIXME: There's no way to have a built-in with an rvalue ref arg. + case 'C': + Type = Type.getQualifiedType(QualType::Const); + break; + } + } + + return Type; +} + +/// GetBuiltinType - Return the type for the specified builtin. +QualType ASTContext::GetBuiltinType(unsigned id, + GetBuiltinTypeError &Error) { + const char *TypeStr = BuiltinInfo.GetTypeString(id); + + llvm::SmallVector<QualType, 8> ArgTypes; + + Error = GE_None; + QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error); + if (Error != GE_None) + return QualType(); + while (TypeStr[0] && TypeStr[0] != '.') { + QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error); + if (Error != GE_None) + return QualType(); + + // Do array -> pointer decay. The builtin should use the decayed type. + if (Ty->isArrayType()) + Ty = getArrayDecayedType(Ty); + + ArgTypes.push_back(Ty); + } + + assert((TypeStr[0] != '.' || TypeStr[1] == 0) && + "'.' should only occur at end of builtin type list!"); + + // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);". + if (ArgTypes.size() == 0 && TypeStr[0] == '.') + return getFunctionNoProtoType(ResType); + return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), + TypeStr[0] == '.', 0); +} diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp deleted file mode 100644 index 8368feb..0000000 --- a/lib/AST/Builtins.cpp +++ /dev/null @@ -1,290 +0,0 @@ -//===--- Builtins.cpp - Builtin function implementation -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements various things for builtin functions. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Builtins.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/TargetInfo.h" -using namespace clang; - -static const Builtin::Info BuiltinInfo[] = { - { "not a builtin function", 0, 0, 0, false }, -#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false }, -#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false }, -#include "clang/AST/Builtins.def" -}; - -const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const { - if (ID < Builtin::FirstTSBuiltin) - return BuiltinInfo[ID]; - assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!"); - return TSRecords[ID - Builtin::FirstTSBuiltin]; -} - -/// \brief Load all of the target builtins. This must be called -/// prior to initializing the builtin identifiers. -void Builtin::Context::InitializeTargetBuiltins(const TargetInfo &Target) { - Target.getTargetBuiltins(TSRecords, NumTSRecords); -} - -/// InitializeBuiltins - Mark the identifiers for all the builtins with their -/// appropriate builtin ID # and mark any non-portable builtin identifiers as -/// such. -void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, - bool NoBuiltins) { - // Step #1: mark all target-independent builtins with their ID's. - for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) - if (!BuiltinInfo[i].Suppressed && - (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) - Table.get(BuiltinInfo[i].Name).setBuiltinID(i); - - // Step #2: Register target-specific builtins. - for (unsigned i = 0, e = NumTSRecords; i != e; ++i) - if (!TSRecords[i].Suppressed && - (!NoBuiltins || - (TSRecords[i].Attributes && - !strchr(TSRecords[i].Attributes, 'f')))) - Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); -} - -void -Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names, - bool NoBuiltins) { - // Final all target-independent names - for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) - if (!BuiltinInfo[i].Suppressed && - (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) - Names.push_back(BuiltinInfo[i].Name); - - // Find target-specific names. - for (unsigned i = 0, e = NumTSRecords; i != e; ++i) - if (!TSRecords[i].Suppressed && - (!NoBuiltins || - (TSRecords[i].Attributes && - !strchr(TSRecords[i].Attributes, 'f')))) - Names.push_back(TSRecords[i].Name); -} - -bool -Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, - bool &HasVAListArg) { - const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP"); - if (!Printf) - return false; - - HasVAListArg = (*Printf == 'P'); - - ++Printf; - assert(*Printf == ':' && "p or P specifier must have be followed by a ':'"); - ++Printf; - - assert(strchr(Printf, ':') && "printf specifier must end with a ':'"); - FormatIdx = strtol(Printf, 0, 10); - return true; -} - -/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the -/// pointer over the consumed characters. This returns the resultant type. -static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, - Builtin::Context::GetBuiltinTypeError &Error, - bool AllowTypeModifiers = true) { - // Modifiers. - int HowLong = 0; - bool Signed = false, Unsigned = false; - - // Read the modifiers first. - bool Done = false; - while (!Done) { - switch (*Str++) { - default: Done = true; --Str; break; - case 'S': - assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); - assert(!Signed && "Can't use 'S' modifier multiple times!"); - Signed = true; - break; - case 'U': - assert(!Signed && "Can't use both 'S' and 'U' modifiers!"); - assert(!Unsigned && "Can't use 'S' modifier multiple times!"); - Unsigned = true; - break; - case 'L': - assert(HowLong <= 2 && "Can't have LLLL modifier"); - ++HowLong; - break; - } - } - - QualType Type; - - // Read the base type. - switch (*Str++) { - default: assert(0 && "Unknown builtin type letter!"); - case 'v': - assert(HowLong == 0 && !Signed && !Unsigned && - "Bad modifiers used with 'v'!"); - Type = Context.VoidTy; - break; - case 'f': - assert(HowLong == 0 && !Signed && !Unsigned && - "Bad modifiers used with 'f'!"); - Type = Context.FloatTy; - break; - case 'd': - assert(HowLong < 2 && !Signed && !Unsigned && - "Bad modifiers used with 'd'!"); - if (HowLong) - Type = Context.LongDoubleTy; - else - Type = Context.DoubleTy; - break; - case 's': - assert(HowLong == 0 && "Bad modifiers used with 's'!"); - if (Unsigned) - Type = Context.UnsignedShortTy; - else - Type = Context.ShortTy; - break; - case 'i': - if (HowLong == 3) - Type = Unsigned ? Context.UnsignedInt128Ty : Context.Int128Ty; - else if (HowLong == 2) - Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy; - else if (HowLong == 1) - Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy; - else - Type = Unsigned ? Context.UnsignedIntTy : Context.IntTy; - break; - case 'c': - assert(HowLong == 0 && "Bad modifiers used with 'c'!"); - if (Signed) - Type = Context.SignedCharTy; - else if (Unsigned) - Type = Context.UnsignedCharTy; - else - Type = Context.CharTy; - break; - case 'b': // boolean - assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'b'!"); - Type = Context.BoolTy; - break; - case 'z': // size_t. - assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'z'!"); - Type = Context.getSizeType(); - break; - case 'F': - Type = Context.getCFConstantStringType(); - break; - case 'a': - Type = Context.getBuiltinVaListType(); - assert(!Type.isNull() && "builtin va list type not initialized!"); - break; - case 'A': - // This is a "reference" to a va_list; however, what exactly - // this means depends on how va_list is defined. There are two - // different kinds of va_list: ones passed by value, and ones - // passed by reference. An example of a by-value va_list is - // x86, where va_list is a char*. An example of by-ref va_list - // is x86-64, where va_list is a __va_list_tag[1]. For x86, - // we want this argument to be a char*&; for x86-64, we want - // it to be a __va_list_tag*. - Type = Context.getBuiltinVaListType(); - assert(!Type.isNull() && "builtin va list type not initialized!"); - if (Type->isArrayType()) { - Type = Context.getArrayDecayedType(Type); - } else { - Type = Context.getLValueReferenceType(Type); - } - break; - case 'V': { - char *End; - - unsigned NumElements = strtoul(Str, &End, 10); - assert(End != Str && "Missing vector size"); - - Str = End; - - QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); - Type = Context.getVectorType(ElementType, NumElements); - break; - } - case 'P': { - IdentifierInfo *II = &Context.Idents.get("FILE"); - DeclContext::lookup_result Lookup - = Context.getTranslationUnitDecl()->lookup(Context, II); - if (Lookup.first != Lookup.second && isa<TypeDecl>(*Lookup.first)) { - Type = Context.getTypeDeclType(cast<TypeDecl>(*Lookup.first)); - break; - } - else { - Error = Builtin::Context::GE_Missing_FILE; - return QualType(); - } - } - } - - if (!AllowTypeModifiers) - return Type; - - Done = false; - while (!Done) { - switch (*Str++) { - default: Done = true; --Str; break; - case '*': - Type = Context.getPointerType(Type); - break; - case '&': - Type = Context.getLValueReferenceType(Type); - break; - // FIXME: There's no way to have a built-in with an rvalue ref arg. - case 'C': - Type = Type.getQualifiedType(QualType::Const); - break; - } - } - - return Type; -} - -/// GetBuiltinType - Return the type for the specified builtin. -QualType Builtin::Context::GetBuiltinType(unsigned id, ASTContext &Context, - GetBuiltinTypeError &Error) const { - const char *TypeStr = GetRecord(id).Type; - - llvm::SmallVector<QualType, 8> ArgTypes; - - Error = GE_None; - QualType ResType = DecodeTypeFromStr(TypeStr, Context, Error); - if (Error != GE_None) - return QualType(); - while (TypeStr[0] && TypeStr[0] != '.') { - QualType Ty = DecodeTypeFromStr(TypeStr, Context, Error); - if (Error != GE_None) - return QualType(); - - // Do array -> pointer decay. The builtin should use the decayed type. - if (Ty->isArrayType()) - Ty = Context.getArrayDecayedType(Ty); - - ArgTypes.push_back(Ty); - } - - assert((TypeStr[0] != '.' || TypeStr[1] == 0) && - "'.' should only occur at end of builtin type list!"); - - // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);". - if (ArgTypes.size() == 0 && TypeStr[0] == '.') - return Context.getFunctionNoProtoType(ResType); - return Context.getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), - TypeStr[0] == '.', 0); -} diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 19ab9f6..ac4cbb2 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -4,7 +4,6 @@ add_clang_library(clangAST APValue.cpp ASTConsumer.cpp ASTContext.cpp - Builtins.cpp CFG.cpp DeclarationName.cpp DeclBase.cpp diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index dfec106..a3e406b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" #include <vector> diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index fd7de71..a39a506 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -95,6 +95,13 @@ void Decl::addDeclKind(Kind k) { } } +bool Decl::isTemplateParameterPack() const { + if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this)) + return TTP->isParameterPack(); + + return false; +} + //===----------------------------------------------------------------------===// // PrettyStackTraceDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 94daf48..8430da2 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -260,7 +260,12 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { // the type of this is const volatile X*. assert(isInstance() && "No 'this' for static methods!"); - QualType ClassTy = C.getTagDeclType(const_cast<CXXRecordDecl*>(getParent())); + + QualType ClassTy; + if (ClassTemplateDecl *TD = getParent()->getDescribedClassTemplate()) + ClassTy = TD->getInjectedClassNameType(C); + else + ClassTy = C.getTagDeclType(const_cast<CXXRecordDecl*>(getParent())); ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers()); return C.getPointerType(ClassTy).withConst(); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index f231abf..2b06e93 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -527,6 +527,9 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { else Out << "class "; + if (TTP->isParameterPack()) + Out << "... "; + Out << ParamType.getAsString(Policy); if (TTP->hasDefaultArgument()) { diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index a534164..5b1bf9b 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -50,7 +50,9 @@ unsigned TemplateParameterList::getMinRequiredArguments() const { ParamBegin = const_cast<TemplateParameterList *>(this)->begin(); while (Param != ParamBegin) { --Param; - if (!(isa<TemplateTypeParmDecl>(*Param) && + + if (!(*Param)->isTemplateParameterPack() && + !(isa<TemplateTypeParmDecl>(*Param) && cast<TemplateTypeParmDecl>(*Param)->hasDefaultArgument()) && !(isa<NonTypeTemplateParmDecl>(*Param) && cast<NonTypeTemplateParmDecl>(*Param)->hasDefaultArgument()) && @@ -186,9 +188,10 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { TemplateTypeParmDecl * TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, bool Typename) { + IdentifierInfo *Id, bool Typename, + bool ParameterPack) { QualType Type = C.getTemplateTypeParmType(D, P, Id); - return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type); + return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type, ParameterPack); } //===----------------------------------------------------------------------===// @@ -246,9 +249,27 @@ void TemplateArgumentListBuilder::push_back(const TemplateArgument& Arg) { break; } + if (!isAddingFromParameterPack()) { + // Add begin and end indicies. + Indices.push_back(Args.size()); + Indices.push_back(Args.size()); + } + Args.push_back(Arg); } +void TemplateArgumentListBuilder::BeginParameterPack() { + assert(!isAddingFromParameterPack() && "Already adding to parameter pack!"); + + Indices.push_back(Args.size()); +} + +void TemplateArgumentListBuilder::EndParameterPack() { + assert(isAddingFromParameterPack() && "Not adding to parameter pack!"); + + Indices.push_back(Args.size()); +} + //===----------------------------------------------------------------------===// // TemplateArgumentList Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index c12dd67..309be41 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" #include <algorithm> using namespace clang; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 8e3c3ce..4815ae5 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -16,6 +16,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Compiler.h" @@ -61,6 +62,13 @@ static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info); // Misc utilities //===----------------------------------------------------------------------===// +static bool EvalPointerValueAsBool(APValue& Value, bool& Result) { + // FIXME: Is this accurate for all kinds of bases? If not, what would + // the check look like? + Result = Value.getLValueBase() || Value.getLValueOffset(); + return true; +} + static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) { if (E->getType()->isIntegralType()) { APSInt IntResult; @@ -78,10 +86,7 @@ static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) { APValue PointerResult; if (!EvaluatePointer(E, PointerResult, Info)) return false; - // FIXME: Is this accurate for all kinds of bases? If not, what would - // the check look like? - Result = PointerResult.getLValueBase() || PointerResult.getLValueOffset(); - return true; + return EvalPointerValueAsBool(PointerResult, Result); } else if (E->getType()->isAnyComplexType()) { APValue ComplexResult; if (!EvaluateComplex(E, ComplexResult, Info)) @@ -936,10 +941,27 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (!EvaluatePointer(E->getRHS(), RHSValue, Info)) return false; - // Reject any bases; this is conservative, but good enough for - // common uses - if (LHSValue.getLValueBase() || RHSValue.getLValueBase()) - return false; + // Reject any bases from the normal codepath; we special-case comparisons + // to null. + if (LHSValue.getLValueBase()) { + if (!E->isEqualityOp()) + return false; + if (RHSValue.getLValueBase() || RHSValue.getLValueOffset()) + return false; + bool bres; + if (!EvalPointerValueAsBool(LHSValue, bres)) + return false; + return Success(bres ^ (E->getOpcode() == BinaryOperator::EQ), E); + } else if (RHSValue.getLValueBase()) { + if (!E->isEqualityOp()) + return false; + if (LHSValue.getLValueBase() || LHSValue.getLValueOffset()) + return false; + bool bres; + if (!EvalPointerValueAsBool(RHSValue, bres)) + return false; + return Success(bres ^ (E->getOpcode() == BinaryOperator::EQ), E); + } if (E->getOpcode() == BinaryOperator::Sub) { const QualType Type = E->getLHS()->getType(); diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 532d16d..f5ca322 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -637,10 +637,10 @@ class VISIBILITY_HIDDEN RetainSummaryManager { /// objects. RetEffect ObjCAllocRetE; - /// ObjCInitRetE - Default return effect for init methods returning Objective-C + /// ObjCInitRetE - Default return effect for init methods returning Objective-C /// objects. RetEffect ObjCInitRetE; - + RetainSummary DefaultSummary; RetainSummary* StopSummary; @@ -780,8 +780,8 @@ public: GCEnabled(gcenabled), AF(BPAlloc), ScratchArgs(AF.GetEmptyMap()), ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned() : RetEffect::MakeOwned(RetEffect::ObjC, true)), - ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned() - : RetEffect::MakeOwnedWhenTrackedReceiver()), + ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned() + : RetEffect::MakeOwnedWhenTrackedReceiver()), DefaultSummary(AF.GetEmptyMap() /* per-argument effects (none) */, RetEffect::MakeNoRet() /* return effect */, MayEscape, /* default argument effect */ @@ -971,15 +971,42 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // FIXME: This should all be refactored into a chain of "summary lookup" // filters. - if (strcmp(FName, "IOServiceGetMatchingServices") == 0) { - // FIXES: <rdar://problem/6326900> - // This should be addressed using a API table. This strcmp is also - // a little gross, but there is no need to super optimize here. - assert (ScratchArgs.isEmpty()); - ScratchArgs = AF.Add(ScratchArgs, 1, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); - break; + switch (strlen(FName)) { + default: break; + case 17: + // Handle: id NSMakeCollectable(CFTypeRef) + if (!memcmp(FName, "NSMakeCollectable", 17)) { + S = (RetTy == Ctx.getObjCIdType()) + ? getUnarySummary(FT, cfmakecollectable) + : getPersistentStopSummary(); + } + break; + + case 27: + if (!memcmp(FName, "IOServiceGetMatchingService", 27)) { + // Part of <rdar://problem/6961230>. + // This should be addressed using a API table. + assert (ScratchArgs.isEmpty()); + ScratchArgs = AF.Add(ScratchArgs, 1, DecRef); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + } + break; + + case 28: + if (!memcmp(FName, "IOServiceGetMatchingServices", 28)) { + // FIXES: <rdar://problem/6326900> + // This should be addressed using a API table. This strcmp is also + // a little gross, but there is no need to super optimize here. + assert (ScratchArgs.isEmpty()); + ScratchArgs = AF.Add(ScratchArgs, 1, DecRef); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + } + break; } + + // Did we get a summary? + if (S) + break; // Enable this code once the semantics of NSDeallocateObject are resolved // for GC. <rdar://problem/6619988> @@ -992,15 +1019,6 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { : getPersistentStopSummary(); } #endif - - // Handle: id NSMakeCollectable(CFTypeRef) - if (strcmp(FName, "NSMakeCollectable") == 0) { - S = (RetTy == Ctx.getObjCIdType()) - ? getUnarySummary(FT, cfmakecollectable) - : getPersistentStopSummary(); - - break; - } if (RetTy->isPointerType()) { // For CoreFoundation ('CF') types. @@ -1173,19 +1191,19 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, if (!FD) return; - QualType RetTy = FD->getResultType(); - + QualType RetTy = FD->getResultType(); + // Determine if there is a special return effect for this method. if (isTrackedObjCObjectType(RetTy)) { if (FD->getAttr<NSReturnsRetainedAttr>()) { Summ.setRetEffect(ObjCAllocRetE); } - else if (FD->getAttr<CFReturnsRetainedAttr>()) { + else if (FD->getAttr<CFReturnsRetainedAttr>()) { Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); - } - } - else if (RetTy->getAsPointerType()) { - if (FD->getAttr<CFReturnsRetainedAttr>()) { + } + } + else if (RetTy->getAsPointerType()) { + if (FD->getAttr<CFReturnsRetainedAttr>()) { Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } } @@ -1379,7 +1397,7 @@ void RetainSummaryManager::InitializeMethodSummaries() { // Create the "init" selector. It just acts as a pass-through for the // receiver. addNSObjectMethSummary(GetNullarySelector("init", Ctx), - getPersistentSummary(ObjCInitRetE, DecRefMsg)); + getPersistentSummary(ObjCInitRetE, DecRefMsg)); // The next methods are allocators. RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE); diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index e8c5be5..7a8fef5 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -18,6 +18,7 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/PrettyStackTrace.h" diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 02d3d1f..eae3aef 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -651,7 +651,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // Get symbol's type. It should be a pointer type. SymbolRef Sym = SR->getSymbol(); QualType T = Sym->getType(getContext()); - QualType EleTy = cast<PointerType>(T.getTypePtr())->getPointeeType(); + QualType EleTy = T->getAsPointerType()->getPointeeType(); SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR); @@ -840,7 +840,7 @@ SVal RegionStoreManager::RetrieveStruct(const GRState* St,const TypedRegion* R){ QualType T = R->getValueType(getContext()); assert(T->isStructureType()); - const RecordType* RT = cast<RecordType>(T.getTypePtr()); + const RecordType* RT = T->getAsStructureType(); RecordDecl* RD = RT->getDecl(); assert(RD->isDefinition()); @@ -1198,6 +1198,11 @@ RegionStoreManager::BindStruct(const GRState* St, const TypedRegion* R, SVal V){ if (V.isUnknown()) return KillStruct(St, R); + // We may get non-CompoundVal accidentally due to imprecise cast logic. Ignore + // them and make struct unknown. + if (!isa<nonloc::CompoundVal>(V)) + return KillStruct(St, R); + nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V); nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end(); RecordDecl::field_iterator FI = RD->field_begin(getContext()), diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp new file mode 100644 index 0000000..ebe0514 --- /dev/null +++ b/lib/Basic/Builtins.cpp @@ -0,0 +1,92 @@ +//===--- Builtins.cpp - Builtin function implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements various things for builtin functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Builtins.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/TargetInfo.h" +using namespace clang; + +static const Builtin::Info BuiltinInfo[] = { + { "not a builtin function", 0, 0, 0, false }, +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false }, +#include "clang/Basic/Builtins.def" +}; + +const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const { + if (ID < Builtin::FirstTSBuiltin) + return BuiltinInfo[ID]; + assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!"); + return TSRecords[ID - Builtin::FirstTSBuiltin]; +} + +/// InitializeBuiltins - Mark the identifiers for all the builtins with their +/// appropriate builtin ID # and mark any non-portable builtin identifiers as +/// such. +void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, + const TargetInfo &Target, + bool NoBuiltins) { + // Step #1: mark all target-independent builtins with their ID's. + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + if (!BuiltinInfo[i].Suppressed && + (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) + Table.get(BuiltinInfo[i].Name).setBuiltinID(i); + + // Get the target specific builtins from the target. + Target.getTargetBuiltins(TSRecords, NumTSRecords); + + // Step #2: Register target-specific builtins. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + if (!TSRecords[i].Suppressed && + (!NoBuiltins || + (TSRecords[i].Attributes && + !strchr(TSRecords[i].Attributes, 'f')))) + Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); +} + +void +Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names, + bool NoBuiltins) { + // Final all target-independent names + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + if (!BuiltinInfo[i].Suppressed && + (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) + Names.push_back(BuiltinInfo[i].Name); + + // Find target-specific names. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + if (!TSRecords[i].Suppressed && + (!NoBuiltins || + (TSRecords[i].Attributes && + !strchr(TSRecords[i].Attributes, 'f')))) + Names.push_back(TSRecords[i].Name); +} + +bool +Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, + bool &HasVAListArg) { + const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP"); + if (!Printf) + return false; + + HasVAListArg = (*Printf == 'P'); + + ++Printf; + assert(*Printf == ':' && "p or P specifier must have be followed by a ':'"); + ++Printf; + + assert(strchr(Printf, ':') && "printf specifier must end with a ':'"); + FormatIdx = strtol(Printf, 0, 10); + return true; +} + diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index 1cbf11c..e0e9a10 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangBasic + Builtins.cpp ConvertUTF.c Diagnostic.cpp FileManager.cpp diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 3b3d61b..323f7a7 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -46,6 +46,7 @@ struct StaticDiagInfoRec { unsigned short DiagID; unsigned Mapping : 3; unsigned Class : 3; + bool SFINAE : 1; const char *Description; const char *OptionGroup; @@ -58,8 +59,8 @@ struct StaticDiagInfoRec { }; static const StaticDiagInfoRec StaticDiagInfo[] = { -#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP) \ - { diag::ENUM, DEFAULT_MAPPING, CLASS, DESC, GROUP }, +#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) \ + { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, DESC, GROUP }, #include "clang/Basic/DiagnosticCommonKinds.inc" #include "clang/Basic/DiagnosticDriverKinds.inc" #include "clang/Basic/DiagnosticFrontendKinds.inc" @@ -68,7 +69,7 @@ static const StaticDiagInfoRec StaticDiagInfo[] = { #include "clang/Basic/DiagnosticASTKinds.inc" #include "clang/Basic/DiagnosticSemaKinds.inc" #include "clang/Basic/DiagnosticAnalysisKinds.inc" -{ 0, 0, 0, 0, 0 } + { 0, 0, 0, 0, 0, 0} }; #undef DIAG @@ -89,7 +90,7 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { #endif // Search the diagnostic table with a binary search. - StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0 }; + StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0 }; const StaticDiagInfoRec *Found = std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find); @@ -115,6 +116,12 @@ const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) { return 0; } +bool Diagnostic::isBuiltinSFINAEDiag(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->SFINAE && Info->Class != CLASS_NOTE; + return false; +} + /// getDiagClass - Return the class field of the diagnostic. /// static unsigned getBuiltinDiagClass(unsigned DiagID) { @@ -399,7 +406,7 @@ bool Diagnostic::setDiagnosticGroupMapping(const char *Group, /// ProcessDiag - This is the method used to report a diagnostic that is /// finally fully formed. -void Diagnostic::ProcessDiag() { +bool Diagnostic::ProcessDiag() { DiagnosticInfo Info(this); // Figure out the diagnostic level of this message. @@ -449,13 +456,13 @@ void Diagnostic::ProcessDiag() { // If a fatal error has already been emitted, silence all subsequent // diagnostics. if (FatalErrorOccurred) - return; + return false; // If the client doesn't care about this message, don't issue it. If this is // a note and the last real diagnostic was ignored, ignore it too. if (DiagLevel == Diagnostic::Ignored || (DiagLevel == Diagnostic::Note && LastDiagLevel == Diagnostic::Ignored)) - return; + return false; // If this diagnostic is in a system header and is not a clang error, suppress // it. @@ -464,7 +471,7 @@ void Diagnostic::ProcessDiag() { Info.getLocation().getSpellingLoc().isInSystemHeader() && (DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) { LastDiagLevel = Diagnostic::Ignored; - return; + return false; } if (DiagLevel >= Diagnostic::Error) { @@ -477,6 +484,8 @@ void Diagnostic::ProcessDiag() { if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics; CurDiagID = ~0U; + + return true; } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index b4e32e9..13758ad 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -12,9 +12,8 @@ // //===----------------------------------------------------------------------===// -// FIXME: Layering violation -#include "clang/AST/Builtins.h" -#include "clang/AST/TargetBuiltins.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/STLExtras.h" @@ -315,7 +314,7 @@ public: const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false }, -#include "clang/AST/PPCBuiltins.def" +#include "clang/Basic/BuiltinsPPC.def" }; @@ -489,7 +488,7 @@ namespace { const Builtin::Info BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false }, -#include "clang/AST/X86Builtins.def" +#include "clang/Basic/BuiltinsX86.def" }; const char *GCCRegNames[] = { @@ -767,6 +766,7 @@ X86TargetInfo::validateAsmConstraint(const char *&Name, // x86_64 instructions. case 'N': // unsigned 8-bit integer constant for use with in and out // instructions. + case 'R': // "legacy" registers: ax, bx, cx, dx, di, si, sp, bp. Info.setAllowsRegister(); return true; } @@ -931,6 +931,10 @@ public: TLSSupported = false; WCharType = SignedShort; WCharWidth = WCharAlign = 16; + DoubleAlign = LongLongAlign = 64; + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" + "a0:0:64-f80:32:32"; } virtual void getTargetDefines(const LangOptions &Opts, std::vector<char> &Defines) const { @@ -965,7 +969,7 @@ public: DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" - "a0:0:64-f80:128:128"; + "a0:0:64-s0:64:64-f80:128:128"; } virtual const char *getVAListDeclaration() const { return "typedef struct __va_list_tag {" diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index f9c44c8..a919dfa 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -17,7 +17,7 @@ #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" -#include "clang/AST/TargetBuiltins.h" +#include "clang/Basic/TargetBuiltins.h" #include "llvm/Intrinsics.h" using namespace clang; using namespace CodeGen; diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index b10b9c2..4037f32 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -682,10 +682,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // location that we would like to return into. QualType RetTy = CallInfo.getReturnType(); const ABIArgInfo &RetAI = CallInfo.getReturnInfo(); - if (CGM.ReturnTypeUsesSret(CallInfo)) { - // Create a temporary alloca to hold the result of the call. :( + + + // If the call returns a temporary with struct return, create a temporary + // alloca to hold the result. + if (CGM.ReturnTypeUsesSret(CallInfo)) Args.push_back(CreateTempAlloca(ConvertTypeForMem(RetTy))); - } assert(CallInfo.arg_size() == CallArgs.size() && "Mismatch between function signature & arguments."); @@ -747,6 +749,35 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, break; } } + + // If the callee is a bitcast of a function to a varargs pointer to function + // type, check to see if we can remove the bitcast. This handles some cases + // with unprototyped functions. + if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Callee)) + if (llvm::Function *CalleeF = dyn_cast<llvm::Function>(CE->getOperand(0))) { + const llvm::PointerType *CurPT=cast<llvm::PointerType>(Callee->getType()); + const llvm::FunctionType *CurFT = + cast<llvm::FunctionType>(CurPT->getElementType()); + const llvm::FunctionType *ActualFT = CalleeF->getFunctionType(); + + if (CE->getOpcode() == llvm::Instruction::BitCast && + ActualFT->getReturnType() == CurFT->getReturnType() && + ActualFT->getNumParams() == CurFT->getNumParams()) { + bool ArgsMatch = true; + for (unsigned i = 0, e = ActualFT->getNumParams(); i != e; ++i) + if (ActualFT->getParamType(i) != CurFT->getParamType(i)) { + ArgsMatch = false; + break; + } + + // Strip the cast if we can get away with it. This is a nice cleanup, + // but also allows us to inline the function at -O0 if it is marked + // always_inline. + if (ArgsMatch) + Callee = CalleeF; + } + } + llvm::BasicBlock *InvokeDest = getInvokeDest(); CodeGen::AttributeListType AttributeList; @@ -765,7 +796,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } CS.setAttributes(Attrs); - if (const llvm::Function *F = dyn_cast<llvm::Function>(Callee->stripPointerCasts())) + if (const llvm::Function *F = + dyn_cast<llvm::Function>(Callee->stripPointerCasts())) CS.setCallingConv(F->getCallingConv()); // If the call doesn't return, finish the basic block and clear the diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index c52e6bd..eb0db61 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1156,10 +1156,9 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { } } - if (const CXXOperatorCallExpr *CE = dyn_cast<CXXOperatorCallExpr>(E)) { + if (const CXXOperatorCallExpr *CE = dyn_cast<CXXOperatorCallExpr>(E)) if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl)) return EmitCXXOperatorMemberCallExpr(CE, MD); - } llvm::Value *Callee = EmitScalarExpr(E->getCallee()); return EmitCall(Callee, E->getCallee()->getType(), diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 41fb725..e1332ff 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -77,7 +77,14 @@ public: /// and returns the result. ComplexPairTy EmitLoadOfLValue(const Expr *E) { LValue LV = CGF.EmitLValue(E); - return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified()); + if (LV.isSimple()) + return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified()); + + if (LV.isPropertyRef()) + return CGF.EmitObjCPropertyGet(LV.getPropertyRefExpr()).getComplexVal(); + + assert(LV.isKVCRef() && "Unknown LValue type!"); + return CGF.EmitObjCPropertyGet(LV.getKVCRefExpr()).getComplexVal(); } /// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load @@ -107,6 +114,18 @@ public: // l-values. ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); } + ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + return EmitLoadOfLValue(E); + } + ComplexPairTy VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + return EmitLoadOfLValue(E); + } + ComplexPairTy VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) { + return EmitLoadOfLValue(E); + } + ComplexPairTy VisitObjCMessageExpr(ObjCMessageExpr *E) { + return CGF.EmitObjCMessageExpr(E).getComplexVal(); + } ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); } ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); } @@ -522,15 +541,32 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) { // Compute the address to store into. LValue LHS = CGF.EmitLValue(E->getLHS()); - - // Store into it. - EmitStoreOfComplex(Val, LHS.getAddress(), LHS.isVolatileQualified()); - // And now return the LHS + + // Store into it, if simple. + if (LHS.isSimple()) { + EmitStoreOfComplex(Val, LHS.getAddress(), LHS.isVolatileQualified()); + + // And now return the LHS + IgnoreReal = ignreal; + IgnoreImag = ignimag; + IgnoreRealAssign = ignreal; + IgnoreImagAssign = ignimag; + return EmitLoadOfComplex(LHS.getAddress(), LHS.isVolatileQualified()); + } + + // Otherwise we must have a property setter (no complex vector/bitfields). + if (LHS.isPropertyRef()) + CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), RValue::getComplex(Val)); + else + CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(), RValue::getComplex(Val)); + + // There is no reload after a store through a method, but we need to restore + // the Ignore* flags. IgnoreReal = ignreal; IgnoreImag = ignimag; IgnoreRealAssign = ignreal; IgnoreImagAssign = ignimag; - return EmitLoadOfComplex(LHS.getAddress(), LHS.isVolatileQualified()); + return Val; } ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) { diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index b30bafb..0e21a00 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -17,6 +17,7 @@ #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/Builtins.h" #include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/GlobalVariable.h" diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 75755ec..bd5b05a 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -1508,6 +1508,8 @@ CodeGen::RValue CGObjCCommonMac::EmitLegacyMessageSend( BuiltinType::Kind k = BT->getKind(); Fn = (k == BuiltinType::LongDouble) ? ObjCTypes.getSendFpretFn2(IsSuper) : ObjCTypes.getSendFn2(IsSuper); + } else { + Fn = ObjCTypes.getSendFn2(IsSuper); } } else diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 5c12c81..82156e9 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -21,6 +21,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -1107,9 +1108,9 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(unsigned BuiltinID) { Name += 10; // Get the type for the builtin. - Builtin::Context::GetBuiltinTypeError Error; - QualType Type = Context.BuiltinInfo.GetBuiltinType(BuiltinID, Context, Error); - assert(Error == Builtin::Context::GE_None && "Can't get builtin type"); + ASTContext::GetBuiltinTypeError Error; + QualType Type = Context.GetBuiltinType(BuiltinID, Error); + assert(Error == ASTContext::GE_None && "Can't get builtin type"); const llvm::FunctionType *Ty = cast<llvm::FunctionType>(getTypes().ConvertType(Type)); @@ -1481,7 +1482,11 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::CXXDestructor: EmitCXXDestructors(cast<CXXDestructorDecl>(D)); break; - + + case Decl::StaticAssert: + // Nothing to do. + break; + // Objective-C Decls // Forward declarations, no (immediate) code generation. diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 6ee1223..14392ab 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -87,19 +87,20 @@ static bool isInCLinkageSpecification(const Decl *D) { bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) { // Clang's "overloadable" attribute extension to C/C++ implies // name mangling (always). - if (FD->hasAttr<OverloadableAttr>()) { - ; // fall into mangling code unconditionally. - } else if (// C functions are not mangled - !Context.getLangOptions().CPlusPlus || - // "main" is not mangled in C++ - FD->isMain() || - // No mangling in an "implicit extern C" header. - (FD->getLocation().isValid() && - Context.getSourceManager().getFileCharacteristic(FD->getLocation())) - == SrcMgr::C_ExternCSystem || - // No name mangling in a C linkage specification. - isInCLinkageSpecification(FD)) - return false; + if (!FD->hasAttr<OverloadableAttr>()) { + // C functions are not mangled, and "main" is never mangled. + if (!Context.getLangOptions().CPlusPlus || FD->isMain()) + return false; + + // No mangling in an "implicit extern C" header. + if (FD->getLocation().isValid() && + Context.getSourceManager().isInExternCSystemHeader(FD->getLocation())) + return false; + + // No name mangling in a C linkage specification. + if (isInCLinkageSpecification(FD)) + return false; + } // If we get here, mangle the decl name! Out << "_Z"; diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index 6f7bea2..361e5c0 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -159,6 +159,23 @@ static bool areAllFields32Or64BitBasicType(const RecordDecl *RD, return true; } +static bool typeContainsSSEVector(const RecordDecl *RD, ASTContext &Context) { + for (RecordDecl::field_iterator i = RD->field_begin(Context), + e = RD->field_end(Context); i != e; ++i) { + const FieldDecl *FD = *i; + + if (FD->getType()->isVectorType() && + Context.getTypeSize(FD->getType()) >= 128) + return true; + + if (const RecordType* RT = FD->getType()->getAsRecordType()) + if (typeContainsSSEVector(RT->getDecl(), Context)) + return true; + } + + return false; +} + namespace { /// DefaultABIInfo - The default implementation for ABI specific /// details. This implementation provides information which results in @@ -193,6 +210,9 @@ class X86_32ABIInfo : public ABIInfo { static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context); + static unsigned getIndirectArgumentAlignment(QualType Ty, + ASTContext &Context); + public: ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context) const; @@ -350,6 +370,16 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, } } +unsigned X86_32ABIInfo::getIndirectArgumentAlignment(QualType Ty, + ASTContext &Context) { + unsigned Align = Context.getTypeAlign(Ty); + if (Align < 128) return 0; + if (const RecordType* RT = Ty->getAsRecordType()) + if (typeContainsSSEVector(RT->getDecl(), Context)) + return 16; + return 0; +} + ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context) const { // FIXME: Set alignment on indirect arguments. @@ -357,11 +387,11 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, // Structures with flexible arrays are always indirect. if (const RecordType *RT = Ty->getAsStructureType()) if (RT->getDecl()->hasFlexibleArrayMember()) - return ABIArgInfo::getIndirect(0); + return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, + Context)); // Ignore empty structs. - uint64_t Size = Context.getTypeSize(Ty); - if (Ty->isStructureType() && Size == 0) + if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0) return ABIArgInfo::getIgnore(); // Expand structs with size <= 128-bits which consist only of @@ -373,7 +403,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, return ABIArgInfo::getExpand(); } - return ABIArgInfo::getIndirect(0); + return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context)); } else { return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 6b082c8..bfc247a 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -43,8 +43,17 @@ void Clang::AddPreprocessingOptions(const Driver &D, ArgStringList &CmdArgs, const InputInfo &Output, const InputInfoList &Inputs) const { - // Handle dependency file generation. Arg *A; + + if ((A = Args.getLastArg(options::OPT_C)) || + (A = Args.getLastArg(options::OPT_CC))) { + if (!Args.hasArg(options::OPT_E)) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << A->getAsString(Args) << "-E"; + A->render(Args, CmdArgs); + } + + // Handle dependency file generation. if ((A = Args.getLastArg(options::OPT_M)) || (A = Args.getLastArg(options::OPT_MM)) || (A = Args.getLastArg(options::OPT_MD)) || @@ -550,8 +559,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_diagnostics_show_option)) CmdArgs.push_back("-fdiagnostics-show-option"); if (!Args.hasFlag(options::OPT_fcolor_diagnostics, - options::OPT_fno_color_diagnostics)) + options::OPT_fno_color_diagnostics)) CmdArgs.push_back("-fno-color-diagnostics"); + if (!Args.hasFlag(options::OPT_fshow_source_location, + options::OPT_fno_show_source_location)) + CmdArgs.push_back("-fno-show-source-location"); // -fdollars-in-identifiers default varies depending on platform and // language; only pass if specified. diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp index 9560b61..d8f8625 100644 --- a/lib/Frontend/Backend.cpp +++ b/lib/Frontend/Backend.cpp @@ -272,9 +272,13 @@ void BackendConsumer::CreatePasses() { llvm::Pass *InliningPass = 0; switch (CompileOpts.Inlining) { case CompileOptions::NoInlining: break; - case CompileOptions::NormalInlining: - InliningPass = createFunctionInliningPass(); // Inline small functions + case CompileOptions::NormalInlining: { + // Inline small functions + unsigned Threshold = (CompileOpts.OptimizeSize || + CompileOpts.OptimizationLevel < 3) ? 50 : 200; + InliningPass = createFunctionInliningPass(Threshold); break; + } case CompileOptions::OnlyAlwaysInlining: InliningPass = createAlwaysInlinerPass(); // Respect always_inline break; diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 10059f6..e6871e3 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -210,6 +210,7 @@ unsigned PCHStmtReader::VisitDoStmt(DoStmt *S) { S->setBody(StmtStack.back()); S->setDoLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); return 2; } diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index b7caee5..73dea10 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -23,7 +23,6 @@ using namespace clang; namespace { class PCHStmtWriter : public StmtVisitor<PCHStmtWriter, void> { - PCHWriter &Writer; PCHWriter::RecordData &Record; @@ -197,6 +196,7 @@ void PCHStmtWriter::VisitDoStmt(DoStmt *S) { Writer.WriteSubStmt(S->getBody()); Writer.AddSourceLocation(S->getDoLoc(), Record); Writer.AddSourceLocation(S->getWhileLoc(), Record); + Writer.AddSourceLocation(S->getRParenLoc(), Record); Code = pch::STMT_DO; } diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index b9fe068..170ab5e 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -327,7 +327,9 @@ namespace { return StmtEmpty(); } virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, - SourceLocation WhileLoc, ExprArg Cond){ + SourceLocation WhileLoc, + SourceLocation LPLoc, ExprArg Cond, + SourceLocation RPLoc){ Out << __FUNCTION__ << "\n"; return StmtEmpty(); } @@ -701,7 +703,8 @@ namespace { } virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, - SourceLocation EqualLoc) { + SourceLocation EqualLoc, + SourceLocation ArgLoc) { Out << __FUNCTION__ << "\n"; } diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index 4938399..5d2bcbb 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -898,7 +898,10 @@ do { \ (row3) = _mm_movelh_ps(tmp3, tmp1); \ } while (0) +/* Ugly hack for backwards-compatibility (compatible with gcc) */ +#ifdef __SSE2__ #include <emmintrin.h> +#endif #endif /* __SSE__ */ diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 4d10974..37ea52b 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -56,6 +56,10 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, PP.Diag(Loc, diag::ext_nonstandard_escape) << "e"; ResultChar = 27; break; + case 'E': + PP.Diag(Loc, diag::ext_nonstandard_escape) << "E"; + ResultChar = 27; + break; case 'f': ResultChar = 12; break; @@ -135,7 +139,6 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, PP.Diag(Loc, diag::ext_nonstandard_escape) << std::string()+(char)ResultChar; break; - // FALL THROUGH. default: if (isgraph(ThisTokBuf[0])) PP.Diag(Loc, diag::ext_unknown_escape) << std::string()+(char)ResultChar; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 55222c9..2867051 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -36,14 +36,14 @@ void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) { /// RegisterBuiltinMacro - Register the specified identifier in the identifier /// table and mark it as a builtin macro to be expanded. -IdentifierInfo *Preprocessor::RegisterBuiltinMacro(const char *Name) { +static IdentifierInfo *RegisterBuiltinMacro(Preprocessor &PP, const char *Name){ // Get the identifier. - IdentifierInfo *Id = getIdentifierInfo(Name); + IdentifierInfo *Id = PP.getIdentifierInfo(Name); // Mark it as being a macro that is builtin. - MacroInfo *MI = AllocateMacroInfo(SourceLocation()); + MacroInfo *MI = PP.AllocateMacroInfo(SourceLocation()); MI->setIsBuiltinMacro(); - setMacroInfo(Id, MI); + PP.setMacroInfo(Id, MI); return Id; } @@ -51,17 +51,21 @@ IdentifierInfo *Preprocessor::RegisterBuiltinMacro(const char *Name) { /// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the /// identifier table. void Preprocessor::RegisterBuiltinMacros() { - Ident__LINE__ = RegisterBuiltinMacro("__LINE__"); - Ident__FILE__ = RegisterBuiltinMacro("__FILE__"); - Ident__DATE__ = RegisterBuiltinMacro("__DATE__"); - Ident__TIME__ = RegisterBuiltinMacro("__TIME__"); - Ident__COUNTER__ = RegisterBuiltinMacro("__COUNTER__"); - Ident_Pragma = RegisterBuiltinMacro("_Pragma"); + Ident__LINE__ = RegisterBuiltinMacro(*this, "__LINE__"); + Ident__FILE__ = RegisterBuiltinMacro(*this, "__FILE__"); + Ident__DATE__ = RegisterBuiltinMacro(*this, "__DATE__"); + Ident__TIME__ = RegisterBuiltinMacro(*this, "__TIME__"); + Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__"); + Ident_Pragma = RegisterBuiltinMacro(*this, "_Pragma"); // GCC Extensions. - Ident__BASE_FILE__ = RegisterBuiltinMacro("__BASE_FILE__"); - Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro("__INCLUDE_LEVEL__"); - Ident__TIMESTAMP__ = RegisterBuiltinMacro("__TIMESTAMP__"); + Ident__BASE_FILE__ = RegisterBuiltinMacro(*this, "__BASE_FILE__"); + Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__"); + Ident__TIMESTAMP__ = RegisterBuiltinMacro(*this, "__TIMESTAMP__"); + + // Clang Extensions. + Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature"); + Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); } /// isTrivialSingleTokenExpansion - Return true if MI, which has a single token @@ -469,6 +473,34 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc, TIMELoc = TmpTok.getLocation(); } + +/// HasFeature - Return true if we recognize and implement the specified feature +/// specified by the identifier. +static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { + const LangOptions &LangOpts = PP.getLangOptions(); + + switch (II->getLength()) { + default: return false; + case 6: + if (II->isStr("blocks")) return LangOpts.Blocks; + return false; + case 22: + if (II->isStr("attribute_overloadable")) return true; + return false; + case 25: + if (II->isStr("attribute_ext_vector_type")) return true; + return false; + case 27: + if (II->isStr("attribute_analyzer_noreturn")) return true; + return false; + case 29: + if (II->isStr("attribute_ns_returns_retained")) return true; + if (II->isStr("attribute_cf_returns_retained")) return true; + return false; + } +} + + /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { @@ -599,6 +631,43 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { sprintf(TmpBuffer, "%u", CounterValue++); Tok.setKind(tok::numeric_constant); CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); + } else if (II == Ident__has_feature || + II == Ident__has_builtin) { + // The argument to these two builtins should be a parenthesized identifier. + SourceLocation StartLoc = Tok.getLocation(); + + bool IsValid = false; + IdentifierInfo *FeatureII = 0; + + // Read the '('. + Lex(Tok); + if (Tok.is(tok::l_paren)) { + // Read the identifier + Lex(Tok); + if (Tok.is(tok::identifier)) { + FeatureII = Tok.getIdentifierInfo(); + + // Read the ')'. + Lex(Tok); + if (Tok.is(tok::r_paren)) + IsValid = true; + } + } + + bool Value = false; + if (!IsValid) + Diag(StartLoc, diag::err_feature_check_malformed); + else if (II == Ident__has_builtin) { + // Check for a builtin is trivial. + Value = FeatureII->getBuiltinID() != 0; + } else { + assert(II == Ident__has_feature && "Must be feature check"); + Value = HasFeature(*this, FeatureII); + } + + sprintf(TmpBuffer, "%d", (int)Value); + Tok.setKind(tok::numeric_constant); + CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); } else { assert(0 && "Unknown identifier!"); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 9aab3b9..9073c6d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -209,17 +209,16 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { /// extended-decl-modifier[opt] /// extended-decl-modifier extended-decl-modifier-seq -AttributeList* Parser::ParseMicrosoftDeclSpec() { +AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) { assert(Tok.is(tok::kw___declspec) && "Not a declspec!"); - AttributeList *CurrAttr = 0; ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "declspec")) { SkipUntil(tok::r_paren, true); // skip until ) or ; return CurrAttr; } - while (Tok.is(tok::identifier) || Tok.is(tok::kw_restrict)) { + while (Tok.getIdentifierInfo()) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); if (Tok.is(tok::l_paren)) { @@ -242,8 +241,24 @@ AttributeList* Parser::ParseMicrosoftDeclSpec() { } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); - // FIXME: Return the attributes once we have some Sema support! - return 0; + return CurrAttr; +} + +AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { + // Treat these like attributes + // FIXME: Allow Sema to distinguish between these and real attributes! + while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || + Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___ptr64) || + Tok.is(tok::kw___w64)) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) + // FIXME: Support these properly! + continue; + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, + SourceLocation(), 0, 0, CurrAttr, true); + } + return CurrAttr; } /// ParseDeclaration - Parse a full 'declaration', which consists of @@ -839,22 +854,22 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Microsoft declspec support. case tok::kw___declspec: - if (!PP.getLangOptions().Microsoft) - goto DoneWithDeclSpec; DS.AddAttributes(ParseMicrosoftDeclSpec()); continue; // Microsoft single token adornments. case tok::kw___forceinline: + // FIXME: Add handling here! + break; + + case tok::kw___ptr64: case tok::kw___w64: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: - if (!PP.getLangOptions().Microsoft) - goto DoneWithDeclSpec; - // Just ignore it. - break; - + DS.AddAttributes(ParseMicrosoftTypeAttributes()); + continue; + // storage-class-specifier case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec); @@ -1213,11 +1228,12 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, ParseTypeofSpecifier(DS); return true; + case tok::kw___ptr64: + case tok::kw___w64: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: - if (!PP.getLangOptions().Microsoft) return false; - ConsumeToken(); + DS.AddAttributes(ParseMicrosoftTypeAttributes()); return true; default: @@ -1671,7 +1687,9 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: - return PP.getLangOptions().Microsoft; + case tok::kw___w64: + case tok::kw___ptr64: + return true; } } @@ -1769,7 +1787,10 @@ bool Parser::isDeclarationSpecifier() { case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: - return PP.getLangOptions().Microsoft; + case tok::kw___w64: + case tok::kw___ptr64: + case tok::kw___forceinline: + return true; } } @@ -1800,14 +1821,16 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) { isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, getLang())*2; break; + case tok::kw___w64: case tok::kw___ptr64: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: - if (!PP.getLangOptions().Microsoft) - goto DoneWithTypeQuals; - // Just ignore it. - break; + if (AttributesAllowed) { + DS.AddAttributes(ParseMicrosoftTypeAttributes()); + continue; + } + goto DoneWithTypeQuals; case tok::kw___attribute: if (AttributesAllowed) { DS.AddAttributes(ParseAttributes()); @@ -2205,9 +2228,11 @@ void Parser::ParseParenDeclarator(Declarator &D) { RequiresArg = true; } // Eat any Microsoft extensions. - while ((Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) || - (Tok.is(tok::kw___fastcall))) && PP.getLangOptions().Microsoft) - ConsumeToken(); + if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) || + Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___w64) || + Tok.is(tok::kw___ptr64)) { + AttrList = ParseMicrosoftTypeAttributes(AttrList); + } // If we haven't past the identifier yet (or where the identifier would be // stored, if this is an abstract declarator), then this is probably just @@ -2445,7 +2470,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, DefArgToks = 0; Actions.ActOnParamDefaultArgumentError(Param); } else - Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc); + Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc, + (*DefArgToks)[1].getLocation()); } else { // Consume the '='. ConsumeToken(); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 0e8eebc..498eaf1 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -123,8 +123,8 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, // Eat the ';'. DeclEnd = Tok.getLocation(); - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - "namespace name", tok::semi); + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_namespace_name, + "", tok::semi); return Actions.ActOnNamespaceAliasDef(CurScope, NamespaceLoc, AliasLoc, Alias, SS, IdentLoc, Ident); @@ -232,8 +232,9 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, // Eat ';'. DeclEnd = Tok.getLocation(); - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - AttrList ? "attributes list" : "namespace name", tok::semi); + ExpectAndConsume(tok::semi, + AttrList ? diag::err_expected_semi_after_attribute_list : + diag::err_expected_semi_after_namespace_name, "", tok::semi); return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS, IdentLoc, NamespcName, AttrList); @@ -409,9 +410,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Attr = ParseAttributes(); // If declspecs exist after tag, parse them. - if (Tok.is(tok::kw___declspec) && PP.getLangOptions().Microsoft) - // FIXME: Need to do something with the attributes! - ParseMicrosoftDeclSpec(); + if (Tok.is(tok::kw___declspec)) + Attr = ParseMicrosoftDeclSpec(Attr); // Parse the (optional) nested-name-specifier. CXXScopeSpec SS; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index cd62c64..3fee78b 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -749,7 +749,13 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, Diag(Tok, diag::err_expected_expression); return ExprError(); } - + + if (SavedKind == tok::kw_typename) { + // postfix-expression: typename-specifier '(' expression-list[opt] ')' + if (!TryAnnotateTypeOrScopeToken()) + return ExprError(); + } + // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' // DeclSpec DS; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index f041d7d..955f00d 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -142,33 +142,33 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { return ParseWhileStatement(); case tok::kw_do: // C99 6.8.5.2: do-statement Res = ParseDoStatement(); - SemiError = "do/while loop"; + SemiError = "do/while"; break; case tok::kw_for: // C99 6.8.5.3: for-statement return ParseForStatement(); case tok::kw_goto: // C99 6.8.6.1: goto-statement Res = ParseGotoStatement(); - SemiError = "goto statement"; + SemiError = "goto"; break; case tok::kw_continue: // C99 6.8.6.2: continue-statement Res = ParseContinueStatement(); - SemiError = "continue statement"; + SemiError = "continue"; break; case tok::kw_break: // C99 6.8.6.3: break-statement Res = ParseBreakStatement(); - SemiError = "break statement"; + SemiError = "break"; break; case tok::kw_return: // C99 6.8.6.4: return-statement Res = ParseReturnStatement(); - SemiError = "return statement"; + SemiError = "return"; break; case tok::kw_asm: { bool msAsm = false; Res = ParseAsmStatement(msAsm); if (msAsm) return move(Res); - SemiError = "asm statement"; + SemiError = "asm"; break; } @@ -180,10 +180,14 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { if (Tok.is(tok::semi)) { ConsumeToken(); } else if (!Res.isInvalid()) { - Diag(Tok, diag::err_expected_semi_after) << SemiError; + // If the result was valid, then we do want to diagnose this. Use + // ExpectAndConsume to emit the diagnostic, even though we know it won't + // succeed. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, SemiError); // Skip until we see a } or ;, but don't eat it. SkipUntil(tok::r_brace, true, true); } + return move(Res); } @@ -487,8 +491,11 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { /// successfully parsed. Note that a successful parse can still have semantic /// errors in the condition. bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, - bool OnlyAllowCondition) { + bool OnlyAllowCondition, + SourceLocation *LParenLocPtr, + SourceLocation *RParenLocPtr) { SourceLocation LParenLoc = ConsumeParen(); + if (LParenLocPtr) *LParenLocPtr = LParenLoc; if (getLang().CPlusPlus) CondExp = ParseCXXCondition(); @@ -507,7 +514,8 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, } // Otherwise the condition is valid or the rparen is present. - MatchRHSPunctuation(tok::r_paren, LParenLoc); + SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (RParenLocPtr) *RParenLocPtr = RPLoc; return false; } @@ -837,14 +845,16 @@ Parser::OwningStmtResult Parser::ParseDoStatement() { // Parse the parenthesized condition. OwningExprResult Cond(Actions); - ParseParenExprOrCondition(Cond, true); + SourceLocation LPLoc, RPLoc; + ParseParenExprOrCondition(Cond, true, &LPLoc, &RPLoc); DoScope.Exit(); if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); - return Actions.ActOnDoStmt(DoLoc, move(Body), WhileLoc, move(Cond)); + return Actions.ActOnDoStmt(DoLoc, move(Body), WhileLoc, LPLoc, + move(Cond), RPLoc); } /// ParseForStatement diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 2a79b99..a9f75d8 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -290,11 +290,11 @@ Parser::ParseTemplateParameterList(unsigned Depth, /// parameter-declaration /// /// type-parameter: (see below) -/// 'class' identifier[opt] +/// 'class' ...[opt][C++0x] identifier[opt] /// 'class' identifier[opt] '=' type-id -/// 'typename' identifier[opt] +/// 'typename' ...[opt][C++0x] identifier[opt] /// 'typename' identifier[opt] '=' type-id -/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] +/// 'template' ...[opt][C++0x] '<' template-parameter-list '>' 'class' identifier[opt] /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression Parser::DeclPtrTy Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { @@ -319,9 +319,9 @@ Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { /// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter. /// /// type-parameter: [C++ temp.param] -/// 'class' identifier[opt] +/// 'class' ...[opt][C++0x] identifier[opt] /// 'class' identifier[opt] '=' type-id -/// 'typename' identifier[opt] +/// 'typename' ...[opt][C++0x] identifier[opt] /// 'typename' identifier[opt] '=' type-id Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){ assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) && @@ -331,6 +331,17 @@ Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){ bool TypenameKeyword = Tok.is(tok::kw_typename); SourceLocation KeyLoc = ConsumeToken(); + // Grab the ellipsis (if given). + bool Ellipsis = false; + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) { + Ellipsis = true; + EllipsisLoc = ConsumeToken(); + + if (!getLang().CPlusPlus0x) + Diag(EllipsisLoc, diag::err_variadic_templates); + } + // Grab the template parameter name (if given) SourceLocation NameLoc; IdentifierInfo* ParamName = 0; @@ -347,6 +358,7 @@ Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){ } DeclPtrTy TypeParam = Actions.ActOnTypeParameter(CurScope, TypenameKeyword, + Ellipsis, EllipsisLoc, KeyLoc, ParamName, NameLoc, Depth, Position); diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 81696d6..f31855b 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -655,7 +655,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: - return PP.getLangOptions().Microsoft ? TPResult::True() : TPResult::False(); + case tok::kw___w64: + case tok::kw___ptr64: + case tok::kw___forceinline: + return TPResult::True(); // The ambiguity resides in a simple-type-specifier/typename-specifier // followed by a '('. The '(' could either be the start of: diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index e3cea5b..a5f2438 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -183,7 +183,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), - CurrentInstantiationScope(0) { + NumSFINAEErrors(0), CurrentInstantiationScope(0) { StdNamespace = 0; TUScope = 0; @@ -316,7 +316,8 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() { } Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { - this->Emit(); + if (!this->Emit()) + return; // If this is not a note, and we're in a template instantiation // that is different from the last template instantiation where diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c558293..0607a89 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -256,6 +256,9 @@ public: /// unit. bool CompleteTranslationUnit; + /// \brief The number of SFINAE diagnostics that have been trapped. + unsigned NumSFINAEErrors; + typedef llvm::DenseMap<Selector, ObjCMethodList> MethodPool; /// Instance/Factory Method Pools - allows efficient lookup when typechecking @@ -297,11 +300,38 @@ public: SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } + explicit SemaDiagnosticBuilder(Sema &SemaRef) + : DiagnosticBuilder(DiagnosticBuilder::Suppress), SemaRef(SemaRef) { } + ~SemaDiagnosticBuilder(); }; /// \brief Emit a diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { + if (isSFINAEContext() && Diagnostic::isBuiltinSFINAEDiag(DiagID)) { + // If we encountered an error during template argument + // deduction, and that error is one of the SFINAE errors, + // suppress the diagnostic. + bool Fatal = false; + switch (Diags.getDiagnosticLevel(DiagID)) { + case Diagnostic::Ignored: + case Diagnostic::Note: + case Diagnostic::Warning: + break; + + case Diagnostic::Error: + ++NumSFINAEErrors; + break; + + case Diagnostic::Fatal: + Fatal = true; + break; + } + + if (!Fatal) + return SemaDiagnosticBuilder(*this); + } + DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); return SemaDiagnosticBuilder(DB, *this, DiagID); } @@ -349,6 +379,11 @@ public: QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, unsigned Quals, SourceLocation Loc, DeclarationName Entity); + QualType BuildMemberPointerType(QualType T, QualType Class, + unsigned Quals, SourceLocation Loc, + DeclarationName Entity); + QualType BuildBlockPointerType(QualType T, unsigned Quals, + SourceLocation Loc, DeclarationName Entity); QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0, TagDecl **OwnedDecl = 0); DeclarationName GetNameForDeclarator(Declarator &D); @@ -409,8 +444,14 @@ public: SourceLocation EqualLoc, ExprArg defarg); virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, - SourceLocation EqualLoc); + SourceLocation EqualLoc, + SourceLocation ArgLoc); virtual void ActOnParamDefaultArgumentError(DeclPtrTy param); + + // Contains the locations of the beginning of unparsed default + // argument locations. + llvm::DenseMap<ParmVarDecl *,SourceLocation> UnparsedDefaultArgLocs; + virtual void AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init); void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit); void ActOnUninitializedDecl(DeclPtrTy dcl); @@ -1194,7 +1235,9 @@ public: virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body); virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, - SourceLocation WhileLoc, ExprArg Cond); + SourceLocation WhileLoc, + SourceLocation CondLParen, ExprArg Cond, + SourceLocation CondRParen); virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, @@ -1871,7 +1914,8 @@ public: bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl); - virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, + virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, + SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, @@ -1940,8 +1984,14 @@ public: ClassTemplateSpecializationDecl *PrevDecl, SourceLocation TemplateNameLoc, SourceRange ScopeSpecifierRange, + bool PartialSpecialization, bool ExplicitInstantiation); + bool CheckClassTemplatePartialSpecializationArgs( + TemplateParameterList *TemplateParams, + const TemplateArgumentListBuilder &TemplateArgs, + bool &MirrorsPrimaryTemplate); + virtual DeclResult ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, SourceLocation KWLoc, @@ -1985,6 +2035,10 @@ public: SourceLocation RAngleLoc, TemplateArgumentListBuilder &Converted); + bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, + const TemplateArgument &Arg, + TemplateArgumentListBuilder &Converted); + bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg, SourceLocation ArgLoc); bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, @@ -1992,7 +2046,7 @@ public: bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member); bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, - TemplateArgumentListBuilder *Converted = 0); + TemplateArgument &Converted); bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg); bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, @@ -2031,10 +2085,122 @@ public: const IdentifierInfo &II, SourceRange Range); - TemplateArgumentList * + /// \brief Describes the result of template argument deduction. + /// + /// The TemplateDeductionResult enumeration describes the result of + /// template argument deduction, as returned from + /// DeduceTemplateArguments(). The separate TemplateDeductionInfo + /// structure provides additional information about the results of + /// template argument deduction, e.g., the deduced template argument + /// list (if successful) or the specific template parameters or + /// deduced arguments that were involved in the failure. + enum TemplateDeductionResult { + /// \brief Template argument deduction was successful. + TDK_Success = 0, + /// \brief Template argument deduction exceeded the maximum template + /// instantiation depth (which has already been diagnosed). + TDK_InstantiationDepth, + /// \brief Template argument deduction did not deduce a value + /// for every template parameter. + TDK_Incomplete, + /// \brief Template argument deduction produced inconsistent + /// deduced values for the given template parameter. + TDK_Inconsistent, + /// \brief Template argument deduction failed due to inconsistent + /// cv-qualifiers on a template parameter type that would + /// otherwise be deduced, e.g., we tried to deduce T in "const T" + /// but were given a non-const "X". + TDK_InconsistentQuals, + /// \brief Substitution of the deduced template argument values + /// resulted in an error. + TDK_SubstitutionFailure, + /// \brief Substitution of the deduced template argument values + /// 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 + }; + + /// \brief Provides information about an attempted template argument + /// deduction, whose success or failure was described by a + /// TemplateDeductionResult value. + class TemplateDeductionInfo { + /// \brief The context in which the template arguments are stored. + ASTContext &Context; + + /// \brief The deduced template argument list. + /// + TemplateArgumentList *Deduced; + + // do not implement these + TemplateDeductionInfo(const TemplateDeductionInfo&); + TemplateDeductionInfo &operator=(const TemplateDeductionInfo&); + + public: + TemplateDeductionInfo(ASTContext &Context) : Context(Context), Deduced(0) { } + + ~TemplateDeductionInfo() { + // FIXME: if (Deduced) Deduced->Destroy(Context); + } + + /// \brief Take ownership of the deduced template argument list. + TemplateArgumentList *take() { + TemplateArgumentList *Result = Deduced; + Deduced = 0; + return Result; + } + + /// \brief Provide a new template argument list that contains the + /// results of template argument deduction. + void reset(TemplateArgumentList *NewDeduced) { + // FIXME: if (Deduced) Deduced->Destroy(Context); + Deduced = NewDeduced; + } + + /// \brief The template parameter to which a template argument + /// deduction failure refers. + /// + /// Depending on the result of template argument deduction, this + /// template parameter may have different meanings: + /// + /// TDK_Incomplete: this is the first template parameter whose + /// corresponding template argument was not deduced. + /// + /// TDK_Inconsistent: this is the template parameter for which + /// two different template argument values were deduced. + TemplateParameter Param; + + /// \brief The first template argument to which the template + /// argument deduction failure refers. + /// + /// Depending on the result of the template argument deduction, + /// this template argument may have different meanings: + /// + /// TDK_Inconsistent: this argument is the first value deduced + /// for the corresponding template parameter. + /// + /// TDK_SubstitutionFailure: this argument is the template + /// argument we were instantiating when we encountered an error. + /// + /// TDK_NonDeducedMismatch: this is the template argument + /// provided in the source code. + TemplateArgument FirstArg; + + /// \brief The second template argument to which the template + /// argument deduction failure refers. + /// + /// FIXME: Finish documenting this. + TemplateArgument SecondArg; + }; + + TemplateDeductionResult DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, - const TemplateArgumentList &TemplateArgs); - + const TemplateArgumentList &TemplateArgs, + TemplateDeductionInfo &Info); + + void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl<bool> &Deduced); + //===--------------------------------------------------------------------===// // C++ Template Instantiation // @@ -2053,7 +2219,16 @@ public: /// parameter. The Entity is the template, and /// TemplateArgs/NumTemplateArguments provides the template /// arguments as specified. - DefaultTemplateArgumentInstantiation + /// FIXME: Use a TemplateArgumentList + DefaultTemplateArgumentInstantiation, + + /// We are performing template argument deduction for a class + /// template partial specialization. The Entity is the class + /// template partial specialization, and + /// TemplateArgs/NumTemplateArgs provides the deduced template + /// arguments. + /// FIXME: Use a TemplateArgumentList + PartialSpecDeductionInstantiation } Kind; /// \brief The point of instantiation within the source code. @@ -2087,6 +2262,7 @@ public: return true; case DefaultTemplateArgumentInstantiation: + case PartialSpecDeductionInstantiation: return X.TemplateArgs == Y.TemplateArgs; } @@ -2143,6 +2319,15 @@ public: unsigned NumTemplateArgs, SourceRange InstantiationRange = SourceRange()); + /// \brief Note that we are instantiating as part of template + /// argument deduction for a class template partial + /// specialization. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ClassTemplatePartialSpecializationDecl *PartialSpec, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange = SourceRange()); + /// \brief Note that we have finished instantiating this template. void Clear(); @@ -2167,6 +2352,32 @@ public: void PrintInstantiationStack(); + /// \brief Determines whether we are currently in a context where + /// template argument substitution failures are not considered + /// errors. + /// + /// When this routine returns true, the emission of most diagnostics + /// will be suppressed and there will be no local error recovery. + bool isSFINAEContext() const; + + /// \brief RAII class used to determine whether SFINAE has + /// trapped any errors that occur during template argument + /// deduction. + class SFINAETrap { + Sema &SemaRef; + unsigned PrevSFINAEErrors; + public: + explicit SFINAETrap(Sema &SemaRef) + : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors) { } + + ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; } + + /// \brief Determine whether any SFINAE errors have been trapped. + bool hasErrorOccurred() const { + return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; + } + }; + /// \brief A stack-allocated class that identifies which local /// variable declaration instantiations are present in this scope. /// @@ -2285,6 +2496,8 @@ public: TemplateName InstantiateTemplateName(TemplateName Name, SourceLocation Loc, const TemplateArgumentList &TemplateArgs); + TemplateArgument Instantiate(TemplateArgument Arg, + const TemplateArgumentList &TemplateArgs); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c67af29..b995717 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -416,14 +416,14 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, if (Context.BuiltinInfo.hasVAListUse(BID)) InitBuiltinVaListType(); - Builtin::Context::GetBuiltinTypeError Error; - QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context, Error); + ASTContext::GetBuiltinTypeError Error; + QualType R = Context.GetBuiltinType(BID, Error); switch (Error) { - case Builtin::Context::GE_None: + case ASTContext::GE_None: // Okay break; - case Builtin::Context::GE_Missing_FILE: + case ASTContext::GE_Missing_FILE: if (ForRedeclaration) Diag(Loc, diag::err_implicit_decl_requires_stdio) << Context.BuiltinInfo.GetName(BID); @@ -3208,7 +3208,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) { if (!FD->getAttr<FormatAttr>()) FD->addAttr(::new (Context) FormatAttr("printf", FormatIdx + 1, - FormatIdx + 2)); + HasVAListArg ? 0 : FormatIdx + 2)); } // Mark const if we don't care about errno and that is the only @@ -3239,10 +3239,12 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { // FIXME: We known better than our headers. const_cast<FormatAttr *>(Format)->setType("printf"); } else - FD->addAttr(::new (Context) FormatAttr("printf", 1, 2)); + FD->addAttr(::new (Context) FormatAttr("printf", 1, + Name->isStr("NSLogv") ? 0 : 2)); } else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) { if (!FD->getAttr<FormatAttr>()) - FD->addAttr(::new (Context) FormatAttr("printf", 2, 3)); + FD->addAttr(::new (Context) FormatAttr("printf", 2, + Name->isStr("vasprintf") ? 0 : 3)); } } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 99b4d77..1afdb60 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1699,6 +1699,9 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, /// the attribute applies to decls. If the attribute is a type attribute, just /// silently ignore it. static void ProcessDeclAttribute(Decl *D, const AttributeList &Attr, Sema &S) { + if (Attr.isDeclspecAttribute()) + // FIXME: Try to deal with __declspec attributes! + return; switch (Attr.getKind()) { case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break; case AttributeList::AT_address_space: diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b59ac87..8f64e78 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -108,6 +108,8 @@ void Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, ExprArg defarg) { ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>()); + UnparsedDefaultArgLocs.erase(Param); + ExprOwningPtr<Expr> DefaultArg(this, defarg.takeAs<Expr>()); QualType ParamType = Param->getType(); @@ -154,16 +156,23 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, /// because we're inside a class definition. Note that this default /// argument will be parsed later. void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param, - SourceLocation EqualLoc) { + SourceLocation EqualLoc, + SourceLocation ArgLoc) { ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>()); if (Param) Param->setUnparsedDefaultArg(); + + UnparsedDefaultArgLocs[Param] = ArgLoc; } /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of /// the default argument for the parameter param failed. void Sema::ActOnParamDefaultArgumentError(DeclPtrTy param) { - cast<ParmVarDecl>(param.getAs<Decl>())->setInvalidDecl(); + ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>()); + + Param->setInvalidDecl(); + + UnparsedDefaultArgLocs.erase(Param); } /// CheckExtraCXXDefaultArguments - Check for any extra default @@ -285,7 +294,7 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { // in a semantically valid state. for (p = 0; p <= LastMissingDefaultArg; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); - if (Param->getDefaultArg()) { + if (Param->hasDefaultArg()) { if (!Param->hasUnparsedDefaultArg()) Param->getDefaultArg()->Destroy(Context); Param->setDefaultArg(0); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index da32d4e..c01c812 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1177,7 +1177,12 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, ValueDependent = true; // - a constant with integral or enumeration type and is // initialized with an expression that is value-dependent - // (FIXME!). + else if (const VarDecl *Dcl = dyn_cast<VarDecl>(VD)) { + if (Dcl->getType().getCVRQualifiers() == QualType::Const && + Dcl->getInit()) { + ValueDependent = Dcl->getInit()->isValueDependent(); + } + } } return Owned(BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc, @@ -2479,9 +2484,19 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // Pass the argument. if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) return true; - } else + } else { + if (FDecl->getParamDecl(i)->hasUnparsedDefaultArg()) { + Diag (Call->getSourceRange().getBegin(), + diag::err_use_of_default_argument_to_function_declared_later) << + FDecl << cast<CXXRecordDecl>(FDecl->getDeclContext())->getDeclName(); + Diag(UnparsedDefaultArgLocs[FDecl->getParamDecl(i)], + diag::note_default_argument_declared_here); + } + // We already type-checked the argument, so we know it works. Arg = new (Context) CXXDefaultArgExpr(FDecl->getParamDecl(i)); + } + QualType ArgType = Arg->getType(); Call->setArg(i, Arg); diff --git a/lib/Sema/SemaInherit.cpp b/lib/Sema/SemaInherit.cpp index 1b968f0..28ca5f6 100644 --- a/lib/Sema/SemaInherit.cpp +++ b/lib/Sema/SemaInherit.cpp @@ -138,6 +138,12 @@ bool Sema::LookupInBases(CXXRecordDecl *Class, // Find the record of the base class subobjects for this type. QualType BaseType = Context.getCanonicalType(BaseSpec->getType()); BaseType = BaseType.getUnqualifiedType(); + + // If a base class of the class template depends on a template-parameter, + // the base class scope is not examined during unqualified name lookup. + // [temp.dep]p3. + if (BaseType->isDependentType()) + continue; // Determine whether we need to visit this base class at all, // updating the count of subobjects appropriately. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 4e0eb1d..4508596 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -674,7 +674,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, // compatible structure or union type. In the latter case, the // initial value of the object, including unnamed members, is // that of the expression. - if (ElemType->isRecordType() && + if ((ElemType->isRecordType() || ElemType->isVectorType()) && SemaRef.Context.hasSameUnqualifiedType(expr->getType(), ElemType)) { UpdateStructuredListElement(StructuredList, StructuredIndex, expr); ++Index; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 6212449..1d26845 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -20,6 +20,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/Parse/DeclSpec.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 15262e9..aa9b8db 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -568,7 +568,8 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) { Action::OwningStmtResult Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, - SourceLocation WhileLoc, ExprArg Cond) { + SourceLocation WhileLoc, SourceLocation CondLParen, + ExprArg Cond, SourceLocation CondRParen) { Expr *condExpr = Cond.takeAs<Expr>(); assert(condExpr && "ActOnDoStmt(): missing expression"); @@ -588,7 +589,7 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, Cond.release(); return Owned(new (Context) DoStmt(Body.takeAs<Stmt>(), condExpr, DoLoc, - WhileLoc)); + WhileLoc, CondRParen)); } Action::OwningStmtResult diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f9176ca..b2a82ed 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -140,7 +140,8 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) { /// ParamName is the location of the parameter name (if any). /// If the type parameter has a default argument, it will be added /// later via ActOnTypeParameterDefault. -Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, +Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, + SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, @@ -162,7 +163,8 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(Context, CurContext, Loc, - Depth, Position, ParamName, Typename); + Depth, Position, ParamName, Typename, + Ellipsis); if (Invalid) Param->setInvalidDecl(); @@ -185,6 +187,14 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, = cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>()); QualType Default = QualType::getFromOpaquePtr(DefaultT); + // C++0x [temp.param]p9: + // A default template-argument may be specified for any kind of + // template-parameter that is not a template parameter pack. + if (Parm->isParameterPack()) { + Diag(DefaultLoc, diag::err_template_param_pack_default_arg); + return; + } + // C++ [temp.param]p14: // A template-parameter shall not be used in its own default argument. // FIXME: Implement this check! Needs a recursive walk over the types. @@ -297,7 +307,9 @@ void Sema::ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParamD, // FIXME: Implement this check! Needs a recursive walk over the types. // Check the well-formedness of the default template argument. - if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default)) { + TemplateArgument Converted; + if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default, + Converted)) { TemplateParm->setInvalidDecl(); return; } @@ -579,6 +591,9 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, bool SawDefaultArgument = false; SourceLocation PreviousDefaultArgLoc; + bool SawParameterPack = false; + SourceLocation ParameterPackLoc; + // Dummy initialization to avoid warnings. TemplateParameterList::iterator OldParam = NewParams->end(); if (OldParams) @@ -595,13 +610,27 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Variables used to diagnose missing default arguments bool MissingDefaultArg = false; + // C++0x [temp.param]p11: + // If a template parameter of a class template is a template parameter pack, + // it must be the last template parameter. + if (SawParameterPack) { + Diag(ParameterPackLoc, + diag::err_template_param_pack_must_be_last_template_parameter); + Invalid = true; + } + // Merge default arguments for template type parameters. if (TemplateTypeParmDecl *NewTypeParm = dyn_cast<TemplateTypeParmDecl>(*NewParam)) { TemplateTypeParmDecl *OldTypeParm = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0; - if (OldTypeParm && OldTypeParm->hasDefaultArgument() && + if (NewTypeParm->isParameterPack()) { + assert(!NewTypeParm->hasDefaultArgument() && + "Parameter packs can't have a default argument!"); + SawParameterPack = true; + ParameterPackLoc = NewTypeParm->getLocation(); + } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() && NewTypeParm->hasDefaultArgument()) { OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); @@ -946,6 +975,33 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name)); } +bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, + const TemplateArgument &Arg, + TemplateArgumentListBuilder &Converted) { + // Check template type parameter. + if (Arg.getKind() != TemplateArgument::Type) { + // C++ [temp.arg.type]p1: + // A template-argument for a template-parameter which is a + // type shall be a type-id. + + // We have a template type parameter but the template argument + // is not a type. + Diag(Arg.getLocation(), diag::err_template_arg_must_be_type); + Diag(Param->getLocation(), diag::note_template_param_here); + + return true; + } + + if (CheckTemplateArgument(Param, Arg.getAsType(), Arg.getLocation())) + return true; + + // Add the converted template type argument. + Converted.push_back( + TemplateArgument(Arg.getLocation(), + Context.getCanonicalType(Arg.getAsType()))); + return false; +} + /// \brief Check that the given template argument list is well-formed /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, @@ -960,7 +1016,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, unsigned NumArgs = NumTemplateArgs; bool Invalid = false; - if (NumArgs > NumParams || + bool HasParameterPack = + NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack(); + + if ((NumArgs > NumParams && !HasParameterPack) || NumArgs < Params->getMinRequiredArguments()) { // FIXME: point at either the first arg beyond what we can handle, // or the '>', depending on whether we have too many or too few @@ -994,6 +1053,13 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // Retrieve the default template argument from the template // parameter. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { + if (TTP->isParameterPack()) { + // We have an empty parameter pack. + Converted.BeginParameterPack(); + Converted.EndParameterPack(); + break; + } + if (!TTP->hasDefaultArgument()) break; @@ -1024,8 +1090,21 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (!NTTP->hasDefaultArgument()) break; - // FIXME: Instantiate default argument - Arg = TemplateArgument(NTTP->getDefaultArgument()); + InstantiatingTemplate Inst(*this, TemplateLoc, + Template, Converted.getFlatArgumentList(), + Converted.flatSize(), + SourceRange(TemplateLoc, RAngleLoc)); + + TemplateArgumentList TemplateArgs(Context, Converted, + /*CopyArgs=*/false, + /*FlattenArgs=*/false); + + Sema::OwningExprResult E = InstantiateExpr(NTTP->getDefaultArgument(), + TemplateArgs); + if (E.isInvalid()) + return true; + + Arg = TemplateArgument(E.takeAs<Expr>()); } else { TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); @@ -1043,27 +1122,19 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { - // Check template type parameters. - if (Arg.getKind() == TemplateArgument::Type) { - if (CheckTemplateArgument(TTP, Arg.getAsType(), Arg.getLocation())) + if (TTP->isParameterPack()) { + Converted.BeginParameterPack(); + // Check all the remaining arguments (if any). + for (; ArgIdx < NumArgs; ++ArgIdx) { + if (CheckTemplateTypeArgument(TTP, TemplateArgs[ArgIdx], Converted)) + Invalid = true; + } + + Converted.EndParameterPack(); + } else { + if (CheckTemplateTypeArgument(TTP, Arg, Converted)) Invalid = true; - - // Add the converted template type argument. - Converted.push_back( - TemplateArgument(Arg.getLocation(), - Context.getCanonicalType(Arg.getAsType()))); - continue; } - - // C++ [temp.arg.type]p1: - // A template-argument for a template-parameter which is a - // type shall be a type-id. - - // We have a template type parameter but the template argument - // is not a type. - Diag(Arg.getLocation(), diag::err_template_arg_must_be_type); - Diag((*Param)->getLocation(), diag::note_template_param_here); - Invalid = true; } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { // Check non-type template parameters. @@ -1103,8 +1174,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, case TemplateArgument::Expression: { Expr *E = Arg.getAsExpr(); - if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted)) + TemplateArgument Result; + if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) Invalid = true; + else + Converted.push_back(Result); break; } @@ -1388,11 +1462,10 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { /// InstantiatedParamType is the type of the non-type template /// parameter after it has been instantiated. /// -/// If Converted is non-NULL and no errors occur, the value -/// of this argument will be added to the end of the Converted vector. +/// If no error was detected, Converted receives the converted template argument. bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, - TemplateArgumentListBuilder *Converted) { + TemplateArgument &Converted) { SourceLocation StartLoc = Arg->getSourceRange().getBegin(); // If either the parameter has a dependent type or the argument is @@ -1400,7 +1473,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // FIXME: Add template argument to Converted! if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) { // FIXME: Produce a cloned, canonical expression? - Converted->push_back(TemplateArgument(Arg)); + Converted = TemplateArgument(Arg); return false; } @@ -1465,7 +1538,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType IntegerType = Context.getCanonicalType(ParamType); if (const EnumType *Enum = IntegerType->getAsEnumType()) - IntegerType = Enum->getDecl()->getIntegerType(); + IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType()); if (!Arg->isValueDependent()) { // Check that an unsigned parameter does not receive a negative @@ -1495,21 +1568,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Value.setIsSigned(IntegerType->isSignedIntegerType()); } - if (Converted) { - // Add the value of this argument to the list of converted - // arguments. We use the bitwidth and signedness of the template - // parameter. - if (Arg->isValueDependent()) { - // The argument is value-dependent. Create a new - // TemplateArgument with the converted expression. - Converted->push_back(TemplateArgument(Arg)); - return false; - } - - Converted->push_back(TemplateArgument(StartLoc, Value, - ParamType->isEnumeralType() ? ParamType : IntegerType)); + // Add the value of this argument to the list of converted + // arguments. We use the bitwidth and signedness of the template + // parameter. + if (Arg->isValueDependent()) { + // The argument is value-dependent. Create a new + // TemplateArgument with the converted expression. + Converted = TemplateArgument(Arg); + return false; } + Converted = TemplateArgument(StartLoc, Value, + ParamType->isEnumeralType() ? ParamType + : IntegerType); return false; } @@ -1576,11 +1647,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentPointerToMember(Arg, Member)) return true; - if (Converted) { - Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member)); - Converted->push_back(TemplateArgument(StartLoc, Member)); - } - + Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member)); + Converted = TemplateArgument(StartLoc, Member); return false; } @@ -1588,10 +1656,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - if (Converted) { - Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity)); - Converted->push_back(TemplateArgument(StartLoc, Entity)); - } + Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity)); + Converted = TemplateArgument(StartLoc, Entity); return false; } @@ -1629,11 +1695,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - if (Converted) { - Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity)); - Converted->push_back(TemplateArgument(StartLoc, Entity)); - } - + Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity)); + Converted = TemplateArgument(StartLoc, Entity); return false; } @@ -1673,11 +1736,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - if (Converted) { - Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity)); - Converted->push_back(TemplateArgument(StartLoc, Entity)); - } - + Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity)); + Converted = TemplateArgument(StartLoc, Entity); return false; } @@ -1705,11 +1765,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentPointerToMember(Arg, Member)) return true; - if (Converted) { - Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member)); - Converted->push_back(TemplateArgument(StartLoc, Member)); - } - + Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member)); + Converted = TemplateArgument(StartLoc, Member); return false; } @@ -1730,7 +1787,12 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, // template template argument with the corresponding parameter; // partial specializations are not considered even if their // parameter lists match that of the template template parameter. - if (!isa<ClassTemplateDecl>(Template)) { + // + // Note that we also allow template template parameters here, which + // will happen when we are dealing with, e.g., class template + // partial specializations. + if (!isa<ClassTemplateDecl>(Template) && + !isa<TemplateTemplateParmDecl>(Template)) { assert(isa<FunctionTemplateDecl>(Template) && "Only function templates are possible here"); Diag(Arg->getSourceRange().getBegin(), @@ -1925,6 +1987,7 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, ClassTemplateSpecializationDecl *PrevDecl, SourceLocation TemplateNameLoc, SourceRange ScopeSpecifierRange, + bool PartialSpecialization, bool ExplicitInstantiation) { // C++ [temp.expl.spec]p2: // An explicit specialization shall be declared in the namespace @@ -1940,8 +2003,9 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, // that encloses the one in which the explicit specialization was // declared. if (CurContext->getLookupContext()->isFunctionOrMethod()) { + int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0; Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope) - << ExplicitInstantiation << ClassTemplate; + << Kind << ClassTemplate; return true; } @@ -1956,11 +2020,12 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, if (DC != TemplateContext) { if (isa<TranslationUnitDecl>(TemplateContext)) Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope_global) + << PartialSpecialization << ClassTemplate << ScopeSpecifierRange; else if (isa<NamespaceDecl>(TemplateContext)) Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope) - << ClassTemplate << cast<NamedDecl>(TemplateContext) - << ScopeSpecifierRange; + << PartialSpecialization << ClassTemplate + << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange; Diag(ClassTemplate->getLocation(), diag::note_template_decl_here); } @@ -1974,16 +2039,17 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, // FIXME: In C++98, we would like to turn these errors into warnings, // dependent on a -Wc++0x flag. bool SuppressedDiag = false; + int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0; if (isa<TranslationUnitDecl>(TemplateContext)) { if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x) Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope) - << ExplicitInstantiation << ClassTemplate << ScopeSpecifierRange; + << Kind << ClassTemplate << ScopeSpecifierRange; else SuppressedDiag = true; } else if (isa<NamespaceDecl>(TemplateContext)) { if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x) Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope) - << ExplicitInstantiation << ClassTemplate + << Kind << ClassTemplate << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange; else SuppressedDiag = true; @@ -1996,6 +2062,126 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, return false; } +/// \brief Check the non-type template arguments of a class template +/// partial specialization according to C++ [temp.class.spec]p9. +/// +/// \param TemplateParams the template parameters of the primary class +/// template. +/// +/// \param TemplateArg the template arguments of the class template +/// partial specialization. +/// +/// \param MirrorsPrimaryTemplate will be set true if the class +/// template partial specialization arguments are identical to the +/// implicit template arguments of the primary template. This is not +/// necessarily an error (C++0x), and it is left to the caller to diagnose +/// this condition when it is an error. +/// +/// \returns true if there was an error, false otherwise. +bool Sema::CheckClassTemplatePartialSpecializationArgs( + TemplateParameterList *TemplateParams, + const TemplateArgumentListBuilder &TemplateArgs, + bool &MirrorsPrimaryTemplate) { + // FIXME: the interface to this function will have to change to + // accommodate variadic templates. + MirrorsPrimaryTemplate = true; + + const TemplateArgument *ArgList = TemplateArgs.getFlatArgumentList(); + + for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { + // Determine whether the template argument list of the partial + // specialization is identical to the implicit argument list of + // the primary template. The caller may need to diagnostic this as + // an error per C++ [temp.class.spec]p9b3. + if (MirrorsPrimaryTemplate) { + if (TemplateTypeParmDecl *TTP + = dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(I))) { + if (Context.getCanonicalType(Context.getTypeDeclType(TTP)) != + Context.getCanonicalType(ArgList[I].getAsType())) + MirrorsPrimaryTemplate = false; + } else if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>( + TemplateParams->getParam(I))) { + // FIXME: We should settle on either Declaration storage or + // Expression storage for template template parameters. + TemplateTemplateParmDecl *ArgDecl + = dyn_cast_or_null<TemplateTemplateParmDecl>( + ArgList[I].getAsDecl()); + if (!ArgDecl) + if (DeclRefExpr *DRE + = dyn_cast_or_null<DeclRefExpr>(ArgList[I].getAsExpr())) + ArgDecl = dyn_cast<TemplateTemplateParmDecl>(DRE->getDecl()); + + if (!ArgDecl || + ArgDecl->getIndex() != TTP->getIndex() || + ArgDecl->getDepth() != TTP->getDepth()) + MirrorsPrimaryTemplate = false; + } + } + + NonTypeTemplateParmDecl *Param + = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I)); + if (!Param) { + continue; + } + + Expr *ArgExpr = ArgList[I].getAsExpr(); + if (!ArgExpr) { + MirrorsPrimaryTemplate = false; + continue; + } + + // C++ [temp.class.spec]p8: + // A non-type argument is non-specialized if it is the name of a + // non-type parameter. All other non-type arguments are + // specialized. + // + // Below, we check the two conditions that only apply to + // specialized non-type arguments, so skip any non-specialized + // arguments. + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl())) { + if (MirrorsPrimaryTemplate && + (Param->getIndex() != NTTP->getIndex() || + Param->getDepth() != NTTP->getDepth())) + MirrorsPrimaryTemplate = false; + + continue; + } + + // C++ [temp.class.spec]p9: + // Within the argument list of a class template partial + // specialization, the following restrictions apply: + // -- A partially specialized non-type argument expression + // shall not involve a template parameter of the partial + // specialization except when the argument expression is a + // simple identifier. + if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) { + Diag(ArgExpr->getLocStart(), + diag::err_dependent_non_type_arg_in_partial_spec) + << ArgExpr->getSourceRange(); + return true; + } + + // -- The type of a template parameter corresponding to a + // specialized non-type argument shall not be dependent on a + // parameter of the specialization. + if (Param->getType()->isDependentType()) { + Diag(ArgExpr->getLocStart(), + diag::err_dependent_typed_non_type_arg_in_partial_spec) + << Param->getType() + << ArgExpr->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + MirrorsPrimaryTemplate = false; + } + + return false; +} + Sema::DeclResult Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, SourceLocation KWLoc, @@ -2032,9 +2218,41 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, return true; } - // FIXME: We'll need more checks, here! - if (TemplateParams->size() > 0) + if (TemplateParams->size() > 0) { isPartialSpecialization = true; + + // C++ [temp.class.spec]p10: + // The template parameter list of a specialization shall not + // contain default template argument values. + for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { + Decl *Param = TemplateParams->getParam(I); + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { + if (TTP->hasDefaultArgument()) { + Diag(TTP->getDefaultArgumentLoc(), + diag::err_default_arg_in_partial_spec); + TTP->setDefaultArgument(QualType(), SourceLocation(), false); + } + } else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + if (Expr *DefArg = NTTP->getDefaultArgument()) { + Diag(NTTP->getDefaultArgumentLoc(), + diag::err_default_arg_in_partial_spec) + << DefArg->getSourceRange(); + NTTP->setDefaultArgument(0); + DefArg->Destroy(Context); + } + } else { + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param); + if (Expr *DefArg = TTP->getDefaultArgument()) { + Diag(TTP->getDefaultArgumentLoc(), + diag::err_default_arg_in_partial_spec) + << DefArg->getSourceRange(); + TTP->setDefaultArgument(0); + DefArg->Destroy(Context); + } + } + } + } } // Check that the specialization uses the same tag kind as the @@ -2066,7 +2284,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // template. TemplateArgumentListBuilder ConvertedTemplateArgs(Context); if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, - &TemplateArgs[0], TemplateArgs.size(), + TemplateArgs.data(), TemplateArgs.size(), RAngleLoc, ConvertedTemplateArgs)) return true; @@ -2077,11 +2295,36 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // Find the class template (partial) specialization declaration that // corresponds to these arguments. llvm::FoldingSetNodeID ID; - if (isPartialSpecialization) + if (isPartialSpecialization) { + bool MirrorsPrimaryTemplate; + if (CheckClassTemplatePartialSpecializationArgs( + ClassTemplate->getTemplateParameters(), + ConvertedTemplateArgs, + MirrorsPrimaryTemplate)) + return true; + + if (MirrorsPrimaryTemplate) { + // C++ [temp.class.spec]p9b3: + // + // -- The argument list of the specialization shall not be identical + // to the implicit argument list of the primary template. + Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) + << (TK == TK_Definition) + << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc, + RAngleLoc)); + return ActOnClassTemplate(S, TagSpec, TK, KWLoc, SS, + ClassTemplate->getIdentifier(), + TemplateNameLoc, + Attr, + move(TemplateParameterLists), + AS_none); + } + // FIXME: Template parameter list matters, too ClassTemplatePartialSpecializationDecl::Profile(ID, ConvertedTemplateArgs.getFlatArgumentList(), ConvertedTemplateArgs.flatSize()); + } else ClassTemplateSpecializationDecl::Profile(ID, ConvertedTemplateArgs.getFlatArgumentList(), @@ -2104,6 +2347,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl, TemplateNameLoc, SS.getRange(), + isPartialSpecialization, /*ExplicitInstantiation=*/false)) return true; @@ -2116,8 +2360,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, Specialization->setLocation(TemplateNameLoc); PrevDecl = 0; } else if (isPartialSpecialization) { - // FIXME: extra checking for partial specializations - // Create a new class template partial specialization declaration node. TemplateParameterList *TemplateParams = static_cast<TemplateParameterList*>(*TemplateParameterLists.get()); @@ -2139,6 +2381,38 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, ClassTemplate->getPartialSpecializations().InsertNode(Partial, InsertPos); } Specialization = Partial; + + // Check that all of the template parameters of the class template + // partial specialization are deducible from the template + // arguments. If not, this class template partial specialization + // will never be used. + llvm::SmallVector<bool, 8> DeducibleParams; + DeducibleParams.resize(TemplateParams->size()); + MarkDeducedTemplateParameters(Partial->getTemplateArgs(), DeducibleParams); + unsigned NumNonDeducible = 0; + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) + if (!DeducibleParams[I]) + ++NumNonDeducible; + + if (NumNonDeducible) { + Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible) + << (NumNonDeducible > 1) + << SourceRange(TemplateNameLoc, RAngleLoc); + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { + if (!DeducibleParams[I]) { + NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); + if (Param->getDeclName()) + Diag(Param->getLocation(), + diag::note_partial_spec_unused_parameter) + << Param->getDeclName(); + else + Diag(Param->getLocation(), + diag::note_partial_spec_unused_parameter) + << std::string("<anonymous>"); + } + } + } + } else { // Create a new class template specialization declaration node for // this explicit specialization. @@ -2185,7 +2459,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // template arguments in the specialization. QualType WrittenTy = Context.getTemplateSpecializationType(Name, - &TemplateArgs[0], + TemplateArgs.data(), TemplateArgs.size(), Context.getTypeDeclType(Specialization)); Specialization->setTypeAsWritten(WrittenTy); @@ -2259,6 +2533,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, if (CheckClassTemplateSpecializationScope(ClassTemplate, 0, TemplateNameLoc, SS.getRange(), + /*PartialSpecialization=*/false, /*ExplicitInstantiation=*/true)) return true; diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index db7e622..84d802d 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -20,6 +20,14 @@ #include "llvm/Support/Compiler.h" using namespace clang; +static Sema::TemplateDeductionResult +DeduceTemplateArguments(ASTContext &Context, + TemplateParameterList *TemplateParams, + const TemplateArgument &Param, + const TemplateArgument &Arg, + Sema::TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<TemplateArgument> &Deduced); + /// \brief If the given expression is of a form that permits the deduction /// of a non-type template parameter, return the declaration of that /// non-type template parameter. @@ -35,12 +43,12 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { /// \brief Deduce the value of the given non-type template parameter /// from the given constant. -/// -/// \returns true if deduction succeeded, false otherwise. -static bool DeduceNonTypeTemplateArgument(ASTContext &Context, - NonTypeTemplateParmDecl *NTTP, - llvm::APInt Value, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { +static Sema::TemplateDeductionResult +DeduceNonTypeTemplateArgument(ASTContext &Context, + NonTypeTemplateParmDecl *NTTP, + llvm::APInt Value, + Sema::TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); @@ -48,25 +56,41 @@ static bool DeduceNonTypeTemplateArgument(ASTContext &Context, Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(), llvm::APSInt(Value), NTTP->getType()); - return true; + return Sema::TDK_Success; } - if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral) - return false; + assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral); // If the template argument was previously deduced to a negative value, // then our deduction fails. const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral(); - assert(PrevValuePtr && "Not an integral template argument?"); - if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative()) - return false; - + if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative()) { + // FIXME: This is wacky; we should be dealing with APSInts and + // checking the actual signs. + Info.Param = NTTP; + Info.FirstArg = Deduced[NTTP->getIndex()]; + Info.SecondArg = TemplateArgument(SourceLocation(), + llvm::APSInt(Value), + NTTP->getType()); + return Sema::TDK_Inconsistent; + } + llvm::APInt PrevValue = *PrevValuePtr; if (Value.getBitWidth() > PrevValue.getBitWidth()) PrevValue.zext(Value.getBitWidth()); else if (Value.getBitWidth() < PrevValue.getBitWidth()) Value.zext(PrevValue.getBitWidth()); - return Value == PrevValue; + + if (Value != PrevValue) { + Info.Param = NTTP; + Info.FirstArg = Deduced[NTTP->getIndex()]; + Info.SecondArg = TemplateArgument(SourceLocation(), + llvm::APSInt(Value), + NTTP->getType()); + return Sema::TDK_Inconsistent; + } + + return Sema::TDK_Success; } /// \brief Deduce the value of the given non-type template parameter @@ -74,10 +98,12 @@ static bool DeduceNonTypeTemplateArgument(ASTContext &Context, /// /// \returns true if deduction succeeded, false otherwise. -static bool DeduceNonTypeTemplateArgument(ASTContext &Context, - NonTypeTemplateParmDecl *NTTP, - Expr *Value, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { +static Sema::TemplateDeductionResult +DeduceNonTypeTemplateArgument(ASTContext &Context, + NonTypeTemplateParmDecl *NTTP, + Expr *Value, + Sema::TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); assert((Value->isTypeDependent() || Value->isValueDependent()) && @@ -86,35 +112,73 @@ static bool DeduceNonTypeTemplateArgument(ASTContext &Context, if (Deduced[NTTP->getIndex()].isNull()) { // FIXME: Clone the Value? Deduced[NTTP->getIndex()] = TemplateArgument(Value); - return true; + return Sema::TDK_Success; } if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral) { // Okay, we deduced a constant in one case and a dependent expression // in another case. FIXME: Later, we will check that instantiating the // dependent expression gives us the constant value. - return true; + return Sema::TDK_Success; } // FIXME: Compare the expressions for equality! - return true; + return Sema::TDK_Success; } -static bool DeduceTemplateArguments(ASTContext &Context, QualType Param, - QualType Arg, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { +static Sema::TemplateDeductionResult +DeduceTemplateArguments(ASTContext &Context, + TemplateName Param, + TemplateName Arg, + Sema::TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + // FIXME: Implement template argument deduction for template + // template parameters. + + // FIXME: this routine does not have enough information to produce + // good diagnostics. + + TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); + TemplateDecl *ArgDecl = Arg.getAsTemplateDecl(); + + if (!ParamDecl || !ArgDecl) { + // FIXME: fill in Info.Param/Info.FirstArg + return Sema::TDK_Inconsistent; + } + + ParamDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ParamDecl)); + ArgDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ArgDecl)); + if (ParamDecl != ArgDecl) { + // FIXME: fill in Info.Param/Info.FirstArg + return Sema::TDK_Inconsistent; + } + + return Sema::TDK_Success; +} + +static Sema::TemplateDeductionResult +DeduceTemplateArguments(ASTContext &Context, + TemplateParameterList *TemplateParams, + QualType ParamIn, QualType ArgIn, + Sema::TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { // We only want to look at the canonical types, since typedefs and // sugar are not part of template argument deduction. - Param = Context.getCanonicalType(Param); - Arg = Context.getCanonicalType(Arg); + 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()) - return Param == Arg; + 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++ [temp.deduct.type]p9: - // // A template type argument T, a template template argument TT or a // template non-type argument i can be deduced if P and A have one of // the following forms: @@ -123,16 +187,21 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param, // cv-list T if (const TemplateTypeParmType *TemplateTypeParm = Param->getAsTemplateTypeParmType()) { + unsigned Index = TemplateTypeParm->getIndex(); + // The argument type can not be less qualified than the parameter // type. - if (Param.isMoreQualifiedThan(Arg)) - return false; + if (Param.isMoreQualifiedThan(Arg)) { + Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); + Info.FirstArg = Deduced[Index]; + Info.SecondArg = TemplateArgument(SourceLocation(), Arg); + return Sema::TDK_InconsistentQuals; + } assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0"); unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers(); QualType DeducedType = Arg.getQualifiedType(Quals); - unsigned Index = TemplateTypeParm->getIndex(); if (Deduced[Index].isNull()) Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType); @@ -143,55 +212,63 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param, // deduced values, or if different pairs yield different deduced // values, or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - if (Deduced[Index].getAsType() != DeducedType) - return false; + if (Deduced[Index].getAsType() != DeducedType) { + Info.Param + = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); + Info.FirstArg = Deduced[Index]; + Info.SecondArg = TemplateArgument(SourceLocation(), Arg); + return Sema::TDK_Inconsistent; + } } - return true; + return Sema::TDK_Success; } + // Set up the template argument deduction information for a failure. + Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn); + Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn); + if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) - return false; + return Sema::TDK_NonDeducedMismatch; switch (Param->getTypeClass()) { // No deduction possible for these types case Type::Builtin: - return false; - + return Sema::TDK_NonDeducedMismatch; // T * case Type::Pointer: { const PointerType *PointerArg = Arg->getAsPointerType(); if (!PointerArg) - return false; + return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArguments(Context, + return DeduceTemplateArguments(Context, TemplateParams, cast<PointerType>(Param)->getPointeeType(), PointerArg->getPointeeType(), - Deduced); + Info, Deduced); } // T & case Type::LValueReference: { const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType(); if (!ReferenceArg) - return false; + return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArguments(Context, + return DeduceTemplateArguments(Context, TemplateParams, cast<LValueReferenceType>(Param)->getPointeeType(), ReferenceArg->getPointeeType(), - Deduced); + Info, Deduced); } // T && [C++0x] case Type::RValueReference: { const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType(); if (!ReferenceArg) - return false; + return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArguments(Context, + return DeduceTemplateArguments(Context, TemplateParams, cast<RValueReferenceType>(Param)->getPointeeType(), ReferenceArg->getPointeeType(), - Deduced); + Info, Deduced); } // T [] (implied, but not stated explicitly) @@ -199,12 +276,12 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param, const IncompleteArrayType *IncompleteArrayArg = Context.getAsIncompleteArrayType(Arg); if (!IncompleteArrayArg) - return false; + return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArguments(Context, + return DeduceTemplateArguments(Context, TemplateParams, Context.getAsIncompleteArrayType(Param)->getElementType(), IncompleteArrayArg->getElementType(), - Deduced); + Info, Deduced); } // T [integer-constant] @@ -212,39 +289,40 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param, const ConstantArrayType *ConstantArrayArg = Context.getAsConstantArrayType(Arg); if (!ConstantArrayArg) - return false; + return Sema::TDK_NonDeducedMismatch; const ConstantArrayType *ConstantArrayParm = Context.getAsConstantArrayType(Param); if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize()) - return false; + return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArguments(Context, + return DeduceTemplateArguments(Context, TemplateParams, ConstantArrayParm->getElementType(), ConstantArrayArg->getElementType(), - Deduced); + Info, Deduced); } // type [i] case Type::DependentSizedArray: { const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg); if (!ArrayArg) - return false; + return Sema::TDK_NonDeducedMismatch; // Check the element type of the arrays const DependentSizedArrayType *DependentArrayParm = cast<DependentSizedArrayType>(Param); - if (!DeduceTemplateArguments(Context, - DependentArrayParm->getElementType(), - ArrayArg->getElementType(), - Deduced)) - return false; + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, TemplateParams, + DependentArrayParm->getElementType(), + ArrayArg->getElementType(), + Info, Deduced)) + return Result; // Determine the array bound is something we can deduce. NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr()); if (!NTTP) - return true; + return Sema::TDK_Success; // We can perform template argument deduction for the given non-type // template parameter. @@ -254,59 +332,209 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param, = dyn_cast<ConstantArrayType>(ArrayArg)) return DeduceNonTypeTemplateArgument(Context, NTTP, ConstantArrayArg->getSize(), - Deduced); + Info, Deduced); if (const DependentSizedArrayType *DependentArrayArg = dyn_cast<DependentSizedArrayType>(ArrayArg)) return DeduceNonTypeTemplateArgument(Context, NTTP, DependentArrayArg->getSizeExpr(), - Deduced); + Info, Deduced); // Incomplete type does not match a dependently-sized array type - return false; + return Sema::TDK_NonDeducedMismatch; } + // type(*)(T) + // T(*)() + // T(*)(T) case Type::FunctionProto: { const FunctionProtoType *FunctionProtoArg = dyn_cast<FunctionProtoType>(Arg); if (!FunctionProtoArg) - return false; + return Sema::TDK_NonDeducedMismatch; const FunctionProtoType *FunctionProtoParam = cast<FunctionProtoType>(Param); - - // Check return types. - if (!DeduceTemplateArguments(Context, - FunctionProtoParam->getResultType(), - FunctionProtoArg->getResultType(), - Deduced)) - return false; + + if (FunctionProtoParam->getTypeQuals() != + FunctionProtoArg->getTypeQuals()) + return Sema::TDK_NonDeducedMismatch; if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs()) - return false; + return Sema::TDK_NonDeducedMismatch; + + if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) + return Sema::TDK_NonDeducedMismatch; + + // Check return types. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, TemplateParams, + FunctionProtoParam->getResultType(), + FunctionProtoArg->getResultType(), + Info, Deduced)) + return Result; for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) { // Check argument types. - if (!DeduceTemplateArguments(Context, - FunctionProtoParam->getArgType(I), - FunctionProtoArg->getArgType(I), - Deduced)) - return false; + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, TemplateParams, + FunctionProtoParam->getArgType(I), + FunctionProtoArg->getArgType(I), + Info, Deduced)) + return Result; } - return true; + return Sema::TDK_Success; } + + // template-name<T> (wheretemplate-name refers to a class template) + // template-name<i> + // TT<T> (TODO) + // TT<i> (TODO) + // TT<> (TODO) + case Type::TemplateSpecialization: { + const TemplateSpecializationType *SpecParam + = cast<TemplateSpecializationType>(Param); + + // Check whether the template argument is a dependent template-id. + // FIXME: This is untested code; it can be tested when we implement + // partial ordering of class template partial specializations. + if (const TemplateSpecializationType *SpecArg + = dyn_cast<TemplateSpecializationType>(Arg)) { + // Perform template argument deduction for the template name. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, + SpecParam->getTemplateName(), + SpecArg->getTemplateName(), + Info, Deduced)) + return Result; + + unsigned NumArgs = SpecParam->getNumArgs(); + + // FIXME: When one of the template-names refers to a + // declaration with default template arguments, do we need to + // fill in those default template arguments here? Most likely, + // the answer is "yes", but I don't see any references. This + // issue may be resolved elsewhere, because we may want to + // instantiate default template arguments when + if (SpecArg->getNumArgs() != NumArgs) + return Sema::TDK_NonDeducedMismatch; + + // Perform template argument deduction on each template + // argument. + for (unsigned I = 0; I != NumArgs; ++I) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, TemplateParams, + SpecParam->getArg(I), + SpecArg->getArg(I), + Info, Deduced)) + return Result; + + return Sema::TDK_Success; + } + + // If the argument type is a class template specialization, we + // perform template argument deduction using its template + // arguments. + const RecordType *RecordArg = dyn_cast<RecordType>(Arg); + if (!RecordArg) + return Sema::TDK_NonDeducedMismatch; + + ClassTemplateSpecializationDecl *SpecArg + = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl()); + if (!SpecArg) + return Sema::TDK_NonDeducedMismatch; + + // Perform template argument deduction for the template name. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, + SpecParam->getTemplateName(), + TemplateName(SpecArg->getSpecializedTemplate()), + Info, Deduced)) + return Result; + + // FIXME: Can the # of arguments in the parameter and the argument differ? + unsigned NumArgs = SpecParam->getNumArgs(); + const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs(); + if (NumArgs != ArgArgs.size()) + return Sema::TDK_NonDeducedMismatch; + + for (unsigned I = 0; I != NumArgs; ++I) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, TemplateParams, + SpecParam->getArg(I), + ArgArgs.get(I), + Info, Deduced)) + return Result; + return Sema::TDK_Success; + } + + // T type::* + // T T::* + // T (type::*)() + // type (T::*)() + // type (type::*)(T) + // type (T::*)(T) + // T (type::*)(T) + // T (T::*)() + // T (T::*)(T) + case Type::MemberPointer: { + const MemberPointerType *MemPtrParam = cast<MemberPointerType>(Param); + const MemberPointerType *MemPtrArg = dyn_cast<MemberPointerType>(Arg); + if (!MemPtrArg) + return Sema::TDK_NonDeducedMismatch; + + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, TemplateParams, + MemPtrParam->getPointeeType(), + MemPtrArg->getPointeeType(), + Info, Deduced)) + return Result; + + return DeduceTemplateArguments(Context, TemplateParams, + QualType(MemPtrParam->getClass(), 0), + QualType(MemPtrArg->getClass(), 0), + Info, Deduced); + } + + // (clang extension) + // + // type(^)(T) + // T(^)() + // T(^)(T) + case Type::BlockPointer: { + const BlockPointerType *BlockPtrParam = cast<BlockPointerType>(Param); + const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg); + + if (!BlockPtrArg) + return Sema::TDK_NonDeducedMismatch; + + return DeduceTemplateArguments(Context, TemplateParams, + BlockPtrParam->getPointeeType(), + BlockPtrArg->getPointeeType(), Info, + Deduced); + } + + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Typename: + // No template argument deduction for these types + return Sema::TDK_Success; + default: break; } // FIXME: Many more cases to go (to go). - return false; + return Sema::TDK_NonDeducedMismatch; } -static bool -DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param, +static Sema::TemplateDeductionResult +DeduceTemplateArguments(ASTContext &Context, + TemplateParameterList *TemplateParams, + const TemplateArgument &Param, const TemplateArgument &Arg, + Sema::TemplateDeductionInfo &Info, llvm::SmallVectorImpl<TemplateArgument> &Deduced) { switch (Param.getKind()) { case TemplateArgument::Null: @@ -315,24 +543,38 @@ DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param, case TemplateArgument::Type: assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch"); - return DeduceTemplateArguments(Context, Param.getAsType(), - Arg.getAsType(), Deduced); + return DeduceTemplateArguments(Context, TemplateParams, + Param.getAsType(), + Arg.getAsType(), Info, Deduced); case TemplateArgument::Declaration: // FIXME: Implement this check assert(false && "Unimplemented template argument deduction case"); - return false; + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Integral: if (Arg.getKind() == TemplateArgument::Integral) { // FIXME: Zero extension + sign checking here? - return *Param.getAsIntegral() == *Arg.getAsIntegral(); + if (*Param.getAsIntegral() == *Arg.getAsIntegral()) + return Sema::TDK_Success; + + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; + } + + if (Arg.getKind() == TemplateArgument::Expression) { + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; } - if (Arg.getKind() == TemplateArgument::Expression) - return false; assert(false && "Type/value mismatch"); - return false; + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Expression: { if (NonTypeTemplateParmDecl *NTTP @@ -340,70 +582,114 @@ DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param, if (Arg.getKind() == TemplateArgument::Integral) // FIXME: Sign problems here return DeduceNonTypeTemplateArgument(Context, NTTP, - *Arg.getAsIntegral(), Deduced); + *Arg.getAsIntegral(), + Info, Deduced); if (Arg.getKind() == TemplateArgument::Expression) return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(), - Deduced); + Info, Deduced); assert(false && "Type/value mismatch"); - return false; + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; } // Can't deduce anything, but that's okay. - return true; + return Sema::TDK_Success; } } - return true; + return Sema::TDK_Success; } -static bool +static Sema::TemplateDeductionResult DeduceTemplateArguments(ASTContext &Context, + TemplateParameterList *TemplateParams, const TemplateArgumentList &ParamList, const TemplateArgumentList &ArgList, + Sema::TemplateDeductionInfo &Info, llvm::SmallVectorImpl<TemplateArgument> &Deduced) { assert(ParamList.size() == ArgList.size()); for (unsigned I = 0, N = ParamList.size(); I != N; ++I) { - if (!DeduceTemplateArguments(Context, ParamList[I], ArgList[I], Deduced)) - return false; + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(Context, TemplateParams, + ParamList[I], ArgList[I], + Info, Deduced)) + return Result; } - return true; + return Sema::TDK_Success; } - -TemplateArgumentList * +/// \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]. +Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, - const TemplateArgumentList &TemplateArgs) { - // Deduce the template arguments for the partial specialization + const TemplateArgumentList &TemplateArgs, + TemplateDeductionInfo &Info) { + // C++ [temp.class.spec.match]p2: + // A partial specialization matches a given actual template + // argument list if the template arguments of the partial + // specialization can be deduced from the actual template argument + // list (14.8.2). + SFINAETrap Trap(*this); llvm::SmallVector<TemplateArgument, 4> Deduced; Deduced.resize(Partial->getTemplateParameters()->size()); - if (! ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(), - TemplateArgs, Deduced)) - return 0; - - // FIXME: Substitute the deduced template arguments into the template - // arguments of the class template partial specialization; the resulting - // template arguments should match TemplateArgs exactly. - + if (TemplateDeductionResult Result + = ::DeduceTemplateArguments(Context, + Partial->getTemplateParameters(), + Partial->getTemplateArgs(), + TemplateArgs, Info, Deduced)) + return Result; + + InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial, + 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(Context); for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { - TemplateArgument &Arg = Deduced[I]; + if (Deduced[I].isNull()) { + Decl *Param + = const_cast<Decl *>(Partial->getTemplateParameters()->getParam(I)); + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) + Info.Param = TTP; + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) + Info.Param = NTTP; + else + Info.Param = cast<TemplateTemplateParmDecl>(Param); + return TDK_Incomplete; + } - // FIXME: If this template argument was not deduced, but the corresponding - // template parameter has a default argument, instantiate the default - // argument. - if (Arg.isNull()) // FIXME: Result->Destroy(Context); - return 0; - + Builder.push_back(Deduced[I]); + } + + // Form the template argument list from the deduced template arguments. + TemplateArgumentList *DeducedArgumentList + = new (Context) TemplateArgumentList(Context, Builder, /*CopyArgs=*/true, + /*FlattenArgs=*/true); + Info.reset(DeducedArgumentList); + + // Now that we have all of the deduced template arguments, take + // another pass through them to convert any integral template + // arguments to the appropriate type. + for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { + TemplateArgument &Arg = Deduced[I]; if (Arg.getKind() == TemplateArgument::Integral) { - // FIXME: Instantiate the type, but we need some context! const NonTypeTemplateParmDecl *Parm = cast<NonTypeTemplateParmDecl>(Partial->getTemplateParameters() ->getParam(I)); - // QualType T = InstantiateType(Parm->getType(), *Result, - // Parm->getLocation(), Parm->getDeclName()); - // if (T.isNull()) // FIXME: Result->Destroy(Context); - // return 0; - QualType T = Parm->getType(); + QualType T = InstantiateType(Parm->getType(), *DeducedArgumentList, + Parm->getLocation(), Parm->getDeclName()); + if (T.isNull()) { + Info.Param = const_cast<NonTypeTemplateParmDecl*>(Parm); + Info.FirstArg = TemplateArgument(Parm->getLocation(), Parm->getType()); + return TDK_SubstitutionFailure; + } // FIXME: Make sure we didn't overflow our data type! llvm::APSInt &Value = *Arg.getAsIntegral(); @@ -413,14 +699,220 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Value.setIsSigned(T->isSignedIntegerType()); Arg.setIntegralType(T); } + + (*DeducedArgumentList)[I] = Arg; } - - // FIXME: This is terrible. DeduceTemplateArguments should use a - // TemplateArgumentListBuilder directly. - TemplateArgumentListBuilder Builder(Context); - for (unsigned I = 0, N = Deduced.size(); I != N; ++I) - Builder.push_back(Deduced[I]); - - return new (Context) TemplateArgumentList(Context, Builder, /*CopyArgs=*/true, - /*FlattenArgs=*/true); + + // Substitute the deduced template arguments into the template + // arguments of the class template partial specialization, and + // verify that the instantiated template arguments are both valid + // and are equivalent to the template arguments originally provided + // to the class template. + ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); + const TemplateArgumentList &PartialTemplateArgs = Partial->getTemplateArgs(); + 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; + } + + if (Context.getCanonicalType(InstArg.getAsType()) + != Context.getCanonicalType(TemplateArgs[I].getAsType())) { + Info.Param = TTP; + Info.FirstArg = TemplateArgs[I]; + Info.SecondArg = InstArg; + return TDK_NonDeducedMismatch; + } + + continue; + } + + // FIXME: Check template template arguments? + } + + if (Trap.hasErrorOccurred()) + return TDK_SubstitutionFailure; + + return TDK_Success; +} + +static void +MarkDeducedTemplateParameters(Sema &SemaRef, + const TemplateArgument &TemplateArg, + llvm::SmallVectorImpl<bool> &Deduced); + +/// \brief Mark the template arguments that are deduced by the given +/// expression. +static void +MarkDeducedTemplateParameters(Expr *E, llvm::SmallVectorImpl<bool> &Deduced) { + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E); + if (!E) + return; + + NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()); + if (!NTTP) + return; + + Deduced[NTTP->getIndex()] = true; +} + +/// \brief Mark the template parameters that are deduced by the given +/// type. +static void +MarkDeducedTemplateParameters(Sema &SemaRef, QualType T, + llvm::SmallVectorImpl<bool> &Deduced) { + // Non-dependent types have nothing deducible + if (!T->isDependentType()) + return; + + T = SemaRef.Context.getCanonicalType(T); + switch (T->getTypeClass()) { + case Type::ExtQual: + MarkDeducedTemplateParameters(SemaRef, + QualType(cast<ExtQualType>(T.getTypePtr())->getBaseType(), 0), + Deduced); + break; + + case Type::Pointer: + MarkDeducedTemplateParameters(SemaRef, + cast<PointerType>(T.getTypePtr())->getPointeeType(), + Deduced); + break; + + case Type::BlockPointer: + MarkDeducedTemplateParameters(SemaRef, + cast<BlockPointerType>(T.getTypePtr())->getPointeeType(), + Deduced); + break; + + case Type::LValueReference: + case Type::RValueReference: + MarkDeducedTemplateParameters(SemaRef, + cast<ReferenceType>(T.getTypePtr())->getPointeeType(), + Deduced); + break; + + case Type::MemberPointer: { + const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr()); + MarkDeducedTemplateParameters(SemaRef, MemPtr->getPointeeType(), Deduced); + MarkDeducedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0), + Deduced); + break; + } + + case Type::DependentSizedArray: + MarkDeducedTemplateParameters( + cast<DependentSizedArrayType>(T.getTypePtr())->getSizeExpr(), + Deduced); + // Fall through to check the element type + + case Type::ConstantArray: + case Type::IncompleteArray: + MarkDeducedTemplateParameters(SemaRef, + cast<ArrayType>(T.getTypePtr())->getElementType(), + Deduced); + break; + + case Type::Vector: + case Type::ExtVector: + MarkDeducedTemplateParameters(SemaRef, + cast<VectorType>(T.getTypePtr())->getElementType(), + Deduced); + break; + + case Type::FunctionProto: { + const FunctionProtoType *Proto = cast<FunctionProtoType>(T.getTypePtr()); + MarkDeducedTemplateParameters(SemaRef, Proto->getResultType(), Deduced); + for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I) + MarkDeducedTemplateParameters(SemaRef, Proto->getArgType(I), Deduced); + break; + } + + case Type::TemplateTypeParm: + Deduced[cast<TemplateTypeParmType>(T.getTypePtr())->getIndex()] = true; + break; + + case Type::TemplateSpecialization: { + const TemplateSpecializationType *Spec + = cast<TemplateSpecializationType>(T.getTypePtr()); + if (TemplateDecl *Template = Spec->getTemplateName().getAsTemplateDecl()) + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Template)) + Deduced[TTP->getIndex()] = true; + + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) + MarkDeducedTemplateParameters(SemaRef, Spec->getArg(I), Deduced); + + break; + } + + // None of these types have any deducible parts. + case Type::Builtin: + case Type::FixedWidthInt: + case Type::Complex: + case Type::VariableArray: + case Type::FunctionNoProto: + case Type::Record: + case Type::Enum: + case Type::Typename: + case Type::ObjCInterface: + case Type::ObjCQualifiedInterface: + case Type::ObjCQualifiedId: +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + break; + } +} + +/// \brief Mark the template parameters that are deduced by this +/// template argument. +static void +MarkDeducedTemplateParameters(Sema &SemaRef, + const TemplateArgument &TemplateArg, + llvm::SmallVectorImpl<bool> &Deduced) { + switch (TemplateArg.getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Integral: + break; + + case TemplateArgument::Type: + MarkDeducedTemplateParameters(SemaRef, TemplateArg.getAsType(), Deduced); + break; + + case TemplateArgument::Declaration: + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) + Deduced[TTP->getIndex()] = true; + break; + + case TemplateArgument::Expression: + MarkDeducedTemplateParameters(TemplateArg.getAsExpr(), Deduced); + break; + } +} + +/// \brief Mark the template parameters can be deduced by the given +/// template argument list. +/// +/// \param TemplateArgs the template argument list from which template +/// parameters will be deduced. +/// +/// \param Deduced a bit vector whose elements will be set to \c true +/// to indicate when the corresponding template parameter will be +/// deduced. +void +Sema::MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl<bool> &Deduced) { + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + ::MarkDeducedTemplateParameters(*this, TemplateArgs[I], Deduced); } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 562749e..18b2d75a 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -90,6 +90,30 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, } } +Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, + SourceLocation PointOfInstantiation, + ClassTemplatePartialSpecializationDecl *PartialSpec, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange) + : SemaRef(SemaRef) { + + Invalid = CheckInstantiationDepth(PointOfInstantiation, + InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind + = ActiveTemplateInstantiation::PartialSpecDeductionInstantiation; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.InstantiationRange = InstantiationRange; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + Invalid = false; + } +} + void Sema::InstantiatingTemplate::Clear() { if (!Invalid) { SemaRef.ActiveTemplateInstantiations.pop_back(); @@ -157,8 +181,50 @@ void Sema::PrintInstantiationStack() { << Active->InstantiationRange; break; } + + case ActiveTemplateInstantiation::PartialSpecDeductionInstantiation: { + ClassTemplatePartialSpecializationDecl *PartialSpec + = cast<ClassTemplatePartialSpecializationDecl>((Decl *)Active->Entity); + // FIXME: The active template instantiation's template arguments + // are interesting, too. We should add something like [with T = + // foo, U = bar, etc.] to the string. + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_partial_spec_deduct_instantiation_here) + << Context.getTypeDeclType(PartialSpec) + << Active->InstantiationRange; + break; + } + + } + } +} + +bool Sema::isSFINAEContext() const { + using llvm::SmallVector; + for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator + Active = ActiveTemplateInstantiations.rbegin(), + ActiveEnd = ActiveTemplateInstantiations.rend(); + Active != ActiveEnd; + ++Active) { + + switch(Active->Kind) { + case ActiveTemplateInstantiation::PartialSpecDeductionInstantiation: + // We're in a template argument deduction context, so SFINAE + // applies. + return true; + + case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: + // A default template argument instantiation may or may not be a + // SFINAE context; look further up the stack. + break; + + case ActiveTemplateInstantiation::TemplateInstantiation: + // This is a template instantiation, so there is no SFINAE. + return false; } } + + return false; } //===----------------------------------------------------------------------===/ @@ -236,9 +302,11 @@ TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T, QualType TemplateTypeInstantiator::InstantiateBlockPointerType(const BlockPointerType *T, unsigned Quals) const { - // FIXME: Implement this - assert(false && "Cannot instantiate BlockPointerType yet"); - return QualType(); + QualType PointeeType = Instantiate(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + return SemaRef.BuildBlockPointerType(PointeeType, Quals, Loc, Entity); } QualType @@ -265,9 +333,16 @@ QualType TemplateTypeInstantiator:: InstantiateMemberPointerType(const MemberPointerType *T, unsigned Quals) const { - // FIXME: Implement this - assert(false && "Cannot instantiate MemberPointerType yet"); - return QualType(); + QualType PointeeType = Instantiate(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + QualType ClassType = Instantiate(QualType(T->getClass(), 0)); + if (ClassType.isNull()) + return QualType(); + + return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Quals, Loc, + Entity); } QualType @@ -390,7 +465,7 @@ InstantiateFunctionProtoType(const FunctionProtoType *T, ParamTypes.push_back(P); } - return SemaRef.BuildFunctionType(ResultType, &ParamTypes[0], + return SemaRef.BuildFunctionType(ResultType, ParamTypes.data(), ParamTypes.size(), T->isVariadic(), T->getTypeQuals(), Loc, Entity); @@ -502,37 +577,11 @@ InstantiateTemplateSpecializationType( InstantiatedTemplateArgs.reserve(T->getNumArgs()); for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end(); Arg != ArgEnd; ++Arg) { - switch (Arg->getKind()) { - case TemplateArgument::Null: - assert(false && "Should never have a NULL template argument"); - break; - - case TemplateArgument::Type: { - QualType T = SemaRef.InstantiateType(Arg->getAsType(), - TemplateArgs, - Arg->getLocation(), - DeclarationName()); - if (T.isNull()) - return QualType(); - - InstantiatedTemplateArgs.push_back( - TemplateArgument(Arg->getLocation(), T)); - break; - } - - case TemplateArgument::Declaration: - case TemplateArgument::Integral: - InstantiatedTemplateArgs.push_back(*Arg); - break; + TemplateArgument InstArg = SemaRef.Instantiate(*Arg, TemplateArgs); + if (InstArg.isNull()) + return QualType(); - case TemplateArgument::Expression: - Sema::OwningExprResult E - = SemaRef.InstantiateExpr(Arg->getAsExpr(), TemplateArgs); - if (E.isInvalid()) - return QualType(); - InstantiatedTemplateArgs.push_back(E.takeAs<Expr>()); - break; - } + InstantiatedTemplateArgs.push_back(InstArg); } // FIXME: We're missing the locations of the template name, '<', and '>'. @@ -542,7 +591,7 @@ InstantiateTemplateSpecializationType( TemplateArgs); return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(), - &InstantiatedTemplateArgs[0], + InstantiatedTemplateArgs.data(), InstantiatedTemplateArgs.size(), SourceLocation()); } @@ -831,8 +880,14 @@ Sema::InstantiateClassTemplateSpecialization( const TemplateArgumentList *TemplateArgs = &ClassTemplateSpec->getTemplateArgs(); - // Determine whether any class template partial specializations - // match the given template arguments. + // C++ [temp.class.spec.match]p1: + // When a class template is used in a context that requires an + // instantiation of the class, it is necessary to determine + // whether the instantiation is to be generated using the primary + // template or one of the partial specializations. This is done by + // matching the template arguments of the class template + // specialization with the template argument lists of the partial + // specializations. typedef std::pair<ClassTemplatePartialSpecializationDecl *, TemplateArgumentList *> MatchResult; llvm::SmallVector<MatchResult, 4> Matched; @@ -841,20 +896,42 @@ Sema::InstantiateClassTemplateSpecialization( PartialEnd = Template->getPartialSpecializations().end(); Partial != PartialEnd; ++Partial) { - if (TemplateArgumentList *Deduced + TemplateDeductionInfo Info(Context); + if (TemplateDeductionResult Result = DeduceTemplateArguments(&*Partial, - ClassTemplateSpec->getTemplateArgs())) - Matched.push_back(std::make_pair(&*Partial, Deduced)); + ClassTemplateSpec->getTemplateArgs(), + Info)) { + // FIXME: Store the failed-deduction information for use in + // diagnostics, later. + (void)Result; + } else { + Matched.push_back(std::make_pair(&*Partial, Info.take())); + } } if (Matched.size() == 1) { + // -- If exactly one matching specialization is found, the + // instantiation is generated from that specialization. Pattern = Matched[0].first; TemplateArgs = Matched[0].second; } else if (Matched.size() > 1) { + // -- If more than one matching specialization is found, the + // partial order rules (14.5.4.2) are used to determine + // whether one of the specializations is more specialized + // than the others. If none of the specializations is more + // specialized than all of the other matching + // specializations, then the use of the class template is + // ambiguous and the program is ill-formed. // FIXME: Implement partial ordering of class template partial // specializations. Diag(ClassTemplateSpec->getLocation(), diag::unsup_template_partial_spec_ordering); + } else { + // -- If no matches are found, the instantiation is generated + // from the primary template. + + // Since we initialized the pattern and template arguments from + // the primary template, there is nothing more we need to do here. } // Note that this is an instantiation. @@ -965,7 +1042,7 @@ Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS, if (T.isNull()) return 0; - if (T->isRecordType() || + if (T->isDependentType() || T->isRecordType() || (getLangOptions().CPlusPlus0x && T->isEnumeralType())) { assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here"); return NestedNameSpecifier::Create(Context, Prefix, @@ -1046,3 +1123,38 @@ Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc, // Decl. However, this won't be needed until we implement member templates. return Name; } + +TemplateArgument Sema::Instantiate(TemplateArgument Arg, + const TemplateArgumentList &TemplateArgs) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + assert(false && "Should never have a NULL template argument"); + break; + + case TemplateArgument::Type: { + QualType T = InstantiateType(Arg.getAsType(), TemplateArgs, + Arg.getLocation(), DeclarationName()); + if (T.isNull()) + return TemplateArgument(); + + return TemplateArgument(Arg.getLocation(), T); + } + + case TemplateArgument::Declaration: + // FIXME: Template instantiation for template template parameters. + return Arg; + + case TemplateArgument::Integral: + return Arg; + + case TemplateArgument::Expression: { + Sema::OwningExprResult E = InstantiateExpr(Arg.getAsExpr(), TemplateArgs); + if (E.isInvalid()) + return TemplateArgument(); + return TemplateArgument(E.takeAs<Expr>()); + } + } + + assert(false && "Unhandled template argument kind"); + return TemplateArgument(); +} diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index fa5fdee..3c67f2a 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -112,6 +112,14 @@ TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { assert(NTTP->getDepth() == 0 && "No nested templates yet"); const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()]; + + // The template argument itself might be an expression, in which + // case we just return that expression. + if (Arg.getKind() == TemplateArgument::Expression) + // FIXME: Clone the expression! + return SemaRef.Owned(Arg.getAsExpr()); + + assert(Arg.getKind() == TemplateArgument::Integral); QualType T = Arg.getIntegralType(); if (T->isCharType() || T->isWideCharType()) return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp index fd349df..efdcec8 100644 --- a/lib/Sema/SemaTemplateInstantiateStmt.cpp +++ b/lib/Sema/SemaTemplateInstantiateStmt.cpp @@ -260,7 +260,7 @@ Sema::OwningStmtResult TemplateStmtInstantiator::VisitDoStmt(DoStmt *S) { return SemaRef.StmtError(); return SemaRef.ActOnDoStmt(S->getDoLoc(), move(Body), S->getWhileLoc(), - move(Cond)); + SourceLocation(), move(Cond), S->getRParenLoc()); } Sema::OwningStmtResult TemplateStmtInstantiator::VisitForStmt(ForStmt *S) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index cd19d97..70a9270 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -600,7 +600,93 @@ QualType Sema::BuildFunctionType(QualType T, return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, Quals); } - + +/// \brief Build a member pointer type \c T Class::*. +/// +/// \param T the type to which the member pointer refers. +/// \param Class the class type into which the member pointer points. +/// \param Quals Qualifiers applied to the member pointer type +/// \param Loc the location where this type begins +/// \param Entity the name of the entity that will have this member pointer type +/// +/// \returns a member pointer type, if successful, or a NULL type if there was +/// an error. +QualType Sema::BuildMemberPointerType(QualType T, QualType Class, + unsigned Quals, SourceLocation Loc, + DeclarationName Entity) { + // Verify that we're not building a pointer to pointer to function with + // exception specification. + if (CheckDistantExceptionSpec(T)) { + Diag(Loc, diag::err_distant_exception_spec); + + // FIXME: If we're doing this as part of template instantiation, + // we should return immediately. + + // Build the type anyway, but use the canonical type so that the + // exception specifiers are stripped off. + T = Context.getCanonicalType(T); + } + + // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member + // with reference type, or "cv void." + if (T->isReferenceType()) { + Diag(Loc, diag::err_illegal_decl_pointer_to_reference) + << (Entity? Entity.getAsString() : "type name"); + return QualType(); + } + + if (T->isVoidType()) { + Diag(Loc, diag::err_illegal_decl_mempointer_to_void) + << (Entity? Entity.getAsString() : "type name"); + return QualType(); + } + + // Enforce C99 6.7.3p2: "Types other than pointer types derived from + // object or incomplete types shall not be restrict-qualified." + if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { + Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) + << T; + + // FIXME: If we're doing this as part of template instantiation, + // we should return immediately. + Quals &= ~QualType::Restrict; + } + + if (!Class->isDependentType() && !Class->isRecordType()) { + Diag(Loc, diag::err_mempointer_in_nonclass_type) << Class; + return QualType(); + } + + return Context.getMemberPointerType(T, Class.getTypePtr()) + .getQualifiedType(Quals); +} + +/// \brief Build a block pointer type. +/// +/// \param T The type to which we'll be building a block pointer. +/// +/// \param Quals The cvr-qualifiers to be applied to the block pointer type. +/// +/// \param Loc The location of the entity whose type involves this +/// block pointer type or, if there is no such entity, the location of the +/// type that will have block pointer type. +/// +/// \param Entity The name of the entity that involves the block pointer +/// type, if known. +/// +/// \returns A suitable block pointer type, if there are no +/// errors. Otherwise, returns a NULL type. +QualType Sema::BuildBlockPointerType(QualType T, unsigned Quals, + SourceLocation Loc, + DeclarationName Entity) { + if (!T.getTypePtr()->isFunctionType()) { + Diag(Loc, diag::err_nonfunction_block_type); + return QualType(); + } + + return Context.getBlockPointerType(T).getQualifiedType(Quals); +} + /// GetTypeForDeclarator - Convert the type for the specified /// declarator to Type instances. Skip the outermost Skip type /// objects. @@ -675,11 +761,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, if (!LangOpts.Blocks) Diag(DeclType.Loc, diag::err_blocks_disable); - if (!T.getTypePtr()->isFunctionType()) - Diag(D.getIdentifierLoc(), diag::err_nonfunction_block_type); - else - T = (Context.getBlockPointerType(T) - .getQualifiedType(DeclType.Cls.TypeQuals)); + T = BuildBlockPointerType(T, DeclType.Cls.TypeQuals, D.getIdentifierLoc(), + Name); break; case DeclaratorChunk::Pointer: // Verify that we're not building a pointer to pointer to function with @@ -870,57 +953,32 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, break; } case DeclaratorChunk::MemberPointer: - // Verify that we're not building a pointer to pointer to function with - // exception specification. - if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { - Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); - D.setInvalidType(true); - // Build the type anyway. - } // The scope spec must refer to a class, or be dependent. - DeclContext *DC = computeDeclContext(DeclType.Mem.Scope()); QualType ClsType; - // FIXME: Extend for dependent types when it's actually supported. - // See ActOnCXXNestedNameSpecifier. - if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC)) { + if (isDependentScopeSpecifier(DeclType.Mem.Scope())) { + NestedNameSpecifier *NNS + = (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep(); + assert(NNS->getAsType() && "Nested-name-specifier must name a type"); + ClsType = QualType(NNS->getAsType(), 0); + } else if (CXXRecordDecl *RD + = dyn_cast_or_null<CXXRecordDecl>( + computeDeclContext(DeclType.Mem.Scope()))) { ClsType = Context.getTagDeclType(RD); } else { - if (DC) { - Diag(DeclType.Mem.Scope().getBeginLoc(), - diag::err_illegal_decl_mempointer_in_nonclass) - << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name") - << DeclType.Mem.Scope().getRange(); - } + Diag(DeclType.Mem.Scope().getBeginLoc(), + diag::err_illegal_decl_mempointer_in_nonclass) + << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name") + << DeclType.Mem.Scope().getRange(); D.setInvalidType(true); - ClsType = Context.IntTy; } - // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member - // with reference type, or "cv void." - if (T->isReferenceType()) { - Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference) - << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); - D.setInvalidType(true); + if (!ClsType.isNull()) + T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals, + DeclType.Loc, D.getIdentifier()); + if (T.isNull()) { T = Context.IntTy; + D.setInvalidType(true); } - if (T->isVoidType()) { - Diag(DeclType.Loc, diag::err_illegal_decl_mempointer_to_void) - << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); - T = Context.IntTy; - } - - // Enforce C99 6.7.3p2: "Types other than pointer types derived from - // object or incomplete types shall not be restrict-qualified." - if ((DeclType.Mem.TypeQuals & QualType::Restrict) && - !T->isIncompleteOrObjectType()) { - Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) - << T; - DeclType.Mem.TypeQuals &= ~QualType::Restrict; - } - - T = Context.getMemberPointerType(T, ClsType.getTypePtr()). - getQualifiedType(DeclType.Mem.TypeQuals); - break; } |