summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp217
-rw-r--r--lib/AST/Builtins.cpp290
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/Decl.cpp1
-rw-r--r--lib/AST/DeclBase.cpp7
-rw-r--r--lib/AST/DeclCXX.cpp7
-rw-r--r--lib/AST/DeclPrinter.cpp3
-rw-r--r--lib/AST/DeclTemplate.cpp27
-rw-r--r--lib/AST/Expr.cpp1
-rw-r--r--lib/AST/ExprConstant.cpp38
-rw-r--r--lib/Analysis/CFRefCount.cpp76
-rw-r--r--lib/Analysis/GRExprEngine.cpp1
-rw-r--r--lib/Analysis/RegionStore.cpp9
-rw-r--r--lib/Basic/Builtins.cpp92
-rw-r--r--lib/Basic/CMakeLists.txt1
-rw-r--r--lib/Basic/Diagnostic.cpp25
-rw-r--r--lib/Basic/Targets.cpp16
-rw-r--r--lib/CodeGen/CGBuiltin.cpp2
-rw-r--r--lib/CodeGen/CGCall.cpp40
-rw-r--r--lib/CodeGen/CGExpr.cpp3
-rw-r--r--lib/CodeGen/CGExprComplex.cpp48
-rw-r--r--lib/CodeGen/CGExprConstant.cpp1
-rw-r--r--lib/CodeGen/CGObjCMac.cpp2
-rw-r--r--lib/CodeGen/CodeGenModule.cpp13
-rw-r--r--lib/CodeGen/Mangle.cpp27
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp38
-rw-r--r--lib/Driver/Tools.cpp16
-rw-r--r--lib/Frontend/Backend.cpp8
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp1
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp2
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp7
-rw-r--r--lib/Headers/xmmintrin.h3
-rw-r--r--lib/Lex/LiteralSupport.cpp5
-rw-r--r--lib/Lex/PPMacroExpansion.cpp95
-rw-r--r--lib/Parse/ParseDecl.cpp74
-rw-r--r--lib/Parse/ParseDeclCXX.cpp14
-rw-r--r--lib/Parse/ParseExpr.cpp8
-rw-r--r--lib/Parse/ParseStmt.cpp32
-rw-r--r--lib/Parse/ParseTemplate.cpp22
-rw-r--r--lib/Parse/ParseTentative.cpp5
-rw-r--r--lib/Sema/Sema.cpp5
-rw-r--r--lib/Sema/Sema.h229
-rw-r--r--lib/Sema/SemaDecl.cpp16
-rw-r--r--lib/Sema/SemaDeclAttr.cpp3
-rw-r--r--lib/Sema/SemaDeclCXX.cpp15
-rw-r--r--lib/Sema/SemaExpr.cpp19
-rw-r--r--lib/Sema/SemaInherit.cpp6
-rw-r--r--lib/Sema/SemaInit.cpp2
-rw-r--r--lib/Sema/SemaLookup.cpp1
-rw-r--r--lib/Sema/SemaStmt.cpp5
-rw-r--r--lib/Sema/SemaTemplate.cpp439
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp756
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp200
-rw-r--r--lib/Sema/SemaTemplateInstantiateExpr.cpp8
-rw-r--r--lib/Sema/SemaTemplateInstantiateStmt.cpp2
-rw-r--r--lib/Sema/SemaType.cpp154
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;
}
OpenPOWER on IntegriCloud