aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2011-06-12 15:46:16 +0000
committerDimitry Andric <dim@FreeBSD.org>2011-06-12 15:46:16 +0000
commit29cafa66ad3878dbb9f82615f19fa0bded2e443c (patch)
treec5e9e10bc189de0058aa763c47b9920a8351b7df /lib
parent01af97d3b23bded2b2b21af19bbc6e4cce49e5b3 (diff)
downloadsrc-29cafa66ad3878dbb9f82615f19fa0bded2e443c.tar.gz
src-29cafa66ad3878dbb9f82615f19fa0bded2e443c.zip
Vendor import of clang trunk r132879:vendor/clang/clang-r132879
Notes
Notes: svn path=/vendor/clang/dist/; revision=223015 svn path=/vendor/clang/clang-r132879/; revision=223016; tag=vendor/clang/clang-r132879
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/APValue.cpp8
-rw-r--r--lib/AST/ASTContext.cpp351
-rw-r--r--lib/AST/ASTDiagnostic.cpp8
-rw-r--r--lib/AST/ASTImporter.cpp29
-rw-r--r--lib/AST/Decl.cpp78
-rw-r--r--lib/AST/DeclBase.cpp9
-rw-r--r--lib/AST/DeclCXX.cpp323
-rw-r--r--lib/AST/DeclObjC.cpp3
-rw-r--r--lib/AST/DeclPrinter.cpp126
-rw-r--r--lib/AST/DeclTemplate.cpp31
-rw-r--r--lib/AST/DumpXML.cpp10
-rw-r--r--lib/AST/Expr.cpp75
-rw-r--r--lib/AST/ExprClassification.cpp11
-rw-r--r--lib/AST/ExprConstant.cpp616
-rw-r--r--lib/AST/ExternalASTSource.cpp2
-rw-r--r--lib/AST/ItaniumMangle.cpp141
-rw-r--r--lib/AST/Mangle.cpp5
-rw-r--r--lib/AST/MicrosoftMangle.cpp4
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp154
-rw-r--r--lib/AST/StmtPrinter.cpp10
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/AST/Type.cpp116
-rw-r--r--lib/AST/TypePrinter.cpp17
-rw-r--r--lib/Analysis/AnalysisContext.cpp8
-rw-r--r--lib/Analysis/CFG.cpp69
-rw-r--r--lib/Analysis/CocoaConventions.cpp1
-rw-r--r--lib/Analysis/LiveVariables.cpp2
-rw-r--r--lib/Analysis/UninitializedValues.cpp51
-rw-r--r--lib/Basic/Diagnostic.cpp47
-rw-r--r--lib/Basic/DiagnosticIDs.cpp185
-rw-r--r--lib/Basic/FileManager.cpp4
-rw-r--r--lib/Basic/IdentifierTable.cpp1
-rw-r--r--lib/Basic/SourceManager.cpp73
-rw-r--r--lib/Basic/Targets.cpp46
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/CodeGen/BackendUtil.cpp75
-rw-r--r--lib/CodeGen/CGBlocks.cpp64
-rw-r--r--lib/CodeGen/CGBuiltin.cpp59
-rw-r--r--lib/CodeGen/CGCXX.cpp24
-rw-r--r--lib/CodeGen/CGCall.cpp120
-rw-r--r--lib/CodeGen/CGCall.h9
-rw-r--r--lib/CodeGen/CGClass.cpp262
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp60
-rw-r--r--lib/CodeGen/CGDebugInfo.h2
-rw-r--r--lib/CodeGen/CGDecl.cpp19
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp12
-rw-r--r--lib/CodeGen/CGException.cpp188
-rw-r--r--lib/CodeGen/CGExpr.cpp5
-rw-r--r--lib/CodeGen/CGExprAgg.cpp2
-rw-r--r--lib/CodeGen/CGExprCXX.cpp437
-rw-r--r--lib/CodeGen/CGExprConstant.cpp11
-rw-r--r--lib/CodeGen/CGExprScalar.cpp100
-rw-r--r--lib/CodeGen/CGObjC.cpp100
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp99
-rw-r--r--lib/CodeGen/CGObjCMac.cpp755
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp13
-rw-r--r--lib/CodeGen/CGObjCRuntime.h7
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp8
-rw-r--r--lib/CodeGen/CGStmt.cpp12
-rw-r--r--lib/CodeGen/CGVTT.cpp2
-rw-r--r--lib/CodeGen/CGVTables.cpp183
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp64
-rw-r--r--lib/CodeGen/CodeGenFunction.h25
-rw-r--r--lib/CodeGen/CodeGenModule.cpp189
-rw-r--r--lib/CodeGen/CodeGenModule.h10
-rw-r--r--lib/CodeGen/CodeGenTypes.h5
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp14
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp2
-rw-r--r--lib/CodeGen/TargetInfo.cpp90
-rw-r--r--lib/Driver/Driver.cpp31
-rw-r--r--lib/Driver/HostInfo.cpp15
-rw-r--r--lib/Driver/ToolChains.cpp205
-rw-r--r--lib/Driver/ToolChains.h5
-rw-r--r--lib/Driver/Tools.cpp242
-rw-r--r--lib/Driver/Tools.h14
-rw-r--r--lib/Frontend/ASTConsumers.cpp2
-rw-r--r--lib/Frontend/ASTUnit.cpp137
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CompilerInstance.cpp3
-rw-r--r--lib/Frontend/CompilerInvocation.cpp69
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp2
-rw-r--r--lib/Frontend/DiagChecker.cpp301
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp52
-rw-r--r--lib/Frontend/InitPreprocessor.cpp69
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp4
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp36
-rw-r--r--lib/Frontend/Warnings.cpp51
-rw-r--r--lib/Headers/emmintrin.h14
-rw-r--r--lib/Headers/mmintrin.h8
-rw-r--r--lib/Headers/xmmintrin.h5
-rw-r--r--lib/Index/CallGraph.cpp2
-rw-r--r--lib/Index/Indexer.cpp2
-rw-r--r--lib/Lex/HeaderSearch.cpp18
-rw-r--r--lib/Lex/Lexer.cpp3
-rw-r--r--lib/Lex/LiteralSupport.cpp19
-rw-r--r--lib/Lex/MacroInfo.cpp1
-rw-r--r--lib/Lex/PPDirectives.cpp4
-rw-r--r--lib/Lex/PPMacroExpansion.cpp53
-rw-r--r--lib/Lex/Pragma.cpp23
-rw-r--r--lib/Lex/PreprocessingRecord.cpp8
-rw-r--r--lib/Lex/Preprocessor.cpp5
-rwxr-xr-xlib/Makefile2
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp157
-rw-r--r--lib/Parse/ParseDecl.cpp60
-rw-r--r--lib/Parse/ParseDeclCXX.cpp487
-rw-r--r--lib/Parse/ParseExpr.cpp72
-rw-r--r--lib/Parse/ParseExprCXX.cpp72
-rw-r--r--lib/Parse/ParseObjc.cpp8
-rw-r--r--lib/Parse/ParsePragma.cpp1
-rw-r--r--lib/Parse/ParseStmt.cpp37
-rw-r--r--lib/Parse/ParseTemplate.cpp8
-rw-r--r--lib/Parse/ParseTentative.cpp6
-rw-r--r--lib/Parse/Parser.cpp155
-rw-r--r--lib/Rewrite/RewriteObjC.cpp15
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp7
-rw-r--r--lib/Sema/DeclSpec.cpp1
-rw-r--r--lib/Sema/JumpDiagnostics.cpp50
-rw-r--r--lib/Sema/Sema.cpp154
-rw-r--r--lib/Sema/SemaAccess.cpp102
-rw-r--r--lib/Sema/SemaCXXCast.cpp75
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp45
-rw-r--r--lib/Sema/SemaChecking.cpp96
-rw-r--r--lib/Sema/SemaCodeComplete.cpp162
-rw-r--r--lib/Sema/SemaDecl.cpp474
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2004
-rw-r--r--lib/Sema/SemaDeclObjC.cpp287
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp28
-rw-r--r--lib/Sema/SemaExpr.cpp719
-rw-r--r--lib/Sema/SemaExprCXX.cpp238
-rw-r--r--lib/Sema/SemaExprObjC.cpp119
-rw-r--r--lib/Sema/SemaInit.cpp103
-rw-r--r--lib/Sema/SemaLookup.cpp211
-rw-r--r--lib/Sema/SemaOverload.cpp235
-rw-r--r--lib/Sema/SemaStmt.cpp134
-rw-r--r--lib/Sema/SemaTemplate.cpp688
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp19
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp81
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp162
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp3
-rw-r--r--lib/Sema/SemaType.cpp182
-rw-r--r--lib/Sema/TreeTransform.h139
-rw-r--r--lib/Serialization/ASTReader.cpp211
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp40
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp6
-rw-r--r--lib/Serialization/ASTWriter.cpp109
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp399
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp112
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/BasicStore.cpp18
-rw-r--r--lib/StaticAnalyzer/Core/BasicValueFactory.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp251
-rw-r--r--lib/StaticAnalyzer/Core/CXXExprEngine.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp17
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp27
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp34
-rw-r--r--lib/StaticAnalyzer/Core/FlatStore.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/GRState.cpp16
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp26
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp6
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp13
-rw-r--r--lib/Tooling/CMakeLists.txt6
-rw-r--r--lib/Tooling/JsonCompileCommandLineDatabase.cpp214
-rw-r--r--lib/Tooling/JsonCompileCommandLineDatabase.h107
-rw-r--r--lib/Tooling/Makefile15
-rw-r--r--lib/Tooling/Tooling.cpp322
168 files changed, 11673 insertions, 4978 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 731d5e046681..ebe99b12cdab 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -18,12 +18,12 @@ using namespace clang;
namespace {
struct LV {
- Expr* Base;
+ const Expr* Base;
CharUnits Offset;
};
}
-APValue::APValue(Expr* B) : Kind(Uninitialized) {
+APValue::APValue(const Expr* B) : Kind(Uninitialized) {
MakeLValue(); setLValue(B, CharUnits::Zero());
}
@@ -118,7 +118,7 @@ void APValue::print(llvm::raw_ostream &OS) const {
}
}
-Expr* APValue::getLValueBase() const {
+const Expr* APValue::getLValueBase() const {
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const void*)Data)->Base;
}
@@ -128,7 +128,7 @@ CharUnits APValue::getLValueOffset() const {
return ((const LV*)(const void*)Data)->Offset;
}
-void APValue::setLValue(Expr *B, const CharUnits &O) {
+void APValue::setLValue(const Expr *B, const CharUnits &O) {
assert(isLValue() && "Invalid accessor");
((LV*)(char*)Data)->Base = B;
((LV*)(char*)Data)->Offset = O;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 8316ea68e9e4..9094abad2ef1 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -31,6 +31,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "CXXABI.h"
+#include <map>
using namespace clang;
@@ -38,8 +39,12 @@ unsigned ASTContext::NumImplicitDefaultConstructors;
unsigned ASTContext::NumImplicitDefaultConstructorsDeclared;
unsigned ASTContext::NumImplicitCopyConstructors;
unsigned ASTContext::NumImplicitCopyConstructorsDeclared;
+unsigned ASTContext::NumImplicitMoveConstructors;
+unsigned ASTContext::NumImplicitMoveConstructorsDeclared;
unsigned ASTContext::NumImplicitCopyAssignmentOperators;
unsigned ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
+unsigned ASTContext::NumImplicitMoveAssignmentOperators;
+unsigned ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
unsigned ASTContext::NumImplicitDestructors;
unsigned ASTContext::NumImplicitDestructorsDeclared;
@@ -317,9 +322,17 @@ void ASTContext::PrintStats() const {
fprintf(stderr, " %u/%u implicit copy constructors created\n",
NumImplicitCopyConstructorsDeclared,
NumImplicitCopyConstructors);
+ if (getLangOptions().CPlusPlus)
+ fprintf(stderr, " %u/%u implicit move constructors created\n",
+ NumImplicitMoveConstructorsDeclared,
+ NumImplicitMoveConstructors);
fprintf(stderr, " %u/%u implicit copy assignment operators created\n",
NumImplicitCopyAssignmentOperatorsDeclared,
NumImplicitCopyAssignmentOperators);
+ if (getLangOptions().CPlusPlus)
+ fprintf(stderr, " %u/%u implicit move assignment operators created\n",
+ NumImplicitMoveAssignmentOperatorsDeclared,
+ NumImplicitMoveAssignmentOperators);
fprintf(stderr, " %u/%u implicit destructors created\n",
NumImplicitDestructorsDeclared, NumImplicitDestructors);
@@ -546,8 +559,28 @@ bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const {
return (FD->isBitField() && LastFD && LastFD->isBitField() &&
- FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0);
+ FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0 &&
+ LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() != 0);
+
+}
+bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const {
+ return (FD->isBitField() && LastFD && LastFD->isBitField() &&
+ FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() &&
+ LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue());
+}
+
+bool ASTContext::NoneBitfieldFollowsBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const {
+ return (!FD->isBitField() && LastFD && LastFD->isBitField() &&
+ LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue());
+}
+
+bool ASTContext::BitfieldFollowsNoneBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const {
+ return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
+ FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue());
}
ASTContext::overridden_cxx_method_iterator
@@ -627,6 +660,10 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
UseAlignAttrOnly = true;
}
}
+ else if (isa<FieldDecl>(D))
+ UseAlignAttrOnly =
+ D->hasAttr<PackedAttr>() ||
+ cast<FieldDecl>(D)->getParent()->hasAttr<PackedAttr>();
// If we're using the align attribute only, just ignore everything
// else about the declaration and its type.
@@ -950,6 +987,9 @@ ASTContext::getTypeInfo(const Type *T) const {
return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
.getTypePtr());
+ case Type::UnaryTransform:
+ return getTypeInfo(cast<UnaryTransformType>(T)->getUnderlyingType());
+
case Type::Elaborated:
return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
@@ -957,13 +997,18 @@ ASTContext::getTypeInfo(const Type *T) const {
return getTypeInfo(
cast<AttributedType>(T)->getEquivalentType().getTypePtr());
- case Type::TemplateSpecialization:
+ case Type::TemplateSpecialization: {
assert(getCanonicalType(T) != T &&
"Cannot request the size of a dependent type");
- // FIXME: this is likely to be wrong once we support template
- // aliases, since a template alias could refer to a typedef that
- // has an __aligned__ attribute on it.
- return getTypeInfo(getCanonicalType(T));
+ const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T);
+ // A type alias template specialization may refer to a typedef with the
+ // aligned attribute on it.
+ if (TST->isTypeAlias())
+ return getTypeInfo(TST->getAliasedType().getTypePtr());
+ else
+ return getTypeInfo(getCanonicalType(T));
+ }
+
}
assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
@@ -1393,6 +1438,9 @@ QualType ASTContext::getBlockPointerType(QualType T) const {
/// lvalue reference to the specified type.
QualType
ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) const {
+ assert(getCanonicalType(T) != OverloadTy &&
+ "Unresolved overloaded function type");
+
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1572,6 +1620,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
+ case Type::UnaryTransform:
case Type::DependentName:
case Type::InjectedClassName:
case Type::TemplateSpecialization:
@@ -2235,10 +2284,10 @@ TypeSourceInfo *
ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
SourceLocation NameLoc,
const TemplateArgumentListInfo &Args,
- QualType CanonType) const {
+ QualType Underlying) const {
assert(!Name.getAsDependentTemplateName() &&
"No dependent template names here!");
- QualType TST = getTemplateSpecializationType(Name, Args, CanonType);
+ QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
TemplateSpecializationTypeLoc TL
@@ -2254,7 +2303,7 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgumentListInfo &Args,
- QualType Canon) const {
+ QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
@@ -2266,35 +2315,46 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
ArgVec.push_back(Args[i].getArgument());
return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs,
- Canon);
+ Underlying);
}
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs,
- QualType Canon) const {
+ QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
// Look through qualified template names.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = TemplateName(QTN->getTemplateDecl());
- if (!Canon.isNull())
- Canon = getCanonicalType(Canon);
- else
- Canon = getCanonicalTemplateSpecializationType(Template, Args, NumArgs);
+ bool isTypeAlias =
+ Template.getAsTemplateDecl() &&
+ isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
+
+ QualType CanonType;
+ if (!Underlying.isNull())
+ CanonType = getCanonicalType(Underlying);
+ else {
+ assert(!isTypeAlias &&
+ "Underlying type for template alias must be computed by caller");
+ CanonType = getCanonicalTemplateSpecializationType(Template, Args,
+ NumArgs);
+ }
// Allocate the (non-canonical) template specialization type, but don't
// try to unique it: these types typically have location information that
// we don't unique and don't want to lose.
- void *Mem = Allocate((sizeof(TemplateSpecializationType) +
- sizeof(TemplateArgument) * NumArgs),
+ void *Mem = Allocate(sizeof(TemplateSpecializationType) +
+ sizeof(TemplateArgument) * NumArgs +
+ (isTypeAlias ? sizeof(QualType) : 0),
TypeAlignment);
TemplateSpecializationType *Spec
= new (Mem) TemplateSpecializationType(Template,
Args, NumArgs,
- Canon);
+ CanonType,
+ isTypeAlias ? Underlying : QualType());
Types.push_back(Spec);
return QualType(Spec, 0);
@@ -2306,6 +2366,10 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
unsigned NumArgs) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
+ assert((!Template.getAsTemplateDecl() ||
+ !isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) &&
+ "Underlying type for template alias must be computed by caller");
+
// Look through qualified template names.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = TemplateName(QTN->getTemplateDecl());
@@ -2334,7 +2398,7 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
TypeAlignment);
Spec = new (Mem) TemplateSpecializationType(CanonTemplate,
CanonArgs.data(), NumArgs,
- QualType());
+ QualType(), QualType());
Types.push_back(Spec);
TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
}
@@ -2754,6 +2818,21 @@ QualType ASTContext::getDecltypeType(Expr *e) const {
return QualType(dt, 0);
}
+/// getUnaryTransformationType - We don't unique these, since the memory
+/// savings are minimal and these are rare.
+QualType ASTContext::getUnaryTransformType(QualType BaseType,
+ QualType UnderlyingType,
+ UnaryTransformType::UTTKind Kind)
+ const {
+ UnaryTransformType *Ty =
+ new (*this, TypeAlignment) UnaryTransformType (BaseType, UnderlyingType,
+ Kind,
+ UnderlyingType->isDependentType() ?
+ QualType() : UnderlyingType);
+ Types.push_back(Ty);
+ return QualType(Ty, 0);
+}
+
/// getAutoType - We only unique auto types after they've been deduced.
QualType ASTContext::getAutoType(QualType DeducedType) const {
void *InsertPos = 0;
@@ -3457,7 +3536,8 @@ QualType ASTContext::getCFConstantStringType() const {
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
CFConstantStringTypeDecl->addDecl(Field);
}
@@ -3498,7 +3578,8 @@ QualType ASTContext::getNSConstantStringType() const {
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
NSConstantStringTypeDecl->addDecl(Field);
}
@@ -3537,7 +3618,8 @@ QualType ASTContext::getObjCFastEnumerationStateType() const {
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
}
@@ -3574,7 +3656,8 @@ QualType ASTContext::getBlockDescriptorType() const {
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3622,7 +3705,8 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3650,7 +3734,7 @@ bool ASTContext::BlockRequiresCopying(QualType Ty) const {
if (getLangOptions().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- return RD->hasConstCopyConstructor(*this);
+ return RD->hasConstCopyConstructor();
}
}
@@ -3707,7 +3791,8 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
SourceLocation(),
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0, /*Mutable=*/false);
+ /*BitWidth=*/0, /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3736,6 +3821,9 @@ static bool isTypeTypedefedAsBOOL(QualType T) {
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
/// purpose.
CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) const {
+ if (!type->isIncompleteArrayType() && type->isIncompleteType())
+ return CharUnits::Zero();
+
CharUnits sz = getTypeSizeInChars(type);
// Make all integer and enum types at least as large as an int
@@ -3803,7 +3891,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
return S;
}
-void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
+bool ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
std::string& S) {
// Encode result type.
getObjCEncodingForType(Decl->getResultType(), S);
@@ -3813,8 +3901,11 @@ void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
E = Decl->param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
+ if (sz.isZero())
+ return true;
+
assert (sz.isPositive() &&
- "getObjCEncodingForMethodDecl - Incomplete param type");
+ "getObjCEncodingForFunctionDecl - Incomplete param type");
ParmOffset += sz;
}
S += charUnitsToString(ParmOffset);
@@ -3837,11 +3928,13 @@ void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
+
+ return false;
}
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
/// declaration.
-void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
+bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
std::string& S) const {
// FIXME: This is not very efficient.
// Encode type qualifer, 'in', 'inout', etc. for the return type.
@@ -3860,6 +3953,9 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
E = Decl->sel_param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
+ if (sz.isZero())
+ return true;
+
assert (sz.isPositive() &&
"getObjCEncodingForMethodDecl - Incomplete param type");
ParmOffset += sz;
@@ -3889,6 +3985,8 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
+
+ return false;
}
/// getObjCEncodingForPropertyDecl - Return the encoded type for this
@@ -4108,7 +4206,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
bool ExpandStructures,
const FieldDecl *FD,
bool OutermostType,
- bool EncodingProperty) const {
+ bool EncodingProperty,
+ bool StructField) const {
if (T->getAs<BuiltinType>()) {
if (FD && FD->isBitField())
return EncodeBitField(this, S, T, FD);
@@ -4193,7 +4292,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (const ArrayType *AT =
// Ignore type qualifiers etc.
dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
- if (isa<IncompleteArrayType>(AT)) {
+ if (isa<IncompleteArrayType>(AT) && !StructField) {
// Incomplete arrays are encoded as a pointer to the array element.
S += '^';
@@ -4202,11 +4301,15 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
} else {
S += '[';
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
- S += llvm::utostr(CAT->getSize().getZExtValue());
- else {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ if (getTypeSize(CAT->getElementType()) == 0)
+ S += '0';
+ else
+ S += llvm::utostr(CAT->getSize().getZExtValue());
+ } else {
//Variable length arrays are encoded as a regular array with 0 elements.
- assert(isa<VariableArrayType>(AT) && "Unknown array type!");
+ assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) &&
+ "Unknown array type!");
S += '0';
}
@@ -4244,24 +4347,30 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
}
if (ExpandStructures) {
S += '=';
- for (RecordDecl::field_iterator Field = RDecl->field_begin(),
- FieldEnd = RDecl->field_end();
- Field != FieldEnd; ++Field) {
- if (FD) {
- S += '"';
- S += Field->getNameAsString();
- S += '"';
- }
+ if (!RDecl->isUnion()) {
+ getObjCEncodingForStructureImpl(RDecl, S, FD);
+ } else {
+ for (RecordDecl::field_iterator Field = RDecl->field_begin(),
+ FieldEnd = RDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ if (FD) {
+ S += '"';
+ S += Field->getNameAsString();
+ S += '"';
+ }
- // Special case bit-fields.
- if (Field->isBitField()) {
- getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
- (*Field));
- } else {
- QualType qt = Field->getType();
- getLegacyIntegralTypeEncoding(qt);
- getObjCEncodingForTypeImpl(qt, S, false, true,
- FD);
+ // Special case bit-fields.
+ if (Field->isBitField()) {
+ getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
+ (*Field));
+ } else {
+ QualType qt = Field->getType();
+ getLegacyIntegralTypeEncoding(qt);
+ getObjCEncodingForTypeImpl(qt, S, false, true,
+ FD, /*OutermostType*/false,
+ /*EncodingProperty*/false,
+ /*StructField*/true);
+ }
}
}
}
@@ -4382,6 +4491,135 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
assert(0 && "@encode for type not implemented!");
}
+void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
+ std::string &S,
+ const FieldDecl *FD,
+ bool includeVBases) const {
+ assert(RDecl && "Expected non-null RecordDecl");
+ assert(!RDecl->isUnion() && "Should not be called for unions");
+ if (!RDecl->getDefinition())
+ return;
+
+ CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(RDecl);
+ std::multimap<uint64_t, NamedDecl *> FieldOrBaseOffsets;
+ const ASTRecordLayout &layout = getASTRecordLayout(RDecl);
+
+ if (CXXRec) {
+ for (CXXRecordDecl::base_class_iterator
+ BI = CXXRec->bases_begin(),
+ BE = CXXRec->bases_end(); BI != BE; ++BI) {
+ if (!BI->isVirtual()) {
+ CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl();
+ uint64_t offs = layout.getBaseClassOffsetInBits(base);
+ FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
+ std::make_pair(offs, base));
+ }
+ }
+ }
+
+ unsigned i = 0;
+ for (RecordDecl::field_iterator Field = RDecl->field_begin(),
+ FieldEnd = RDecl->field_end();
+ Field != FieldEnd; ++Field, ++i) {
+ uint64_t offs = layout.getFieldOffset(i);
+ FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
+ std::make_pair(offs, *Field));
+ }
+
+ if (CXXRec && includeVBases) {
+ for (CXXRecordDecl::base_class_iterator
+ BI = CXXRec->vbases_begin(),
+ BE = CXXRec->vbases_end(); BI != BE; ++BI) {
+ CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl();
+ uint64_t offs = layout.getVBaseClassOffsetInBits(base);
+ FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
+ std::make_pair(offs, base));
+ }
+ }
+
+ CharUnits size;
+ if (CXXRec) {
+ size = includeVBases ? layout.getSize() : layout.getNonVirtualSize();
+ } else {
+ size = layout.getSize();
+ }
+
+ uint64_t CurOffs = 0;
+ std::multimap<uint64_t, NamedDecl *>::iterator
+ CurLayObj = FieldOrBaseOffsets.begin();
+
+ if (CurLayObj != FieldOrBaseOffsets.end() && CurLayObj->first != 0) {
+ assert(CXXRec && CXXRec->isDynamicClass() &&
+ "Offset 0 was empty but no VTable ?");
+ if (FD) {
+ S += "\"_vptr$";
+ std::string recname = CXXRec->getNameAsString();
+ if (recname.empty()) recname = "?";
+ S += recname;
+ S += '"';
+ }
+ S += "^^?";
+ CurOffs += getTypeSize(VoidPtrTy);
+ }
+
+ if (!RDecl->hasFlexibleArrayMember()) {
+ // Mark the end of the structure.
+ uint64_t offs = toBits(size);
+ FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
+ std::make_pair(offs, (NamedDecl*)0));
+ }
+
+ for (; CurLayObj != FieldOrBaseOffsets.end(); ++CurLayObj) {
+ assert(CurOffs <= CurLayObj->first);
+
+ if (CurOffs < CurLayObj->first) {
+ uint64_t padding = CurLayObj->first - CurOffs;
+ // FIXME: There doesn't seem to be a way to indicate in the encoding that
+ // packing/alignment of members is different that normal, in which case
+ // the encoding will be out-of-sync with the real layout.
+ // If the runtime switches to just consider the size of types without
+ // taking into account alignment, we could make padding explicit in the
+ // encoding (e.g. using arrays of chars). The encoding strings would be
+ // longer then though.
+ CurOffs += padding;
+ }
+
+ NamedDecl *dcl = CurLayObj->second;
+ if (dcl == 0)
+ break; // reached end of structure.
+
+ if (CXXRecordDecl *base = dyn_cast<CXXRecordDecl>(dcl)) {
+ // We expand the bases without their virtual bases since those are going
+ // in the initial structure. Note that this differs from gcc which
+ // expands virtual bases each time one is encountered in the hierarchy,
+ // making the encoding type bigger than it really is.
+ getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false);
+ if (!base->isEmpty())
+ CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize());
+ } else {
+ FieldDecl *field = cast<FieldDecl>(dcl);
+ if (FD) {
+ S += '"';
+ S += field->getNameAsString();
+ S += '"';
+ }
+
+ if (field->isBitField()) {
+ EncodeBitField(this, S, field->getType(), field);
+ CurOffs += field->getBitWidth()->EvaluateAsInt(*this).getZExtValue();
+ } else {
+ QualType qt = field->getType();
+ getLegacyIntegralTypeEncoding(qt);
+ getObjCEncodingForTypeImpl(qt, S, false, true, FD,
+ /*OutermostType*/false,
+ /*EncodingProperty*/false,
+ /*StructField*/true);
+ CurOffs += getTypeSize(field->getType());
+ }
+ }
+ }
+}
+
void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
std::string& S) const {
if (QT & Decl::OBJC_TQ_In)
@@ -6068,7 +6306,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Forward declarations aren't required.
- if (!FD->isThisDeclarationADefinition())
+ if (!FD->doesThisDeclarationHaveABody())
return false;
// Constructors and destructors are required.
@@ -6105,10 +6343,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
// Structs that have non-trivial constructors or destructors are required.
// FIXME: Handle references.
+ // FIXME: Be more selective about which constructors we care about.
if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- if (RD->hasDefinition() &&
- (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor()))
+ if (RD->hasDefinition() && !(RD->hasTrivialDefaultConstructor() &&
+ RD->hasTrivialCopyConstructor() &&
+ RD->hasTrivialMoveConstructor() &&
+ RD->hasTrivialDestructor()))
return true;
}
}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 897b4a4c1f27..16d2f853606e 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -56,9 +56,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
continue;
}
- // Don't desugar template specializations.
- if (isa<TemplateSpecializationType>(Ty))
- break;
+ // Don't desugar template specializations, unless it's an alias template.
+ if (const TemplateSpecializationType *TST
+ = dyn_cast<TemplateSpecializationType>(Ty))
+ if (!TST->isTypeAlias())
+ break;
// Don't desugar magic Objective-C types.
if (QualType(Ty,0) == Context.getObjCIdType() ||
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index dc881ba86960..100e604d1c46 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -64,6 +64,7 @@ namespace {
// FIXME: DependentTypeOfExprType
QualType VisitTypeOfType(const TypeOfType *T);
QualType VisitDecltypeType(const DecltypeType *T);
+ QualType VisitUnaryTransformType(const UnaryTransformType *T);
QualType VisitAutoType(const AutoType *T);
// FIXME: DependentDecltypeType
QualType VisitRecordType(const RecordType *T);
@@ -604,7 +605,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
cast<TypeOfType>(T2)->getUnderlyingType()))
return false;
break;
-
+
+ case Type::UnaryTransform:
+ if (!IsStructurallyEquivalent(Context,
+ cast<UnaryTransformType>(T1)->getUnderlyingType(),
+ cast<UnaryTransformType>(T1)->getUnderlyingType()))
+ return false;
+ break;
+
case Type::Decltype:
if (!IsStructurallyEquivalent(Context,
cast<DecltypeType>(T1)->getUnderlyingExpr(),
@@ -1572,6 +1580,17 @@ QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) {
return Importer.getToContext().getDecltypeType(ToExpr);
}
+QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) {
+ QualType ToBaseType = Importer.Import(T->getBaseType());
+ QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType());
+ if (ToBaseType.isNull() || ToUnderlyingType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getUnaryTransformType(ToBaseType,
+ ToUnderlyingType,
+ T->getUTTKind());
+}
+
QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
// FIXME: Make sure that the "to" context supports C++0x!
QualType FromDeduced = T->getDeducedType();
@@ -2493,9 +2512,12 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
- T, TInfo, BitWidth, D->isMutable());
+ T, TInfo, BitWidth, D->isMutable(),
+ D->hasInClassInitializer());
ToField->setAccess(D->getAccess());
ToField->setLexicalDeclContext(LexicalDC);
+ if (ToField->hasInClassInitializer())
+ ToField->setInClassInitializer(D->getInClassInitializer());
Importer.Imported(D, ToField);
LexicalDC->addDecl(ToField);
return ToField;
@@ -2851,7 +2873,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
D->isVariadic(),
D->isSynthesized(),
D->isDefined(),
- D->getImplementationControl());
+ D->getImplementationControl(),
+ D->hasRelatedResultType());
// FIXME: When we decide to merge method definitions, we'll need to
// deal with implicit parameters.
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index b21ba9a65e76..12357c07a794 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1422,6 +1422,31 @@ bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
return false;
}
+bool FunctionDecl::hasTrivialBody() const
+{
+ Stmt *S = getBody();
+ if (!S) {
+ // Since we don't have a body for this function, we don't know if it's
+ // trivial or not.
+ return false;
+ }
+
+ if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty())
+ return true;
+ return false;
+}
+
+bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) {
+ Definition = I->IsDeleted ? I->getCanonicalDecl() : *I;
+ return true;
+ }
+ }
+
+ return false;
+}
+
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
if (I->Body) {
@@ -1450,10 +1475,34 @@ void FunctionDecl::setPure(bool P) {
}
bool FunctionDecl::isMain() const {
- ASTContext &Context = getASTContext();
- return !Context.getLangOptions().Freestanding &&
- getDeclContext()->getRedeclContext()->isTranslationUnit() &&
- getIdentifier() && getIdentifier()->isStr("main");
+ const TranslationUnitDecl *tunit =
+ dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
+ return tunit &&
+ !tunit->getASTContext().getLangOptions().Freestanding &&
+ getIdentifier() &&
+ getIdentifier()->isStr("main");
+}
+
+bool FunctionDecl::isReservedGlobalPlacementOperator() const {
+ assert(getDeclName().getNameKind() == DeclarationName::CXXOperatorName);
+ assert(getDeclName().getCXXOverloadedOperator() == OO_New ||
+ getDeclName().getCXXOverloadedOperator() == OO_Delete ||
+ getDeclName().getCXXOverloadedOperator() == OO_Array_New ||
+ getDeclName().getCXXOverloadedOperator() == OO_Array_Delete);
+
+ if (isa<CXXRecordDecl>(getDeclContext())) return false;
+ assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+
+ const FunctionProtoType *proto = getType()->castAs<FunctionProtoType>();
+ if (proto->getNumArgs() != 2 || proto->isVariadic()) return false;
+
+ ASTContext &Context =
+ cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext())
+ ->getASTContext();
+
+ // The result type and first argument type are constant across all
+ // these operators. The second argument must be exactly void*.
+ return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy);
}
bool FunctionDecl::isExternC() const {
@@ -1690,11 +1739,11 @@ bool FunctionDecl::isInlined() const {
/// an externally visible symbol, but "extern inline" will not create an
/// externally visible symbol.
bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
- assert(isThisDeclarationADefinition() && "Must have the function definition");
+ assert(doesThisDeclarationHaveABody() && "Must have the function definition");
assert(isInlined() && "Function must be inline");
ASTContext &Context = getASTContext();
- if (!Context.getLangOptions().C99 || hasAttr<GNUInlineAttr>()) {
+ if (Context.getLangOptions().GNUInline || hasAttr<GNUInlineAttr>()) {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then this inline definition is
// externally visible.
@@ -2028,9 +2077,10 @@ SourceRange FunctionDecl::getSourceRange() const {
FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
+ TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
+ bool HasInit) {
return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
- BW, Mutable);
+ BW, Mutable, HasInit);
}
bool FieldDecl::isAnonymousStructOrUnion() const {
@@ -2059,8 +2109,7 @@ unsigned FieldDecl::getFieldIndex() const {
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are ignored.
- if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD) ||
- getASTContext().ZeroBitfieldFollowsBitfield((*i), LastFD)) {
+ if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD)) {
++i;
continue;
}
@@ -2076,10 +2125,17 @@ unsigned FieldDecl::getFieldIndex() const {
SourceRange FieldDecl::getSourceRange() const {
if (isBitField())
- return SourceRange(getInnerLocStart(), BitWidth->getLocEnd());
+ return SourceRange(getInnerLocStart(), getBitWidth()->getLocEnd());
return DeclaratorDecl::getSourceRange();
}
+void FieldDecl::setInClassInitializer(Expr *Init) {
+ assert(!InitializerOrBitWidth.getPointer() &&
+ "bit width or initializer already set");
+ InitializerOrBitWidth.setPointer(Init);
+ InitializerOrBitWidth.setInt(0);
+}
+
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 6d517c544089..1766d39c1405 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -439,6 +439,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Typedef:
case TypeAlias:
+ case TypeAliasTemplate:
case UnresolvedUsingTypename:
case TemplateTypeParm:
return IDNS_Ordinary | IDNS_Type;
@@ -1165,10 +1166,10 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
if (!D->getDeclName())
return;
- // FIXME: This feels like a hack. Should DeclarationName support
- // template-ids, or is there a better way to keep specializations
- // from being visible?
- if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter())
+ // Skip entities that can't be found by name lookup into a particular
+ // context.
+ if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) ||
+ D->isTemplateParameter())
return;
ASTContext *C = 0;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 9099cd524f1a..08ac2a5be4d9 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -29,19 +29,21 @@ using namespace clang;
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
: UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
- UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
+ UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false),
+ UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
- HasTrivialConstructor(true), HasConstExprNonCopyMoveConstructor(false),
- HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true),
- HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true),
- HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false),
- ComputedVisibleConversions(false),
- DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
- DeclaredCopyAssignment(false), DeclaredDestructor(false),
- NumBases(0), NumVBases(0), Bases(), VBases(),
- Definition(D), FirstFriend(0) {
+ HasMutableFields(false), HasTrivialDefaultConstructor(true),
+ HasConstExprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true),
+ HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
+ HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
+ HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
+ UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
+ DeclaredCopyConstructor(false), DeclaredMoveConstructor(false),
+ DeclaredCopyAssignment(false), DeclaredMoveAssignment(false),
+ DeclaredDestructor(false), NumBases(0), NumVBases(0), Bases(), VBases(),
+ Definition(D), FirstFriend(0) {
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -165,8 +167,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().Empty = false;
// C++ [class.ctor]p5:
- // A constructor is trivial if its class has no virtual base classes.
- data().HasTrivialConstructor = false;
+ // A default constructor is trivial [...] if:
+ // -- its class has [...] no virtual bases
+ data().HasTrivialDefaultConstructor = false;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if it is neither
@@ -188,10 +191,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().IsStandardLayout = false;
} else {
// C++ [class.ctor]p5:
- // A constructor is trivial if all the direct base classes of its
- // class have trivial constructors.
- if (!BaseClassDecl->hasTrivialConstructor())
- data().HasTrivialConstructor = false;
+ // A default constructor is trivial [...] if:
+ // -- all the direct base classes of its class have trivial default
+ // constructors.
+ if (!BaseClassDecl->hasTrivialDefaultConstructor())
+ data().HasTrivialDefaultConstructor = false;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
@@ -223,6 +227,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// have trivial destructors.
if (!BaseClassDecl->hasTrivialDestructor())
data().HasTrivialDestructor = false;
+
+ // Keep track of the presence of mutable fields.
+ if (BaseClassDecl->hasMutableFields())
+ data().HasMutableFields = true;
}
if (VBases.empty())
@@ -262,8 +270,8 @@ bool CXXRecordDecl::hasAnyDependentBases() const {
return !forallBases(SawBase, 0);
}
-bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const {
- return getCopyConstructor(Context, Qualifiers::Const) != 0;
+bool CXXRecordDecl::hasConstCopyConstructor() const {
+ return getCopyConstructor(Qualifiers::Const) != 0;
}
bool CXXRecordDecl::isTriviallyCopyable() const {
@@ -306,8 +314,8 @@ GetBestOverloadCandidateSimple(
return Cands[Best].first;
}
-CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context,
- unsigned TypeQuals) const{
+CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{
+ ASTContext &Context = getASTContext();
QualType ClassType
= Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
DeclarationName ConstructorName
@@ -337,6 +345,14 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context,
GetBestOverloadCandidateSimple(Found));
}
+CXXConstructorDecl *CXXRecordDecl::getMoveConstructor() const {
+ for (ctor_iterator I = ctor_begin(), E = ctor_end(); I != E; ++I)
+ if (I->isMoveConstructor())
+ return *I;
+
+ return 0;
+}
+
CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
ASTContext &Context = getASTContext();
QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
@@ -387,6 +403,14 @@ CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
return GetBestOverloadCandidateSimple(Found);
}
+CXXMethodDecl *CXXRecordDecl::getMoveAssignmentOperator() const {
+ for (method_iterator I = method_begin(), E = method_end(); I != E; ++I)
+ if (I->isMoveAssignmentOperator())
+ return *I;
+
+ return 0;
+}
+
void CXXRecordDecl::markedVirtualFunctionPure() {
// C++ [class.abstract]p2:
// A class is abstract if it has at least one pure virtual function.
@@ -421,8 +445,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
// polymorphic class.
data().Polymorphic = true;
- // None of the special member functions are trivial.
- data().HasTrivialConstructor = false;
+ // C++0x [class.ctor]p5
+ // A default constructor is trivial [...] if:
+ // -- its class has no virtual functions [...]
+ data().HasTrivialDefaultConstructor = false;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
@@ -451,32 +477,32 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (ASTMutationListener *L = getASTMutationListener())
L->AddedCXXImplicitMember(data().Definition, D);
+ // If this is a special member function, note that it was added and then
+ // return early.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- // If this is the implicit default constructor, note that we have now
- // declared it.
if (Constructor->isDefaultConstructor())
data().DeclaredDefaultConstructor = true;
- // If this is the implicit copy constructor, note that we have now
- // declared it.
else if (Constructor->isCopyConstructor())
data().DeclaredCopyConstructor = true;
+ else if (Constructor->isMoveConstructor())
+ data().DeclaredMoveConstructor = true;
+ else
+ goto NotASpecialMember;
return;
- }
-
- if (isa<CXXDestructorDecl>(D)) {
+ } else if (isa<CXXDestructorDecl>(D)) {
data().DeclaredDestructor = true;
return;
- }
-
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- // If this is the implicit copy constructor, note that we have now
- // declared it.
- // FIXME: Move constructors
- if (Method->getOverloadedOperator() == OO_Equal)
+ } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ if (Method->isCopyAssignmentOperator())
data().DeclaredCopyAssignment = true;
+ else if (Method->isMoveAssignmentOperator())
+ data().DeclaredMoveAssignment = true;
+ else
+ goto NotASpecialMember;
return;
}
+NotASpecialMember:;
// Any other implicit declarations are handled like normal declarations.
}
@@ -485,23 +511,20 @@ void CXXRecordDecl::addedMember(Decl *D) {
// Note that we have a user-declared constructor.
data().UserDeclaredConstructor = true;
- // Note that we have no need of an implicitly-declared default constructor.
- data().DeclaredDefaultConstructor = true;
-
- // C++ [dcl.init.aggr]p1:
- // An aggregate is an array or a class (clause 9) with no
- // user-declared constructors (12.1) [...].
- data().Aggregate = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- data().PlainOldData = false;
-
- // C++ [class.ctor]p5:
- // A constructor is trivial if it is an implicitly-declared default
- // constructor.
- // FIXME: C++0x: don't do this for "= default" default constructors.
- data().HasTrivialConstructor = false;
+ // FIXME: Under C++0x, /only/ special member functions may be user-provided.
+ // This is probably a defect.
+ bool UserProvided = false;
+
+ // C++0x [class.ctor]p5:
+ // A default constructor is trivial if it is not user-provided [...]
+ if (Constructor->isDefaultConstructor()) {
+ data().DeclaredDefaultConstructor = true;
+ if (Constructor->isUserProvided()) {
+ data().HasTrivialDefaultConstructor = false;
+ data().UserProvidedDefaultConstructor = true;
+ UserProvided = true;
+ }
+ }
// Note when we have a user-declared copy or move constructor, which will
// suppress the implicit declaration of those constructors.
@@ -511,16 +534,23 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().DeclaredCopyConstructor = true;
// C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is neither
- // user-provided nor deleted
- // FIXME: C++0x: don't do this for "= default" copy constructors.
- data().HasTrivialCopyConstructor = false;
+ // A copy/move constructor for class X is trivial if it is not
+ // user-provided [...]
+ if (Constructor->isUserProvided()) {
+ data().HasTrivialCopyConstructor = false;
+ UserProvided = true;
+ }
} else if (Constructor->isMoveConstructor()) {
+ data().UserDeclaredMoveConstructor = true;
+ data().DeclaredMoveConstructor = true;
+
// C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is neither
- // user-provided nor deleted
- // FIXME: C++0x: don't do this for "= default" move constructors.
- data().HasTrivialMoveConstructor = false;
+ // A copy/move constructor for class X is trivial if it is not
+ // user-provided [...]
+ if (Constructor->isUserProvided()) {
+ data().HasTrivialMoveConstructor = false;
+ UserProvided = true;
+ }
}
}
if (Constructor->isConstExpr() &&
@@ -530,88 +560,81 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().HasConstExprNonCopyMoveConstructor = true;
}
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is an array or a class with no user-declared
+ // constructors [...].
+ // C++0x [dcl.init.aggr]p1:
+ // An aggregate is an array or a class with no user-provided
+ // constructors [...].
+ if (!getASTContext().getLangOptions().CPlusPlus0x || UserProvided)
+ data().Aggregate = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
+ // type is technically an aggregate in C++0x since it wouldn't be in 03.
+ data().PlainOldData = false;
+
return;
}
// Handle (user-declared) destructors.
- if (isa<CXXDestructorDecl>(D)) {
+ if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) {
data().DeclaredDestructor = true;
data().UserDeclaredDestructor = true;
// C++ [class]p4:
// A POD-struct is an aggregate class that has [...] no user-defined
// destructor.
+ // This bit is the C++03 POD bit, not the 0x one.
data().PlainOldData = false;
- // C++ [class.dtor]p3:
- // A destructor is trivial if it is an implicitly-declared destructor and
- // [...].
- //
- // FIXME: C++0x: don't do this for "= default" destructors
- data().HasTrivialDestructor = false;
+ // C++0x [class.dtor]p5:
+ // A destructor is trivial if it is not user-provided and [...]
+ if (DD->isUserProvided())
+ data().HasTrivialDestructor = false;
return;
}
// Handle (user-declared) member functions.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- if (Method->getOverloadedOperator() == OO_Equal) {
- // We're interested specifically in copy assignment operators.
- const FunctionProtoType *FnType
- = Method->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Overloaded operator has no proto function type.");
- assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
-
- // Copy assignment operators must be non-templates.
- if (Method->getPrimaryTemplate() || FunTmpl)
- return;
-
- ASTContext &Context = getASTContext();
- QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
- const_cast<CXXRecordDecl*>(this)));
-
- bool isRValueRefArg = false;
- QualType ArgType = FnType->getArgType(0);
- if (const LValueReferenceType *Ref =
- ArgType->getAs<LValueReferenceType>()) {
- ArgType = Ref->getPointeeType();
- } else if (const RValueReferenceType *Ref =
- ArgType->getAs<RValueReferenceType>()) {
- ArgType = Ref->getPointeeType();
- isRValueRefArg = true;
- }
- if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
- return;
-
+ if (Method->isCopyAssignmentOperator()) {
// C++ [class]p4:
// A POD-struct is an aggregate class that [...] has no user-defined
// copy assignment operator [...].
- // FIXME: This should be probably determined dynamically in terms of
- // other more precise attributes to correctly model how it is specified
- // in C++0x. Setting it here happens to do the right thing.
+ // This is the C++03 bit only.
data().PlainOldData = false;
- if (!isRValueRefArg) {
- // This is a copy assignment operator.
+ // This is a copy assignment operator.
- // Suppress the implicit declaration of a copy constructor.
- data().UserDeclaredCopyAssignment = true;
- data().DeclaredCopyAssignment = true;
+ // Suppress the implicit declaration of a copy constructor.
+ data().UserDeclaredCopyAssignment = true;
+ data().DeclaredCopyAssignment = true;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- // FIXME: C++0x: don't do this for "= default" copy operators.
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted [...]
+ if (Method->isUserProvided())
data().HasTrivialCopyAssignment = false;
- } else {
- // This is a move assignment operator.
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- // FIXME: C++0x: don't do this for "= default" copy operators.
+ return;
+ }
+
+ if (Method->isMoveAssignmentOperator()) {
+ // This is an extension in C++03 mode, but we'll keep consistency by
+ // taking a move assignment operator to induce non-POD-ness
+ data().PlainOldData = false;
+
+ // This is a move assignment operator.
+ data().UserDeclaredMoveAssignment = true;
+ data().DeclaredMoveAssignment = true;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted [...]
+ if (Method->isUserProvided())
data().HasTrivialMoveAssignment = false;
- }
}
// Keep the list of conversion functions up-to-date.
@@ -667,6 +690,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().HasPublicFields) > 1)
data().IsStandardLayout = false;
+ // Keep track of the presence of mutable fields.
+ if (Field->isMutable())
+ data().HasMutableFields = true;
+
// C++0x [class]p9:
// A POD struct is a class that is both a trivial class and a
// standard-layout class, and has no non-static data members of type
@@ -676,7 +703,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!T->isPODType())
data().PlainOldData = false;
if (T->isReferenceType()) {
- data().HasTrivialConstructor = false;
+ data().HasTrivialDefaultConstructor = false;
// C++0x [class]p7:
// A standard-layout class is a class that:
@@ -688,11 +715,32 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
data().HasNonLiteralTypeFieldsOrBases = true;
+ if (Field->hasInClassInitializer()) {
+ // C++0x [class]p5:
+ // A default constructor is trivial if [...] no non-static data member
+ // of its class has a brace-or-equal-initializer.
+ data().HasTrivialDefaultConstructor = false;
+
+ // C++0x [dcl.init.aggr]p1:
+ // An aggregate is a [...] class with [...] no
+ // brace-or-equal-initializers for non-static data members.
+ data().Aggregate = false;
+
+ // C++0x [class]p10:
+ // A POD struct is [...] a trivial class.
+ data().PlainOldData = false;
+ }
+
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
- if (!FieldRec->hasTrivialConstructor())
- data().HasTrivialConstructor = false;
+ // C++0x [class.ctor]p5:
+ // A defulat constructor is trivial [...] if:
+ // -- for all the non-static data members of its class that are of
+ // class type (or array thereof), each such class has a trivial
+ // default constructor.
+ if (!FieldRec->hasTrivialDefaultConstructor())
+ data().HasTrivialDefaultConstructor = false;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
@@ -753,6 +801,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
}
}
}
+
+ // Keep track of the presence of mutable fields.
+ if (FieldRec->hasMutableFields())
+ data().HasMutableFields = true;
}
}
@@ -1135,14 +1187,13 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
}
bool CXXMethodDecl::isCopyAssignmentOperator() const {
- // C++0x [class.copy]p19:
+ // C++0x [class.copy]p17:
// A user-declared copy assignment operator X::operator= is a non-static
// non-template member function of class X with exactly one parameter of
// type X, X&, const X&, volatile X& or const volatile X&.
if (/*operator=*/getOverloadedOperator() != OO_Equal ||
/*non-static*/ isStatic() ||
- /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
- /*exactly one parameter*/getNumParams() != 1)
+ /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate())
return false;
QualType ParamType = getParamDecl(0)->getType();
@@ -1155,6 +1206,26 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const {
return Context.hasSameUnqualifiedType(ClassType, ParamType);
}
+bool CXXMethodDecl::isMoveAssignmentOperator() const {
+ // C++0x [class.copy]p19:
+ // A user-declared move assignment operator X::operator= is a non-static
+ // non-template member function of class X with exactly one parameter of type
+ // X&&, const X&&, volatile X&&, or const volatile X&&.
+ if (getOverloadedOperator() != OO_Equal || isStatic() ||
+ getPrimaryTemplate() || getDescribedFunctionTemplate())
+ return false;
+
+ QualType ParamType = getParamDecl(0)->getType();
+ if (!isa<RValueReferenceType>(ParamType))
+ return false;
+ ParamType = ParamType->getPointeeType();
+
+ ASTContext &Context = getASTContext();
+ QualType ClassType
+ = Context.getCanonicalType(Context.getTypeDeclType(getParent()));
+ return Context.hasSameUnqualifiedType(ClassType, ParamType);
+}
+
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
assert(MD->isCanonicalDecl() && "Method is not canonical!");
assert(!MD->getParent()->isDependentContext() &&
@@ -1290,11 +1361,21 @@ const Type *CXXCtorInitializer::getBaseClass() const {
SourceLocation CXXCtorInitializer::getSourceLocation() const {
if (isAnyMemberInitializer() || isDelegatingInitializer())
return getMemberLocation();
+
+ if (isInClassMemberInitializer())
+ return getAnyMember()->getLocation();
return getBaseClassLoc().getLocalSourceRange().getBegin();
}
SourceRange CXXCtorInitializer::getSourceRange() const {
+ if (isInClassMemberInitializer()) {
+ FieldDecl *D = getAnyMember();
+ if (Expr *I = D->getInClassInitializer())
+ return I->getSourceRange();
+ return SourceRange();
+ }
+
return SourceRange(getSourceLocation(), getRParenLoc());
}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 24d281e8b66d..e2c4f38ff9be 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -339,12 +339,14 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
bool isSynthesized,
bool isDefined,
ImplementationControl impControl,
+ bool HasRelatedResultType,
unsigned numSelectorArgs) {
return new (C) ObjCMethodDecl(beginLoc, endLoc,
SelInfo, T, ResultTInfo, contextDecl,
isInstance,
isVariadic, isSynthesized, isDefined,
impControl,
+ HasRelatedResultType,
numSelectorArgs);
}
@@ -446,6 +448,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
case OMF_release:
case OMF_autorelease:
case OMF_retainCount:
+ case OMF_self:
if (!isInstanceMethod())
family = OMF_None;
break;
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 2fd88d7c808d..421770ea70fb 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -400,7 +400,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->getNumParams()) POut << ", ";
POut << "...";
}
- } else if (D->isThisDeclarationADefinition() && !D->hasPrototype()) {
+ } else if (D->doesThisDeclarationHaveABody() && !D->hasPrototype()) {
for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
if (i)
Proto += ", ";
@@ -450,62 +450,67 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->hasAttr<NoReturnAttr>())
Proto += " __attribute((noreturn))";
if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
- if (CDecl->getNumCtorInitializers() > 0) {
- Proto += " : ";
- Out << Proto;
- Proto.clear();
- for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
- E = CDecl->init_end();
- B != E; ++B) {
- CXXCtorInitializer * BMInitializer = (*B);
- if (B != CDecl->init_begin())
- Out << ", ";
- if (BMInitializer->isAnyMemberInitializer()) {
- FieldDecl *FD = BMInitializer->getAnyMember();
- Out << FD;
- } else {
- Out << QualType(BMInitializer->getBaseClass(),
- 0).getAsString(Policy);
- }
+ bool HasInitializerList = false;
+ for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
+ E = CDecl->init_end();
+ B != E; ++B) {
+ CXXCtorInitializer * BMInitializer = (*B);
+ if (BMInitializer->isInClassMemberInitializer())
+ continue;
+
+ if (!HasInitializerList) {
+ Proto += " : ";
+ Out << Proto;
+ Proto.clear();
+ HasInitializerList = true;
+ } else
+ Out << ", ";
+
+ if (BMInitializer->isAnyMemberInitializer()) {
+ FieldDecl *FD = BMInitializer->getAnyMember();
+ Out << FD;
+ } else {
+ Out << QualType(BMInitializer->getBaseClass(),
+ 0).getAsString(Policy);
+ }
+
+ Out << "(";
+ if (!BMInitializer->getInit()) {
+ // Nothing to print
+ } else {
+ Expr *Init = BMInitializer->getInit();
+ if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
+ Init = Tmp->getSubExpr();
+
+ Init = Init->IgnoreParens();
- Out << "(";
- if (!BMInitializer->getInit()) {
- // Nothing to print
- } else {
- Expr *Init = BMInitializer->getInit();
- if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
- Init = Tmp->getSubExpr();
-
- Init = Init->IgnoreParens();
-
- Expr *SimpleInit = 0;
- Expr **Args = 0;
- unsigned NumArgs = 0;
- if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
- Args = ParenList->getExprs();
- NumArgs = ParenList->getNumExprs();
- } else if (CXXConstructExpr *Construct
- = dyn_cast<CXXConstructExpr>(Init)) {
- Args = Construct->getArgs();
- NumArgs = Construct->getNumArgs();
- } else
- SimpleInit = Init;
-
- if (SimpleInit)
- SimpleInit->printPretty(Out, Context, 0, Policy, Indentation);
- else {
- for (unsigned I = 0; I != NumArgs; ++I) {
- if (isa<CXXDefaultArgExpr>(Args[I]))
- break;
-
- if (I)
- Out << ", ";
- Args[I]->printPretty(Out, Context, 0, Policy, Indentation);
- }
+ Expr *SimpleInit = 0;
+ Expr **Args = 0;
+ unsigned NumArgs = 0;
+ if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
+ Args = ParenList->getExprs();
+ NumArgs = ParenList->getNumExprs();
+ } else if (CXXConstructExpr *Construct
+ = dyn_cast<CXXConstructExpr>(Init)) {
+ Args = Construct->getArgs();
+ NumArgs = Construct->getNumArgs();
+ } else
+ SimpleInit = Init;
+
+ if (SimpleInit)
+ SimpleInit->printPretty(Out, Context, 0, Policy, Indentation);
+ else {
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ if (isa<CXXDefaultArgExpr>(Args[I]))
+ break;
+
+ if (I)
+ Out << ", ";
+ Args[I]->printPretty(Out, Context, 0, Policy, Indentation);
}
}
- Out << ")";
}
+ Out << ")";
}
}
else
@@ -518,9 +523,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isPure())
Out << " = 0";
- else if (D->isDeleted())
+ else if (D->isDeletedAsWritten())
Out << " = delete";
- else if (D->isThisDeclarationADefinition()) {
+ else if (D->doesThisDeclarationHaveABody()) {
if (!D->hasPrototype() && D->getNumParams()) {
// This is a K&R function definition, so we need to print the
// parameters.
@@ -553,6 +558,12 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
Out << " : ";
D->getBitWidth()->printPretty(Out, Context, 0, Policy, Indentation);
}
+
+ Expr *Init = D->getInClassInitializer();
+ if (!Policy.SuppressInitializers && Init) {
+ Out << " = ";
+ Init->printPretty(Out, Context, 0, Policy, Indentation);
+ }
}
void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
@@ -932,6 +943,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
Out << (first ? ' ' : ',') << "nonatomic";
first = false;
}
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_atomic) {
+ Out << (first ? ' ' : ',') << "atomic";
+ first = false;
+ }
Out << " )";
}
Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl;
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 6272340691bf..bc375d0ad2d3 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -735,3 +735,34 @@ FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context,
EmptyShell Empty) {
return new (Context) FriendTemplateDecl(Empty);
}
+
+//===----------------------------------------------------------------------===//
+// TypeAliasTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation L,
+ DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl) {
+ AdoptTemplateParameterList(Params, DC);
+ return new (C) TypeAliasTemplateDecl(DC, L, Name, Params, Decl);
+}
+
+TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
+ EmptyShell) {
+ return new (C) TypeAliasTemplateDecl(0, SourceLocation(), DeclarationName(),
+ 0, 0);
+}
+
+void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) {
+ static_cast<Common *>(Ptr)->~Common();
+}
+RedeclarableTemplateDecl::CommonBase *
+TypeAliasTemplateDecl::newCommon(ASTContext &C) {
+ Common *CommonPtr = new (C) Common;
+ C.AddDeallocation(DeallocateCommon, CommonPtr);
+ return CommonPtr;
+}
+
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 7d593bc46f6c..dfe0119f597d 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -482,18 +482,20 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
setFlag("trivial", D->isTrivial());
setFlag("returnzero", D->hasImplicitReturnZero());
setFlag("prototype", D->hasWrittenPrototype());
- setFlag("deleted", D->isDeleted());
+ setFlag("deleted", D->isDeletedAsWritten());
if (D->getStorageClass() != SC_None)
set("storage",
VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
setFlag("inline", D->isInlineSpecified());
+ if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>())
+ set("asmlabel", ALA->getLabel());
// TODO: instantiation, etc.
}
void visitFunctionDeclChildren(FunctionDecl *D) {
for (FunctionDecl::param_iterator
I = D->param_begin(), E = D->param_end(); I != E; ++I)
dispatch(*I);
- if (D->isThisDeclarationADefinition())
+ if (D->doesThisDeclarationHaveABody())
dispatch(D->getBody());
}
@@ -619,7 +621,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
// TemplateDecl
void visitTemplateDeclChildren(TemplateDecl *D) {
visitTemplateParameters(D->getTemplateParameters());
- dispatch(D->getTemplatedDecl());
+ if (D->getTemplatedDecl())
+ dispatch(D->getTemplatedDecl());
}
// FunctionTemplateDecl
@@ -845,6 +848,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
setFlag("variadic", D->isVariadic());
setFlag("synthesized", D->isSynthesized());
setFlag("defined", D->isDefined());
+ setFlag("related_result_type", D->hasRelatedResultType());
}
void visitObjCMethodDeclChildren(ObjCMethodDecl *D) {
dispatch(D->getResultType());
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 6499f327b07e..987213907e45 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -1653,7 +1654,8 @@ static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) {
return R;
}
-static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D,
+static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E,
+ const Decl *D,
bool NullThrows = true) {
if (!D)
return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
@@ -1683,6 +1685,15 @@ static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D,
if (!FT)
return Expr::CT_Can;
+ if (FT->getExceptionSpecType() == EST_Delayed) {
+ assert(isa<CXXConstructorDecl>(D) &&
+ "only constructor exception specs can be unknown");
+ Ctx.getDiagnostics().Report(E->getLocStart(),
+ diag::err_exception_spec_unknown)
+ << E->getSourceRange();
+ return Expr::CT_Can;
+ }
+
return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;
}
@@ -1693,6 +1704,9 @@ static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {
if (!DC->getTypeAsWritten()->isReferenceType())
return Expr::CT_Cannot;
+ if (DC->getSubExpr()->isTypeDependent())
+ return Expr::CT_Dependent;
+
return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot;
}
@@ -1747,7 +1761,14 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CallExprClass:
case CXXOperatorCallExprClass:
case CXXMemberCallExprClass: {
- CanThrowResult CT = CanCalleeThrow(C,cast<CallExpr>(this)->getCalleeDecl());
+ const CallExpr *CE = cast<CallExpr>(this);
+ CanThrowResult CT;
+ if (isTypeDependent())
+ CT = CT_Dependent;
+ else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
+ CT = CT_Cannot;
+ else
+ CT = CanCalleeThrow(C, this, CE->getCalleeDecl());
if (CT == CT_Can)
return CT;
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
@@ -1755,7 +1776,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CXXConstructExprClass:
case CXXTemporaryObjectExprClass: {
- CanThrowResult CT = CanCalleeThrow(C,
+ CanThrowResult CT = CanCalleeThrow(C, this,
cast<CXXConstructExpr>(this)->getConstructor());
if (CT == CT_Can)
return CT;
@@ -1763,9 +1784,13 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
}
case CXXNewExprClass: {
- CanThrowResult CT = MergeCanThrow(
- CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()),
- CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(),
+ CanThrowResult CT;
+ if (isTypeDependent())
+ CT = CT_Dependent;
+ else
+ CT = MergeCanThrow(
+ CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew()),
+ CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getConstructor(),
/*NullThrows*/false));
if (CT == CT_Can)
return CT;
@@ -1773,29 +1798,26 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
}
case CXXDeleteExprClass: {
- CanThrowResult CT = CanCalleeThrow(C,
- cast<CXXDeleteExpr>(this)->getOperatorDelete());
- if (CT == CT_Can)
- return CT;
- const Expr *Arg = cast<CXXDeleteExpr>(this)->getArgument();
- // Unwrap exactly one implicit cast, which converts all pointers to void*.
- if (const ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
- Arg = Cast->getSubExpr();
- if (const PointerType *PT = Arg->getType()->getAs<PointerType>()) {
- if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) {
- CanThrowResult CT2 = CanCalleeThrow(C,
- cast<CXXRecordDecl>(RT->getDecl())->getDestructor());
- if (CT2 == CT_Can)
- return CT2;
- CT = MergeCanThrow(CT, CT2);
+ CanThrowResult CT;
+ QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType();
+ if (DTy.isNull() || DTy->isDependentType()) {
+ CT = CT_Dependent;
+ } else {
+ CT = CanCalleeThrow(C, this,
+ cast<CXXDeleteExpr>(this)->getOperatorDelete());
+ if (const RecordType *RT = DTy->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor()));
}
+ if (CT == CT_Can)
+ return CT;
}
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
}
case CXXBindTemporaryExprClass: {
// The bound temporary has to be destroyed again, which might throw.
- CanThrowResult CT = CanCalleeThrow(C,
+ CanThrowResult CT = CanCalleeThrow(C, this,
cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
if (CT == CT_Can)
return CT;
@@ -1978,6 +2000,14 @@ Expr *Expr::IgnoreParenImpCasts() {
}
}
+Expr *Expr::IgnoreConversionOperator() {
+ if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(this)) {
+ if (isa<CXXConversionDecl>(MCE->getMethodDecl()))
+ return MCE->getImplicitObjectArgument();
+ }
+ return this;
+}
+
/// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the
/// value (including ptr->int casts of the same size). Strip off any
/// ParenExpr or CastExprs, returning their operand.
@@ -3013,4 +3043,3 @@ BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK,
ExprBits.TypeDependent = TypeDependent;
ExprBits.ValueDependent = ValueDependent;
}
-
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 888a93c8aac0..d177cb5cbc97 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -161,6 +161,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::InitListExprClass:
case Expr::SizeOfPackExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
+ case Expr::AsTypeExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
@@ -465,14 +466,16 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) {
// is a pointer to a data member is of the same value category as its first
// operand.
if (E->getOpcode() == BO_PtrMemD)
- return E->getType()->isFunctionType() ? Cl::CL_MemberFunction :
- ClassifyInternal(Ctx, E->getLHS());
+ return (E->getType()->isFunctionType() || E->getType() == Ctx.BoundMemberTy)
+ ? Cl::CL_MemberFunction
+ : ClassifyInternal(Ctx, E->getLHS());
// C++ [expr.mptr.oper]p6: The result of an ->* expression is an lvalue if its
// second operand is a pointer to data member and a prvalue otherwise.
if (E->getOpcode() == BO_PtrMemI)
- return E->getType()->isFunctionType() ?
- Cl::CL_MemberFunction : Cl::CL_LValue;
+ return (E->getType()->isFunctionType() || E->getType() == Ctx.BoundMemberTy)
+ ? Cl::CL_MemberFunction
+ : Cl::CL_LValue;
// All other binary operations are prvalues.
return Cl::CL_PRValue;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index c2caf8d40b16..06c5645afb3f 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -102,10 +102,10 @@ namespace {
};
struct LValue {
- Expr *Base;
+ const Expr *Base;
CharUnits Offset;
- Expr *getLValueBase() { return Base; }
+ const Expr *getLValueBase() { return Base; }
CharUnits getLValueOffset() { return Offset; }
void moveInto(APValue &v) const {
@@ -221,7 +221,7 @@ static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
APFloat &Value, const ASTContext &Ctx) {
unsigned DestWidth = Ctx.getIntWidth(DestType);
// Determine whether we are converting to unsigned or signed.
- bool DestSigned = DestType->isSignedIntegerType();
+ bool DestSigned = DestType->isSignedIntegerOrEnumerationType();
// FIXME: Warning for overflow.
uint64_t Space[4];
@@ -247,7 +247,7 @@ static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
// Figure out if this is a truncate, extend or noop cast.
// If the input is signed, do a sign extend, noop, or truncate.
Result = Result.extOrTrunc(DestWidth);
- Result.setIsUnsigned(DestType->isUnsignedIntegerType());
+ Result.setIsUnsigned(DestType->isUnsignedIntegerOrEnumerationType());
return Result;
}
@@ -262,69 +262,69 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
namespace {
class HasSideEffect
- : public StmtVisitor<HasSideEffect, bool> {
+ : public ConstStmtVisitor<HasSideEffect, bool> {
EvalInfo &Info;
public:
HasSideEffect(EvalInfo &info) : Info(info) {}
// Unhandled nodes conservatively default to having side effects.
- bool VisitStmt(Stmt *S) {
+ bool VisitStmt(const Stmt *S) {
return true;
}
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ bool VisitParenExpr(const ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
return Visit(E->getResultExpr());
}
- bool VisitDeclRefExpr(DeclRefExpr *E) {
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
return false;
}
// We don't want to evaluate BlockExprs multiple times, as they generate
// a ton of code.
- bool VisitBlockExpr(BlockExpr *E) { return true; }
- bool VisitPredefinedExpr(PredefinedExpr *E) { return false; }
- bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E)
+ bool VisitBlockExpr(const BlockExpr *E) { return true; }
+ bool VisitPredefinedExpr(const PredefinedExpr *E) { return false; }
+ bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E)
{ return Visit(E->getInitializer()); }
- bool VisitMemberExpr(MemberExpr *E) { return Visit(E->getBase()); }
- bool VisitIntegerLiteral(IntegerLiteral *E) { return false; }
- bool VisitFloatingLiteral(FloatingLiteral *E) { return false; }
- bool VisitStringLiteral(StringLiteral *E) { return false; }
- bool VisitCharacterLiteral(CharacterLiteral *E) { return false; }
- bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E)
+ bool VisitMemberExpr(const MemberExpr *E) { return Visit(E->getBase()); }
+ bool VisitIntegerLiteral(const IntegerLiteral *E) { return false; }
+ bool VisitFloatingLiteral(const FloatingLiteral *E) { return false; }
+ bool VisitStringLiteral(const StringLiteral *E) { return false; }
+ bool VisitCharacterLiteral(const CharacterLiteral *E) { return false; }
+ bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E)
{ return false; }
- bool VisitArraySubscriptExpr(ArraySubscriptExpr *E)
+ bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E)
{ return Visit(E->getLHS()) || Visit(E->getRHS()); }
- bool VisitChooseExpr(ChooseExpr *E)
+ bool VisitChooseExpr(const ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
- bool VisitCastExpr(CastExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitBinAssign(BinaryOperator *E) { return true; }
- bool VisitCompoundAssignOperator(BinaryOperator *E) { return true; }
- bool VisitBinaryOperator(BinaryOperator *E)
+ bool VisitCastExpr(const CastExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitBinAssign(const BinaryOperator *E) { return true; }
+ bool VisitCompoundAssignOperator(const BinaryOperator *E) { return true; }
+ bool VisitBinaryOperator(const BinaryOperator *E)
{ return Visit(E->getLHS()) || Visit(E->getRHS()); }
- bool VisitUnaryPreInc(UnaryOperator *E) { return true; }
- bool VisitUnaryPostInc(UnaryOperator *E) { return true; }
- bool VisitUnaryPreDec(UnaryOperator *E) { return true; }
- bool VisitUnaryPostDec(UnaryOperator *E) { return true; }
- bool VisitUnaryDeref(UnaryOperator *E) {
+ bool VisitUnaryPreInc(const UnaryOperator *E) { return true; }
+ bool VisitUnaryPostInc(const UnaryOperator *E) { return true; }
+ bool VisitUnaryPreDec(const UnaryOperator *E) { return true; }
+ bool VisitUnaryPostDec(const UnaryOperator *E) { return true; }
+ bool VisitUnaryDeref(const UnaryOperator *E) {
if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
return Visit(E->getSubExpr());
}
- bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); }
+ bool VisitUnaryOperator(const UnaryOperator *E) { return Visit(E->getSubExpr()); }
// Has side effects if any element does.
- bool VisitInitListExpr(InitListExpr *E) {
+ bool VisitInitListExpr(const InitListExpr *E) {
for (unsigned i = 0, e = E->getNumInits(); i != e; ++i)
if (Visit(E->getInit(i))) return true;
- if (Expr *filler = E->getArrayFiller())
+ if (const Expr *filler = E->getArrayFiller())
return Visit(filler);
return false;
}
- bool VisitSizeOfPackExpr(SizeOfPackExpr *) { return false; }
+ bool VisitSizeOfPackExpr(const SizeOfPackExpr *) { return false; }
};
class OpaqueValueEvaluation {
@@ -354,15 +354,89 @@ public:
} // end anonymous namespace
//===----------------------------------------------------------------------===//
+// Generic Evaluation
+//===----------------------------------------------------------------------===//
+namespace {
+
+template <class Derived, typename RetTy=void>
+class ExprEvaluatorBase
+ : public ConstStmtVisitor<Derived, RetTy> {
+private:
+ RetTy DerivedSuccess(const APValue &V, const Expr *E) {
+ return static_cast<Derived*>(this)->Success(V, E);
+ }
+ RetTy DerivedError(const Expr *E) {
+ return static_cast<Derived*>(this)->Error(E);
+ }
+
+protected:
+ EvalInfo &Info;
+ typedef ConstStmtVisitor<Derived, RetTy> StmtVisitorTy;
+ typedef ExprEvaluatorBase ExprEvaluatorBaseTy;
+
+public:
+ ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
+
+ RetTy VisitStmt(const Stmt *) {
+ assert(0 && "Expression evaluator should not be called on stmts");
+ return DerivedError(0);
+ }
+ RetTy VisitExpr(const Expr *E) {
+ return DerivedError(E);
+ }
+
+ RetTy VisitParenExpr(const ParenExpr *E)
+ { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ RetTy VisitUnaryExtension(const UnaryOperator *E)
+ { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ RetTy VisitUnaryPlus(const UnaryOperator *E)
+ { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ RetTy VisitChooseExpr(const ChooseExpr *E)
+ { return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); }
+ RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E)
+ { return StmtVisitorTy::Visit(E->getResultExpr()); }
+
+ RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
+ OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon());
+ if (opaque.hasError())
+ return DerivedError(E);
+
+ bool cond;
+ if (!HandleConversionToBool(E->getCond(), cond, Info))
+ return DerivedError(E);
+
+ return StmtVisitorTy::Visit(cond ? E->getTrueExpr() : E->getFalseExpr());
+ }
+
+ RetTy VisitConditionalOperator(const ConditionalOperator *E) {
+ bool BoolResult;
+ if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
+ return DerivedError(E);
+
+ Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
+ return StmtVisitorTy::Visit(EvalExpr);
+ }
+
+ RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
+ const APValue *value = Info.getOpaqueValue(E);
+ if (!value)
+ return (E->getSourceExpr() ? StmtVisitorTy::Visit(E->getSourceExpr())
+ : DerivedError(E));
+ return DerivedSuccess(*value, E);
+ }
+};
+
+}
+
+//===----------------------------------------------------------------------===//
// LValue Evaluation
//===----------------------------------------------------------------------===//
namespace {
class LValueExprEvaluator
- : public StmtVisitor<LValueExprEvaluator, bool> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<LValueExprEvaluator, bool> {
LValue &Result;
- bool Success(Expr *E) {
+ bool Success(const Expr *E) {
Result.Base = E;
Result.Offset = CharUnits::Zero();
return true;
@@ -370,30 +444,26 @@ class LValueExprEvaluator
public:
LValueExprEvaluator(EvalInfo &info, LValue &Result) :
- Info(info), Result(Result) {}
+ ExprEvaluatorBaseTy(info), Result(Result) {}
- bool VisitStmt(Stmt *S) {
+ bool Success(const APValue &V, const Expr *E) {
+ Result.setFrom(V);
+ return true;
+ }
+ bool Error(const Expr *E) {
return false;
}
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
- }
- bool VisitDeclRefExpr(DeclRefExpr *E);
- bool VisitPredefinedExpr(PredefinedExpr *E) { return Success(E); }
- bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
- bool VisitMemberExpr(MemberExpr *E);
- bool VisitStringLiteral(StringLiteral *E) { return Success(E); }
- bool VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return Success(E); }
- bool VisitArraySubscriptExpr(ArraySubscriptExpr *E);
- bool VisitUnaryDeref(UnaryOperator *E);
- bool VisitUnaryExtension(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
- bool VisitChooseExpr(const ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
-
- bool VisitCastExpr(CastExpr *E) {
+ bool VisitDeclRefExpr(const DeclRefExpr *E);
+ bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); }
+ bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
+ bool VisitMemberExpr(const MemberExpr *E);
+ bool VisitStringLiteral(const StringLiteral *E) { return Success(E); }
+ bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); }
+ bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
+ bool VisitUnaryDeref(const UnaryOperator *E);
+
+ bool VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
return false;
@@ -403,36 +473,37 @@ public:
}
}
// FIXME: Missing: __real__, __imag__
+
};
} // end anonymous namespace
static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) {
- return LValueExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+ return LValueExprEvaluator(Info, Result).Visit(E);
}
-bool LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
+bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
if (isa<FunctionDecl>(E->getDecl())) {
return Success(E);
- } else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
+ } else if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
if (!VD->getType()->isReferenceType())
return Success(E);
// Reference parameters can refer to anything even if they have an
// "initializer" in the form of a default argument.
- if (isa<ParmVarDecl>(VD))
- return false;
- // FIXME: Check whether VD might be overridden!
- if (const Expr *Init = VD->getAnyInitializer())
- return Visit(const_cast<Expr *>(Init));
+ if (!isa<ParmVarDecl>(VD))
+ // FIXME: Check whether VD might be overridden!
+ if (const Expr *Init = VD->getAnyInitializer())
+ return Visit(Init);
}
- return false;
+ return ExprEvaluatorBaseTy::VisitDeclRefExpr(E);
}
-bool LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+bool
+LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
return Success(E);
}
-bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
+bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
QualType Ty;
if (E->isArrow()) {
if (!EvaluatePointer(E->getBase(), Result, Info))
@@ -444,10 +515,10 @@ bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
Ty = E->getBase()->getType();
}
- RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
+ const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
- FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+ const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
if (!FD) // FIXME: deal with other kinds of member expressions
return false;
@@ -467,7 +538,7 @@ bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
return true;
}
-bool LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
if (!EvaluatePointer(E->getBase(), Result, Info))
return false;
@@ -480,7 +551,7 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
return true;
}
-bool LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
+bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
return EvaluatePointer(E->getSubExpr(), Result, Info);
}
@@ -490,11 +561,10 @@ bool LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
namespace {
class PointerExprEvaluator
- : public StmtVisitor<PointerExprEvaluator, bool> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<PointerExprEvaluator, bool> {
LValue &Result;
- bool Success(Expr *E) {
+ bool Success(const Expr *E) {
Result.Base = E;
Result.Offset = CharUnits::Zero();
return true;
@@ -502,49 +572,41 @@ class PointerExprEvaluator
public:
PointerExprEvaluator(EvalInfo &info, LValue &Result)
- : Info(info), Result(Result) {}
+ : ExprEvaluatorBaseTy(info), Result(Result) {}
- bool VisitStmt(Stmt *S) {
- return false;
+ bool Success(const APValue &V, const Expr *E) {
+ Result.setFrom(V);
+ return true;
}
-
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
+ bool Error(const Stmt *S) {
+ return false;
}
bool VisitBinaryOperator(const BinaryOperator *E);
- bool VisitCastExpr(CastExpr* E);
- bool VisitUnaryExtension(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
+ bool VisitCastExpr(const CastExpr* E);
bool VisitUnaryAddrOf(const UnaryOperator *E);
- bool VisitObjCStringLiteral(ObjCStringLiteral *E)
+ bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
{ return Success(E); }
- bool VisitAddrLabelExpr(AddrLabelExpr *E)
+ bool VisitAddrLabelExpr(const AddrLabelExpr *E)
{ return Success(E); }
- bool VisitCallExpr(CallExpr *E);
- bool VisitBlockExpr(BlockExpr *E) {
+ bool VisitCallExpr(const CallExpr *E);
+ bool VisitBlockExpr(const BlockExpr *E) {
if (!E->getBlockDecl()->hasCaptures())
return Success(E);
return false;
}
- bool VisitImplicitValueInitExpr(ImplicitValueInitExpr *E)
+ bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E)
{ return Success((Expr*)0); }
- bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
- bool VisitConditionalOperator(ConditionalOperator *E);
- bool VisitChooseExpr(ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
- bool VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
+ bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E)
{ return Success((Expr*)0); }
- bool VisitOpaqueValueExpr(OpaqueValueExpr *E);
// FIXME: Missing: @protocol, @selector
};
} // end anonymous namespace
static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) {
assert(E->getType()->hasPointerRepresentation());
- return PointerExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+ return PointerExprEvaluator(Info, Result).Visit(E);
}
bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
@@ -592,8 +654,8 @@ bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
}
-bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
- Expr* SubExpr = E->getSubExpr();
+bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
+ const Expr* SubExpr = E->getSubExpr();
switch (E->getCastKind()) {
default:
@@ -671,42 +733,14 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
return false;
}
-bool PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
+bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (E->isBuiltinCall(Info.Ctx) ==
Builtin::BI__builtin___CFStringMakeConstantString ||
E->isBuiltinCall(Info.Ctx) ==
Builtin::BI__builtin___NSStringMakeConstantString)
return Success(E);
- return false;
-}
-
-bool PointerExprEvaluator::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
- const APValue *value = Info.getOpaqueValue(e);
- if (!value)
- return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
- Result.setFrom(*value);
- return true;
-}
-
-bool PointerExprEvaluator::
-VisitBinaryConditionalOperator(BinaryConditionalOperator *e) {
- OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
- if (opaque.hasError()) return false;
- bool cond;
- if (!HandleConversionToBool(e->getCond(), cond, Info))
- return false;
-
- return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
-}
-
-bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
- bool BoolResult;
- if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
- return false;
-
- Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
- return Visit(EvalExpr);
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
//===----------------------------------------------------------------------===//
@@ -715,25 +749,15 @@ bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
namespace {
class VectorExprEvaluator
- : public StmtVisitor<VectorExprEvaluator, APValue> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<VectorExprEvaluator, APValue> {
APValue GetZeroVector(QualType VecType);
public:
- VectorExprEvaluator(EvalInfo &info) : Info(info) {}
+ VectorExprEvaluator(EvalInfo &info) : ExprEvaluatorBaseTy(info) {}
- APValue VisitStmt(Stmt *S) {
- return APValue();
- }
+ APValue Success(const APValue &V, const Expr *E) { return V; }
+ APValue Error(const Expr *E) { return APValue(); }
- APValue VisitParenExpr(ParenExpr *E)
- { return Visit(E->getSubExpr()); }
- APValue VisitGenericSelectionExpr(GenericSelectionExpr *E)
- { return Visit(E->getResultExpr()); }
- APValue VisitUnaryExtension(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
- APValue VisitUnaryPlus(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
APValue VisitUnaryReal(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
APValue VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E)
@@ -741,9 +765,6 @@ namespace {
APValue VisitCastExpr(const CastExpr* E);
APValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
APValue VisitInitListExpr(const InitListExpr *E);
- APValue VisitConditionalOperator(const ConditionalOperator *E);
- APValue VisitChooseExpr(const ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
APValue VisitUnaryImag(const UnaryOperator *E);
// FIXME: Missing: unary -, unary ~, binary add/sub/mul/div,
// binary comparisons, binary and/or/xor,
@@ -756,7 +777,7 @@ namespace {
static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
if (!E->getType()->isVectorType())
return false;
- Result = VectorExprEvaluator(Info).Visit(const_cast<Expr*>(E));
+ Result = VectorExprEvaluator(Info).Visit(E);
return !Result.isUninit();
}
@@ -792,7 +813,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
}
case CK_BitCast: {
if (SETy->isVectorType())
- return Visit(const_cast<Expr*>(SE));
+ return Visit(SE);
if (!SETy->isIntegerType())
return APValue();
@@ -819,7 +840,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
}
case CK_LValueToRValue:
case CK_NoOp:
- return Visit(const_cast<Expr*>(SE));
+ return Visit(SE);
default:
return APValue();
}
@@ -827,7 +848,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
APValue
VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
- return this->Visit(const_cast<Expr*>(E->getInitializer()));
+ return this->Visit(E->getInitializer());
}
APValue
@@ -905,19 +926,6 @@ VectorExprEvaluator::GetZeroVector(QualType T) {
return APValue(&Elements[0], Elements.size());
}
-APValue VectorExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
- bool BoolResult;
- if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
- return APValue();
-
- Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
-
- APValue Result;
- if (EvaluateVector(EvalExpr, Result, Info))
- return Result;
- return APValue();
-}
-
APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
if (!E->getSubExpr()->isEvaluatable(Info.Ctx))
Info.EvalResult.HasSideEffects = true;
@@ -930,17 +938,16 @@ APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
namespace {
class IntExprEvaluator
- : public StmtVisitor<IntExprEvaluator, bool> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<IntExprEvaluator, bool> {
APValue &Result;
public:
IntExprEvaluator(EvalInfo &info, APValue &result)
- : Info(info), Result(result) {}
+ : ExprEvaluatorBaseTy(info), Result(result) {}
bool Success(const llvm::APSInt &SI, const Expr *E) {
assert(E->getType()->isIntegralOrEnumerationType() &&
"Invalid evaluation result.");
- assert(SI.isSigned() == E->getType()->isSignedIntegerType() &&
+ assert(SI.isSigned() == E->getType()->isSignedIntegerOrEnumerationType() &&
"Invalid evaluation result.");
assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
"Invalid evaluation result.");
@@ -954,7 +961,8 @@ public:
assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
"Invalid evaluation result.");
Result = APValue(APSInt(I));
- Result.getInt().setIsUnsigned(E->getType()->isUnsignedIntegerType());
+ Result.getInt().setIsUnsigned(
+ E->getType()->isUnsignedIntegerOrEnumerationType());
return true;
}
@@ -980,23 +988,16 @@ public:
return false;
}
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- bool VisitStmt(Stmt *) {
- assert(0 && "This should be called on integers, stmts are not integers");
- return false;
+ bool Success(const APValue &V, const Expr *E) {
+ return Success(V.getInt(), E);
}
-
- bool VisitExpr(Expr *E) {
+ bool Error(const Expr *E) {
return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
}
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
- }
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
bool VisitIntegerLiteral(const IntegerLiteral *E) {
return Success(E->getValue(), E);
@@ -1005,18 +1006,12 @@ public:
return Success(E->getValue(), E);
}
- bool VisitOpaqueValueExpr(OpaqueValueExpr *e) {
- const APValue *value = Info.getOpaqueValue(e);
- if (!value) {
- if (e->getSourceExpr()) return Visit(e->getSourceExpr());
- return Error(e->getExprLoc(), diag::note_invalid_subexpr_in_ice, e);
- }
- return Success(value->getInt(), e);
- }
-
bool CheckReferencedDecl(const Expr *E, const Decl *D);
bool VisitDeclRefExpr(const DeclRefExpr *E) {
- return CheckReferencedDecl(E, E->getDecl());
+ if (CheckReferencedDecl(E, E->getDecl()))
+ return true;
+
+ return ExprEvaluatorBaseTy::VisitDeclRefExpr(E);
}
bool VisitMemberExpr(const MemberExpr *E) {
if (CheckReferencedDecl(E, E->getMemberDecl())) {
@@ -1024,17 +1019,16 @@ public:
Info.EvalResult.HasSideEffects = true;
return true;
}
- return false;
+
+ return ExprEvaluatorBaseTy::VisitMemberExpr(E);
}
- bool VisitCallExpr(CallExpr *E);
+ bool VisitCallExpr(const CallExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitOffsetOfExpr(const OffsetOfExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
- bool VisitConditionalOperator(const ConditionalOperator *E);
- bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);
- bool VisitCastExpr(CastExpr* E);
+ bool VisitCastExpr(const CastExpr* E);
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
@@ -1069,10 +1063,6 @@ public:
return Success(E->getValue(), E);
}
- bool VisitChooseExpr(const ChooseExpr *E) {
- return Visit(E->getChosenSubExpr(Info.Ctx));
- }
-
bool VisitUnaryReal(const UnaryOperator *E);
bool VisitUnaryImag(const UnaryOperator *E);
@@ -1083,14 +1073,14 @@ private:
CharUnits GetAlignOfExpr(const Expr *E);
CharUnits GetAlignOfType(QualType T);
static QualType GetObjectType(const Expr *E);
- bool TryEvaluateBuiltinObjectSize(CallExpr *E);
+ bool TryEvaluateBuiltinObjectSize(const CallExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
} // end anonymous namespace
static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) {
assert(E->getType()->isIntegralOrEnumerationType());
- return IntExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+ return IntExprEvaluator(Info, Result).Visit(E);
}
static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
@@ -1114,18 +1104,18 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
== Qualifiers::Const) {
if (isa<ParmVarDecl>(D))
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return false;
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (const Expr *Init = VD->getAnyInitializer()) {
if (APValue *V = VD->getEvaluatedValue()) {
if (V->isInt())
return Success(V->getInt(), E);
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return false;
}
if (VD->isEvaluatingValue())
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return false;
VD->setEvaluatingValue();
@@ -1144,7 +1134,7 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
}
// Otherwise, random variable references are not constants.
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return false;
}
/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way
@@ -1216,7 +1206,7 @@ QualType IntExprEvaluator::GetObjectType(const Expr *E) {
return QualType();
}
-bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) {
+bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) {
// TODO: Perhaps we should let LLVM lower this?
LValue Base;
if (!EvaluatePointer(E->getArg(0), Base, Info))
@@ -1244,10 +1234,10 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) {
return Success(Size, E);
}
-bool IntExprEvaluator::VisitCallExpr(CallExpr *E) {
+bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (E->isBuiltinCall(Info.Ctx)) {
default:
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
case Builtin::BI__builtin_object_size: {
if (TryEvaluateBuiltinObjectSize(E))
@@ -1285,7 +1275,7 @@ bool IntExprEvaluator::VisitCallExpr(CallExpr *E) {
case Builtin::BI__builtin_strlen:
// As an extension, we support strlen() and __builtin_strlen() as constant
// expressions when the argument is a string literal.
- if (StringLiteral *S
+ if (const StringLiteral *S
= dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) {
// The string literal may have embedded null characters. Find the first
// one and truncate there.
@@ -1574,26 +1564,6 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
}
}
-bool IntExprEvaluator::
-VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) {
- OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
- if (opaque.hasError()) return false;
-
- bool cond;
- if (!HandleConversionToBool(e->getCond(), cond, Info))
- return false;
-
- return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
-}
-
-bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
- bool Cond;
- if (!HandleConversionToBool(E->getCond(), Cond, Info))
- return false;
-
- return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
-}
-
CharUnits IntExprEvaluator::GetAlignOfType(QualType T) {
// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
// the result is the size of the referenced type."
@@ -1679,18 +1649,17 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
return false;
}
-bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
+bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
CharUnits Result;
- unsigned n = E->getNumComponents();
- OffsetOfExpr* OOE = const_cast<OffsetOfExpr*>(E);
+ unsigned n = OOE->getNumComponents();
if (n == 0)
return false;
- QualType CurrentType = E->getTypeSourceInfo()->getType();
+ QualType CurrentType = OOE->getTypeSourceInfo()->getType();
for (unsigned i = 0; i != n; ++i) {
OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i);
switch (ON.getKind()) {
case OffsetOfExpr::OffsetOfNode::Array: {
- Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex());
+ const Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex());
APSInt IdxResult;
if (!EvaluateInteger(Idx, IdxResult, Info))
return false;
@@ -1745,7 +1714,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
}
}
}
- return Success(Result, E);
+ return Success(Result, OOE);
}
bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
@@ -1788,8 +1757,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
/// HandleCast - This is used to evaluate implicit or explicit casts where the
/// result type is integer.
-bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
- Expr *SubExpr = E->getSubExpr();
+bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
+ const Expr *SubExpr = E->getSubExpr();
QualType DestType = E->getType();
QualType SrcType = SubExpr->getType();
@@ -1936,48 +1905,33 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
namespace {
class FloatExprEvaluator
- : public StmtVisitor<FloatExprEvaluator, bool> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<FloatExprEvaluator, bool> {
APFloat &Result;
public:
FloatExprEvaluator(EvalInfo &info, APFloat &result)
- : Info(info), Result(result) {}
+ : ExprEvaluatorBaseTy(info), Result(result) {}
- bool VisitStmt(Stmt *S) {
+ bool Success(const APValue &V, const Expr *e) {
+ Result = V.getFloat();
+ return true;
+ }
+ bool Error(const Stmt *S) {
return false;
}
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
- }
bool VisitCallExpr(const CallExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitFloatingLiteral(const FloatingLiteral *E);
- bool VisitCastExpr(CastExpr *E);
- bool VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
- bool VisitConditionalOperator(ConditionalOperator *E);
- bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);
- bool VisitChooseExpr(const ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
- bool VisitUnaryExtension(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
bool VisitUnaryReal(const UnaryOperator *E);
bool VisitUnaryImag(const UnaryOperator *E);
bool VisitDeclRefExpr(const DeclRefExpr *E);
- bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) {
- const APValue *value = Info.getOpaqueValue(e);
- if (!value)
- return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
- Result = value->getFloat();
- return true;
- }
-
// FIXME: Missing: array subscript of vector, member of vector,
// ImplicitValueInitExpr
};
@@ -1985,7 +1939,7 @@ public:
static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
assert(E->getType()->isRealFloatingType());
- return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+ return FloatExprEvaluator(Info, Result).Visit(E);
}
static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
@@ -2015,7 +1969,9 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (E->isBuiltinCall(Info.Ctx)) {
- default: return false;
+ default:
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
case Builtin::BI__builtin_huge_val:
case Builtin::BI__builtin_huge_valf:
case Builtin::BI__builtin_huge_vall:
@@ -2066,6 +2022,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
bool FloatExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
+ if (ExprEvaluatorBaseTy::VisitDeclRefExpr(E))
+ return true;
+
const Decl *D = E->getDecl();
if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D)) return false;
const VarDecl *VD = cast<VarDecl>(D);
@@ -2196,8 +2155,8 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
return true;
}
-bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
- Expr* SubExpr = E->getSubExpr();
+bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
+ const Expr* SubExpr = E->getSubExpr();
switch (E->getCastKind()) {
default:
@@ -2236,77 +2195,42 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
return false;
}
-bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
+bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType()));
return true;
}
-bool FloatExprEvaluator::
-VisitBinaryConditionalOperator(BinaryConditionalOperator *e) {
- OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
- if (opaque.hasError()) return false;
-
- bool cond;
- if (!HandleConversionToBool(e->getCond(), cond, Info))
- return false;
-
- return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
-}
-
-bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
- bool Cond;
- if (!HandleConversionToBool(E->getCond(), Cond, Info))
- return false;
-
- return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
-}
-
//===----------------------------------------------------------------------===//
// Complex Evaluation (for float and integer)
//===----------------------------------------------------------------------===//
namespace {
class ComplexExprEvaluator
- : public StmtVisitor<ComplexExprEvaluator, bool> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<ComplexExprEvaluator, bool> {
ComplexValue &Result;
public:
ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result)
- : Info(info), Result(Result) {}
+ : ExprEvaluatorBaseTy(info), Result(Result) {}
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- bool VisitStmt(Stmt *S) {
+ bool Success(const APValue &V, const Expr *e) {
+ Result.setFrom(V);
+ return true;
+ }
+ bool Error(const Expr *E) {
return false;
}
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
- }
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
- bool VisitImaginaryLiteral(ImaginaryLiteral *E);
+ bool VisitImaginaryLiteral(const ImaginaryLiteral *E);
- bool VisitCastExpr(CastExpr *E);
+ bool VisitCastExpr(const CastExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
- bool VisitConditionalOperator(const ConditionalOperator *E);
- bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);
- bool VisitChooseExpr(const ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
- bool VisitUnaryExtension(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
- bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) {
- const APValue *value = Info.getOpaqueValue(e);
- if (!value)
- return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
- Result.setFrom(*value);
- return true;
- }
// FIXME Missing: ImplicitValueInitExpr
};
} // end anonymous namespace
@@ -2314,11 +2238,11 @@ public:
static bool EvaluateComplex(const Expr *E, ComplexValue &Result,
EvalInfo &Info) {
assert(E->getType()->isAnyComplexType());
- return ComplexExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+ return ComplexExprEvaluator(Info, Result).Visit(E);
}
-bool ComplexExprEvaluator::VisitImaginaryLiteral(ImaginaryLiteral *E) {
- Expr* SubExpr = E->getSubExpr();
+bool ComplexExprEvaluator::VisitImaginaryLiteral(const ImaginaryLiteral *E) {
+ const Expr* SubExpr = E->getSubExpr();
if (SubExpr->getType()->isRealFloatingType()) {
Result.makeComplexFloat();
@@ -2342,7 +2266,7 @@ bool ComplexExprEvaluator::VisitImaginaryLiteral(ImaginaryLiteral *E) {
}
}
-bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) {
+bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
case CK_BitCast:
@@ -2627,26 +2551,6 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
}
}
-bool ComplexExprEvaluator::
-VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) {
- OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
- if (opaque.hasError()) return false;
-
- bool cond;
- if (!HandleConversionToBool(e->getCond(), cond, Info))
- return false;
-
- return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
-}
-
-bool ComplexExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
- bool Cond;
- if (!HandleConversionToBool(E->getCond(), Cond, Info))
- return false;
-
- return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
-}
-
//===----------------------------------------------------------------------===//
// Top level Expr::Evaluate method.
//===----------------------------------------------------------------------===//
@@ -2655,8 +2559,8 @@ static bool Evaluate(EvalInfo &Info, const Expr *E) {
if (E->getType()->isVectorType()) {
if (!EvaluateVector(E, Info.EvalResult.Val, Info))
return false;
- } else if (E->getType()->isIntegerType()) {
- if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(const_cast<Expr*>(E)))
+ } else if (E->getType()->isIntegralOrEnumerationType()) {
+ if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(E))
return false;
if (Info.EvalResult.Val.isLValue() &&
!IsGlobalLValue(Info.EvalResult.Val.getLValueBase()))
@@ -2737,7 +2641,7 @@ bool Expr::isEvaluatable(const ASTContext &Ctx) const {
bool Expr::HasSideEffects(const ASTContext &Ctx) const {
Expr::EvalResult Result;
EvalInfo Info(Ctx, Result);
- return HasSideEffect(Info).Visit(const_cast<Expr*>(this));
+ return HasSideEffect(Info).Visit(this);
}
APSInt Expr::EvaluateAsInt(const ASTContext &Ctx) const {
@@ -2866,6 +2770,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::OpaqueValueExprClass:
case Expr::PackExpansionExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
+ case Expr::AsTypeExprClass:
return ICEDiag(2, E->getLocStart());
case Expr::SizeOfPackExprClass:
@@ -3053,6 +2958,21 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case BO_LAnd:
case BO_LOr: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
+
+ // C++0x [expr.const]p2:
+ // [...] subexpressions of logical AND (5.14), logical OR
+ // (5.15), and condi- tional (5.16) operations that are not
+ // evaluated are not considered.
+ if (Ctx.getLangOptions().CPlusPlus0x && LHSResult.Val == 0) {
+ if (Exp->getOpcode() == BO_LAnd &&
+ Exp->getLHS()->EvaluateAsInt(Ctx) == 0)
+ return LHSResult;
+
+ if (Exp->getOpcode() == BO_LOr &&
+ Exp->getLHS()->EvaluateAsInt(Ctx) != 0)
+ return LHSResult;
+ }
+
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
if (LHSResult.Val == 0 && RHSResult.Val == 1) {
// Rare case where the RHS has a comma "side-effect"; we need
@@ -3111,10 +3031,22 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
return NoDiag();
}
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
- ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
- ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
if (CondResult.Val == 2)
return CondResult;
+
+ // C++0x [expr.const]p2:
+ // subexpressions of [...] conditional (5.16) operations that
+ // are not evaluated are not considered
+ bool TrueBranch = Ctx.getLangOptions().CPlusPlus0x
+ ? Exp->getCond()->EvaluateAsInt(Ctx) != 0
+ : false;
+ ICEDiag TrueResult = NoDiag();
+ if (!Ctx.getLangOptions().CPlusPlus0x || TrueBranch)
+ TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
+ ICEDiag FalseResult = NoDiag();
+ if (!Ctx.getLangOptions().CPlusPlus0x || !TrueBranch)
+ FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
+
if (TrueResult.Val == 2)
return TrueResult;
if (FalseResult.Val == 2)
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index 89bf56db1af7..f428318a21e3 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -57,3 +57,5 @@ ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC,
llvm::SmallVectorImpl<Decl*> &Result) {
return true;
}
+
+void ExternalASTSource::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { }
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index c460929c461d..e81ec7e54b62 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -255,7 +255,8 @@ private:
DeclarationName name,
unsigned KnownArity = UnknownArity);
- void mangleUnresolvedType(QualType type);
+ static bool isUnresolvedType(const Type *type);
+ void mangleUnresolvedType(const Type *type);
void mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
@@ -277,6 +278,7 @@ private:
unsigned NumTemplateArgs);
void manglePrefix(NestedNameSpecifier *qualifier);
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
+ void manglePrefix(QualType type);
void mangleTemplatePrefix(const TemplateDecl *ND);
void mangleTemplatePrefix(TemplateName Template);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
@@ -317,6 +319,8 @@ private:
void mangleTemplateArgs(const TemplateParameterList &PL,
const TemplateArgumentList &AL);
void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A);
+ void mangleUnresolvedTemplateArgs(const TemplateArgument *args,
+ unsigned numArgs);
void mangleTemplateParameter(unsigned Index);
@@ -667,7 +671,7 @@ void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) {
Out << '_';
}
-void CXXNameMangler::mangleUnresolvedType(QualType type) {
+void CXXNameMangler::manglePrefix(QualType type) {
if (const TemplateSpecializationType *TST =
type->getAs<TemplateSpecializationType>()) {
if (!mangleSubstitution(QualType(TST, 0))) {
@@ -698,6 +702,31 @@ void CXXNameMangler::mangleUnresolvedType(QualType type) {
}
}
+/// Returns true if the given type, appearing within an
+/// unresolved-name, should be mangled as an unresolved-type.
+bool CXXNameMangler::isUnresolvedType(const Type *type) {
+ // <unresolved-type> ::= <template-param>
+ // ::= <decltype>
+ // ::= <template-template-param> <template-args>
+ // (this last is not official yet)
+
+ if (isa<TemplateTypeParmType>(type)) return true;
+ if (isa<DecltypeType>(type)) return true;
+ // typeof?
+ if (const TemplateSpecializationType *tst =
+ dyn_cast<TemplateSpecializationType>(type)) {
+ TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl();
+ if (temp && isa<TemplateTemplateParmDecl>(temp))
+ return true;
+ }
+ return false;
+}
+
+void CXXNameMangler::mangleUnresolvedType(const Type *type) {
+ // This seems to be do everything we want.
+ mangleType(QualType(type, 0));
+}
+
/// Mangle everything prior to the base-unresolved-name in an unresolved-name.
///
/// \param firstQualifierLookup - the entity found by unqualified lookup
@@ -752,17 +781,60 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
- // Both cases want this.
- Out << "sr";
+ const Type *type = qualifier->getAsType();
- // We only get here recursively if we're followed by identifiers.
- if (recursive) Out << 'N';
+ // We only want to use an unresolved-type encoding if this is one of:
+ // - a decltype
+ // - a template type parameter
+ // - a template template parameter with arguments
+ // In all of these cases, we should have no prefix.
+ if (qualifier->getPrefix()) {
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ } else {
+ // Otherwise, all the cases want this.
+ Out << "sr";
- mangleUnresolvedType(QualType(qualifier->getAsType(), 0));
+ if (isUnresolvedType(type)) {
+ // We only get here recursively if we're followed by identifiers.
+ if (recursive) Out << 'N';
+ mangleUnresolvedType(type);
- // We never want to print 'E' directly after an unresolved-type,
- // so we return directly.
- return;
+ // We never want to print 'E' directly after an unresolved-type,
+ // so we return directly.
+ return;
+ }
+ }
+
+ assert(!isUnresolvedType(type));
+
+ // Only certain other types are valid as prefixes; enumerate them.
+ // FIXME: can we get ElaboratedTypes here?
+ // FIXME: SubstTemplateTypeParmType?
+ if (const TagType *t = dyn_cast<TagType>(type)) {
+ mangleSourceName(t->getDecl()->getIdentifier());
+ } else if (const TypedefType *t = dyn_cast<TypedefType>(type)) {
+ mangleSourceName(t->getDecl()->getIdentifier());
+ } else if (const UnresolvedUsingType *t
+ = dyn_cast<UnresolvedUsingType>(type)) {
+ mangleSourceName(t->getDecl()->getIdentifier());
+ } else if (const DependentNameType *t
+ = dyn_cast<DependentNameType>(type)) {
+ mangleSourceName(t->getIdentifier());
+ } else if (const TemplateSpecializationType *tst
+ = dyn_cast<TemplateSpecializationType>(type)) {
+ TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl();
+ assert(temp && "no template for template specialization type");
+ mangleSourceName(temp->getIdentifier());
+ mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs());
+ } else if (const DependentTemplateSpecializationType *tst
+ = dyn_cast<DependentTemplateSpecializationType>(type)) {
+ mangleSourceName(tst->getIdentifier());
+ mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs());
+ } else {
+ llvm_unreachable("unexpected type in nested name specifier!");
+ }
+ break;
}
case NestedNameSpecifier::Identifier:
@@ -1050,6 +1122,12 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
// := Z <function encoding> E s [<discriminator>]
// <discriminator> := _ <non-negative number>
const DeclContext *DC = ND->getDeclContext();
+ if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) {
+ // Don't add objc method name mangling to locally declared function
+ mangleUnqualifiedName(ND);
+ return;
+ }
+
Out << 'Z';
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
@@ -1097,7 +1175,7 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
- mangleUnresolvedType(QualType(qualifier->getAsType(), 0));
+ manglePrefix(QualType(qualifier->getAsType(), 0));
return;
case NestedNameSpecifier::Identifier:
@@ -1867,6 +1945,22 @@ void CXXNameMangler::mangleType(const DecltypeType *T) {
Out << 'E';
}
+void CXXNameMangler::mangleType(const UnaryTransformType *T) {
+ // If this is dependent, we need to record that. If not, we simply
+ // mangle it as the underlying type since they are equivalent.
+ if (T->isDependentType()) {
+ Out << 'U';
+
+ switch (T->getUTTKind()) {
+ case UnaryTransformType::EnumUnderlyingType:
+ Out << "3eut";
+ break;
+ }
+ }
+
+ mangleType(T->getUnderlyingType());
+}
+
void CXXNameMangler::mangleType(const AutoType *T) {
QualType D = T->getDeducedType();
// <builtin-type> ::= Da # dependent auto
@@ -1951,6 +2045,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
// ::= <function-param>
// ::= sr <type> <unqualified-name> # dependent name
// ::= sr <type> <unqualified-name> <template-args> # dependent template-id
+ // ::= ds <expression> <expression> # expr.*expr
// ::= sZ <template-param> # size of a parameter pack
// ::= sZ <function-param> # size of a function parameter pack
// ::= <expr-primary>
@@ -2005,7 +2100,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::VAArgExprClass:
case Expr::CXXUuidofExprClass:
case Expr::CXXNoexceptExprClass:
- case Expr::CUDAKernelCallExprClass: {
+ case Expr::CUDAKernelCallExprClass:
+ case Expr::AsTypeExprClass:
+ {
// As bad as this diagnostic is, it's better than crashing.
Diagnostic &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
@@ -2227,8 +2324,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::CompoundAssignOperatorClass: // fallthrough
case Expr::BinaryOperatorClass: {
const BinaryOperator *BO = cast<BinaryOperator>(E);
- mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
- /*Arity=*/2);
+ if (BO->getOpcode() == BO_PtrMemD)
+ Out << "ds";
+ else
+ mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
+ /*Arity=*/2);
mangleExpression(BO->getLHS());
mangleExpression(BO->getRHS());
break;
@@ -2552,8 +2652,8 @@ void CXXNameMangler::mangleTemplateArgs(
const ExplicitTemplateArgumentList &TemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
- for (unsigned I = 0, E = TemplateArgs.NumTemplateArgs; I != E; ++I)
- mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[I].getArgument());
+ for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i)
+ mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[i].getArgument());
Out << 'E';
}
@@ -2564,10 +2664,15 @@ void CXXNameMangler::mangleTemplateArgs(TemplateName Template,
return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs,
NumTemplateArgs);
+ mangleUnresolvedTemplateArgs(TemplateArgs, NumTemplateArgs);
+}
+
+void CXXNameMangler::mangleUnresolvedTemplateArgs(const TemplateArgument *args,
+ unsigned numArgs) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
- for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(0, TemplateArgs[i]);
+ for (unsigned i = 0; i != numArgs; ++i)
+ mangleTemplateArg(0, args[i]);
Out << 'E';
}
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index 3a0b9094307f..c3f3b11caccf 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -48,6 +48,11 @@ static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) {
const DeclContext *ExpectedDC = BD->getDeclContext();
while (isa<BlockDecl>(ExpectedDC) || isa<EnumDecl>(ExpectedDC))
ExpectedDC = ExpectedDC->getParent();
+ // In-class initializers for non-static data members are lexically defined
+ // within the class, but are mangled as if they were specified as constructor
+ // member initializers.
+ if (isa<CXXRecordDecl>(ExpectedDC) && DC != ExpectedDC)
+ DC = DC->getParent();
assert(DC == ExpectedDC && "Given decl context did not match expected!");
#endif
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 5424bebc81b0..4f920f9aaca7 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -1113,6 +1113,10 @@ void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) {
assert(false && "Don't know how to mangle DecltypeTypes yet!");
}
+void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T) {
+ assert(false && "Don't know how to mangle UnaryTransformationTypes yet!");
+}
+
void MicrosoftCXXNameMangler::mangleType(const AutoType *T) {
assert(false && "Don't know how to mangle AutoTypes yet!");
}
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 0770e1f15143..de0b1d0ed9db 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -582,7 +582,7 @@ protected:
CharUnits NonVirtualSize;
CharUnits NonVirtualAlignment;
- CharUnits ZeroLengthBitfieldAlignment;
+ FieldDecl *ZeroLengthBitfield;
/// PrimaryBase - the primary base class (if one exists) of the class
/// we're laying out.
@@ -621,7 +621,7 @@ protected:
UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
- ZeroLengthBitfieldAlignment(CharUnits::Zero()), PrimaryBase(0),
+ ZeroLengthBitfield(0), PrimaryBase(0),
PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
void Layout(const RecordDecl *D);
@@ -1258,27 +1258,112 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
const FieldDecl *LastFD = 0;
+ ZeroLengthBitfield = 0;
+ unsigned RemainingInAlignment = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
if (IsMsStruct) {
- const FieldDecl *FD = (*Field);
- if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD)) {
- // FIXME. Multiple zero bitfields may follow a bitfield.
- // set ZeroLengthBitfieldAlignment to max. of its
- // currrent and alignment of 'FD'.
- std::pair<CharUnits, CharUnits> FieldInfo =
- Context.getTypeInfoInChars(FD->getType());
- ZeroLengthBitfieldAlignment = FieldInfo.second;
- continue;
- }
+ FieldDecl *FD = (*Field);
+ if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD))
+ ZeroLengthBitfield = FD;
// Zero-length bitfields following non-bitfield members are
// ignored:
- if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
+ else if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
continue;
+ // FIXME. streamline these conditions into a simple one.
+ else if (Context.BitfieldFollowsBitfield(FD, LastFD) ||
+ Context.BitfieldFollowsNoneBitfield(FD, LastFD) ||
+ Context.NoneBitfieldFollowsBitfield(FD, LastFD)) {
+ // 1) Adjacent bit fields are packed into the same 1-, 2-, or
+ // 4-byte allocation unit if the integral types are the same
+ // size and if the next bit field fits into the current
+ // allocation unit without crossing the boundary imposed by the
+ // common alignment requirements of the bit fields.
+ // 2) Establish a new alignment for a bitfield following
+ // a non-bitfield if size of their types differ.
+ // 3) Establish a new alignment for a non-bitfield following
+ // a bitfield if size of their types differ.
+ std::pair<uint64_t, unsigned> FieldInfo =
+ Context.getTypeInfo(FD->getType());
+ uint64_t TypeSize = FieldInfo.first;
+ unsigned FieldAlign = FieldInfo.second;
+ // This check is needed for 'long long' in -m32 mode.
+ if (TypeSize > FieldAlign)
+ FieldAlign = TypeSize;
+ FieldInfo = Context.getTypeInfo(LastFD->getType());
+ uint64_t TypeSizeLastFD = FieldInfo.first;
+ unsigned FieldAlignLastFD = FieldInfo.second;
+ // This check is needed for 'long long' in -m32 mode.
+ if (TypeSizeLastFD > FieldAlignLastFD)
+ FieldAlignLastFD = TypeSizeLastFD;
+
+ if (TypeSizeLastFD != TypeSize) {
+ if (RemainingInAlignment &&
+ LastFD && LastFD->isBitField() &&
+ LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+ // If previous field was a bitfield with some remaining unfilled
+ // bits, pad the field so current field starts on its type boundary.
+ uint64_t FieldOffset =
+ getDataSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ RemainingInAlignment = 0;
+ }
+
+ uint64_t UnpaddedFieldOffset =
+ getDataSizeInBits() - UnfilledBitsInLastByte;
+ FieldAlign = std::max(FieldAlign, FieldAlignLastFD);
+
+ // The maximum field alignment overrides the aligned attribute.
+ if (!MaxFieldAlignment.isZero()) {
+ unsigned MaxFieldAlignmentInBits =
+ Context.toBits(MaxFieldAlignment);
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
+ }
+
+ uint64_t NewSizeInBits =
+ llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign);
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
+ UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ }
+ if (FD->isBitField()) {
+ uint64_t FieldSize =
+ FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+ assert (FieldSize > 0 && "LayoutFields - ms_struct layout");
+ if (RemainingInAlignment < FieldSize)
+ RemainingInAlignment = TypeSize - FieldSize;
+ else
+ RemainingInAlignment -= FieldSize;
+ }
+ }
+ else if (FD->isBitField()) {
+ uint64_t FieldSize =
+ FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+ std::pair<uint64_t, unsigned> FieldInfo =
+ Context.getTypeInfo(FD->getType());
+ uint64_t TypeSize = FieldInfo.first;
+ RemainingInAlignment = TypeSize - FieldSize;
+ }
LastFD = FD;
}
LayoutField(*Field);
}
+ if (IsMsStruct && RemainingInAlignment &&
+ LastFD && LastFD->isBitField() &&
+ LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+ // If we ended a bitfield before the full length of the type then
+ // pad the struct out to the full length of the last type.
+ uint64_t FieldOffset =
+ getDataSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ }
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
@@ -1355,6 +1440,27 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
+
+ // This check is needed for 'long long' in -m32 mode.
+ if (IsMsStruct && (TypeSize > FieldAlign))
+ FieldAlign = TypeSize;
+
+ if (ZeroLengthBitfield) {
+ // If a zero-length bitfield is inserted after a bitfield,
+ // and the alignment of the zero-length bitfield is
+ // greater than the member that follows it, `bar', `bar'
+ // will be aligned as the type of the zero-length bitfield.
+ if (ZeroLengthBitfield != D) {
+ std::pair<uint64_t, unsigned> FieldInfo =
+ Context.getTypeInfo(ZeroLengthBitfield->getType());
+ unsigned ZeroLengthBitfieldAlignment = FieldInfo.second;
+ // Ignore alignment of subsequent zero-length bitfields.
+ if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0))
+ FieldAlign = ZeroLengthBitfieldAlignment;
+ if (FieldSize)
+ ZeroLengthBitfield = 0;
+ }
+ }
if (FieldSize > TypeSize) {
LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D);
@@ -1455,11 +1561,21 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
Context.getTypeInfoInChars(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
- if (ZeroLengthBitfieldAlignment > FieldAlign)
- FieldAlign = ZeroLengthBitfieldAlignment;
- ZeroLengthBitfieldAlignment = CharUnits::Zero();
+
+ if (ZeroLengthBitfield) {
+ // If a zero-length bitfield is inserted after a bitfield,
+ // and the alignment of the zero-length bitfield is
+ // greater than the member that follows it, `bar', `bar'
+ // will be aligned as the type of the zero-length bitfield.
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(ZeroLengthBitfield->getType());
+ CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second;
+ if (ZeroLengthBitfieldAlignment > FieldAlign)
+ FieldAlign = ZeroLengthBitfieldAlignment;
+ ZeroLengthBitfield = 0;
+ }
- if (Context.getLangOptions().MSBitfields) {
+ if (Context.getLangOptions().MSBitfields || IsMsStruct) {
// If MS bitfield layout is required, figure out what type is being
// laid out and align the field to the width of that type.
@@ -1641,10 +1757,10 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (!RD->isPolymorphic())
return 0;
- // A class inside an anonymous namespace doesn't have a key function. (Or
+ // A class that is not externally visible doesn't have a key function. (Or
// at least, there's no point to assigning a key function to such a class;
// this doesn't affect the ABI.)
- if (RD->isInAnonymousNamespace())
+ if (RD->getLinkage() != ExternalLinkage)
return 0;
// Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6.
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 0d13502e8d58..87588e451884 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1297,7 +1297,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
case UTT_HasNothrowCopy: return "__has_nothrow_copy";
case UTT_HasTrivialAssign: return "__has_trivial_assign";
- case UTT_HasTrivialConstructor: return "__has_trivial_constructor";
+ case UTT_HasTrivialDefaultConstructor: return "__has_trivial_constructor";
case UTT_HasTrivialCopy: return "__has_trivial_copy";
case UTT_HasTrivialDestructor: return "__has_trivial_destructor";
case UTT_HasVirtualDestructor: return "__has_virtual_destructor";
@@ -1329,6 +1329,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
case UTT_IsSigned: return "__is_signed";
case UTT_IsStandardLayout: return "__is_standard_layout";
case UTT_IsTrivial: return "__is_trivial";
+ case UTT_IsTriviallyCopyable: return "__is_trivially_copyable";
case UTT_IsUnion: return "__is_union";
case UTT_IsUnsigned: return "__is_unsigned";
case UTT_IsVoid: return "__is_void";
@@ -1498,6 +1499,13 @@ void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {}
+void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
+ OS << "__builtin_astype(";
+ PrintExpr(Node->getSrcExpr());
+ OS << ", " << Node->getType().getAsString();
+ OS << ")";
+}
+
//===----------------------------------------------------------------------===//
// Stmt method implementations
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 44818e8c0847..b117cd9a525f 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -679,6 +679,10 @@ void StmtProfiler::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *S) {
VisitCallExpr(S);
}
+void StmtProfiler::VisitAsTypeExpr(AsTypeExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) {
VisitExplicitCastExpr(S);
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 9eb497bea629..d28755284477 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -517,7 +517,7 @@ bool Type::isIntegerType() const {
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- return ET->getDecl()->isComplete();
+ return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
return false;
}
@@ -641,13 +641,27 @@ bool Type::isSignedIntegerType() const {
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- if (ET->getDecl()->isComplete())
+ if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
return ET->getDecl()->getIntegerType()->isSignedIntegerType();
}
return false;
}
+bool Type::isSignedIntegerOrEnumerationType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return BT->getKind() >= BuiltinType::Char_S &&
+ BT->getKind() <= BuiltinType::Int128;
+ }
+
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
+ if (ET->getDecl()->isComplete())
+ return ET->getDecl()->getIntegerType()->isSignedIntegerType();
+ }
+
+ return false;
+}
+
bool Type::hasSignedIntegerRepresentation() const {
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isSignedIntegerType();
@@ -667,13 +681,27 @@ bool Type::isUnsignedIntegerType() const {
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- if (ET->getDecl()->isComplete())
+ if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
}
return false;
}
+bool Type::isUnsignedIntegerOrEnumerationType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::UInt128;
+ }
+
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
+ if (ET->getDecl()->isComplete())
+ return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
+ }
+
+ return false;
+}
+
bool Type::hasUnsignedIntegerRepresentation() const {
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isUnsignedIntegerType();
@@ -954,10 +982,37 @@ bool Type::isTrivialType() const {
if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
if (const CXXRecordDecl *ClassDecl =
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // C++0x [class]p5:
- // A trivial class is a class that has a trivial default constructor
- if (!ClassDecl->hasTrivialConstructor()) return false;
- // and is trivially copyable.
+ if (!ClassDecl->isTrivial()) return false;
+ }
+
+ return true;
+ }
+
+ // No other types can match.
+ return false;
+}
+
+bool Type::isTriviallyCopyableType() const {
+ if (isDependentType())
+ return false;
+
+ // C++0x [basic.types]p9
+ // Scalar types, trivially copyable class types, arrays of such types, and
+ // cv-qualified versions of these types are collectively called trivial
+ // types.
+ const Type *BaseTy = getBaseElementTypeUnsafe();
+ assert(BaseTy && "NULL element type");
+
+ // Return false for incomplete types after skipping any incomplete array types
+ // which are expressly allowed by the standard and thus our API.
+ if (BaseTy->isIncompleteType())
+ return false;
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!ClassDecl->isTriviallyCopyable()) return false;
}
@@ -1027,11 +1082,7 @@ bool Type::isCXX11PODType() const {
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
// C++11 [class]p10:
// A POD struct is a non-union class that is both a trivial class [...]
- // C++11 [class]p5:
- // A trivial class is a class that has a trivial default constructor
- if (!ClassDecl->hasTrivialConstructor()) return false;
- // and is trivially copyable.
- if (!ClassDecl->isTriviallyCopyable()) return false;
+ if (!ClassDecl->isTrivial()) return false;
// C++11 [class]p10:
// A POD struct is a non-union class that is both a trivial class and
@@ -1484,6 +1535,16 @@ static TagDecl *getInterestingTagDecl(TagDecl *decl) {
return decl;
}
+UnaryTransformType::UnaryTransformType(QualType BaseType,
+ QualType UnderlyingType,
+ UTTKind UKind,
+ QualType CanonicalType)
+ : Type(UnaryTransform, CanonicalType, UnderlyingType->isDependentType(),
+ UnderlyingType->isVariablyModifiedType(),
+ BaseType->containsUnexpandedParameterPack())
+ , BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind)
+{}
+
TagDecl *TagType::getDecl() const {
return getInterestingTagDecl(decl);
}
@@ -1559,13 +1620,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) {
TemplateSpecializationType::
TemplateSpecializationType(TemplateName T,
- const TemplateArgument *Args,
- unsigned NumArgs, QualType Canon)
+ const TemplateArgument *Args, unsigned NumArgs,
+ QualType Canon, QualType AliasedType)
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
- T.isDependent(), false, T.containsUnexpandedParameterPack()),
- Template(T), NumArgs(NumArgs)
-{
+ Canon.isNull()? T.isDependent() : Canon->isDependentType(),
+ false, T.containsUnexpandedParameterPack()),
+ Template(T), NumArgs(NumArgs) {
assert(!T.getAsDependentTemplateName() &&
"Use DependentTemplateSpecializationType for dependent template-name");
assert((!Canon.isNull() ||
@@ -1576,7 +1637,12 @@ TemplateSpecializationType(TemplateName T,
= reinterpret_cast<TemplateArgument *>(this + 1);
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
// Update dependent and variably-modified bits.
- if (Args[Arg].isDependent())
+ // If the canonical type exists and is non-dependent, the template
+ // specialization type can be non-dependent even if one of the type
+ // arguments is. Given:
+ // template<typename T> using U = int;
+ // U<T> is always non-dependent, irrespective of the type T.
+ if (Canon.isNull() && Args[Arg].isDependent())
setDependent();
if (Args[Arg].getKind() == TemplateArgument::Type &&
Args[Arg].getAsType()->isVariablyModifiedType())
@@ -1586,6 +1652,15 @@ TemplateSpecializationType(TemplateName T,
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
}
+
+ // Store the aliased type if this is a type alias template specialization.
+ bool IsTypeAlias = !AliasedType.isNull();
+ assert(IsTypeAlias == isTypeAlias() &&
+ "allocated wrong size for type alias");
+ if (IsTypeAlias) {
+ TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
+ *reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType;
+ }
}
void
@@ -1599,6 +1674,11 @@ TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
Args[Idx].Profile(ID, Context);
}
+bool TemplateSpecializationType::isTypeAlias() const {
+ TemplateDecl *D = Template.getAsTemplateDecl();
+ return D && isa<TypeAliasTemplateDecl>(D);
+}
+
QualType
QualifierCollector::apply(const ASTContext &Context, QualType QT) const {
if (!hasNonFastQualifiers())
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 0c5df7fae671..4519606f6e82 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -94,6 +94,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
+ case Type::UnaryTransform:
case Type::Record:
case Type::Enum:
case Type::Elaborated:
@@ -512,6 +513,20 @@ void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) {
S = "decltype(" + s.str() + ")" + S;
}
+void TypePrinter::printUnaryTransform(const UnaryTransformType *T,
+ std::string &S) {
+ if (!S.empty())
+ S = ' ' + S;
+ std::string Str;
+ print(T->getBaseType(), Str);
+
+ switch (T->getUTTKind()) {
+ case UnaryTransformType::EnumUnderlyingType:
+ S = "__underlying_type(" + Str + ")" + S;
+ break;
+ }
+}
+
void TypePrinter::printAuto(const AutoType *T, std::string &S) {
// If the type has been deduced, do not print 'auto'.
if (T->isDeduced()) {
@@ -963,7 +978,7 @@ TemplateSpecializationType::PrintTemplateArgumentList(
SpecString += '<';
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (SpecString.size() > !SkipBrackets)
+ if (SpecString.size() > unsigned(!SkipBrackets))
SpecString += ", ";
// Print the argument into a string.
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index ddc5e887031b..678f02fd71fb 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -78,16 +78,16 @@ void AnalysisContext::registerForcedBlockExpression(const Stmt *stmt) {
if (!forcedBlkExprs)
forcedBlkExprs = new CFG::BuildOptions::ForcedBlkExprs();
// Default construct an entry for 'stmt'.
- if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt))
- stmt = pe->IgnoreParens();
+ if (const Expr *e = dyn_cast<Expr>(stmt))
+ stmt = e->IgnoreParens();
(void) (*forcedBlkExprs)[stmt];
}
const CFGBlock *
AnalysisContext::getBlockForRegisteredExpression(const Stmt *stmt) {
assert(forcedBlkExprs);
- if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt))
- stmt = pe->IgnoreParens();
+ if (const Expr *e = dyn_cast<Expr>(stmt))
+ stmt = e->IgnoreParens();
CFG::BuildOptions::ForcedBlkExprs::const_iterator itr =
forcedBlkExprs->find(stmt);
assert(itr != forcedBlkExprs->end());
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index de16334ce137..3e540203eaa0 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -320,7 +320,6 @@ private:
AddStmtChoice asc);
CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C,
AddStmtChoice asc);
- CFGBlock *VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc);
CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc);
CFGBlock *VisitCaseStmt(CaseStmt *C);
CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc);
@@ -398,6 +397,8 @@ private:
if (alwaysAdd(S))
cachedEntry->second = B;
+ // All block-level expressions should have already been IgnoreParens()ed.
+ assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S);
B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext());
}
void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
@@ -444,7 +445,7 @@ private:
return Result.Val.getInt().getBoolValue();
if (Result.Val.isLValue()) {
- Expr *e = Result.Val.getLValueBase();
+ const Expr *e = Result.Val.getLValueBase();
const CharUnits &c = Result.Val.getLValueOffset();
if (!e && c.isZero())
return false;
@@ -842,11 +843,14 @@ void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock* Blk,
/// blocks for ternary operators, &&, and ||. We also process "," and
/// DeclStmts (which may contain nested control-flow).
CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
-tryAgain:
if (!S) {
badCFG = true;
return 0;
}
+
+ if (Expr *E = dyn_cast<Expr>(S))
+ S = E->IgnoreParens();
+
switch (S->getStmtClass()) {
default:
return VisitStmt(S, asc);
@@ -868,6 +872,7 @@ tryAgain:
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass:
+ case Stmt::CXXMemberCallExprClass:
return VisitCallExpr(cast<CallExpr>(S), asc);
case Stmt::CaseStmtClass:
@@ -903,9 +908,6 @@ tryAgain:
case Stmt::CXXTemporaryObjectExprClass:
return VisitCXXTemporaryObjectExpr(cast<CXXTemporaryObjectExpr>(S), asc);
- case Stmt::CXXMemberCallExprClass:
- return VisitCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), asc);
-
case Stmt::CXXThrowExprClass:
return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
@@ -960,10 +962,6 @@ tryAgain:
case Stmt::ObjCForCollectionStmtClass:
return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
- case Stmt::ParenExprClass:
- S = cast<ParenExpr>(S)->getSubExpr();
- goto tryAgain;
-
case Stmt::NullStmtClass:
return Block;
@@ -1153,12 +1151,19 @@ static bool CanThrow(Expr *E, ASTContext &Ctx) {
}
CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
- // If this is a call to a no-return function, this stops the block here.
- bool NoReturn = false;
- if (getFunctionExtInfo(*C->getCallee()->getType()).getNoReturn()) {
- NoReturn = true;
+ // Compute the callee type.
+ QualType calleeType = C->getCallee()->getType();
+ if (calleeType == Context->BoundMemberTy) {
+ QualType boundType = Expr::findBoundMemberType(C->getCallee());
+
+ // We should only get a null bound type if processing a dependent
+ // CFG. Recover by assuming nothing.
+ if (!boundType.isNull()) calleeType = boundType;
}
+ // If this is a call to a no-return function, this stops the block here.
+ bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn();
+
bool AddEHEdge = false;
// Languages without exceptions are assumed to not throw.
@@ -1314,6 +1319,12 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
}
CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
+ // Check if the Decl is for an __label__. If so, elide it from the
+ // CFG entirely.
+ if (isa<LabelDecl>(*DS->decl_begin()))
+ return Block;
+
+ // This case also handles static_asserts.
if (DS->isSingleDecl())
return VisitDeclSubExpr(DS);
@@ -1346,7 +1357,14 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
/// DeclStmts and initializers in them.
CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt* DS) {
assert(DS->isSingleDecl() && "Can handle single declarations only.");
-
+ Decl *D = DS->getSingleDecl();
+
+ if (isa<StaticAssertDecl>(D)) {
+ // static_asserts aren't added to the CFG because they do not impact
+ // runtime semantics.
+ return Block;
+ }
+
VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
if (!VD) {
@@ -2686,13 +2704,6 @@ CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C,
return VisitChildren(C);
}
-CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C,
- AddStmtChoice asc) {
- autoCreateBlock();
- appendStmt(Block, C);
- return VisitChildren(C);
-}
-
CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
AddStmtChoice asc) {
if (asc.alwaysAdd(*this, E)) {
@@ -3039,6 +3050,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
if (!CS)
continue;
if (Expr* Exp = dyn_cast<Expr>(CS->getStmt())) {
+ assert((Exp->IgnoreParens() == Exp) && "No parens on block-level exps");
if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
// Assignment expressions that are not nested within another
@@ -3046,13 +3058,16 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
// another expression.
if (B->isAssignmentOp() && !SubExprAssignments.count(Exp))
continue;
- } else if (const StmtExpr* Terminator = dyn_cast<StmtExpr>(Exp)) {
+ } else if (const StmtExpr* SE = dyn_cast<StmtExpr>(Exp)) {
// Special handling for statement expressions. The last statement in
// the statement expression is also a block-level expr.
- const CompoundStmt* C = Terminator->getSubStmt();
+ const CompoundStmt* C = SE->getSubStmt();
if (!C->body_empty()) {
+ const Stmt *Last = C->body_back();
+ if (const Expr *LastEx = dyn_cast<Expr>(Last))
+ Last = LastEx->IgnoreParens();
unsigned x = M->size();
- (*M)[C->body_back()] = x;
+ (*M)[Last] = x;
}
}
@@ -3066,8 +3081,8 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
Stmt* S = (*I)->getTerminatorCondition();
if (S && M->find(S) == M->end()) {
- unsigned x = M->size();
- (*M)[S] = x;
+ unsigned x = M->size();
+ (*M)[S] = x;
}
}
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index 4c62f36e6c92..946c38c875d5 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -44,6 +44,7 @@ cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
case OMF_release:
case OMF_retain:
case OMF_retainCount:
+ case OMF_self:
return NoConvention;
case OMF_init:
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 303dc0f604d7..7b36f85ab62c 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -157,7 +157,7 @@ void TransferFuncs::Visit(Stmt *S) {
}
else {
// For block-level expressions, mark that they are live.
- LiveState(S,AD) = Alive;
+ LiveState(S, AD) = Alive;
}
}
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 88a2db751a43..e80e282813af 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -14,7 +14,7 @@
#include <utility>
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/PackedVector.h"
#include "llvm/ADT/DenseMap.h"
#include "clang/AST/Decl.h"
#include "clang/Analysis/CFG.h"
@@ -93,39 +93,8 @@ static bool isAlwaysUninit(const Value v) {
}
namespace {
-class ValueVector {
- llvm::BitVector vec;
-public:
- ValueVector() {}
- ValueVector(unsigned size) : vec(size << 1) {}
- void resize(unsigned n) { vec.resize(n << 1); }
- void merge(const ValueVector &rhs) { vec |= rhs.vec; }
- bool operator!=(const ValueVector &rhs) const { return vec != rhs.vec; }
- void reset() { vec.reset(); }
-
- class reference {
- ValueVector &vv;
- const unsigned idx;
-
- reference(); // Undefined
- public:
- reference(ValueVector &vv, unsigned idx) : vv(vv), idx(idx) {}
- ~reference() {}
-
- reference &operator=(Value v) {
- vv.vec[idx << 1] = (((unsigned) v) & 0x1) ? true : false;
- vv.vec[(idx << 1) | 1] = (((unsigned) v) & 0x2) ? true : false;
- return *this;
- }
- operator Value() {
- unsigned x = (vv.vec[idx << 1] ? 1 : 0) | (vv.vec[(idx << 1) | 1] ? 2 :0);
- return (Value) x;
- }
- };
-
- reference operator[](unsigned idx) { return reference(*this, idx); }
-};
+typedef llvm::PackedVector<Value, 2> ValueVector;
typedef std::pair<ValueVector *, ValueVector *> BVPair;
class CFGBlockValues {
@@ -214,11 +183,15 @@ static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
if (!b || !b->isLogicalOp())
return 0;
- if (block->pred_size() == 2 &&
- ((block->succ_size() == 2 && block->getTerminatorCondition() == b) ||
- block->size() == 1))
- return b;
-
+ if (block->pred_size() == 2) {
+ if (block->getTerminatorCondition() == b) {
+ if (block->succ_size() == 2)
+ return b;
+ }
+ else if (block->size() == 1)
+ return b;
+ }
+
return 0;
}
@@ -255,7 +228,7 @@ void CFGBlockValues::mergeIntoScratch(ValueVector const &source,
if (isFirst)
scratch = source;
else
- scratch.merge(source);
+ scratch |= source;
}
#if 0
static void printVector(const CFGBlock *block, ValueVector &bv,
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index e8cd21885d22..11887ab0fe95 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -212,6 +212,42 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
FullSourceLoc(Loc, *SourceMgr)));
}
+void Diagnostic::Report(const StoredDiagnostic &storedDiag) {
+ assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
+
+ CurDiagLoc = storedDiag.getLocation();
+ CurDiagID = storedDiag.getID();
+ NumDiagArgs = 0;
+
+ NumDiagRanges = storedDiag.range_size();
+ assert(NumDiagRanges < sizeof(DiagRanges)/sizeof(DiagRanges[0]) &&
+ "Too many arguments to diagnostic!");
+ unsigned i = 0;
+ for (StoredDiagnostic::range_iterator
+ RI = storedDiag.range_begin(),
+ RE = storedDiag.range_end(); RI != RE; ++RI)
+ DiagRanges[i++] = *RI;
+
+ NumFixItHints = storedDiag.fixit_size();
+ assert(NumFixItHints < Diagnostic::MaxFixItHints && "Too many fix-it hints!");
+ i = 0;
+ for (StoredDiagnostic::fixit_iterator
+ FI = storedDiag.fixit_begin(),
+ FE = storedDiag.fixit_end(); FI != FE; ++FI)
+ FixItHints[i++] = *FI;
+
+ assert(Client && "DiagnosticClient not set!");
+ Level DiagLevel = storedDiag.getLevel();
+ DiagnosticInfo Info(this, storedDiag.getMessage());
+ Client->HandleDiagnostic(DiagLevel, Info);
+ if (Client->IncludeInDiagnosticCounts()) {
+ if (DiagLevel == Diagnostic::Warning)
+ ++NumWarnings;
+ }
+
+ CurDiagID = ~0U;
+}
+
void DiagnosticBuilder::FlushCounts() {
DiagObj->NumDiagArgs = NumArgs;
DiagObj->NumDiagRanges = NumRanges;
@@ -486,10 +522,15 @@ static void HandlePluralModifier(const DiagnosticInfo &DInfo, unsigned ValNo,
/// array.
void DiagnosticInfo::
FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
- const char *DiagStr = getDiags()->getDiagnosticIDs()->getDescription(getID());
- const char *DiagEnd = DiagStr+strlen(DiagStr);
+ if (!StoredDiagMessage.empty()) {
+ OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end());
+ return;
+ }
+
+ llvm::StringRef Diag =
+ getDiags()->getDiagnosticIDs()->getDescription(getID());
- FormatDiagnostic(DiagStr, DiagEnd, OutStr);
+ FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
}
void DiagnosticInfo::
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index b4dd575a9684..6d7e3204cba3 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -45,14 +45,37 @@ struct StaticDiagInfoRec {
unsigned SFINAE : 1;
unsigned AccessControl : 1;
unsigned Category : 5;
-
- const char *Name;
-
- const char *Description;
- const char *OptionGroup;
- const char *BriefExplanation;
- const char *FullExplanation;
+ uint8_t NameLen;
+ uint8_t OptionGroupLen;
+
+ uint16_t DescriptionLen;
+ uint16_t BriefExplanationLen;
+ uint16_t FullExplanationLen;
+
+ const char *NameStr;
+ const char *OptionGroupStr;
+
+ const char *DescriptionStr;
+ const char *BriefExplanationStr;
+ const char *FullExplanationStr;
+
+ llvm::StringRef getName() const {
+ return llvm::StringRef(NameStr, NameLen);
+ }
+ llvm::StringRef getOptionGroup() const {
+ return llvm::StringRef(OptionGroupStr, OptionGroupLen);
+ }
+
+ llvm::StringRef getDescription() const {
+ return llvm::StringRef(DescriptionStr, DescriptionLen);
+ }
+ llvm::StringRef getBriefExplanation() const {
+ return llvm::StringRef(BriefExplanationStr, BriefExplanationLen);
+ }
+ llvm::StringRef getFullExplanation() const {
+ return llvm::StringRef(FullExplanationStr, FullExplanationLen);
+ }
bool operator<(const StaticDiagInfoRec &RHS) const {
return DiagID < RHS.DiagID;
@@ -60,27 +83,42 @@ struct StaticDiagInfoRec {
};
struct StaticDiagNameIndexRec {
- const char *Name;
+ const char *NameStr;
unsigned short DiagID;
-
+ uint8_t NameLen;
+
+ llvm::StringRef getName() const {
+ return llvm::StringRef(NameStr, NameLen);
+ }
+
bool operator<(const StaticDiagNameIndexRec &RHS) const {
- assert(Name && RHS.Name && "Null Diagnostic Name");
- return strcmp(Name, RHS.Name) == -1;
+ return getName() < RHS.getName();
}
bool operator==(const StaticDiagNameIndexRec &RHS) const {
- assert(Name && RHS.Name && "Null Diagnostic Name");
- return strcmp(Name, RHS.Name) == 0;
+ return getName() == RHS.getName();
}
};
-}
+template <size_t SizeOfStr, typename FieldType>
+class StringSizerHelper {
+ char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1];
+public:
+ enum { Size = SizeOfStr };
+};
+
+} // namespace anonymous
+
+#define STR_SIZE(str, fieldTy) StringSizerHelper<sizeof(str)-1, fieldTy>::Size
static const StaticDiagInfoRec StaticDiagInfo[] = {
-#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \
- { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, \
- ACCESS, CATEGORY, #ENUM, DESC, GROUP, BRIEF, FULL },
+#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \
+ { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, \
+ STR_SIZE(#ENUM, uint8_t), STR_SIZE(GROUP, uint8_t), \
+ STR_SIZE(DESC, uint16_t), STR_SIZE(BRIEF, uint16_t), \
+ STR_SIZE(FULL, uint16_t), \
+ #ENUM, GROUP, DESC, BRIEF, FULL },
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
@@ -90,7 +128,7 @@ static const StaticDiagInfoRec StaticDiagInfo[] = {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
static const unsigned StaticDiagInfoSize =
@@ -98,10 +136,10 @@ static const unsigned StaticDiagInfoSize =
/// To be sorted before first use (since it's splitted among multiple files)
static StaticDiagNameIndexRec StaticDiagNameIndex[] = {
-#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM },
+#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
#include "clang/Basic/DiagnosticIndexName.inc"
#undef DIAG_NAME_INDEX
- { 0, 0 }
+ { 0, 0, 0 }
};
static const unsigned StaticDiagNameIndexSize =
@@ -127,7 +165,7 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
#endif
// Search the diagnostic table with a binary search.
- StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 };
const StaticDiagInfoRec *Found =
std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
@@ -147,10 +185,10 @@ static unsigned GetDefaultDiagMapping(unsigned DiagID) {
/// getWarningOptionForDiag - Return the lowest-level warning option that
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
/// the diagnostic, this returns null.
-const char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
+llvm::StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->OptionGroup;
- return 0;
+ return Info->getOptionGroup();
+ return llvm::StringRef();
}
/// getCategoryNumberForDiag - Return the category number that a specified
@@ -161,23 +199,36 @@ unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
return 0;
}
-/// getCategoryNameFromID - Given a category ID, return the name of the
-/// category, an empty string if CategoryID is zero, or null if CategoryID is
-/// invalid.
-const char *DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
- // Second the table of options, sorted by name for fast binary lookup.
- static const char *CategoryNameTable[] = {
+// The diagnostic category names.
+struct StaticDiagCategoryRec {
+ const char *NameStr;
+ uint8_t NameLen;
+
+ llvm::StringRef getName() const {
+ return llvm::StringRef(NameStr, NameLen);
+ }
+};
+
+static StaticDiagCategoryRec CategoryNameTable[] = {
#define GET_CATEGORY_TABLE
-#define CATEGORY(X) X,
+#define CATEGORY(X) { X, STR_SIZE(X, uint8_t) },
#include "clang/Basic/DiagnosticGroups.inc"
#undef GET_CATEGORY_TABLE
- "<<END>>"
- };
- static const size_t CategoryNameTableSize =
- sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1;
-
- if (CategoryID >= CategoryNameTableSize) return 0;
- return CategoryNameTable[CategoryID];
+ { 0, 0 }
+};
+
+/// getNumberOfCategories - Return the number of categories
+unsigned DiagnosticIDs::getNumberOfCategories() {
+ return sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1;
+}
+
+/// getCategoryNameFromID - Given a category ID, return the name of the
+/// category, an empty string if CategoryID is zero, or null if CategoryID is
+/// invalid.
+llvm::StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
+ if (CategoryID >= getNumberOfCategories())
+ return llvm::StringRef();
+ return CategoryNameTable[CategoryID].getName();
}
@@ -202,25 +253,25 @@ DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
}
/// getName - Given a diagnostic ID, return its name
-const char *DiagnosticIDs::getName(unsigned DiagID) {
+llvm::StringRef DiagnosticIDs::getName(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->Name;
- return 0;
+ return Info->getName();
+ return llvm::StringRef();
}
/// getIdFromName - Given a diagnostic name, return its ID, or 0
-unsigned DiagnosticIDs::getIdFromName(char const *Name) {
+unsigned DiagnosticIDs::getIdFromName(llvm::StringRef Name) {
StaticDiagNameIndexRec *StaticDiagNameIndexEnd =
StaticDiagNameIndex + StaticDiagNameIndexSize;
- if (Name == 0) { return diag::DIAG_UPPER_LIMIT; }
+ if (Name.empty()) { return diag::DIAG_UPPER_LIMIT; }
- StaticDiagNameIndexRec Find = { Name, 0 };
+ StaticDiagNameIndexRec Find = { Name.data(), 0, Name.size() };
const StaticDiagNameIndexRec *Found =
std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find);
if (Found == StaticDiagNameIndexEnd ||
- strcmp(Found->Name, Name) != 0)
+ Found->getName() != Name)
return diag::DIAG_UPPER_LIMIT;
return Found->DiagID;
@@ -228,18 +279,18 @@ unsigned DiagnosticIDs::getIdFromName(char const *Name) {
/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
/// of the issue
-const char *DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
+llvm::StringRef DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->BriefExplanation;
- return 0;
+ return Info->getBriefExplanation();
+ return llvm::StringRef();
}
/// getFullExplanation - Given a diagnostic ID, return a full explanation
/// of the issue
-const char *DiagnosticIDs::getFullExplanation(unsigned DiagID) {
+llvm::StringRef DiagnosticIDs::getFullExplanation(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->FullExplanation;
- return 0;
+ return Info->getFullExplanation();
+ return llvm::StringRef();
}
/// getBuiltinDiagClass - Return the class field of the diagnostic.
@@ -264,10 +315,10 @@ namespace clang {
/// getDescription - Return the description of the specified custom
/// diagnostic.
- const char *getDescription(unsigned DiagID) const {
+ llvm::StringRef getDescription(unsigned DiagID) const {
assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
"Invalid diagnosic ID");
- return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str();
+ return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
}
/// getLevel - Return the level of the specified custom diagnostic.
@@ -352,9 +403,9 @@ bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
/// getDescription - Given a diagnostic ID, return a description of the
/// issue.
-const char *DiagnosticIDs::getDescription(unsigned DiagID) const {
+llvm::StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->Description;
+ return Info->getDescription();
return CustomDiagInfo->getDescription(DiagID);
}
@@ -493,9 +544,15 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
}
struct WarningOption {
- const char *Name;
+ // Be safe with the size of 'NameLen' because we don't statically check if the
+ // size will fit in the field; the struct size won't decrease with a shorter
+ // type anyway.
+ size_t NameLen;
+ const char *NameStr;
const short *Members;
const short *SubGroups;
+
+ llvm::StringRef getName() const { return llvm::StringRef(NameStr, NameLen); }
};
#define GET_DIAG_ARRAYS
@@ -513,7 +570,7 @@ sizeof(OptionTable) / sizeof(OptionTable[0]);
static bool WarningOptionCompare(const WarningOption &LHS,
const WarningOption &RHS) {
- return strcmp(LHS.Name, RHS.Name) < 0;
+ return LHS.getName() < RHS.getName();
}
static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
@@ -534,10 +591,10 @@ static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
/// "unknown-pragmas" to have the specified mapping. This returns true and
/// ignores the request if "Group" was unknown, false otherwise.
-bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group,
- diag::Mapping Map,
- SourceLocation Loc,
- Diagnostic &Diag) const {
+bool DiagnosticIDs::setDiagnosticGroupMapping(llvm::StringRef Group,
+ diag::Mapping Map,
+ SourceLocation Loc,
+ Diagnostic &Diag) const {
assert((Loc.isValid() ||
Diag.DiagStatePoints.empty() ||
Diag.DiagStatePoints.back().Loc.isInvalid()) &&
@@ -548,12 +605,12 @@ bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group,
Diag.DiagStatePoints.back().Loc)) &&
"Source location of new mapping is before the previous one!");
- WarningOption Key = { Group, 0, 0 };
+ WarningOption Key = { Group.size(), Group.data(), 0, 0 };
const WarningOption *Found =
std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
WarningOptionCompare);
if (Found == OptionTable + OptionTableSize ||
- strcmp(Found->Name, Group) != 0)
+ Found->getName() != Group)
return true; // Option not found.
MapGroupMembers(Found, Map, Loc, Diag);
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 4e5a129082f4..f747c534c0ed 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -264,10 +264,6 @@ void FileManager::addAncestorsAsVirtualDirs(llvm::StringRef Path) {
/// exist.
///
const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) {
- // stat doesn't like trailing separators (at least on Windows).
- if (DirName.size() > 1 && llvm::sys::path::is_separator(DirName.back()))
- DirName = DirName.substr(0, DirName.size()-1);
-
++NumDirLookups;
llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
SeenDirEntries.GetOrCreateValue(DirName);
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index cb1f55b75773..4711faa1a519 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -392,6 +392,7 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
if (name == "release") return OMF_release;
if (name == "retain") return OMF_retain;
if (name == "retainCount") return OMF_retainCount;
+ if (name == "self") return OMF_self;
}
// The other method families may begin with a prefix of underscores.
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index c3e03933e5e5..2de8ab7528ab 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -961,6 +961,12 @@ static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
/// about to emit a diagnostic.
unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
bool *Invalid) const {
+ if (FID.isInvalid()) {
+ if (Invalid)
+ *Invalid = true;
+ return 1;
+ }
+
ContentCache *Content;
if (LastLineNoFileIDQuery == FID)
Content = LastLineNoContentCache;
@@ -1207,6 +1213,73 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
return PresumedLoc(Filename, LineNo, ColNo, IncludeLoc);
}
+/// \brief Returns true if the given MacroID location points at the first
+/// token of the macro instantiation.
+bool SourceManager::isAtStartOfMacroInstantiation(SourceLocation loc) const {
+ assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
+
+ unsigned FID = getFileID(loc).ID;
+ assert(FID > 1);
+ std::pair<SourceLocation, SourceLocation>
+ instRange = getImmediateInstantiationRange(loc);
+
+ bool invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID-1, &invalid);
+ if (invalid)
+ return false;
+
+ // If the FileID immediately before it is a file then this is the first token
+ // in the macro.
+ if (Entry.isFile())
+ return true;
+
+ // If the FileID immediately before it (which is a macro token) is the
+ // immediate instantiated macro, check this macro token's location.
+ if (getFileID(instRange.second).ID == FID-1)
+ return isAtStartOfMacroInstantiation(instRange.first);
+
+ // If the FileID immediately before it (which is a macro token) came from a
+ // different instantiation, then this is the first token in the macro.
+ if (getInstantiationLoc(Entry.getInstantiation().getInstantiationLocStart())
+ != getInstantiationLoc(loc))
+ return true;
+
+ // It is inside the macro or the last token in the macro.
+ return false;
+}
+
+/// \brief Returns true if the given MacroID location points at the last
+/// token of the macro instantiation.
+bool SourceManager::isAtEndOfMacroInstantiation(SourceLocation loc) const {
+ assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
+
+ unsigned FID = getFileID(loc).ID;
+ assert(FID > 1);
+ std::pair<SourceLocation, SourceLocation>
+ instRange = getInstantiationRange(loc);
+
+ // If there's no FileID after it, it is the last token in the macro.
+ if (FID+1 == sloc_entry_size())
+ return true;
+
+ bool invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID+1, &invalid);
+ if (invalid)
+ return false;
+
+ // If the FileID immediately after it is a file or a macro token which
+ // came from a different instantiation, then this is the last token in the
+ // macro.
+ if (Entry.isFile())
+ return true;
+ if (getInstantiationLoc(Entry.getInstantiation().getInstantiationLocStart())
+ != instRange.first)
+ return true;
+
+ // It is inside the macro or the first token in the macro.
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Other miscellaneous methods.
//===----------------------------------------------------------------------===//
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 97109caf1237..dd167dca47b2 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -1121,7 +1121,7 @@ public:
}
virtual bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const;
- virtual std::string convertConstraint(const char Constraint) const;
+ virtual std::string convertConstraint(const char *&Constraint) const;
virtual const char *getClobbers() const {
return "~{dirflag},~{fpsr},~{flags}";
}
@@ -1180,7 +1180,7 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
else if (CPU == "corei7") {
setFeatureEnabled(Features, "sse4", true);
setFeatureEnabled(Features, "aes", true);
- } else if (CPU == "sandybridge") {
+ } else if (CPU == "corei7-avx") {
setFeatureEnabled(Features, "sse4", true);
setFeatureEnabled(Features, "aes", true);
// setFeatureEnabled(Features, "avx", true);
@@ -1449,8 +1449,8 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
std::string
-X86TargetInfo::convertConstraint(const char Constraint) const {
- switch (Constraint) {
+X86TargetInfo::convertConstraint(const char *&Constraint) const {
+ switch (*Constraint) {
case 'a': return std::string("{ax}");
case 'b': return std::string("{bx}");
case 'c': return std::string("{cx}");
@@ -1464,7 +1464,7 @@ X86TargetInfo::convertConstraint(const char Constraint) const {
case 'u': // second from top of floating point stack.
return std::string("{st(1)}"); // second from top of floating point stack.
default:
- return std::string(1, Constraint);
+ return std::string(1, *Constraint);
}
}
} // end anonymous namespace
@@ -1993,11 +1993,11 @@ public:
if (CPU == "xscale")
Builder.defineMacro("__XSCALE__");
- bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7"));
+ bool IsARMv7 = CPUArch.startswith("7");
if (IsThumb) {
Builder.defineMacro("__THUMBEL__");
Builder.defineMacro("__thumb__");
- if (IsThumb2)
+ if (CPUArch == "6T2" || IsARMv7)
Builder.defineMacro("__thumb2__");
}
@@ -2011,7 +2011,7 @@ public:
// the VFP define, hence the soft float and arch check. This is subtly
// different from gcc, we follow the intent which was that it should be set
// when Neon instructions are actually available.
- if (FPU == NeonFPU && !SoftFloat && IsThumb2)
+ if (FPU == NeonFPU && !SoftFloat && IsARMv7)
Builder.defineMacro("__ARM_NEON__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -2020,7 +2020,7 @@ public:
NumRecords = clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
virtual const char *getVAListDeclaration() const {
- return "typedef char* __builtin_va_list;";
+ return "typedef void* __builtin_va_list;";
}
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
@@ -2037,9 +2037,31 @@ public:
case 'P': // VFP Floating point register double precision
Info.setAllowsRegister();
return true;
+ case 'U': // a memory reference...
+ switch (Name[1]) {
+ case 'q': // ...ARMV4 ldrsb
+ case 'v': // ...VFP load/store (reg+constant offset)
+ case 'y': // ...iWMMXt load/store
+ Info.setAllowsMemory();
+ Name++;
+ return true;
+ }
}
return false;
}
+ std::string
+ virtual convertConstraint(const char *&Constraint) const {
+ std::string R;
+ switch (*Constraint) {
+ case 'U': // Two-character constraint; add "^" hint for later parsing.
+ R = std::string("^") + std::string(Constraint, 2);
+ Constraint++;
+ break;
+ default:
+ return std::string(1, *Constraint);
+ }
+ return R;
+ }
virtual const char *getClobbers() const {
// FIXME: Is this really right?
return "";
@@ -2531,7 +2553,9 @@ class MipsTargetInfo : public TargetInfo {
public:
MipsTargetInfo(const std::string& triple) : TargetInfo(triple), ABI("o32") {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
}
virtual const char *getABI() const { return ABI.c_str(); }
virtual bool setABI(const std::string &Name) {
@@ -2663,7 +2687,7 @@ class MipselTargetInfo : public MipsTargetInfo {
public:
MipselTargetInfo(const std::string& triple) : MipsTargetInfo(triple) {
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 0943e2b1c785..b4574344bc5f 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -13,4 +13,3 @@ add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
add_subdirectory(Index)
add_subdirectory(StaticAnalyzer)
-add_subdirectory(Tooling)
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 1264473dabce..01d15ff7f7fd 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -21,12 +21,11 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/StandardPasses.h"
+#include "llvm/Support/PassManagerBuilder.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
-#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegistry.h"
@@ -109,67 +108,62 @@ void EmitAssemblyHelper::CreatePasses() {
OptLevel = 0;
Inlining = CodeGenOpts.NoInlining;
}
-
- FunctionPassManager *FPM = getPerFunctionPasses();
-
- TargetLibraryInfo *TLI =
- new TargetLibraryInfo(Triple(TheModule->getTargetTriple()));
+
+ PassManagerBuilder PMBuilder;
+ PMBuilder.OptLevel = OptLevel;
+ PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
+
+ PMBuilder.DisableSimplifyLibCalls = !CodeGenOpts.SimplifyLibCalls;
+ PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime;
+ PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops;
+
+ // Figure out TargetLibraryInfo.
+ Triple TargetTriple(TheModule->getTargetTriple());
+ PMBuilder.LibraryInfo = new TargetLibraryInfo(TargetTriple);
if (!CodeGenOpts.SimplifyLibCalls)
- TLI->disableAllFunctions();
- FPM->add(TLI);
-
- // In -O0 if checking is disabled, we don't even have per-function passes.
- if (CodeGenOpts.VerifyModule)
- FPM->add(createVerifierPass());
-
- // Assume that standard function passes aren't run for -O0.
- if (OptLevel > 0)
- llvm::createStandardFunctionPasses(FPM, OptLevel);
-
- llvm::Pass *InliningPass = 0;
+ PMBuilder.LibraryInfo->disableAllFunctions();
+
switch (Inlining) {
case CodeGenOptions::NoInlining: break;
case CodeGenOptions::NormalInlining: {
- // Set the inline threshold following llvm-gcc.
- //
// FIXME: Derive these constants in a principled fashion.
unsigned Threshold = 225;
- if (CodeGenOpts.OptimizeSize == 1) //-Os
+ if (CodeGenOpts.OptimizeSize == 1) // -Os
Threshold = 75;
- else if (CodeGenOpts.OptimizeSize == 2) //-Oz
+ else if (CodeGenOpts.OptimizeSize == 2) // -Oz
Threshold = 25;
else if (OptLevel > 2)
Threshold = 275;
- InliningPass = createFunctionInliningPass(Threshold);
+ PMBuilder.Inliner = createFunctionInliningPass(Threshold);
break;
}
case CodeGenOptions::OnlyAlwaysInlining:
- InliningPass = createAlwaysInlinerPass(); // Respect always_inline
+ // Respect always_inline.
+ PMBuilder.Inliner = createAlwaysInlinerPass();
break;
}
- PassManager *MPM = getPerModulePasses();
+
+ // Set up the per-function pass manager.
+ FunctionPassManager *FPM = getPerFunctionPasses();
+ if (CodeGenOpts.VerifyModule)
+ FPM->add(createVerifierPass());
+ PMBuilder.populateFunctionPassManager(*FPM);
- TLI = new TargetLibraryInfo(Triple(TheModule->getTargetTriple()));
- if (!CodeGenOpts.SimplifyLibCalls)
- TLI->disableAllFunctions();
- MPM->add(TLI);
+ // Set up the per-module pass manager.
+ PassManager *MPM = getPerModulePasses();
if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) {
MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes,
- CodeGenOpts.EmitGcovArcs));
+ CodeGenOpts.EmitGcovArcs,
+ TargetTriple.isMacOSX()));
+
if (!CodeGenOpts.DebugInfo)
MPM->add(createStripSymbolsPass(true));
}
-
- // For now we always create per module passes.
- llvm::createStandardModulePasses(MPM, OptLevel,
- CodeGenOpts.OptimizeSize,
- CodeGenOpts.UnitAtATime,
- CodeGenOpts.UnrollLoops,
- CodeGenOpts.SimplifyLibCalls,
- /*HaveExceptions=*/true,
- InliningPass);
+
+
+ PMBuilder.populateModulePassManager(*MPM);
}
bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
@@ -215,7 +209,6 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
llvm::UnsafeFPMath = CodeGenOpts.UnsafeFPMath;
llvm::UseSoftFloat = CodeGenOpts.SoftFloat;
- UnwindTablesMandatory = CodeGenOpts.UnwindTables;
TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose);
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 99a69a4f4a93..e5da703a61b2 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -189,23 +189,6 @@ namespace {
}
}
-/// Determines if the given record type has a mutable field.
-static bool hasMutableField(const CXXRecordDecl *record) {
- for (CXXRecordDecl::field_iterator
- i = record->field_begin(), e = record->field_end(); i != e; ++i)
- if ((*i)->isMutable())
- return true;
-
- for (CXXRecordDecl::base_class_const_iterator
- i = record->bases_begin(), e = record->bases_end(); i != e; ++i) {
- const RecordType *record = i->getType()->castAs<RecordType>();
- if (hasMutableField(cast<CXXRecordDecl>(record->getDecl())))
- return true;
- }
-
- return false;
-}
-
/// Determines if the given type is safe for constant capture in C++.
static bool isSafeForCXXConstantCapture(QualType type) {
const RecordType *recordType =
@@ -222,7 +205,7 @@ static bool isSafeForCXXConstantCapture(QualType type) {
// Otherwise, we just have to make sure there aren't any mutable
// fields that might have changed since initialization.
- return !hasMutableField(record);
+ return !record->hasMutableFields();
}
/// It is illegal to modify a const object after initialization.
@@ -262,7 +245,7 @@ static CharUnits getLowBit(CharUnits v) {
}
static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
- std::vector<const llvm::Type*> &elementTypes) {
+ llvm::SmallVectorImpl<const llvm::Type*> &elementTypes) {
ASTContext &C = CGM.getContext();
// The header is basically a 'struct { void *; int; int; void *; void *; }'.
@@ -299,7 +282,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
ASTContext &C = CGM.getContext();
const BlockDecl *block = info.getBlockDecl();
- std::vector<const llvm::Type*> elementTypes;
+ llvm::SmallVector<const llvm::Type*, 8> elementTypes;
initializeForBlockHeader(CGM, info, elementTypes);
if (!block->hasCaptures()) {
@@ -321,7 +304,11 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
const DeclContext *DC = block->getDeclContext();
for (; isa<BlockDecl>(DC); DC = cast<BlockDecl>(DC)->getDeclContext())
;
- QualType thisType = cast<CXXMethodDecl>(DC)->getThisType(C);
+ QualType thisType;
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC))
+ thisType = C.getPointerType(C.getRecordType(RD));
+ else
+ thisType = cast<CXXMethodDecl>(DC)->getThisType(C);
const llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType);
std::pair<CharUnits,CharUnits> tinfo
@@ -720,9 +707,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
BlockLiteral = Builder.CreateBitCast(BlockLiteral, VoidPtrTy, "tmp");
// Add the block literal.
- QualType VoidPtrTy = getContext().getPointerType(getContext().VoidTy);
CallArgList Args;
- Args.add(RValue::get(BlockLiteral), VoidPtrTy);
+ Args.add(RValue::get(BlockLiteral), getContext().VoidPtrTy);
QualType FnType = BPT->getPointeeType();
@@ -1063,6 +1049,10 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
IdentifierInfo *II
= &CGM.getContext().Idents.get("__copy_helper_block_");
+ // Check if we should generate debug info for this block helper function.
+ if (CGM.getModuleDebugInfo())
+ DebugInfo = CGM.getModuleDebugInfo();
+
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
SourceLocation(),
@@ -1150,6 +1140,10 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__destroy_helper_block_", &CGM.getModule());
+ // Check if we should generate debug info for this block destroy function.
+ if (CGM.getModuleDebugInfo())
+ DebugInfo = CGM.getModuleDebugInfo();
+
IdentifierInfo *II
= &CGM.getContext().Idents.get("__destroy_helper_block_");
@@ -1508,29 +1502,29 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
QualType Ty = D->getType();
- std::vector<const llvm::Type *> Types;
+ llvm::SmallVector<const llvm::Type *, 8> types;
llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(getLLVMContext());
// void *__isa;
- Types.push_back(Int8PtrTy);
+ types.push_back(Int8PtrTy);
// void *__forwarding;
- Types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder));
+ types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder));
// int32_t __flags;
- Types.push_back(Int32Ty);
+ types.push_back(Int32Ty);
// int32_t __size;
- Types.push_back(Int32Ty);
+ types.push_back(Int32Ty);
bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty);
if (HasCopyAndDispose) {
/// void *__copy_helper;
- Types.push_back(Int8PtrTy);
+ types.push_back(Int8PtrTy);
/// void *__destroy_helper;
- Types.push_back(Int8PtrTy);
+ types.push_back(Int8PtrTy);
}
bool Packed = false;
@@ -1553,11 +1547,11 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
if (NumPaddingBytes > 0) {
const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext());
// FIXME: We need a sema error for alignment larger than the minimum of
- // the maximal stack alignmint and the alignment of malloc on the system.
+ // the maximal stack alignment and the alignment of malloc on the system.
if (NumPaddingBytes > 1)
Ty = llvm::ArrayType::get(Ty, NumPaddingBytes);
- Types.push_back(Ty);
+ types.push_back(Ty);
// We want a packed struct.
Packed = true;
@@ -1565,9 +1559,9 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
}
// T x;
- Types.push_back(ConvertTypeForMem(Ty));
+ types.push_back(ConvertTypeForMem(Ty));
- const llvm::Type *T = llvm::StructType::get(getLLVMContext(), Types, Packed);
+ const llvm::Type *T = llvm::StructType::get(getLLVMContext(), types, Packed);
cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T);
CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(),
@@ -1575,7 +1569,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
Info.first = ByRefTypeHolder.get();
- Info.second = Types.size() - 1;
+ Info.second = types.size() - 1;
return Info.first;
}
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 7a0c8da50248..14bebaf3c1cb 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -164,9 +164,8 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
}
// The prototype is something that takes and returns whatever V's type is.
- std::vector<const llvm::Type*> Args;
- Args.push_back(V->getType());
- llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), Args, false);
+ llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), V->getType(),
+ false);
llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName);
return CGF.Builder.CreateCall(Fn, V, "abs");
@@ -1186,6 +1185,41 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops.begin(), Ops.end());
}
+ if (BuiltinID == ARM::BI__builtin_arm_ldrexd) {
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_ldrexd);
+
+ Value *LdPtr = EmitScalarExpr(E->getArg(0));
+ Value *Val = Builder.CreateCall(F, LdPtr, "ldrexd");
+
+ Value *Val0 = Builder.CreateExtractValue(Val, 1);
+ Value *Val1 = Builder.CreateExtractValue(Val, 0);
+ Val0 = Builder.CreateZExt(Val0, Int64Ty);
+ Val1 = Builder.CreateZExt(Val1, Int64Ty);
+
+ Value *ShiftCst = llvm::ConstantInt::get(Int64Ty, 32);
+ Val = Builder.CreateShl(Val0, ShiftCst, "shl", true /* nuw */);
+ return Builder.CreateOr(Val, Val1);
+ }
+
+ if (BuiltinID == ARM::BI__builtin_arm_strexd) {
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_strexd);
+ llvm::Type *STy = llvm::StructType::get(getLLVMContext(), Int32Ty, Int32Ty,
+ NULL);
+
+ Value *One = llvm::ConstantInt::get(Int32Ty, 1);
+ Value *Tmp = Builder.CreateAlloca(Int64Ty, One, "tmp");
+ Value *Val = EmitScalarExpr(E->getArg(0));
+ Builder.CreateStore(Val, Tmp);
+
+ Value *LdPtr = Builder.CreateBitCast(Tmp,llvm::PointerType::getUnqual(STy));
+ Val = Builder.CreateLoad(LdPtr);
+
+ Value *Arg0 = Builder.CreateExtractValue(Val, 0);
+ Value *Arg1 = Builder.CreateExtractValue(Val, 1);
+ Value *StPtr = EmitScalarExpr(E->getArg(1));
+ return Builder.CreateCall3(F, Arg0, Arg1, StPtr, "strexd");
+ }
+
llvm::SmallVector<Value*, 4> Ops;
for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++)
Ops.push_back(EmitScalarExpr(E->getArg(i)));
@@ -2143,16 +2177,21 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
- case X86::BI__builtin_ia32_loaddqu: {
- const llvm::Type *VecTy = ConvertType(E->getType());
- const llvm::Type *IntTy = llvm::IntegerType::get(getLLVMContext(), 128);
+ case X86::BI__builtin_ia32_movntps:
+ case X86::BI__builtin_ia32_movntpd:
+ case X86::BI__builtin_ia32_movntdq:
+ case X86::BI__builtin_ia32_movnti: {
+ llvm::MDNode *Node = llvm::MDNode::get(getLLVMContext(),
+ Builder.getInt32(1));
+ // Convert the type of the pointer to a pointer to the stored type.
Value *BC = Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(IntTy),
+ llvm::PointerType::getUnqual(Ops[1]->getType()),
"cast");
- LoadInst *LI = Builder.CreateLoad(BC);
- LI->setAlignment(1); // Unaligned load.
- return Builder.CreateBitCast(LI, VecTy, "loadu.cast");
+ StoreInst *SI = Builder.CreateStore(Ops[1], BC);
+ SI->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
+ SI->setAlignment(16);
+ return SI;
}
// 3DNow!
case X86::BI__builtin_ia32_pavgusb:
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 184147cb728d..f6fc202eaae2 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -28,17 +28,6 @@
using namespace clang;
using namespace CodeGen;
-/// Determines whether the given function has a trivial body that does
-/// not require any specific codegen.
-static bool HasTrivialBody(const FunctionDecl *FD) {
- Stmt *S = FD->getBody();
- if (!S)
- return true;
- if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty())
- return true;
- return false;
-}
-
/// Try to emit a base destructor as an alias to its primary
/// base-class destructor.
bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
@@ -47,7 +36,7 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
// If the destructor doesn't have a trivial body, we have to emit it
// separately.
- if (!HasTrivialBody(D))
+ if (!D->hasTrivialBody())
return true;
const CXXRecordDecl *Class = D->getParent();
@@ -187,7 +176,10 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
// The constructor used for constructing this as a complete class;
// constucts the virtual bases, then calls the base constructor.
- EmitGlobal(GlobalDecl(D, Ctor_Complete));
+ if (!D->getParent()->isAbstract()) {
+ // We don't need to emit the complete ctor if the class is abstract.
+ EmitGlobal(GlobalDecl(D, Ctor_Complete));
+ }
// The constructor used for constructing this as a base class;
// ignores virtual bases.
@@ -244,7 +236,11 @@ void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
// The destructor used for destructing this as a most-derived class;
// call the base destructor and then destructs any virtual bases.
- EmitGlobal(GlobalDecl(D, Dtor_Complete));
+ if (!D->getParent()->isAbstract() || D->isVirtual()) {
+ // We don't need to emit the complete ctor if the class is abstract,
+ // unless the destructor is virtual and needs to be in the vtable.
+ EmitGlobal(GlobalDecl(D, Dtor_Complete));
+ }
// The destructor used for destructing this as a base class; ignores
// virtual bases.
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index a765f0f3439a..712ae89a4888 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -309,10 +309,10 @@ CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
/***/
-void CodeGenTypes::GetExpandedTypes(QualType Ty,
- std::vector<const llvm::Type*> &ArgTys,
- bool IsRecursive) {
- const RecordType *RT = Ty->getAsStructureType();
+void CodeGenTypes::GetExpandedTypes(QualType type,
+ llvm::SmallVectorImpl<const llvm::Type*> &expandedTypes,
+ bool isRecursive) {
+ const RecordType *RT = type->getAsStructureType();
assert(RT && "Can only expand structure types.");
const RecordDecl *RD = RT->getDecl();
assert(!RD->hasFlexibleArrayMember() &&
@@ -324,11 +324,11 @@ void CodeGenTypes::GetExpandedTypes(QualType Ty,
assert(!FD->isBitField() &&
"Cannot expand structure with bit-field members.");
- QualType FT = FD->getType();
- if (CodeGenFunction::hasAggregateLLVMType(FT))
- GetExpandedTypes(FT, ArgTys, IsRecursive);
+ QualType fieldType = FD->getType();
+ if (fieldType->isRecordType())
+ GetExpandedTypes(fieldType, expandedTypes, isRecursive);
else
- ArgTys.push_back(ConvertType(FT, IsRecursive));
+ expandedTypes.push_back(ConvertType(fieldType, isRecursive));
}
}
@@ -513,6 +513,29 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
return CGF.Builder.CreateLoad(Tmp);
}
+// Function to store a first-class aggregate into memory. We prefer to
+// store the elements rather than the aggregate to be more friendly to
+// fast-isel.
+// FIXME: Do we need to recurse here?
+static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val,
+ llvm::Value *DestPtr, bool DestIsVolatile,
+ bool LowAlignment) {
+ // Prefer scalar stores to first-class aggregate stores.
+ if (const llvm::StructType *STy =
+ dyn_cast<llvm::StructType>(Val->getType())) {
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+ llvm::Value *EltPtr = CGF.Builder.CreateConstGEP2_32(DestPtr, 0, i);
+ llvm::Value *Elt = CGF.Builder.CreateExtractValue(Val, i);
+ llvm::StoreInst *SI = CGF.Builder.CreateStore(Elt, EltPtr,
+ DestIsVolatile);
+ if (LowAlignment)
+ SI->setAlignment(1);
+ }
+ } else {
+ CGF.Builder.CreateStore(Val, DestPtr, DestIsVolatile);
+ }
+}
+
/// CreateCoercedStore - Create a store to \arg DstPtr from \arg Src,
/// where the source and destination may have different types.
///
@@ -553,7 +576,7 @@ static void CreateCoercedStore(llvm::Value *Src,
llvm::Value *Casted =
CGF.Builder.CreateBitCast(DstPtr, llvm::PointerType::getUnqual(SrcTy));
// FIXME: Use better alignment / avoid requiring aligned store.
- CGF.Builder.CreateStore(Src, Casted, DstIsVolatile)->setAlignment(1);
+ BuildAggStore(CGF, Src, Casted, DstIsVolatile, true);
} else {
// Otherwise do coercion through memory. This is stupid, but
// simple.
@@ -612,49 +635,49 @@ const llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
}
const llvm::FunctionType *
-CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic,
- bool IsRecursive) {
- std::vector<const llvm::Type*> ArgTys;
+CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic,
+ bool isRecursive) {
+ llvm::SmallVector<const llvm::Type*, 8> argTypes;
+ const llvm::Type *resultType = 0;
- const llvm::Type *ResultType = 0;
-
- QualType RetTy = FI.getReturnType();
- const ABIArgInfo &RetAI = FI.getReturnInfo();
- switch (RetAI.getKind()) {
+ const ABIArgInfo &retAI = FI.getReturnInfo();
+ switch (retAI.getKind()) {
case ABIArgInfo::Expand:
- assert(0 && "Invalid ABI kind for return argument");
+ llvm_unreachable("Invalid ABI kind for return argument");
case ABIArgInfo::Extend:
case ABIArgInfo::Direct:
- ResultType = RetAI.getCoerceToType();
+ resultType = retAI.getCoerceToType();
break;
case ABIArgInfo::Indirect: {
- assert(!RetAI.getIndirectAlign() && "Align unused on indirect return.");
- ResultType = llvm::Type::getVoidTy(getLLVMContext());
- const llvm::Type *STy = ConvertType(RetTy, IsRecursive);
- unsigned AS = Context.getTargetAddressSpace(RetTy);
- ArgTys.push_back(llvm::PointerType::get(STy, AS));
+ assert(!retAI.getIndirectAlign() && "Align unused on indirect return.");
+ resultType = llvm::Type::getVoidTy(getLLVMContext());
+
+ QualType ret = FI.getReturnType();
+ const llvm::Type *ty = ConvertType(ret, isRecursive);
+ unsigned addressSpace = Context.getTargetAddressSpace(ret);
+ argTypes.push_back(llvm::PointerType::get(ty, addressSpace));
break;
}
case ABIArgInfo::Ignore:
- ResultType = llvm::Type::getVoidTy(getLLVMContext());
+ resultType = llvm::Type::getVoidTy(getLLVMContext());
break;
}
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
ie = FI.arg_end(); it != ie; ++it) {
- const ABIArgInfo &AI = it->info;
+ const ABIArgInfo &argAI = it->info;
- switch (AI.getKind()) {
+ switch (argAI.getKind()) {
case ABIArgInfo::Ignore:
break;
case ABIArgInfo::Indirect: {
// indirect arguments are always on the stack, which is addr space #0.
- const llvm::Type *LTy = ConvertTypeForMem(it->type, IsRecursive);
- ArgTys.push_back(llvm::PointerType::getUnqual(LTy));
+ const llvm::Type *LTy = ConvertTypeForMem(it->type, isRecursive);
+ argTypes.push_back(LTy->getPointerTo());
break;
}
@@ -663,23 +686,23 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic,
// If the coerce-to type is a first class aggregate, flatten it. Either
// way is semantically identical, but fast-isel and the optimizer
// generally likes scalar values better than FCAs.
- const llvm::Type *ArgTy = AI.getCoerceToType();
- if (const llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgTy)) {
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
- ArgTys.push_back(STy->getElementType(i));
+ const llvm::Type *argType = argAI.getCoerceToType();
+ if (const llvm::StructType *st = dyn_cast<llvm::StructType>(argType)) {
+ for (unsigned i = 0, e = st->getNumElements(); i != e; ++i)
+ argTypes.push_back(st->getElementType(i));
} else {
- ArgTys.push_back(ArgTy);
+ argTypes.push_back(argType);
}
break;
}
case ABIArgInfo::Expand:
- GetExpandedTypes(it->type, ArgTys, IsRecursive);
+ GetExpandedTypes(it->type, argTypes, isRecursive);
break;
}
}
- return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic);
+ return llvm::FunctionType::get(resultType, argTypes, isVariadic);
}
const llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
@@ -786,9 +809,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
// sense to do it here because parameters are so messed up.
switch (AI.getKind()) {
case ABIArgInfo::Extend:
- if (ParamType->isSignedIntegerType())
+ if (ParamType->isSignedIntegerOrEnumerationType())
Attributes |= llvm::Attribute::SExt;
- else if (ParamType->isUnsignedIntegerType())
+ else if (ParamType->isUnsignedIntegerOrEnumerationType())
Attributes |= llvm::Attribute::ZExt;
// FALL THROUGH
case ABIArgInfo::Direct:
@@ -822,12 +845,12 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
continue;
case ABIArgInfo::Expand: {
- std::vector<const llvm::Type*> Tys;
+ llvm::SmallVector<const llvm::Type*, 8> types;
// FIXME: This is rather inefficient. Do we ever actually need to do
// anything here? The result should be just reconstructed on the other
// side, so extension should be a non-issue.
- getTypes().GetExpandedTypes(ParamType, Tys, false);
- Index += Tys.size();
+ getTypes().GetExpandedTypes(ParamType, types, false);
+ Index += types.size();
continue;
}
}
@@ -1166,6 +1189,15 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0),
type);
+ if (hasAggregateLLVMType(type) && isa<ImplicitCastExpr>(E) &&
+ cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
+ LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
+ assert(L.isSimple());
+ args.add(RValue::getAggregate(L.getAddress(), L.isVolatileQualified()),
+ type, /*NeedsCopy*/true);
+ return;
+ }
+
args.add(EmitAnyExprToTemp(E), type);
}
@@ -1231,6 +1263,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Alignment, I->Ty);
else
StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
+ } else if (I->NeedsCopy && !ArgInfo.getIndirectByVal()) {
+ Args.push_back(CreateMemTemp(I->Ty));
+ EmitAggregateCopy(Args.back(), RV.getAggregateAddr(), I->Ty,
+ RV.isVolatileQualified());
} else {
Args.push_back(RV.getAggregateAddr());
}
@@ -1409,7 +1445,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
}
- Builder.CreateStore(CI, DestPtr, DestIsVolatile);
+ BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false);
return RValue::getAggregate(DestPtr);
}
return RValue::get(CI);
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 3f600c04e59d..160a62eab367 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -47,8 +47,9 @@ namespace CodeGen {
struct CallArg {
RValue RV;
QualType Ty;
- CallArg(RValue rv, QualType ty)
- : RV(rv), Ty(ty)
+ bool NeedsCopy;
+ CallArg(RValue rv, QualType ty, bool needscopy)
+ : RV(rv), Ty(ty), NeedsCopy(needscopy)
{ }
};
@@ -57,8 +58,8 @@ namespace CodeGen {
class CallArgList :
public llvm::SmallVector<CallArg, 16> {
public:
- void add(RValue rvalue, QualType type) {
- push_back(CallArg(rvalue, type));
+ void add(RValue rvalue, QualType type, bool needscopy = false) {
+ push_back(CallArg(rvalue, type, needscopy));
}
};
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index ca8b6576c7ad..5725d80b7d03 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -520,6 +520,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
FunctionArgList &Args) {
assert(MemberInit->isAnyMemberInitializer() &&
"Must have member initializer!");
+ assert(MemberInit->getInit() && "Must have initializer!");
// non-static data member initializers.
FieldDecl *Field = MemberInit->getAnyMember();
@@ -726,12 +727,13 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
B != E; ++B) {
CXXCtorInitializer *Member = (*B);
- if (Member->isBaseInitializer())
+ if (Member->isBaseInitializer()) {
EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
- else if (Member->isAnyMemberInitializer())
+ } else {
+ assert(Member->isAnyMemberInitializer() &&
+ "Delegating initializer on non-delegating constructor");
MemberInitializers.push_back(Member);
- else
- llvm_unreachable("Delegating initializer on non-delegating constructor");
+ }
}
InitializeVTablePointers(ClassDecl);
@@ -740,6 +742,94 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args);
}
+static bool
+FieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field);
+
+static bool
+HasTrivialDestructorBody(ASTContext &Context,
+ const CXXRecordDecl *BaseClassDecl,
+ const CXXRecordDecl *MostDerivedClassDecl)
+{
+ // If the destructor is trivial we don't have to check anything else.
+ if (BaseClassDecl->hasTrivialDestructor())
+ return true;
+
+ if (!BaseClassDecl->getDestructor()->hasTrivialBody())
+ return false;
+
+ // Check fields.
+ for (CXXRecordDecl::field_iterator I = BaseClassDecl->field_begin(),
+ E = BaseClassDecl->field_end(); I != E; ++I) {
+ const FieldDecl *Field = *I;
+
+ if (!FieldHasTrivialDestructorBody(Context, Field))
+ return false;
+ }
+
+ // Check non-virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I =
+ BaseClassDecl->bases_begin(), E = BaseClassDecl->bases_end();
+ I != E; ++I) {
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *NonVirtualBase =
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ if (!HasTrivialDestructorBody(Context, NonVirtualBase,
+ MostDerivedClassDecl))
+ return false;
+ }
+
+ if (BaseClassDecl == MostDerivedClassDecl) {
+ // Check virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I =
+ BaseClassDecl->vbases_begin(), E = BaseClassDecl->vbases_end();
+ I != E; ++I) {
+ const CXXRecordDecl *VirtualBase =
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ if (!HasTrivialDestructorBody(Context, VirtualBase,
+ MostDerivedClassDecl))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool
+FieldHasTrivialDestructorBody(ASTContext &Context,
+ const FieldDecl *Field)
+{
+ QualType FieldBaseElementType = Context.getBaseElementType(Field->getType());
+
+ const RecordType *RT = FieldBaseElementType->getAs<RecordType>();
+ if (!RT)
+ return true;
+
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl);
+}
+
+/// CanSkipVTablePointerInitialization - Check whether we need to initialize
+/// any vtable pointers before calling this destructor.
+static bool CanSkipVTablePointerInitialization(ASTContext &Context,
+ const CXXDestructorDecl *Dtor) {
+ if (!Dtor->hasTrivialBody())
+ return false;
+
+ // Check the fields.
+ const CXXRecordDecl *ClassDecl = Dtor->getParent();
+ for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); I != E; ++I) {
+ const FieldDecl *Field = *I;
+
+ if (!FieldHasTrivialDestructorBody(Context, Field))
+ return false;
+ }
+
+ return true;
+}
+
/// EmitDestructorBody - Emits the body of the current destructor.
void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl());
@@ -791,7 +881,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
EnterDtorCleanups(Dtor, Dtor_Base);
// Initialize the vtable pointers before entering the body.
- InitializeVTablePointers(Dtor->getParent());
+ if (!CanSkipVTablePointerInitialization(getContext(), Dtor))
+ InitializeVTablePointers(Dtor->getParent());
if (isTryBody)
EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock());
@@ -1269,6 +1360,23 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
ReturnValueSlot(), DelegateArgs, Ctor);
}
+namespace {
+ struct CallDelegatingCtorDtor : EHScopeStack::Cleanup {
+ const CXXDestructorDecl *Dtor;
+ llvm::Value *Addr;
+ CXXDtorType Type;
+
+ CallDelegatingCtorDtor(const CXXDestructorDecl *D, llvm::Value *Addr,
+ CXXDtorType Type)
+ : Dtor(D), Addr(Addr), Type(Type) {}
+
+ void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
+ Addr);
+ }
+ };
+}
+
void
CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
const FunctionArgList &Args) {
@@ -1279,8 +1387,17 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true);
EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
-}
+ const CXXRecordDecl *ClassDecl = Ctor->getParent();
+ if (CGM.getLangOptions().Exceptions && !ClassDecl->hasTrivialDestructor()) {
+ CXXDtorType Type =
+ CurGD.getCtorType() == Ctor_Complete ? Dtor_Complete : Dtor_Base;
+
+ EHStack.pushCleanup<CallDelegatingCtorDtor>(EHCleanup,
+ ClassDecl->getDestructor(),
+ ThisPtr, Type);
+ }
+}
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
@@ -1494,3 +1611,136 @@ llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This,
llvm::Value *VTablePtrSrc = Builder.CreateBitCast(This, Ty->getPointerTo());
return Builder.CreateLoad(VTablePtrSrc, "vtable");
}
+
+static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) {
+ const Expr *E = Base;
+
+ while (true) {
+ E = E->IgnoreParens();
+ if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
+ if (CE->getCastKind() == CK_DerivedToBase ||
+ CE->getCastKind() == CK_UncheckedDerivedToBase ||
+ CE->getCastKind() == CK_NoOp) {
+ E = CE->getSubExpr();
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ QualType DerivedType = E->getType();
+ if (const PointerType *PTy = DerivedType->getAs<PointerType>())
+ DerivedType = PTy->getPointeeType();
+
+ return cast<CXXRecordDecl>(DerivedType->castAs<RecordType>()->getDecl());
+}
+
+// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do
+// quite what we want.
+static const Expr *skipNoOpCastsAndParens(const Expr *E) {
+ while (true) {
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
+ E = PE->getSubExpr();
+ continue;
+ }
+
+ if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
+ if (CE->getCastKind() == CK_NoOp) {
+ E = CE->getSubExpr();
+ continue;
+ }
+ }
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (UO->getOpcode() == UO_Extension) {
+ E = UO->getSubExpr();
+ continue;
+ }
+ }
+ return E;
+ }
+}
+
+/// canDevirtualizeMemberFunctionCall - Checks whether the given virtual member
+/// function call on the given expr can be devirtualized.
+/// expr can be devirtualized.
+static bool canDevirtualizeMemberFunctionCall(const Expr *Base,
+ const CXXMethodDecl *MD) {
+ // If the most derived class is marked final, we know that no subclass can
+ // override this member function and so we can devirtualize it. For example:
+ //
+ // struct A { virtual void f(); }
+ // struct B final : A { };
+ //
+ // void f(B *b) {
+ // b->f();
+ // }
+ //
+ const CXXRecordDecl *MostDerivedClassDecl = getMostDerivedClassDecl(Base);
+ if (MostDerivedClassDecl->hasAttr<FinalAttr>())
+ return true;
+
+ // If the member function is marked 'final', we know that it can't be
+ // overridden and can therefore devirtualize it.
+ if (MD->hasAttr<FinalAttr>())
+ return true;
+
+ // Similarly, if the class itself is marked 'final' it can't be overridden
+ // and we can therefore devirtualize the member function call.
+ if (MD->getParent()->hasAttr<FinalAttr>())
+ return true;
+
+ Base = skipNoOpCastsAndParens(Base);
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ // This is a record decl. We know the type and can devirtualize it.
+ return VD->getType()->isRecordType();
+ }
+
+ return false;
+ }
+
+ // We can always devirtualize calls on temporary object expressions.
+ if (isa<CXXConstructExpr>(Base))
+ return true;
+
+ // And calls on bound temporaries.
+ if (isa<CXXBindTemporaryExpr>(Base))
+ return true;
+
+ // Check if this is a call expr that returns a record type.
+ if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
+ return CE->getCallReturnType()->isRecordType();
+
+ // We can't devirtualize the call.
+ return false;
+}
+
+static bool UseVirtualCall(ASTContext &Context,
+ const CXXOperatorCallExpr *CE,
+ const CXXMethodDecl *MD) {
+ if (!MD->isVirtual())
+ return false;
+
+ // When building with -fapple-kext, all calls must go through the vtable since
+ // the kernel linker can do runtime patching of vtables.
+ if (Context.getLangOptions().AppleKext)
+ return true;
+
+ return !canDevirtualizeMemberFunctionCall(CE->getArg(0), MD);
+}
+
+llvm::Value *
+CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
+ const CXXMethodDecl *MD,
+ llvm::Value *This) {
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+
+ if (UseVirtualCall(getContext(), E, MD))
+ return BuildVirtualCall(MD, This, Ty);
+
+ return CGM.GetAddrOfFunction(MD, Ty);
+}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index f2e1c024dd05..98d30db647d5 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -335,10 +335,12 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break;
case BuiltinType::UShort:
case BuiltinType::UInt:
+ case BuiltinType::UInt128:
case BuiltinType::ULong:
case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break;
case BuiltinType::Short:
case BuiltinType::Int:
+ case BuiltinType::Int128:
case BuiltinType::Long:
case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break;
case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break;
@@ -553,9 +555,12 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
// We don't set size information, but do specify where the typedef was
// declared.
unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
- llvm::DIType DbgTy = DBuilder.createTypedef(Src, Ty->getDecl()->getName(),
- Unit, Line);
- return DbgTy;
+ const TypedefNameDecl *TyDecl = Ty->getDecl();
+ llvm::DIDescriptor TydefContext =
+ getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
+
+ return
+ DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TydefContext);
}
llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
@@ -628,8 +633,7 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
FieldDecl *field = *I;
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are ignored
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD) ||
- CGM.getContext().ZeroBitfieldFollowsBitfield((field), LastFD)) {
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) {
--fieldNo;
continue;
}
@@ -1240,9 +1244,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+ unsigned Flags = 0;
+ if (ID->getImplementation())
+ Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
+
llvm::DIType RealDecl =
DBuilder.createStructType(Unit, ID->getName(), DefUnit,
- Line, Size, Align, 0,
+ Line, Size, Align, Flags,
Elements, RuntimeLang);
// Now that we have a real decl for the struct, replace anything using the
@@ -1439,6 +1447,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
case Type::Decltype:
T = cast<DecltypeType>(T)->getUnderlyingType();
break;
+ case Type::UnaryTransform:
+ T = cast<UnaryTransformType>(T)->getUnderlyingType();
+ break;
case Type::Attributed:
T = cast<AttributedType>(T)->getEquivalentType();
break;
@@ -1554,6 +1565,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
+ case Type::UnaryTransform:
case Type::Auto:
llvm_unreachable("type should have been unwrapped!");
return llvm::DIType();
@@ -1612,6 +1624,33 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
return llvm::DISubprogram();
}
+// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include
+// implicit parameter "this".
+llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D, QualType FnType,
+ llvm::DIFile F) {
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ return getOrCreateMethodType(Method, F);
+ else if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) {
+ // Add "self" and "_cmd"
+ llvm::SmallVector<llvm::Value *, 16> Elts;
+
+ // First element is always return type. For 'void' functions it is NULL.
+ Elts.push_back(getOrCreateType(OMethod->getResultType(), F));
+ // "self" pointer is always first argument.
+ Elts.push_back(getOrCreateType(OMethod->getSelfDecl()->getType(), F));
+ // "cmd" pointer is always second argument.
+ Elts.push_back(getOrCreateType(OMethod->getCmdDecl()->getType(), F));
+ // Get rest of the arguments.
+ for (ObjCMethodDecl::param_iterator PI = OMethod->param_begin(),
+ PE = OMethod->param_end(); PI != PE; ++PI)
+ Elts.push_back(getOrCreateType((*PI)->getType(), F));
+
+ llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
+ return DBuilder.createSubroutineType(F, EltTypeArray);
+ }
+ return getOrCreateType(FnType, F);
+}
+
/// EmitFunctionStart - Constructs the debug code for entering a function -
/// "llvm.dbg.func.start.".
void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
@@ -1644,7 +1683,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
}
Name = getFunctionName(FD);
// Use mangled name as linkage name for c/c++ functions.
- LinkageName = CGM.getMangledName(GD);
+ if (!Fn->hasInternalLinkage())
+ LinkageName = CGM.getMangledName(GD);
if (LinkageName == Name)
LinkageName = llvm::StringRef();
if (FD->hasPrototype())
@@ -1652,6 +1692,9 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (const NamespaceDecl *NSDecl =
dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNameSpace(NSDecl);
+ else if (const RecordDecl *RDecl =
+ dyn_cast_or_null<RecordDecl>(FD->getDeclContext()))
+ FDContext = getContextDescriptor(cast<Decl>(RDecl->getDeclContext()));
// Collect template parameters.
TParamsArray = CollectFunctionTemplateParams(FD, Unit);
@@ -1672,11 +1715,10 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
unsigned LineNo = getLineNumber(CurLoc);
if (D->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
- llvm::DIType SPTy = getOrCreateType(FnType, Unit);
llvm::DISubprogram SPDecl = getFunctionDeclaration(D);
llvm::DISubprogram SP =
DBuilder.createFunction(FDContext, Name, LinkageName, Unit,
- LineNo, SPTy,
+ LineNo, getOrCreateFunctionType(D, FnType, Unit),
Fn->hasInternalLinkage(), true/*definition*/,
Flags, CGM.getLangOptions().Optimize, Fn,
TParamsArray, SPDecl);
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 27d991bbee42..6ec6b65f5e01 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -98,6 +98,8 @@ class CGDebugInfo {
llvm::DIType CreateEnumType(const EnumDecl *ED);
llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile F);
+ llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType,
+ llvm::DIFile F);
llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F);
llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N);
llvm::DIType CreatePointeeType(QualType PointeeTy, llvm::DIFile F);
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index c02737581814..8a1a8536dab1 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -51,6 +51,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::ImplicitParam:
case Decl::ClassTemplate:
case Decl::FunctionTemplate:
+ case Decl::TypeAliasTemplate:
case Decl::TemplateTemplateParm:
case Decl::ObjCMethod:
case Decl::ObjCCategory:
@@ -628,15 +629,14 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
emission.Address = DeclPtr;
// Emit debug info for local var declaration.
- if (CGDebugInfo *DI = getDebugInfo()) {
- assert(HaveInsertPoint() && "Unexpected unreachable point!");
-
- DI->setLocation(D.getLocation());
- if (Target.useGlobalsForAutomaticVariables()) {
- DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), &D);
- } else
- DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
- }
+ if (HaveInsertPoint())
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ DI->setLocation(D.getLocation());
+ if (Target.useGlobalsForAutomaticVariables()) {
+ DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), &D);
+ } else
+ DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
+ }
return emission;
}
@@ -741,6 +741,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
llvm::GlobalValue::InternalLinkage,
constant, Name, 0, false, 0);
GV->setAlignment(alignment.getQuantity());
+ GV->setUnnamedAddr(true);
llvm::Value *SrcPtr = GV;
if (SrcPtr->getType() != BP)
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 45b0b969be67..178badd44d81 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -117,19 +117,13 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
return;
}
- std::vector<const llvm::Type *> Params;
- Params.push_back(Int8PtrTy);
-
// Get the destructor function type
const llvm::Type *DtorFnTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
- Params, false);
+ Int8PtrTy, false);
DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
- Params.clear();
- Params.push_back(DtorFnTy);
- Params.push_back(Int8PtrTy);
- Params.push_back(Int8PtrTy);
+ const llvm::Type *Params[] = { DtorFnTy, Int8PtrTy, Int8PtrTy };
// Get the __cxa_atexit function type
// extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
@@ -248,6 +242,8 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
&CXXGlobalInits[0],
CXXGlobalInits.size());
AddGlobalCtor(Fn);
+ CXXGlobalInits.clear();
+ PrioritizedCXXGlobalInits.clear();
}
void CodeGenModule::EmitCXXGlobalDtorFunc() {
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 6cb9599e257d..e8ad6da2f980 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -112,11 +112,18 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
+llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
+
+ if (CGM.getLangOptions().SjLjExceptions)
+ return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
+ return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume");
+}
+
llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Int8PtrTy,
- /*IsVarArgs=*/false);
+ llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
if (CGM.getLangOptions().SjLjExceptions)
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow");
@@ -354,13 +361,17 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e,
}
llvm::Value *CodeGenFunction::getExceptionSlot() {
- if (!ExceptionSlot) {
- const llvm::Type *i8p = llvm::Type::getInt8PtrTy(getLLVMContext());
- ExceptionSlot = CreateTempAlloca(i8p, "exn.slot");
- }
+ if (!ExceptionSlot)
+ ExceptionSlot = CreateTempAlloca(Int8PtrTy, "exn.slot");
return ExceptionSlot;
}
+llvm::Value *CodeGenFunction::getEHSelectorSlot() {
+ if (!EHSelectorSlot)
+ EHSelectorSlot = CreateTempAlloca(Int32Ty, "ehselector.slot");
+ return EHSelectorSlot;
+}
+
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
if (!E->getSubExpr()) {
if (getInvokeDest()) {
@@ -563,47 +574,59 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() {
return LP;
}
+// This code contains a hack to work around a design flaw in
+// LLVM's EH IR which breaks semantics after inlining. This same
+// hack is implemented in llvm-gcc.
+//
+// The LLVM EH abstraction is basically a thin veneer over the
+// traditional GCC zero-cost design: for each range of instructions
+// in the function, there is (at most) one "landing pad" with an
+// associated chain of EH actions. A language-specific personality
+// function interprets this chain of actions and (1) decides whether
+// or not to resume execution at the landing pad and (2) if so,
+// provides an integer indicating why it's stopping. In LLVM IR,
+// the association of a landing pad with a range of instructions is
+// achieved via an invoke instruction, the chain of actions becomes
+// the arguments to the @llvm.eh.selector call, and the selector
+// call returns the integer indicator. Other than the required
+// presence of two intrinsic function calls in the landing pad,
+// the IR exactly describes the layout of the output code.
+//
+// A principal advantage of this design is that it is completely
+// language-agnostic; in theory, the LLVM optimizers can treat
+// landing pads neutrally, and targets need only know how to lower
+// the intrinsics to have a functioning exceptions system (assuming
+// that platform exceptions follow something approximately like the
+// GCC design). Unfortunately, landing pads cannot be combined in a
+// language-agnostic way: given selectors A and B, there is no way
+// to make a single landing pad which faithfully represents the
+// semantics of propagating an exception first through A, then
+// through B, without knowing how the personality will interpret the
+// (lowered form of the) selectors. This means that inlining has no
+// choice but to crudely chain invokes (i.e., to ignore invokes in
+// the inlined function, but to turn all unwindable calls into
+// invokes), which is only semantically valid if every unwind stops
+// at every landing pad.
+//
+// Therefore, the invoke-inline hack is to guarantee that every
+// landing pad has a catch-all.
+enum CleanupHackLevel_t {
+ /// A level of hack that requires that all landing pads have
+ /// catch-alls.
+ CHL_MandatoryCatchall,
+
+ /// A level of hack that requires that all landing pads handle
+ /// cleanups.
+ CHL_MandatoryCleanup,
+
+ /// No hacks at all; ideal IR generation.
+ CHL_Ideal
+};
+const CleanupHackLevel_t CleanupHackLevel = CHL_MandatoryCleanup;
+
llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
assert(EHStack.requiresLandingPad());
- // This function contains a hack to work around a design flaw in
- // LLVM's EH IR which breaks semantics after inlining. This same
- // hack is implemented in llvm-gcc.
- //
- // The LLVM EH abstraction is basically a thin veneer over the
- // traditional GCC zero-cost design: for each range of instructions
- // in the function, there is (at most) one "landing pad" with an
- // associated chain of EH actions. A language-specific personality
- // function interprets this chain of actions and (1) decides whether
- // or not to resume execution at the landing pad and (2) if so,
- // provides an integer indicating why it's stopping. In LLVM IR,
- // the association of a landing pad with a range of instructions is
- // achieved via an invoke instruction, the chain of actions becomes
- // the arguments to the @llvm.eh.selector call, and the selector
- // call returns the integer indicator. Other than the required
- // presence of two intrinsic function calls in the landing pad,
- // the IR exactly describes the layout of the output code.
- //
- // A principal advantage of this design is that it is completely
- // language-agnostic; in theory, the LLVM optimizers can treat
- // landing pads neutrally, and targets need only know how to lower
- // the intrinsics to have a functioning exceptions system (assuming
- // that platform exceptions follow something approximately like the
- // GCC design). Unfortunately, landing pads cannot be combined in a
- // language-agnostic way: given selectors A and B, there is no way
- // to make a single landing pad which faithfully represents the
- // semantics of propagating an exception first through A, then
- // through B, without knowing how the personality will interpret the
- // (lowered form of the) selectors. This means that inlining has no
- // choice but to crudely chain invokes (i.e., to ignore invokes in
- // the inlined function, but to turn all unwindable calls into
- // invokes), which is only semantically valid if every unwind stops
- // at every landing pad.
- //
- // Therefore, the invoke-inline hack is to guarantee that every
- // landing pad has a catch-all.
- const bool UseInvokeInlineHack = true;
-
for (EHScopeStack::iterator ir = EHStack.begin(); ; ) {
assert(ir != EHStack.end() &&
"stack requiring landing pad is nothing but non-EH scopes?");
@@ -736,16 +759,23 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
EHSelector.append(EHFilters.begin(), EHFilters.end());
// Also check whether we need a cleanup.
- if (UseInvokeInlineHack || HasEHCleanup)
- EHSelector.push_back(UseInvokeInlineHack
+ if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup)
+ EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall
? getCatchAllValue(*this)
: getCleanupValue(*this));
// Otherwise, signal that we at least have cleanups.
- } else if (UseInvokeInlineHack || HasEHCleanup) {
- EHSelector.push_back(UseInvokeInlineHack
+ } else if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup) {
+ EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall
? getCatchAllValue(*this)
: getCleanupValue(*this));
+
+ // At the MandatoryCleanup hack level, we don't need to actually
+ // spuriously tell the unwinder that we have cleanups, but we do
+ // need to always be prepared to handle cleanups.
+ } else if (CleanupHackLevel == CHL_MandatoryCleanup) {
+ // Just don't decrement LastToEmitInLoop.
+
} else {
assert(LastToEmitInLoop > 2);
LastToEmitInLoop--;
@@ -758,6 +788,10 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector),
EHSelector.begin(), EHSelector.end(), "eh.selector");
Selection->setDoesNotThrow();
+
+ // Save the selector value in mandatory-cleanup mode.
+ if (CleanupHackLevel == CHL_MandatoryCleanup)
+ Builder.CreateStore(Selection, getEHSelectorSlot());
// Select the right handler.
llvm::Value *llvm_eh_typeid_for =
@@ -833,22 +867,13 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// If there was a cleanup, we'll need to actually check whether we
// landed here because the filter triggered.
- if (UseInvokeInlineHack || HasEHCleanup) {
- llvm::BasicBlock *RethrowBB = createBasicBlock("cleanup");
+ if (CleanupHackLevel != CHL_Ideal || HasEHCleanup) {
llvm::BasicBlock *UnexpectedBB = createBasicBlock("ehspec.unexpected");
- llvm::Constant *Zero = llvm::ConstantInt::get(Builder.getInt32Ty(), 0);
+ llvm::Constant *Zero = llvm::ConstantInt::get(Int32Ty, 0);
llvm::Value *FailsFilter =
Builder.CreateICmpSLT(SavedSelection, Zero, "ehspec.fails");
- Builder.CreateCondBr(FailsFilter, UnexpectedBB, RethrowBB);
-
- // The rethrow block is where we land if this was a cleanup.
- // TODO: can this be _Unwind_Resume if the InvokeInlineHack is off?
- EmitBlock(RethrowBB);
- Builder.CreateCall(getUnwindResumeOrRethrowFn(),
- Builder.CreateLoad(getExceptionSlot()))
- ->setDoesNotReturn();
- Builder.CreateUnreachable();
+ Builder.CreateCondBr(FailsFilter, UnexpectedBB, getRethrowDest().getBlock());
EmitBlock(UnexpectedBB);
}
@@ -863,7 +888,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
Builder.CreateUnreachable();
// ...or a normal catch handler...
- } else if (!UseInvokeInlineHack && !HasEHCleanup) {
+ } else if (CleanupHackLevel == CHL_Ideal && !HasEHCleanup) {
llvm::Value *Type = EHSelector.back();
EmitBranchThroughEHCleanup(EHHandlers[Type]);
@@ -1440,14 +1465,39 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() {
// This can always be a call because we necessarily didn't find
// anything on the EH stack which needs our help.
llvm::StringRef RethrowName = Personality.getCatchallRethrowFnName();
- llvm::Constant *RethrowFn;
- if (!RethrowName.empty())
- RethrowFn = getCatchallRethrowFn(*this, RethrowName);
- else
- RethrowFn = getUnwindResumeOrRethrowFn();
+ if (!RethrowName.empty()) {
+ Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName),
+ Builder.CreateLoad(getExceptionSlot()))
+ ->setDoesNotReturn();
+ } else {
+ llvm::Value *Exn = Builder.CreateLoad(getExceptionSlot());
+
+ switch (CleanupHackLevel) {
+ case CHL_MandatoryCatchall:
+ // In mandatory-catchall mode, we need to use
+ // _Unwind_Resume_or_Rethrow, or whatever the personality's
+ // equivalent is.
+ Builder.CreateCall(getUnwindResumeOrRethrowFn(), Exn)
+ ->setDoesNotReturn();
+ break;
+ case CHL_MandatoryCleanup: {
+ // In mandatory-cleanup mode, we should use llvm.eh.resume.
+ llvm::Value *Selector = Builder.CreateLoad(getEHSelectorSlot());
+ Builder.CreateCall2(CGM.getIntrinsic(llvm::Intrinsic::eh_resume),
+ Exn, Selector)
+ ->setDoesNotReturn();
+ break;
+ }
+ case CHL_Ideal:
+ // In an idealized mode where we don't have to worry about the
+ // optimizer combining landing pads, we should just use
+ // _Unwind_Resume (or the personality's equivalent).
+ Builder.CreateCall(getUnwindResumeFn(), Exn)
+ ->setDoesNotReturn();
+ break;
+ }
+ }
- Builder.CreateCall(RethrowFn, Builder.CreateLoad(getExceptionSlot()))
- ->setDoesNotReturn();
Builder.CreateUnreachable();
Builder.restoreIP(SavedIP);
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index bc2cd35bc591..2f6b55bd7b0b 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -1390,7 +1390,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// The index must always be an integer, which is not an aggregate. Emit it.
llvm::Value *Idx = EmitScalarExpr(E->getIdx());
QualType IdxTy = E->getIdx()->getType();
- bool IdxSigned = IdxTy->isSignedIntegerType();
+ bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
// If the base is a vector type, then we are forming a vector element lvalue
// with this subscript.
@@ -1635,7 +1635,8 @@ LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue,
IndirectFieldDecl::chain_iterator I = Field->chain_begin(),
IEnd = Field->chain_end();
while (true) {
- LValue LV = EmitLValueForField(BaseValue, cast<FieldDecl>(*I), CVRQualifiers);
+ LValue LV = EmitLValueForField(BaseValue, cast<FieldDecl>(*I),
+ CVRQualifiers);
if (++I == IEnd) return LV;
assert(LV.isSimple());
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 29c76887a7c9..d8da642a6b38 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -642,7 +642,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (const RecordType *RT = CGF.getContext()
.getBaseElementType(ElementType)->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- hasNonTrivialCXXConstructor = !RD->hasTrivialConstructor();
+ hasNonTrivialCXXConstructor = !RD->hasTrivialDefaultConstructor();
}
// FIXME: were we intentionally ignoring address spaces and GC attributes?
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index bdaa873f1832..81fee677f61a 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -345,18 +345,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
}
}
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Value *Callee;
- if (MD->isVirtual() &&
- !canDevirtualizeMemberFunctionCalls(getContext(),
- E->getArg(0), MD))
- Callee = BuildVirtualCall(MD, This, Ty);
- else
- Callee = CGM.GetAddrOfFunction(MD, Ty);
-
+ llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
E->arg_begin() + 1, E->arg_end());
}
@@ -403,18 +392,26 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
E->arg_begin(), E->arg_end());
}
else {
- CXXCtorType Type;
- CXXConstructExpr::ConstructionKind K = E->getConstructionKind();
- if (K == CXXConstructExpr::CK_Delegating) {
+ CXXCtorType Type = Ctor_Complete;
+ bool ForVirtualBase = false;
+
+ switch (E->getConstructionKind()) {
+ case CXXConstructExpr::CK_Delegating:
// We should be emitting a constructor; GlobalDecl will assert this
Type = CurGD.getCtorType();
- } else {
- Type = (E->getConstructionKind() == CXXConstructExpr::CK_Complete)
- ? Ctor_Complete : Ctor_Base;
- }
+ break;
+
+ case CXXConstructExpr::CK_Complete:
+ Type = Ctor_Complete;
+ break;
+
+ case CXXConstructExpr::CK_VirtualBase:
+ ForVirtualBase = true;
+ // fall-through
- bool ForVirtualBase =
- E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase;
+ case CXXConstructExpr::CK_NonVirtualBase:
+ Type = Ctor_Base;
+ }
// Call the constructor.
EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest.getAddr(),
@@ -447,204 +444,256 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtor(llvm::Value *Dest,
E->arg_begin(), E->arg_end());
}
-/// Check whether the given operator new[] is the global placement
-/// operator new[].
-static bool IsPlacementOperatorNewArray(ASTContext &Ctx,
- const FunctionDecl *Fn) {
- // Must be in global scope. Note that allocation functions can't be
- // declared in namespaces.
- if (!Fn->getDeclContext()->getRedeclContext()->isFileContext())
- return false;
-
- // Signature must be void *operator new[](size_t, void*).
- // The size_t is common to all operator new[]s.
- if (Fn->getNumParams() != 2)
- return false;
-
- CanQualType ParamType = Ctx.getCanonicalType(Fn->getParamDecl(1)->getType());
- return (ParamType == Ctx.VoidPtrTy);
-}
-
static CharUnits CalculateCookiePadding(CodeGenFunction &CGF,
const CXXNewExpr *E) {
if (!E->isArray())
return CharUnits::Zero();
- // No cookie is required if the new operator being used is
- // ::operator new[](size_t, void*).
- const FunctionDecl *OperatorNew = E->getOperatorNew();
- if (IsPlacementOperatorNewArray(CGF.getContext(), OperatorNew))
+ // No cookie is required if the operator new[] being used is the
+ // reserved placement operator new[].
+ if (E->getOperatorNew()->isReservedGlobalPlacementOperator())
return CharUnits::Zero();
return CGF.CGM.getCXXABI().GetArrayCookieSize(E);
}
-static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context,
- CodeGenFunction &CGF,
- const CXXNewExpr *E,
- llvm::Value *&NumElements,
- llvm::Value *&SizeWithoutCookie) {
- QualType ElemType = E->getAllocatedType();
-
- const llvm::IntegerType *SizeTy =
- cast<llvm::IntegerType>(CGF.ConvertType(CGF.getContext().getSizeType()));
-
- CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(ElemType);
-
- if (!E->isArray()) {
- SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity());
- return SizeWithoutCookie;
+static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
+ const CXXNewExpr *e,
+ llvm::Value *&numElements,
+ llvm::Value *&sizeWithoutCookie) {
+ QualType type = e->getAllocatedType();
+
+ if (!e->isArray()) {
+ CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type);
+ sizeWithoutCookie
+ = llvm::ConstantInt::get(CGF.SizeTy, typeSize.getQuantity());
+ return sizeWithoutCookie;
}
+ // The width of size_t.
+ unsigned sizeWidth = CGF.SizeTy->getBitWidth();
+
// Figure out the cookie size.
- CharUnits CookieSize = CalculateCookiePadding(CGF, E);
+ llvm::APInt cookieSize(sizeWidth,
+ CalculateCookiePadding(CGF, e).getQuantity());
// Emit the array size expression.
// We multiply the size of all dimensions for NumElements.
// e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6.
- NumElements = CGF.EmitScalarExpr(E->getArraySize());
- assert(NumElements->getType() == SizeTy && "element count not a size_t");
-
- uint64_t ArraySizeMultiplier = 1;
+ numElements = CGF.EmitScalarExpr(e->getArraySize());
+ assert(isa<llvm::IntegerType>(numElements->getType()));
+
+ // The number of elements can be have an arbitrary integer type;
+ // essentially, we need to multiply it by a constant factor, add a
+ // cookie size, and verify that the result is representable as a
+ // size_t. That's just a gloss, though, and it's wrong in one
+ // important way: if the count is negative, it's an error even if
+ // the cookie size would bring the total size >= 0.
+ bool isSigned
+ = e->getArraySize()->getType()->isSignedIntegerOrEnumerationType();
+ const llvm::IntegerType *numElementsType
+ = cast<llvm::IntegerType>(numElements->getType());
+ unsigned numElementsWidth = numElementsType->getBitWidth();
+
+ // Compute the constant factor.
+ llvm::APInt arraySizeMultiplier(sizeWidth, 1);
while (const ConstantArrayType *CAT
- = CGF.getContext().getAsConstantArrayType(ElemType)) {
- ElemType = CAT->getElementType();
- ArraySizeMultiplier *= CAT->getSize().getZExtValue();
+ = CGF.getContext().getAsConstantArrayType(type)) {
+ type = CAT->getElementType();
+ arraySizeMultiplier *= CAT->getSize();
}
- llvm::Value *Size;
+ CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type);
+ llvm::APInt typeSizeMultiplier(sizeWidth, typeSize.getQuantity());
+ typeSizeMultiplier *= arraySizeMultiplier;
+
+ // This will be a size_t.
+ llvm::Value *size;
// If someone is doing 'new int[42]' there is no need to do a dynamic check.
// Don't bloat the -O0 code.
- if (llvm::ConstantInt *NumElementsC =
- dyn_cast<llvm::ConstantInt>(NumElements)) {
- llvm::APInt NEC = NumElementsC->getValue();
- unsigned SizeWidth = NEC.getBitWidth();
-
- // Determine if there is an overflow here by doing an extended multiply.
- NEC = NEC.zext(SizeWidth*2);
- llvm::APInt SC(SizeWidth*2, TypeSize.getQuantity());
- SC *= NEC;
-
- if (!CookieSize.isZero()) {
- // Save the current size without a cookie. We don't care if an
- // overflow's already happened because SizeWithoutCookie isn't
- // used if the allocator returns null or throws, as it should
- // always do on an overflow.
- llvm::APInt SWC = SC.trunc(SizeWidth);
- SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, SWC);
-
- // Add the cookie size.
- SC += llvm::APInt(SizeWidth*2, CookieSize.getQuantity());
+ if (llvm::ConstantInt *numElementsC =
+ dyn_cast<llvm::ConstantInt>(numElements)) {
+ const llvm::APInt &count = numElementsC->getValue();
+
+ bool hasAnyOverflow = false;
+
+ // If 'count' was a negative number, it's an overflow.
+ if (isSigned && count.isNegative())
+ hasAnyOverflow = true;
+
+ // We want to do all this arithmetic in size_t. If numElements is
+ // wider than that, check whether it's already too big, and if so,
+ // overflow.
+ else if (numElementsWidth > sizeWidth &&
+ numElementsWidth - sizeWidth > count.countLeadingZeros())
+ hasAnyOverflow = true;
+
+ // Okay, compute a count at the right width.
+ llvm::APInt adjustedCount = count.zextOrTrunc(sizeWidth);
+
+ // Scale numElements by that. This might overflow, but we don't
+ // care because it only overflows if allocationSize does, too, and
+ // if that overflows then we shouldn't use this.
+ numElements = llvm::ConstantInt::get(CGF.SizeTy,
+ adjustedCount * arraySizeMultiplier);
+
+ // Compute the size before cookie, and track whether it overflowed.
+ bool overflow;
+ llvm::APInt allocationSize
+ = adjustedCount.umul_ov(typeSizeMultiplier, overflow);
+ hasAnyOverflow |= overflow;
+
+ // Add in the cookie, and check whether it's overflowed.
+ if (cookieSize != 0) {
+ // Save the current size without a cookie. This shouldn't be
+ // used if there was overflow.
+ sizeWithoutCookie = llvm::ConstantInt::get(CGF.SizeTy, allocationSize);
+
+ allocationSize = allocationSize.uadd_ov(cookieSize, overflow);
+ hasAnyOverflow |= overflow;
}
-
- if (SC.countLeadingZeros() >= SizeWidth) {
- SC = SC.trunc(SizeWidth);
- Size = llvm::ConstantInt::get(SizeTy, SC);
+
+ // On overflow, produce a -1 so operator new will fail.
+ if (hasAnyOverflow) {
+ size = llvm::Constant::getAllOnesValue(CGF.SizeTy);
} else {
- // On overflow, produce a -1 so operator new throws.
- Size = llvm::Constant::getAllOnesValue(SizeTy);
+ size = llvm::ConstantInt::get(CGF.SizeTy, allocationSize);
}
- // Scale NumElements while we're at it.
- uint64_t N = NEC.getZExtValue() * ArraySizeMultiplier;
- NumElements = llvm::ConstantInt::get(SizeTy, N);
-
- // Otherwise, we don't need to do an overflow-checked multiplication if
- // we're multiplying by one.
- } else if (TypeSize.isOne()) {
- assert(ArraySizeMultiplier == 1);
-
- Size = NumElements;
-
- // If we need a cookie, add its size in with an overflow check.
- // This is maybe a little paranoid.
- if (!CookieSize.isZero()) {
- SizeWithoutCookie = Size;
+ // Otherwise, we might need to use the overflow intrinsics.
+ } else {
+ // There are up to four conditions we need to test for:
+ // 1) if isSigned, we need to check whether numElements is negative;
+ // 2) if numElementsWidth > sizeWidth, we need to check whether
+ // numElements is larger than something representable in size_t;
+ // 3) we need to compute
+ // sizeWithoutCookie := numElements * typeSizeMultiplier
+ // and check whether it overflows; and
+ // 4) if we need a cookie, we need to compute
+ // size := sizeWithoutCookie + cookieSize
+ // and check whether it overflows.
+
+ llvm::Value *hasOverflow = 0;
+
+ // If numElementsWidth > sizeWidth, then one way or another, we're
+ // going to have to do a comparison for (2), and this happens to
+ // take care of (1), too.
+ if (numElementsWidth > sizeWidth) {
+ llvm::APInt threshold(numElementsWidth, 1);
+ threshold <<= sizeWidth;
+
+ llvm::Value *thresholdV
+ = llvm::ConstantInt::get(numElementsType, threshold);
+
+ hasOverflow = CGF.Builder.CreateICmpUGE(numElements, thresholdV);
+ numElements = CGF.Builder.CreateTrunc(numElements, CGF.SizeTy);
+
+ // Otherwise, if we're signed, we want to sext up to size_t.
+ } else if (isSigned) {
+ if (numElementsWidth < sizeWidth)
+ numElements = CGF.Builder.CreateSExt(numElements, CGF.SizeTy);
+
+ // If there's a non-1 type size multiplier, then we can do the
+ // signedness check at the same time as we do the multiply
+ // because a negative number times anything will cause an
+ // unsigned overflow. Otherwise, we have to do it here.
+ if (typeSizeMultiplier == 1)
+ hasOverflow = CGF.Builder.CreateICmpSLT(numElements,
+ llvm::ConstantInt::get(CGF.SizeTy, 0));
+
+ // Otherwise, zext up to size_t if necessary.
+ } else if (numElementsWidth < sizeWidth) {
+ numElements = CGF.Builder.CreateZExt(numElements, CGF.SizeTy);
+ }
- llvm::Value *CookieSizeV
- = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity());
+ assert(numElements->getType() == CGF.SizeTy);
- const llvm::Type *Types[] = { SizeTy };
- llvm::Value *UAddF
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, Types, 1);
- llvm::Value *AddRes
- = CGF.Builder.CreateCall2(UAddF, Size, CookieSizeV);
+ size = numElements;
- Size = CGF.Builder.CreateExtractValue(AddRes, 0);
- llvm::Value *DidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1);
- Size = CGF.Builder.CreateSelect(DidOverflow,
- llvm::ConstantInt::get(SizeTy, -1),
- Size);
+ // Multiply by the type size if necessary. This multiplier
+ // includes all the factors for nested arrays.
+ //
+ // This step also causes numElements to be scaled up by the
+ // nested-array factor if necessary. Overflow on this computation
+ // can be ignored because the result shouldn't be used if
+ // allocation fails.
+ if (typeSizeMultiplier != 1) {
+ const llvm::Type *intrinsicTypes[] = { CGF.SizeTy };
+ llvm::Value *umul_with_overflow
+ = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow,
+ intrinsicTypes, 1);
+
+ llvm::Value *tsmV =
+ llvm::ConstantInt::get(CGF.SizeTy, typeSizeMultiplier);
+ llvm::Value *result =
+ CGF.Builder.CreateCall2(umul_with_overflow, size, tsmV);
+
+ llvm::Value *overflowed = CGF.Builder.CreateExtractValue(result, 1);
+ if (hasOverflow)
+ hasOverflow = CGF.Builder.CreateOr(hasOverflow, overflowed);
+ else
+ hasOverflow = overflowed;
+
+ size = CGF.Builder.CreateExtractValue(result, 0);
+
+ // Also scale up numElements by the array size multiplier.
+ if (arraySizeMultiplier != 1) {
+ // If the base element type size is 1, then we can re-use the
+ // multiply we just did.
+ if (typeSize.isOne()) {
+ assert(arraySizeMultiplier == typeSizeMultiplier);
+ numElements = size;
+
+ // Otherwise we need a separate multiply.
+ } else {
+ llvm::Value *asmV =
+ llvm::ConstantInt::get(CGF.SizeTy, arraySizeMultiplier);
+ numElements = CGF.Builder.CreateMul(numElements, asmV);
+ }
+ }
+ } else {
+ // numElements doesn't need to be scaled.
+ assert(arraySizeMultiplier == 1);
}
+
+ // Add in the cookie size if necessary.
+ if (cookieSize != 0) {
+ sizeWithoutCookie = size;
+
+ const llvm::Type *intrinsicTypes[] = { CGF.SizeTy };
+ llvm::Value *uadd_with_overflow
+ = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow,
+ intrinsicTypes, 1);
+
+ llvm::Value *cookieSizeV = llvm::ConstantInt::get(CGF.SizeTy, cookieSize);
+ llvm::Value *result =
+ CGF.Builder.CreateCall2(uadd_with_overflow, size, cookieSizeV);
+
+ llvm::Value *overflowed = CGF.Builder.CreateExtractValue(result, 1);
+ if (hasOverflow)
+ hasOverflow = CGF.Builder.CreateOr(hasOverflow, overflowed);
+ else
+ hasOverflow = overflowed;
- // Otherwise use the int.umul.with.overflow intrinsic.
- } else {
- llvm::Value *OutermostElementSize
- = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity());
-
- llvm::Value *NumOutermostElements = NumElements;
-
- // Scale NumElements by the array size multiplier. This might
- // overflow, but only if the multiplication below also overflows,
- // in which case this multiplication isn't used.
- if (ArraySizeMultiplier != 1)
- NumElements = CGF.Builder.CreateMul(NumElements,
- llvm::ConstantInt::get(SizeTy, ArraySizeMultiplier));
-
- // The requested size of the outermost array is non-constant.
- // Multiply that by the static size of the elements of that array;
- // on unsigned overflow, set the size to -1 to trigger an
- // exception from the allocation routine. This is sufficient to
- // prevent buffer overruns from the allocator returning a
- // seemingly valid pointer to insufficient space. This idea comes
- // originally from MSVC, and GCC has an open bug requesting
- // similar behavior:
- // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19351
- //
- // This will not be sufficient for C++0x, which requires a
- // specific exception class (std::bad_array_new_length).
- // That will require ABI support that has not yet been specified.
- const llvm::Type *Types[] = { SizeTy };
- llvm::Value *UMulF
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, Types, 1);
- llvm::Value *MulRes = CGF.Builder.CreateCall2(UMulF, NumOutermostElements,
- OutermostElementSize);
-
- // The overflow bit.
- llvm::Value *DidOverflow = CGF.Builder.CreateExtractValue(MulRes, 1);
-
- // The result of the multiplication.
- Size = CGF.Builder.CreateExtractValue(MulRes, 0);
-
- // If we have a cookie, we need to add that size in, too.
- if (!CookieSize.isZero()) {
- SizeWithoutCookie = Size;
-
- llvm::Value *CookieSizeV
- = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity());
- llvm::Value *UAddF
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, Types, 1);
- llvm::Value *AddRes
- = CGF.Builder.CreateCall2(UAddF, SizeWithoutCookie, CookieSizeV);
-
- Size = CGF.Builder.CreateExtractValue(AddRes, 0);
-
- llvm::Value *AddDidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1);
- DidOverflow = CGF.Builder.CreateOr(DidOverflow, AddDidOverflow);
+ size = CGF.Builder.CreateExtractValue(result, 0);
}
- Size = CGF.Builder.CreateSelect(DidOverflow,
- llvm::ConstantInt::get(SizeTy, -1),
- Size);
+ // If we had any possibility of dynamic overflow, make a select to
+ // overwrite 'size' with an all-ones value, which should cause
+ // operator new to throw.
+ if (hasOverflow)
+ size = CGF.Builder.CreateSelect(hasOverflow,
+ llvm::Constant::getAllOnesValue(CGF.SizeTy),
+ size);
}
- if (CookieSize.isZero())
- SizeWithoutCookie = Size;
+ if (cookieSize == 0)
+ sizeWithoutCookie = size;
else
- assert(SizeWithoutCookie && "didn't set SizeWithoutCookie?");
+ assert(sizeWithoutCookie && "didn't set sizeWithoutCookie?");
- return Size;
+ return size;
}
static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E,
@@ -741,7 +790,7 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
if (E->isArray()) {
if (CXXConstructorDecl *Ctor = E->getConstructor()) {
bool RequiresZeroInitialization = false;
- if (Ctor->getParent()->hasTrivialConstructor()) {
+ if (Ctor->getParent()->hasTrivialDefaultConstructor()) {
// If new expression did not specify value-initialization, then there
// is no initialization.
if (!E->hasInitializer() || Ctor->getParent()->isEmpty())
@@ -972,8 +1021,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
llvm::Value *numElements = 0;
llvm::Value *allocSizeWithoutCookie = 0;
llvm::Value *allocSize =
- EmitCXXNewAllocSize(getContext(), *this, E, numElements,
- allocSizeWithoutCookie);
+ EmitCXXNewAllocSize(*this, E, numElements, allocSizeWithoutCookie);
allocatorArgs.add(RValue::get(allocSize), sizeType);
@@ -1007,11 +1055,19 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
EmitCallArg(allocatorArgs, *placementArg, placementArg->getType());
}
- // Emit the allocation call.
- RValue RV =
- EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType),
- CGM.GetAddrOfFunction(allocator), ReturnValueSlot(),
- allocatorArgs, allocator);
+ // Emit the allocation call. If the allocator is a global placement
+ // operator, just "inline" it directly.
+ RValue RV;
+ if (allocator->isReservedGlobalPlacementOperator()) {
+ assert(allocatorArgs.size() == 2);
+ RV = allocatorArgs[1].RV;
+ // TODO: kill any unnecessary computations done for the size
+ // argument.
+ } else {
+ RV = EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType),
+ CGM.GetAddrOfFunction(allocator), ReturnValueSlot(),
+ allocatorArgs, allocator);
+ }
// Emit a null check on the allocation result if the allocation
// function is allowed to return null (because it has a non-throwing
@@ -1056,7 +1112,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// If there's an operator delete, enter a cleanup to call it if an
// exception is thrown.
EHScopeStack::stable_iterator operatorDeleteCleanup;
- if (E->getOperatorDelete()) {
+ if (E->getOperatorDelete() &&
+ !E->getOperatorDelete()->isReservedGlobalPlacementOperator()) {
EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocatorArgs);
operatorDeleteCleanup = EHStack.stable_begin();
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 463b913d9285..da37bd5b0a1f 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -352,8 +352,7 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are
// ignored:
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((*Field), LastFD) ||
- CGM.getContext().ZeroBitfieldFollowsBitfield((*Field), LastFD)) {
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((*Field), LastFD)) {
--FieldNo;
continue;
}
@@ -611,12 +610,12 @@ public:
return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(destType));
case CK_IntegralCast: {
- bool isSigned = subExpr->getType()->isSignedIntegerType();
+ bool isSigned = subExpr->getType()->isSignedIntegerOrEnumerationType();
return llvm::ConstantExpr::getIntegerCast(C, destType, isSigned);
}
case CK_IntegralToPointer: {
- bool isSigned = subExpr->getType()->isSignedIntegerType();
+ bool isSigned = subExpr->getType()->isSignedIntegerOrEnumerationType();
C = llvm::ConstantExpr::getIntegerCast(C, CGM.IntPtrTy, isSigned);
return llvm::ConstantExpr::getIntToPtr(C, destType);
}
@@ -626,13 +625,13 @@ public:
llvm::Constant::getNullValue(C->getType()));
case CK_IntegralToFloating:
- if (subExpr->getType()->isSignedIntegerType())
+ if (subExpr->getType()->isSignedIntegerOrEnumerationType())
return llvm::ConstantExpr::getSIToFP(C, destType);
else
return llvm::ConstantExpr::getUIToFP(C, destType);
case CK_FloatingToIntegral:
- if (E->getType()->isSignedIntegerType())
+ if (E->getType()->isSignedIntegerOrEnumerationType())
return llvm::ConstantExpr::getFPToSI(C, destType);
else
return llvm::ConstantExpr::getFPToUI(C, destType);
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 6bcc425ce62f..dff7bf45e0c3 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -400,7 +400,7 @@ public:
// Binary Operators.
Value *EmitMul(const BinOpInfo &Ops) {
- if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
@@ -508,6 +508,7 @@ public:
Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
return CGF.EmitObjCStringLiteral(E);
}
+ Value *VisitAsTypeExpr(AsTypeExpr *CE);
};
} // end anonymous namespace.
@@ -568,7 +569,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// First, convert to the correct width so that we control the kind of
// extension.
const llvm::Type *MiddleTy = CGF.IntPtrTy;
- bool InputSigned = SrcType->isSignedIntegerType();
+ bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
llvm::Value* IntResult =
Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv");
// Then, cast to pointer.
@@ -610,7 +611,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// Finally, we have the arithmetic types: real int/float.
if (isa<llvm::IntegerType>(Src->getType())) {
- bool InputSigned = SrcType->isSignedIntegerType();
+ bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
if (isa<llvm::IntegerType>(DstTy))
return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
else if (InputSigned)
@@ -621,7 +622,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
assert(Src->getType()->isFloatingPointTy() && "Unknown real conversion");
if (isa<llvm::IntegerType>(DstTy)) {
- if (DstType->isSignedIntegerType())
+ if (DstType->isSignedIntegerOrEnumerationType())
return Builder.CreateFPToSI(Src, DstTy, "conv");
else
return Builder.CreateFPToUI(Src, DstTy, "conv");
@@ -758,19 +759,13 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Value* V2 = CGF.EmitScalarExpr(E->getExpr(1));
// Handle vec3 special since the index will be off by one for the RHS.
+ const llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType());
llvm::SmallVector<llvm::Constant*, 32> indices;
for (unsigned i = 2; i < E->getNumSubExprs(); i++) {
- llvm::Constant *C = cast<llvm::Constant>(CGF.EmitScalarExpr(E->getExpr(i)));
- const llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType());
- if (VTy->getNumElements() == 3) {
- if (llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(C)) {
- uint64_t cVal = CI->getZExtValue();
- if (cVal > 3) {
- C = llvm::ConstantInt::get(C->getType(), cVal-1);
- }
- }
- }
- indices.push_back(C);
+ unsigned Idx = E->getShuffleMaskIdx(CGF.getContext(), i-2);
+ if (VTy->getNumElements() == 3 && Idx > 3)
+ Idx -= 1;
+ indices.push_back(Builder.getInt32(Idx));
}
Value *SV = llvm::ConstantVector::get(indices);
@@ -813,7 +808,7 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
// integer value.
Value *Base = Visit(E->getBase());
Value *Idx = Visit(E->getIdx());
- bool IdxSigned = E->getIdx()->getType()->isSignedIntegerType();
+ bool IdxSigned = E->getIdx()->getType()->isSignedIntegerOrEnumerationType();
Idx = Builder.CreateIntCast(Idx, CGF.Int32Ty, IdxSigned, "vecidxcast");
return Builder.CreateExtractElement(Base, Idx, "vecext");
}
@@ -1142,7 +1137,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
// First, convert to the correct width so that we control the kind of
// extension.
const llvm::Type *MiddleTy = CGF.IntPtrTy;
- bool InputSigned = E->getType()->isSignedIntegerType();
+ bool InputSigned = E->getType()->isSignedIntegerOrEnumerationType();
llvm::Value* IntResult =
Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv");
@@ -1285,7 +1280,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Note that signed integer inc/dec with width less than int can't
// overflow because of promotion rules; we're just eliding a few steps here.
- if (type->isSignedIntegerType() &&
+ if (type->isSignedIntegerOrEnumerationType() &&
value->getType()->getPrimitiveSizeInBits() >=
CGF.CGM.IntTy->getBitWidth())
value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
@@ -1333,10 +1328,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (type->hasIntegerRepresentation()) {
llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount);
- if (type->hasSignedIntegerRepresentation())
- value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
- else
- value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
+ value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
} else {
value = Builder.CreateFAdd(
value,
@@ -1447,7 +1439,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
// Compute the index
Expr *IdxExpr = E->getIndexExpr(ON.getArrayExprIndex());
llvm::Value* Idx = CGF.EmitScalarExpr(IdxExpr);
- bool IdxSigned = IdxExpr->getType()->isSignedIntegerType();
+ bool IdxSigned = IdxExpr->getType()->isSignedIntegerOrEnumerationType();
Idx = Builder.CreateIntCast(Idx, ResultType, IdxSigned, "conv");
// Save the element type
@@ -1797,9 +1789,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
// Get the overflow handler.
const llvm::Type *Int8Ty = llvm::Type::getInt8Ty(VMContext);
- std::vector<const llvm::Type*> argTypes;
- argTypes.push_back(CGF.Int64Ty); argTypes.push_back(CGF.Int64Ty);
- argTypes.push_back(Int8Ty); argTypes.push_back(Int8Ty);
+ const llvm::Type *argTypes[] = { CGF.Int64Ty, CGF.Int64Ty, Int8Ty, Int8Ty };
llvm::FunctionType *handlerTy =
llvm::FunctionType::get(CGF.Int64Ty, argTypes, true);
llvm::Value *handler = CGF.CGM.CreateRuntimeFunction(handlerTy, *handlerName);
@@ -1829,7 +1819,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
if (!Ops.Ty->isAnyPointerType()) {
- if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
return Builder.CreateNSWAdd(Ops.LHS, Ops.RHS, "add");
@@ -1879,7 +1869,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
// Zero or sign extend the pointer value based on whether the index is
// signed or not.
const llvm::Type *IdxType = CGF.IntPtrTy;
- if (IdxExp->getType()->isSignedIntegerType())
+ if (IdxExp->getType()->isSignedIntegerOrEnumerationType())
Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
else
Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
@@ -1914,7 +1904,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
if (!isa<llvm::PointerType>(Ops.LHS->getType())) {
- if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub");
@@ -1954,7 +1944,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
// Zero or sign extend the pointer value based on whether the index is
// signed or not.
const llvm::Type *IdxType = CGF.IntPtrTy;
- if (BinOp->getRHS()->getType()->isSignedIntegerType())
+ if (BinOp->getRHS()->getType()->isSignedIntegerOrEnumerationType())
Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
else
Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
@@ -2556,6 +2546,56 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) {
return CGF.EmitBlockLiteral(block);
}
+Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
+ Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
+ const llvm::Type * DstTy = ConvertType(E->getDstType());
+
+ // Going from vec4->vec3 or vec3->vec4 is a special case and requires
+ // a shuffle vector instead of a bitcast.
+ const llvm::Type *SrcTy = Src->getType();
+ if (isa<llvm::VectorType>(DstTy) && isa<llvm::VectorType>(SrcTy)) {
+ unsigned numElementsDst = cast<llvm::VectorType>(DstTy)->getNumElements();
+ unsigned numElementsSrc = cast<llvm::VectorType>(SrcTy)->getNumElements();
+ if ((numElementsDst == 3 && numElementsSrc == 4)
+ || (numElementsDst == 4 && numElementsSrc == 3)) {
+
+
+ // In the case of going from int4->float3, a bitcast is needed before
+ // doing a shuffle.
+ const llvm::Type *srcElemTy =
+ cast<llvm::VectorType>(SrcTy)->getElementType();
+ const llvm::Type *dstElemTy =
+ cast<llvm::VectorType>(DstTy)->getElementType();
+
+ if ((srcElemTy->isIntegerTy() && dstElemTy->isFloatTy())
+ || (srcElemTy->isFloatTy() && dstElemTy->isIntegerTy())) {
+ // Create a float type of the same size as the source or destination.
+ const llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy,
+ numElementsSrc);
+
+ Src = Builder.CreateBitCast(Src, newSrcTy, "astypeCast");
+ }
+
+ llvm::Value *UnV = llvm::UndefValue::get(Src->getType());
+
+ llvm::SmallVector<llvm::Constant*, 3> Args;
+ Args.push_back(Builder.getInt32(0));
+ Args.push_back(Builder.getInt32(1));
+ Args.push_back(Builder.getInt32(2));
+
+ if (numElementsDst == 4)
+ Args.push_back(llvm::UndefValue::get(
+ llvm::Type::getInt32Ty(CGF.getLLVMContext())));
+
+ llvm::Constant *Mask = llvm::ConstantVector::get(Args);
+
+ return Builder.CreateShuffleVector(Src, UnV, Mask, "astype");
+ }
+ }
+
+ return Builder.CreateBitCast(Src, DstTy, "astype");
+}
+
//===----------------------------------------------------------------------===//
// Entry Point into this File
//===----------------------------------------------------------------------===//
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 5b0d41e776f2..fa42cd1f36ab 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -47,6 +47,23 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
return CGM.getObjCRuntime().GenerateProtocolRef(Builder, E->getProtocol());
}
+/// \brief Adjust the type of the result of an Objective-C message send
+/// expression when the method has a related result type.
+static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
+ const Expr *E,
+ const ObjCMethodDecl *Method,
+ RValue Result) {
+ if (!Method)
+ return Result;
+ if (!Method->hasRelatedResultType() ||
+ CGF.getContext().hasSameType(E->getType(), Method->getResultType()) ||
+ !Result.isScalar())
+ return Result;
+
+ // We have applied a related result type. Cast the rvalue appropriately.
+ return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(),
+ CGF.ConvertType(E->getType())));
+}
RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return) {
@@ -59,15 +76,17 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
bool isClassMessage = false;
ObjCInterfaceDecl *OID = 0;
// Find the receiver
+ QualType ReceiverType;
llvm::Value *Receiver = 0;
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
Receiver = EmitScalarExpr(E->getInstanceReceiver());
+ ReceiverType = E->getInstanceReceiver()->getType();
break;
case ObjCMessageExpr::Class: {
- const ObjCObjectType *ObjTy
- = E->getClassReceiver()->getAs<ObjCObjectType>();
+ ReceiverType = E->getClassReceiver();
+ const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>();
assert(ObjTy && "Invalid Objective-C class message send");
OID = ObjTy->getInterface();
assert(OID && "Invalid Objective-C class message send");
@@ -77,11 +96,13 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
}
case ObjCMessageExpr::SuperInstance:
+ ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
break;
case ObjCMessageExpr::SuperClass:
+ ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
isClassMessage = true;
@@ -94,31 +115,35 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
QualType ResultType =
E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType();
+ RValue result;
if (isSuperMessage) {
// super is only valid in an Objective-C method
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
- return Runtime.GenerateMessageSendSuper(*this, Return, ResultType,
- E->getSelector(),
- OMD->getClassInterface(),
- isCategoryImpl,
- Receiver,
- isClassMessage,
- Args,
- E->getMethodDecl());
+ result = Runtime.GenerateMessageSendSuper(*this, Return, ResultType,
+ E->getSelector(),
+ OMD->getClassInterface(),
+ isCategoryImpl,
+ Receiver,
+ isClassMessage,
+ Args,
+ E->getMethodDecl());
+ } else {
+ result = Runtime.GenerateMessageSend(*this, Return, ResultType,
+ E->getSelector(),
+ Receiver, Args, OID,
+ E->getMethodDecl());
}
-
- return Runtime.GenerateMessageSend(*this, Return, ResultType,
- E->getSelector(),
- Receiver, Args, OID,
- E->getMethodDecl());
+
+ return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result);
}
/// StartObjCMethod - Begin emission of an ObjCMethod. This generates
/// the LLVM function and sets the other context used by
/// CodeGenFunction.
void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD) {
+ const ObjCContainerDecl *CD,
+ SourceLocation StartLoc) {
FunctionArgList args;
// Check if we should generate debug info for this method.
if (CGM.getModuleDebugInfo() && !OMD->hasAttr<NoDebugAttr>())
@@ -138,7 +163,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
CurGD = OMD;
- StartFunction(OMD, OMD->getResultType(), Fn, FI, args, OMD->getLocStart());
+ StartFunction(OMD, OMD->getResultType(), Fn, FI, args, StartLoc);
}
void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
@@ -151,16 +176,14 @@ void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
// objc_copyStruct (ReturnValue, &structIvar,
// sizeof (Type of Ivar), isAtomic, false);
CallArgList Args;
- RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue,
- Types.ConvertType(getContext().VoidPtrTy)));
+ RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, VoidPtrTy));
Args.add(RV, getContext().VoidPtrTy);
- RV = RValue::get(Builder.CreateBitCast(LV.getAddress(),
- Types.ConvertType(getContext().VoidPtrTy)));
+ RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), VoidPtrTy));
Args.add(RV, getContext().VoidPtrTy);
// sizeof (Type of Ivar)
CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType());
llvm::Value *SizeVal =
- llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy),
+ llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy),
Size.getQuantity());
Args.add(RValue::get(SizeVal), getContext().LongTy);
llvm::Value *isAtomic =
@@ -179,7 +202,7 @@ void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
/// Generate an Objective-C method. An Objective-C method is a C function with
/// its pointer, name, and types registered in the class struture.
void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
- StartObjCMethod(OMD, OMD->getClassInterface());
+ StartObjCMethod(OMD, OMD->getClassInterface(), OMD->getLocStart());
EmitStmt(OMD->getBody());
FinishFunction(OMD->getBodyRBrace());
}
@@ -199,7 +222,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
- StartObjCMethod(OMD, IMP->getClassInterface());
+ StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart());
// Determine if we should use an objc_getProperty call for
// this. Non-atomic properties are directly evaluated.
@@ -292,7 +315,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const CXXRecordDecl *classDecl = IVART->getAsCXXRecordDecl();
if (PID->getGetterCXXConstructor() &&
- classDecl && !classDecl->hasTrivialConstructor()) {
+ classDecl && !classDecl->hasTrivialDefaultConstructor()) {
ReturnStmt *Stmt =
new (getContext()) ReturnStmt(SourceLocation(),
PID->getGetterCXXConstructor(),
@@ -398,7 +421,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)");
- StartObjCMethod(OMD, IMP->getClassInterface());
+ StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart());
const llvm::Triple &Triple = getContext().Target.getTriple();
QualType IVART = Ivar->getType();
bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy;
@@ -496,7 +519,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
}
else {
// FIXME: Find a clean way to avoid AST node creation.
- SourceLocation Loc = PD->getLocation();
+ SourceLocation Loc = PID->getLocStart();
ValueDecl *Self = OMD->getSelfDecl();
ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
DeclRefExpr Base(Self, Self->getType(), VK_RValue, Loc);
@@ -618,7 +641,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
ObjCMethodDecl *MD,
bool ctor) {
MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
- StartObjCMethod(MD, IMP->getClassInterface());
+ StartObjCMethod(MD, IMP->getClassInterface(), MD->getLocStart());
// Emit .cxx_construct.
if (ctor) {
@@ -712,26 +735,31 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
const ObjCPropertyRefExpr *E = LV.getPropertyRefExpr();
QualType ResultType = E->getGetterResultType();
Selector S;
+ const ObjCMethodDecl *method;
if (E->isExplicitProperty()) {
const ObjCPropertyDecl *Property = E->getExplicitProperty();
S = Property->getGetterName();
+ method = Property->getGetterMethodDecl();
} else {
- const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter();
- S = Getter->getSelector();
+ method = E->getImplicitPropertyGetter();
+ S = method->getSelector();
}
llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
// Accesses to 'super' follow a different code path.
if (E->isSuperReceiver())
- return GenerateMessageSendSuper(*this, Return, ResultType,
- S, Receiver, CallArgList());
-
+ return AdjustRelatedResultType(*this, E, method,
+ GenerateMessageSendSuper(*this, Return,
+ ResultType,
+ S, Receiver,
+ CallArgList()));
const ObjCInterfaceDecl *ReceiverClass
= (E->isClassReceiver() ? E->getClassReceiver() : 0);
- return CGM.getObjCRuntime().
- GenerateMessageSend(*this, Return, ResultType, S,
- Receiver, CallArgList(), ReceiverClass);
+ return AdjustRelatedResultType(*this, E, method,
+ CGM.getObjCRuntime().
+ GenerateMessageSend(*this, Return, ResultType, S,
+ Receiver, CallArgList(), ReceiverClass));
}
void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index c4dc4c41da6d..f0993c5dadbb 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -52,7 +52,7 @@ class LazyRuntimeFunction {
CodeGenModule *CGM;
std::vector<const llvm::Type*> ArgTys;
const char *FunctionName;
- llvm::Function *Function;
+ llvm::Constant *Function;
public:
/// Constructor leaves this class uninitialized, because it is intended to
/// be used as a field in another class and not all of the types that are
@@ -78,7 +78,7 @@ class LazyRuntimeFunction {
}
/// Overloaded cast operator, allows the class to be implicitly cast to an
/// LLVM constant.
- operator llvm::Function*() {
+ operator llvm::Constant*() {
if (!Function) {
if (0 == FunctionName) return 0;
// We put the return type on the end of the vector, so pop it back off
@@ -86,13 +86,17 @@ class LazyRuntimeFunction {
ArgTys.pop_back();
llvm::FunctionType *FTy = llvm::FunctionType::get(RetTy, ArgTys, false);
Function =
- cast<llvm::Function>(CGM->CreateRuntimeFunction(FTy, FunctionName));
+ cast<llvm::Constant>(CGM->CreateRuntimeFunction(FTy, FunctionName));
// We won't need to use the types again, so we may as well clean up the
// vector now
ArgTys.resize(0);
}
return Function;
}
+ operator llvm::Function*() {
+ return cast<llvm::Function>((llvm::Constant*)*this);
+ }
+
};
@@ -314,7 +318,7 @@ private:
/// The version of the runtime that this class targets. Must match the
/// version in the runtime.
- const int RuntimeVersion;
+ int RuntimeVersion;
/// The version of the protocol class. Used to differentiate between ObjC1
/// and ObjC2 protocols. Objective-C 1 protocols can not contain optional
/// components and can not contain declared properties. We always emit
@@ -444,10 +448,10 @@ public:
const ObjCProtocolDecl *PD);
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Function *ModuleInitFunction();
- virtual llvm::Function *GetPropertyGetFunction();
- virtual llvm::Function *GetPropertySetFunction();
- virtual llvm::Function *GetSetStructFunction();
- virtual llvm::Function *GetGetStructFunction();
+ virtual llvm::Constant *GetPropertyGetFunction();
+ virtual llvm::Constant *GetPropertySetFunction();
+ virtual llvm::Constant *GetSetStructFunction();
+ virtual llvm::Constant *GetGetStructFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryStmt(CodeGenFunction &CGF,
@@ -484,6 +488,10 @@ public:
const CGBlockInfo &blockInfo) {
return NULLPtr;
}
+
+ virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
+ return 0;
+ }
};
/// Class representing the legacy GCC Objective-C ABI. This is the default when
/// -fobjc-nonfragile-abi is not specified.
@@ -654,7 +662,6 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
: CGM(cgm), TheModule(CGM.getModule()), VMContext(cgm.getLLVMContext()),
ClassPtrAlias(0), MetaClassPtrAlias(0), RuntimeVersion(runtimeABIVersion),
ProtocolVersion(protocolClassVersion) {
-
msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
@@ -729,14 +736,16 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
PtrDiffTy, BoolTy, BoolTy, NULL);
// IMP type
- std::vector<const llvm::Type*> IMPArgs;
- IMPArgs.push_back(IdTy);
- IMPArgs.push_back(SelectorTy);
+ const llvm::Type *IMPArgs[] = { IdTy, SelectorTy };
IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs,
true));
// Don't bother initialising the GC stuff unless we're compiling in GC mode
if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ // This is a bit of an hack. We should sort this out by having a proper
+ // CGObjCGNUstep subclass for GC, but we may want to really support the old
+ // ABI and GC added in ObjectiveC2.framework, so we fudge it a bit for now
+ RuntimeVersion = 10;
// Get selectors needed in GC mode
RetainSel = GetNullarySelector("retain", CGM.getContext());
ReleaseSel = GetNullarySelector("release", CGM.getContext());
@@ -775,11 +784,8 @@ llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
EmitClassRef(OID->getNameAsString());
ClassName = Builder.CreateStructGEP(ClassName, 0);
- std::vector<const llvm::Type*> Params(1, PtrToInt8Ty);
llvm::Constant *ClassLookupFn =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy,
- Params,
- true),
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true),
"objc_lookup_class");
return Builder.CreateCall(ClassLookupFn, ClassName);
}
@@ -945,16 +951,17 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
- if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ CGBuilderTy &Builder = CGF.Builder;
+ if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) {
if (Sel == RetainSel || Sel == AutoreleaseSel) {
- return RValue::get(Receiver);
+ return RValue::get(EnforceType(Builder, Receiver,
+ CGM.getTypes().ConvertType(ResultType)));
}
if (Sel == ReleaseSel) {
return RValue::get(0);
}
}
- CGBuilderTy &Builder = CGF.Builder;
llvm::Value *cmd = GetSelector(Builder, Sel);
@@ -971,14 +978,12 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
llvm::Value *ReceiverClass = 0;
if (isCategoryImpl) {
llvm::Constant *classLookupFunction = 0;
- std::vector<const llvm::Type*> Params;
- Params.push_back(PtrTy);
if (IsClassMessage) {
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- IdTy, Params, true), "objc_get_meta_class");
+ IdTy, PtrTy, true), "objc_get_meta_class");
} else {
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- IdTy, Params, true), "objc_get_class");
+ IdTy, PtrTy, true), "objc_get_class");
}
ReceiverClass = Builder.CreateCall(classLookupFunction,
MakeConstantString(Class->getNameAsString()));
@@ -1052,18 +1057,19 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
+ CGBuilderTy &Builder = CGF.Builder;
+
// Strip out message sends to retain / release in GC mode
- if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) {
if (Sel == RetainSel || Sel == AutoreleaseSel) {
- return RValue::get(Receiver);
+ return RValue::get(EnforceType(Builder, Receiver,
+ CGM.getTypes().ConvertType(ResultType)));
}
if (Sel == ReleaseSel) {
return RValue::get(0);
}
}
- CGBuilderTy &Builder = CGF.Builder;
-
// If the return type is something that goes in an integer register, the
// runtime will handle 0 returns. For other cases, we fill in the 0 value
// ourselves.
@@ -2127,7 +2133,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// The symbol table is contained in a module which has some version-checking
// constants
llvm::StructType * ModuleTy = llvm::StructType::get(VMContext, LongTy, LongTy,
- PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL);
+ PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy),
+ (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) ? NULL : IntTy,
+ NULL);
Elements.clear();
// Runtime version, used for ABI compatibility checking.
Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
@@ -2144,8 +2152,17 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
std::string path =
std::string(mainFile->getDir()->getName()) + '/' + mainFile->getName();
Elements.push_back(MakeConstantString(path, ".objc_source_file_name"));
-
Elements.push_back(SymTab);
+
+ switch (CGM.getLangOptions().getGCMode()) {
+ case LangOptions::GCOnly:
+ Elements.push_back(llvm::ConstantInt::get(IntTy, 2));
+ case LangOptions::NonGC:
+ break;
+ case LangOptions::HybridGC:
+ Elements.push_back(llvm::ConstantInt::get(IntTy, 1));
+ }
+
llvm::Value *Module = MakeGlobal(ModuleTy, Elements);
// Create the load function calling the runtime entry point with the module
@@ -2159,10 +2176,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
CGBuilderTy Builder(VMContext);
Builder.SetInsertPoint(EntryBB);
- std::vector<const llvm::Type*> Params(1,
- llvm::PointerType::getUnqual(ModuleTy));
- llvm::Value *Register = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- llvm::Type::getVoidTy(VMContext), Params, true), "__objc_exec_class");
+ llvm::FunctionType *FT =
+ llvm::FunctionType::get(Builder.getVoidTy(),
+ llvm::PointerType::getUnqual(ModuleTy), true);
+ llvm::Value *Register = CGM.CreateRuntimeFunction(FT, "__objc_exec_class");
Builder.CreateCall(Register, Module);
Builder.CreateRetVoid();
@@ -2192,18 +2209,18 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
return Method;
}
-llvm::Function *CGObjCGNU::GetPropertyGetFunction() {
+llvm::Constant *CGObjCGNU::GetPropertyGetFunction() {
return GetPropertyFn;
}
-llvm::Function *CGObjCGNU::GetPropertySetFunction() {
+llvm::Constant *CGObjCGNU::GetPropertySetFunction() {
return SetPropertyFn;
}
-llvm::Function *CGObjCGNU::GetGetStructFunction() {
+llvm::Constant *CGObjCGNU::GetGetStructFunction() {
return GetStructPropertyFn;
}
-llvm::Function *CGObjCGNU::GetSetStructFunction() {
+llvm::Constant *CGObjCGNU::GetSetStructFunction() {
return SetStructPropertyFn;
}
@@ -2273,7 +2290,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
CGBuilderTy B = CGF.Builder;
- AddrWeakObj = EnforceType(B, AddrWeakObj, IdTy);
+ AddrWeakObj = EnforceType(B, AddrWeakObj, PtrToIdTy);
return B.CreateCall(WeakReadFn, AddrWeakObj);
}
@@ -2303,7 +2320,7 @@ void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
llvm::Value *ivarOffset) {
CGBuilderTy B = CGF.Builder;
src = EnforceType(B, src, IdTy);
- dst = EnforceType(B, dst, PtrToIdTy);
+ dst = EnforceType(B, dst, IdTy);
B.CreateCall3(IvarAssignFn, src, dst, ivarOffset);
}
@@ -2320,8 +2337,8 @@ void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF,
llvm::Value *SrcPtr,
llvm::Value *Size) {
CGBuilderTy B = CGF.Builder;
- DestPtr = EnforceType(B, DestPtr, IdTy);
- SrcPtr = EnforceType(B, SrcPtr, PtrToIdTy);
+ DestPtr = EnforceType(B, DestPtr, PtrTy);
+ SrcPtr = EnforceType(B, SrcPtr, PtrTy);
B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, Size);
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 2b1cfe3da5bd..8c3e9a36e307 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -43,18 +43,6 @@ using namespace clang;
using namespace CodeGen;
-static void EmitNullReturnInitialization(CodeGenFunction &CGF,
- ReturnValueSlot &returnSlot,
- QualType resultType) {
- // Force the return slot to exist.
- if (!returnSlot.getValue())
- returnSlot = ReturnValueSlot(CGF.CreateMemTemp(resultType), false);
- CGF.EmitNullInitialization(returnSlot.getValue(), resultType);
-}
-
-
-///
-
namespace {
typedef std::vector<llvm::Constant*> ConstantVector;
@@ -67,89 +55,89 @@ protected:
llvm::LLVMContext &VMContext;
private:
+ // The types of these functions don't really matter because we
+ // should always bitcast before calling them.
+
+ /// id objc_msgSend (id, SEL, ...)
+ ///
+ /// The default messenger, used for sends whose ABI is unchanged from
+ /// the all-integer/pointer case.
llvm::Constant *getMessageSendFn() const {
- // id objc_msgSend (id, SEL, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(SelectorPtrTy);
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
- "objc_msgSend");
+ const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ params, true),
+ "objc_msgSend");
}
+ /// void objc_msgSend_stret (id, SEL, ...)
+ ///
+ /// The messenger used when the return value is an aggregate returned
+ /// by indirect reference in the first argument, and therefore the
+ /// self and selector parameters are shifted over by one.
llvm::Constant *getMessageSendStretFn() const {
- // id objc_msgSend_stret (id, SEL, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(SelectorPtrTy);
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, true),
- "objc_msgSend_stret");
+ const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy,
+ params, true),
+ "objc_msgSend_stret");
}
+ /// [double | long double] objc_msgSend_fpret(id self, SEL op, ...)
+ ///
+ /// The messenger used when the return value is returned on the x87
+ /// floating-point stack; without a special entrypoint, the nil case
+ /// would be unbalanced.
llvm::Constant *getMessageSendFpretFn() const {
- // FIXME: This should be long double on x86_64?
- // [double | long double] objc_msgSend_fpret(id self, SEL op, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(SelectorPtrTy);
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::Type::getDoubleTy(VMContext),
- Params,
- true),
- "objc_msgSend_fpret");
+ params, true),
+ "objc_msgSend_fpret");
}
+ /// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
+ ///
+ /// The messenger used for super calls, which have different dispatch
+ /// semantics. The class passed is the superclass of the current
+ /// class.
llvm::Constant *getMessageSendSuperFn() const {
- // id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
- const char *SuperName = "objc_msgSendSuper";
- std::vector<const llvm::Type*> Params;
- Params.push_back(SuperPtrTy);
- Params.push_back(SelectorPtrTy);
+ const llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
- SuperName);
+ params, true),
+ "objc_msgSendSuper");
}
+ /// id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
+ ///
+ /// A slightly different messenger used for super calls. The class
+ /// passed is the current class.
llvm::Constant *getMessageSendSuperFn2() const {
- // id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
- const char *SuperName = "objc_msgSendSuper2";
- std::vector<const llvm::Type*> Params;
- Params.push_back(SuperPtrTy);
- Params.push_back(SelectorPtrTy);
+ const llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
- SuperName);
+ params, true),
+ "objc_msgSendSuper2");
}
+ /// void objc_msgSendSuper_stret(void *stretAddr, struct objc_super *super,
+ /// SEL op, ...)
+ ///
+ /// The messenger used for super calls which return an aggregate indirectly.
llvm::Constant *getMessageSendSuperStretFn() const {
- // void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super,
- // SEL op, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(Int8PtrTy);
- Params.push_back(SuperPtrTy);
- Params.push_back(SelectorPtrTy);
+ const llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, true),
+ llvm::FunctionType::get(CGM.VoidTy, params, true),
"objc_msgSendSuper_stret");
}
+ /// void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super,
+ /// SEL op, ...)
+ ///
+ /// objc_msgSendSuper_stret with the super2 semantics.
llvm::Constant *getMessageSendSuperStretFn2() const {
- // void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super,
- // SEL op, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(Int8PtrTy);
- Params.push_back(SuperPtrTy);
- Params.push_back(SelectorPtrTy);
+ const llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, true),
+ llvm::FunctionType::get(CGM.VoidTy, params, true),
"objc_msgSendSuper2_stret");
}
@@ -282,107 +270,97 @@ public:
/// GcReadWeakFn -- LLVM objc_read_weak (id *src) function.
llvm::Constant *getGcReadWeakFn() {
// id objc_read_weak (id *)
- std::vector<const llvm::Type*> Args;
- Args.push_back(ObjectPtrTy->getPointerTo());
+ const llvm::Type *args[] = { ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
}
/// GcAssignWeakFn -- LLVM objc_assign_weak function.
llvm::Constant *getGcAssignWeakFn() {
// id objc_assign_weak (id, id *)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
- Args.push_back(ObjectPtrTy->getPointerTo());
+ const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
}
/// GcAssignGlobalFn -- LLVM objc_assign_global function.
llvm::Constant *getGcAssignGlobalFn() {
// id objc_assign_global(id, id *)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
- Args.push_back(ObjectPtrTy->getPointerTo());
+ const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
}
/// GcAssignThreadLocalFn -- LLVM objc_assign_threadlocal function.
llvm::Constant *getGcAssignThreadLocalFn() {
// id objc_assign_threadlocal(id src, id * dest)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
- Args.push_back(ObjectPtrTy->getPointerTo());
+ const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal");
}
/// GcAssignIvarFn -- LLVM objc_assign_ivar function.
llvm::Constant *getGcAssignIvarFn() {
// id objc_assign_ivar(id, id *, ptrdiff_t)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
- Args.push_back(ObjectPtrTy->getPointerTo());
- Args.push_back(LongTy);
+ const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo(),
+ CGM.PtrDiffTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
}
/// GcMemmoveCollectableFn -- LLVM objc_memmove_collectable function.
llvm::Constant *GcMemmoveCollectableFn() {
// void *objc_memmove_collectable(void *dst, const void *src, size_t size)
- std::vector<const llvm::Type*> Args(1, Int8PtrTy);
- Args.push_back(Int8PtrTy);
- Args.push_back(LongTy);
- llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
+ const llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, LongTy };
+ llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
}
/// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function.
llvm::Constant *getGcAssignStrongCastFn() {
// id objc_assign_strongCast(id, id *)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
- Args.push_back(ObjectPtrTy->getPointerTo());
+ const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
}
/// ExceptionThrowFn - LLVM objc_exception_throw function.
llvm::Constant *getExceptionThrowFn() {
// void objc_exception_throw(id)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ const llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
+ llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
}
/// ExceptionRethrowFn - LLVM objc_exception_rethrow function.
llvm::Constant *getExceptionRethrowFn() {
// void objc_exception_rethrow(void)
- std::vector<const llvm::Type*> Args;
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false);
return CGM.CreateRuntimeFunction(FTy, "objc_exception_rethrow");
}
/// SyncEnterFn - LLVM object_sync_enter function.
llvm::Constant *getSyncEnterFn() {
// void objc_sync_enter (id)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ const llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
+ llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
}
/// SyncExitFn - LLVM object_sync_exit function.
llvm::Constant *getSyncExitFn() {
// void objc_sync_exit (id)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ const llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
+ llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
}
@@ -474,55 +452,44 @@ public:
/// ExceptionTryEnterFn - LLVM objc_exception_try_enter function.
llvm::Constant *getExceptionTryEnterFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy));
+ const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, false),
+ llvm::FunctionType::get(CGM.VoidTy, params, false),
"objc_exception_try_enter");
}
/// ExceptionTryExitFn - LLVM objc_exception_try_exit function.
llvm::Constant *getExceptionTryExitFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy));
+ const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, false),
+ llvm::FunctionType::get(CGM.VoidTy, params, false),
"objc_exception_try_exit");
}
/// ExceptionExtractFn - LLVM objc_exception_extract function.
llvm::Constant *getExceptionExtractFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy));
+ const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, false),
+ params, false),
"objc_exception_extract");
-
}
/// ExceptionMatchFn - LLVM objc_exception_match function.
llvm::Constant *getExceptionMatchFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(ClassPtrTy);
- Params.push_back(ObjectPtrTy);
+ const llvm::Type *params[] = { ClassPtrTy, ObjectPtrTy };
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext),
- Params, false),
+ llvm::FunctionType::get(CGM.Int32Ty, params, false),
"objc_exception_match");
}
/// SetJmpFn - LLVM _setjmp function.
llvm::Constant *getSetJmpFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(llvm::Type::getInt32PtrTy(VMContext));
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext),
- Params, false),
- "_setjmp");
-
+ // This is specifically the prototype for x86.
+ const llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
+ params, false),
+ "_setjmp");
}
public:
@@ -608,68 +575,56 @@ public:
llvm::Constant *getMessageSendFixupFn() {
// id objc_msgSend_fixup(id, struct message_ref_t*, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(MessageRefPtrTy);
+ const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
+ params, true),
"objc_msgSend_fixup");
}
llvm::Constant *getMessageSendFpretFixupFn() {
// id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(MessageRefPtrTy);
+ const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
+ params, true),
"objc_msgSend_fpret_fixup");
}
llvm::Constant *getMessageSendStretFixupFn() {
// id objc_msgSend_stret_fixup(id, struct message_ref_t*, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(MessageRefPtrTy);
+ const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
+ params, true),
"objc_msgSend_stret_fixup");
}
llvm::Constant *getMessageSendSuper2FixupFn() {
// id objc_msgSendSuper2_fixup (struct objc_super *,
// struct _super_message_ref_t*, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(SuperPtrTy);
- Params.push_back(SuperMessageRefPtrTy);
+ const llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
+ params, true),
"objc_msgSendSuper2_fixup");
}
llvm::Constant *getMessageSendSuper2StretFixupFn() {
// id objc_msgSendSuper2_stret_fixup(struct objc_super *,
// struct _super_message_ref_t*, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(SuperPtrTy);
- Params.push_back(SuperMessageRefPtrTy);
+ const llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
+ params, true),
"objc_msgSendSuper2_stret_fixup");
}
llvm::Constant *getObjCEndCatchFn() {
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- false),
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy, false),
"objc_end_catch");
}
llvm::Constant *getObjCBeginCatchFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(Int8PtrTy);
+ const llvm::Type *params[] = { Int8PtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(Int8PtrTy,
- Params, false),
+ params, false),
"objc_begin_catch");
}
@@ -865,16 +820,16 @@ protected:
unsigned Align,
bool AddToUsed);
- CodeGen::RValue EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- llvm::Value *Sel,
- llvm::Value *Arg0,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *OMD,
- const ObjCCommonTypesHelper &ObjCTypes);
+ CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
+ QualType ResultType,
+ llvm::Value *Sel,
+ llvm::Value *Arg0,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *OMD,
+ const ObjCCommonTypesHelper &ObjCTypes);
/// EmitImageInfo - Emit the image info marker used to encode some module
/// level information.
@@ -1093,6 +1048,13 @@ public:
virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
+
+ /// GetClassGlobal - Return the global variable for the Objective-C
+ /// class of the given name.
+ virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
+ assert(false && "CGObjCMac::GetClassGlobal");
+ return 0;
+ }
};
class CGObjCNonFragileABIMac : public CGObjCCommonMac {
@@ -1110,16 +1072,16 @@ private:
/// EHTypeReferences - uniqued class ehtype references.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> EHTypeReferences;
- /// NonLegacyDispatchMethods - List of methods for which we do *not* generate
- /// legacy messaging dispatch.
- llvm::DenseSet<Selector> NonLegacyDispatchMethods;
+ /// VTableDispatchMethods - List of methods for which we generate
+ /// vtable-based message dispatch.
+ llvm::DenseSet<Selector> VTableDispatchMethods;
/// DefinedMetaClasses - List of defined meta-classes.
std::vector<llvm::GlobalValue*> DefinedMetaClasses;
- /// LegacyDispatchedSelector - Returns true if SEL is not in the list of
- /// NonLegacyDispatchMethods; false otherwise.
- bool LegacyDispatchedSelector(Selector Sel);
+ /// isVTableDispatchedSelector - Returns true if SEL is a
+ /// vtable-based selector.
+ bool isVTableDispatchedSelector(Selector Sel);
/// FinishNonFragileABIModule - Write out global data structures at the end of
/// processing a translation unit.
@@ -1178,20 +1140,20 @@ private:
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end);
- CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method);
-
+ CodeGen::RValue EmitVTableMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method);
+
/// GetClassGlobal - Return the global variable for the Objective-C
/// class of the given name.
llvm::GlobalVariable *GetClassGlobal(const std::string &Name);
-
+
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class reference.
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
@@ -1347,6 +1309,46 @@ public:
const ObjCIvarDecl *Ivar);
};
+/// A helper class for performing the null-initialization of a return
+/// value.
+struct NullReturnState {
+ llvm::BasicBlock *NullBB;
+
+ NullReturnState() : NullBB(0) {}
+
+ void init(CodeGenFunction &CGF, llvm::Value *receiver) {
+ // Make blocks for the null-init and call edges.
+ NullBB = CGF.createBasicBlock("msgSend.nullinit");
+ llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call");
+
+ // Check for a null receiver and, if there is one, jump to the
+ // null-init test.
+ llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
+ CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
+
+ // Otherwise, start performing the call.
+ CGF.EmitBlock(callBB);
+ }
+
+ RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType) {
+ if (!NullBB) return result;
+
+ // Finish the call path.
+ llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont");
+ if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB);
+
+ // Emit the null-init block and perform the null-initialization there.
+ CGF.EmitBlock(NullBB);
+ assert(result.isAggregate() && "null init of non-aggregate result?");
+ CGF.EmitNullInitialization(result.getAggregateAddr(), resultType);
+
+ // Jump to the continuation block.
+ CGF.EmitBlock(contBB);
+
+ return result;
+ }
+};
+
} // end anonymous namespace
/* *** Helper Functions *** */
@@ -1487,10 +1489,10 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
- return EmitLegacyMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
- ObjCSuper, ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method, ObjCTypes);
+ return EmitMessageSend(CGF, Return, ResultType,
+ EmitSelector(CGF.Builder, Sel),
+ ObjCSuper, ObjCTypes.SuperPtrCTy,
+ true, CallArgs, Method, ObjCTypes);
}
/// Generate code for a message send expression.
@@ -1502,23 +1504,23 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
- return EmitLegacyMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
- Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method, ObjCTypes);
+ return EmitMessageSend(CGF, Return, ResultType,
+ EmitSelector(CGF.Builder, Sel),
+ Receiver, CGF.getContext().getObjCIdType(),
+ false, CallArgs, Method, ObjCTypes);
}
CodeGen::RValue
-CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- llvm::Value *Sel,
- llvm::Value *Arg0,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method,
- const ObjCCommonTypesHelper &ObjCTypes) {
+CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
+ QualType ResultType,
+ llvm::Value *Sel,
+ llvm::Value *Arg0,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method,
+ const ObjCCommonTypesHelper &ObjCTypes) {
CallArgList ActualArgs;
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
@@ -1537,9 +1539,11 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
CGM.getContext().getCanonicalType(ResultType) &&
"Result type mismatch!");
+ NullReturnState nullReturn;
+
llvm::Constant *Fn = NULL;
if (CGM.ReturnTypeUsesSRet(FnInfo)) {
- EmitNullReturnInitialization(CGF, Return, ResultType);
+ if (!IsSuper) nullReturn.init(CGF, Arg0);
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
@@ -1550,7 +1554,8 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
: ObjCTypes.getSendFn(IsSuper);
}
Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
- return CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
+ RValue rvalue = CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
+ return nullReturn.complete(CGF, rvalue, ResultType);
}
static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
@@ -1681,6 +1686,7 @@ void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
if (DefinedProtocols.count(PD->getIdentifier()))
return GetOrEmitProtocol(PD);
+
return GetOrEmitProtocolRef(PD);
}
@@ -1714,6 +1720,9 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (!C)
+ return GetOrEmitProtocolRef(PD);
+
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptInstanceMethods.push_back(C);
} else {
@@ -1725,6 +1734,9 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (!C)
+ return GetOrEmitProtocolRef(PD);
+
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptClassMethods.push_back(C);
} else {
@@ -1968,6 +1980,9 @@ CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
ObjCTypes.SelectorPtrTy);
Desc[1] = GetMethodVarType(MD);
+ if (!Desc[1])
+ return 0;
+
return llvm::ConstantStruct::get(ObjCTypes.MethodDescriptionTy,
Desc);
}
@@ -2730,10 +2745,10 @@ void FragileHazards::collectLocals() {
}
llvm::FunctionType *FragileHazards::GetAsmFnType() {
- std::vector<const llvm::Type *> Tys(Locals.size());
- for (unsigned I = 0, E = Locals.size(); I != E; ++I)
- Tys[I] = Locals[I]->getType();
- return llvm::FunctionType::get(CGF.Builder.getVoidTy(), Tys, false);
+ llvm::SmallVector<const llvm::Type *, 16> tys(Locals.size());
+ for (unsigned i = 0, e = Locals.size(); i != e; ++i)
+ tys[i] = Locals[i]->getType();
+ return llvm::FunctionType::get(CGF.VoidTy, tys, false);
}
/*
@@ -3930,8 +3945,10 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) {
std::string TypeStr;
- CGM.getContext().getObjCEncodingForMethodDecl(const_cast<ObjCMethodDecl*>(D),
- TypeStr);
+ if (CGM.getContext().getObjCEncodingForMethodDecl(
+ const_cast<ObjCMethodDecl*>(D),
+ TypeStr))
+ return 0;
llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
@@ -4081,9 +4098,9 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_objc_super"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCIdType(), 0, 0, false));
+ Ctx.getObjCIdType(), 0, 0, false, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCClassType(), 0, 0, false));
+ Ctx.getObjCClassType(), 0, 0, false, false));
RD->completeDefinition();
SuperCTy = Ctx.getTagDeclType(RD);
@@ -4480,11 +4497,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
ClassRonfABITy);
// ImpnfABITy - LLVM for id (*)(id, SEL, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(SelectorPtrTy);
- ImpnfABITy = llvm::PointerType::getUnqual(
- llvm::FunctionType::get(ObjectPtrTy, Params, false));
+ const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ ImpnfABITy = llvm::FunctionType::get(ObjectPtrTy, params, false)
+ ->getPointerTo();
// struct _class_t {
// struct _class_t *isa;
@@ -4544,9 +4559,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_message_ref_t"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.VoidPtrTy, 0, 0, false));
+ Ctx.VoidPtrTy, 0, 0, false, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCSelType(), 0, 0, false));
+ Ctx.getObjCSelType(), 0, 0, false, false));
RD->completeDefinition();
MessageRefCTy = Ctx.getTagDeclType(RD);
@@ -4658,56 +4673,68 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
EmitImageInfo();
}
-/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
-/// NonLegacyDispatchMethods; false otherwise. What this means is that
+/// isVTableDispatchedSelector - Returns true if SEL is not in the list of
+/// VTableDispatchMethods; false otherwise. What this means is that
/// except for the 19 selectors in the list, we generate 32bit-style
/// message dispatch call for all the rest.
-///
-bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
+bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
+ // At various points we've experimented with using vtable-based
+ // dispatch for all methods.
switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
default:
- assert(0 && "Invalid dispatch method!");
+ llvm_unreachable("Invalid dispatch method!");
case CodeGenOptions::Legacy:
- return true;
- case CodeGenOptions::NonLegacy:
return false;
+ case CodeGenOptions::NonLegacy:
+ return true;
case CodeGenOptions::Mixed:
break;
}
// If so, see whether this selector is in the white-list of things which must
// use the new dispatch convention. We lazily build a dense set for this.
- if (NonLegacyDispatchMethods.empty()) {
- NonLegacyDispatchMethods.insert(GetNullarySelector("alloc"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("class"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("self"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("isFlipped"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("length"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("count"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("retain"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("release"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("autorelease"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("hash"));
-
- NonLegacyDispatchMethods.insert(GetUnarySelector("allocWithZone"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("objectForKey"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("isEqualToString"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("isEqual"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("addObject"));
- // "countByEnumeratingWithState:objects:count"
- IdentifierInfo *KeyIdents[] = {
- &CGM.getContext().Idents.get("countByEnumeratingWithState"),
- &CGM.getContext().Idents.get("objects"),
- &CGM.getContext().Idents.get("count")
- };
- NonLegacyDispatchMethods.insert(
- CGM.getContext().Selectors.getSelector(3, KeyIdents));
- }
-
- return (NonLegacyDispatchMethods.count(Sel) == 0);
+ if (VTableDispatchMethods.empty()) {
+ VTableDispatchMethods.insert(GetNullarySelector("alloc"));
+ VTableDispatchMethods.insert(GetNullarySelector("class"));
+ VTableDispatchMethods.insert(GetNullarySelector("self"));
+ VTableDispatchMethods.insert(GetNullarySelector("isFlipped"));
+ VTableDispatchMethods.insert(GetNullarySelector("length"));
+ VTableDispatchMethods.insert(GetNullarySelector("count"));
+
+ // These are vtable-based if GC is disabled.
+ // Optimistically use vtable dispatch for hybrid compiles.
+ if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
+ VTableDispatchMethods.insert(GetNullarySelector("retain"));
+ VTableDispatchMethods.insert(GetNullarySelector("release"));
+ VTableDispatchMethods.insert(GetNullarySelector("autorelease"));
+ }
+
+ VTableDispatchMethods.insert(GetUnarySelector("allocWithZone"));
+ VTableDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
+ VTableDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
+ VTableDispatchMethods.insert(GetUnarySelector("objectForKey"));
+ VTableDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
+ VTableDispatchMethods.insert(GetUnarySelector("isEqualToString"));
+ VTableDispatchMethods.insert(GetUnarySelector("isEqual"));
+
+ // These are vtable-based if GC is enabled.
+ // Optimistically use vtable dispatch for hybrid compiles.
+ if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ VTableDispatchMethods.insert(GetNullarySelector("hash"));
+ VTableDispatchMethods.insert(GetUnarySelector("addObject"));
+
+ // "countByEnumeratingWithState:objects:count"
+ IdentifierInfo *KeyIdents[] = {
+ &CGM.getContext().Idents.get("countByEnumeratingWithState"),
+ &CGM.getContext().Idents.get("objects"),
+ &CGM.getContext().Idents.get("count")
+ };
+ VTableDispatchMethods.insert(
+ CGM.getContext().Selectors.getSelector(3, KeyIdents));
+ }
+ }
+
+ return VTableDispatchMethods.count(Sel);
}
// Metadata flags
@@ -5209,7 +5236,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
IvarOffsetGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
else
IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility);
- IvarOffsetGV->setSection("__DATA, __objc_const");
+ IvarOffsetGV->setSection("__DATA, __objc_ivar");
return IvarOffsetGV;
}
@@ -5344,6 +5371,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (!C)
+ return GetOrEmitProtocolRef(PD);
+
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptInstanceMethods.push_back(C);
} else {
@@ -5355,6 +5385,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (!C)
+ return GetOrEmitProtocolRef(PD);
+
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptClassMethods.push_back(C);
} else {
@@ -5494,6 +5527,9 @@ CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
ObjCTypes.SelectorPtrTy);
Desc[1] = GetMethodVarType(MD);
+ if (!Desc[1])
+ return 0;
+
// Protocol methods have no implementation. So, this entry is always NULL.
Desc[2] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Desc);
@@ -5523,90 +5559,131 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),"ivar");
}
-CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
- CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method) {
- // FIXME. Even though IsSuper is passes. This function doese not handle calls
- // to 'super' receivers.
- CodeGenTypes &Types = CGM.getTypes();
- llvm::Value *Arg0 = Receiver;
- if (!IsSuper)
- Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
+static void appendSelectorForMessageRefTable(std::string &buffer,
+ Selector selector) {
+ if (selector.isUnarySelector()) {
+ buffer += selector.getNameForSlot(0);
+ return;
+ }
- // Find the message function name.
- // FIXME. This is too much work to get the ABI-specific result type needed to
- // find the message name.
- const CGFunctionInfo &FnInfo
- = Types.getFunctionInfo(ResultType, CallArgList(),
- FunctionType::ExtInfo());
- llvm::Constant *Fn = 0;
- std::string Name("\01l_");
- if (CGM.ReturnTypeUsesSRet(FnInfo)) {
- EmitNullReturnInitialization(CGF, Return, ResultType);
- if (IsSuper) {
- Fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
- Name += "objc_msgSendSuper2_stret_fixup";
+ for (unsigned i = 0, e = selector.getNumArgs(); i != e; ++i) {
+ buffer += selector.getNameForSlot(i);
+ buffer += '_';
+ }
+}
+
+/// Emit a "v-table" message send. We emit a weak hidden-visibility
+/// struct, initially containing the selector pointer and a pointer to
+/// a "fixup" variant of the appropriate objc_msgSend. To call, we
+/// load and call the function pointer, passing the address of the
+/// struct as the second parameter. The runtime determines whether
+/// the selector is currently emitted using vtable dispatch; if so, it
+/// substitutes a stub function which simply tail-calls through the
+/// appropriate vtable slot, and if not, it substitues a stub function
+/// which tail-calls objc_msgSend. Both stubs adjust the selector
+/// argument to correctly point to the selector.
+RValue
+CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
+ ReturnValueSlot returnSlot,
+ QualType resultType,
+ Selector selector,
+ llvm::Value *arg0,
+ QualType arg0Type,
+ bool isSuper,
+ const CallArgList &formalArgs,
+ const ObjCMethodDecl *method) {
+ // Compute the actual arguments.
+ CallArgList args;
+
+ // First argument: the receiver / super-call structure.
+ if (!isSuper)
+ arg0 = CGF.Builder.CreateBitCast(arg0, ObjCTypes.ObjectPtrTy);
+ args.add(RValue::get(arg0), arg0Type);
+
+ // Second argument: a pointer to the message ref structure. Leave
+ // the actual argument value blank for now.
+ args.add(RValue::get(0), ObjCTypes.MessageRefCPtrTy);
+
+ args.insert(args.end(), formalArgs.begin(), formalArgs.end());
+
+ const CGFunctionInfo &fnInfo =
+ CGM.getTypes().getFunctionInfo(resultType, args,
+ FunctionType::ExtInfo());
+
+ NullReturnState nullReturn;
+
+ // Find the function to call and the mangled name for the message
+ // ref structure. Using a different mangled name wouldn't actually
+ // be a problem; it would just be a waste.
+ //
+ // The runtime currently never uses vtable dispatch for anything
+ // except normal, non-super message-sends.
+ // FIXME: don't use this for that.
+ llvm::Constant *fn = 0;
+ std::string messageRefName("\01l_");
+ if (CGM.ReturnTypeUsesSRet(fnInfo)) {
+ if (isSuper) {
+ fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
+ messageRefName += "objc_msgSendSuper2_stret_fixup";
} else {
- Fn = ObjCTypes.getMessageSendStretFixupFn();
- Name += "objc_msgSend_stret_fixup";
+ nullReturn.init(CGF, arg0);
+ fn = ObjCTypes.getMessageSendStretFixupFn();
+ messageRefName += "objc_msgSend_stret_fixup";
}
- } else if (!IsSuper && CGM.ReturnTypeUsesFPRet(ResultType)) {
- Fn = ObjCTypes.getMessageSendFpretFixupFn();
- Name += "objc_msgSend_fpret_fixup";
+ } else if (!isSuper && CGM.ReturnTypeUsesFPRet(resultType)) {
+ fn = ObjCTypes.getMessageSendFpretFixupFn();
+ messageRefName += "objc_msgSend_fpret_fixup";
} else {
- if (IsSuper) {
- Fn = ObjCTypes.getMessageSendSuper2FixupFn();
- Name += "objc_msgSendSuper2_fixup";
+ if (isSuper) {
+ fn = ObjCTypes.getMessageSendSuper2FixupFn();
+ messageRefName += "objc_msgSendSuper2_fixup";
} else {
- Fn = ObjCTypes.getMessageSendFixupFn();
- Name += "objc_msgSend_fixup";
+ fn = ObjCTypes.getMessageSendFixupFn();
+ messageRefName += "objc_msgSend_fixup";
}
}
- assert(Fn && "CGObjCNonFragileABIMac::EmitMessageSend");
- Name += '_';
- std::string SelName(Sel.getAsString());
- // Replace all ':' in selector name with '_' ouch!
- for (unsigned i = 0; i < SelName.size(); i++)
- if (SelName[i] == ':')
- SelName[i] = '_';
- Name += SelName;
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
- if (!GV) {
- // Build message ref table entry.
- std::vector<llvm::Constant*> Values(2);
- Values[0] = Fn;
- Values[1] = GetMethodVarName(Sel);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
- GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::WeakAnyLinkage,
- Init,
- Name);
- GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- GV->setAlignment(16);
- GV->setSection("__DATA, __objc_msgrefs, coalesced");
- }
- llvm::Value *Arg1 = CGF.Builder.CreateBitCast(GV, ObjCTypes.MessageRefPtrTy);
-
- CallArgList ActualArgs;
- ActualArgs.add(RValue::get(Arg0), Arg0Ty);
- ActualArgs.add(RValue::get(Arg1), ObjCTypes.MessageRefCPtrTy);
- ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
- const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs,
- FunctionType::ExtInfo());
- llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0);
- Callee = CGF.Builder.CreateLoad(Callee);
- const llvm::FunctionType *FTy =
- Types.GetFunctionType(FnInfo1, Method ? Method->isVariadic() : false);
- Callee = CGF.Builder.CreateBitCast(Callee,
- llvm::PointerType::getUnqual(FTy));
- return CGF.EmitCall(FnInfo1, Callee, Return, ActualArgs);
+ assert(fn && "CGObjCNonFragileABIMac::EmitMessageSend");
+ messageRefName += '_';
+
+ // Append the selector name, except use underscores anywhere we
+ // would have used colons.
+ appendSelectorForMessageRefTable(messageRefName, selector);
+
+ llvm::GlobalVariable *messageRef
+ = CGM.getModule().getGlobalVariable(messageRefName);
+ if (!messageRef) {
+ // Build the message ref structure.
+ llvm::Constant *values[] = { fn, GetMethodVarName(selector) };
+ llvm::Constant *init =
+ llvm::ConstantStruct::get(VMContext, values, 2, false);
+ messageRef = new llvm::GlobalVariable(CGM.getModule(),
+ init->getType(),
+ /*constant*/ false,
+ llvm::GlobalValue::WeakAnyLinkage,
+ init,
+ messageRefName);
+ messageRef->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ messageRef->setAlignment(16);
+ messageRef->setSection("__DATA, __objc_msgrefs, coalesced");
+ }
+ llvm::Value *mref =
+ CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy);
+
+ // Update the message ref argument.
+ args[1].RV = RValue::get(mref);
+
+ // Load the function to call from the message ref table.
+ llvm::Value *callee = CGF.Builder.CreateStructGEP(mref, 0);
+ callee = CGF.Builder.CreateLoad(callee, "msgSend_fn");
+
+ bool variadic = method ? method->isVariadic() : false;
+ const llvm::FunctionType *fnType =
+ CGF.getTypes().GetFunctionType(fnInfo, variadic);
+ callee = CGF.Builder.CreateBitCast(callee,
+ llvm::PointerType::getUnqual(fnType));
+
+ RValue result = CGF.EmitCall(fnInfo, callee, returnSlot, args);
+ return nullReturn.complete(CGF, result, resultType);
}
/// Generate code for a message send expression in the nonfragile abi.
@@ -5619,14 +5696,14 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
- return LegacyDispatchedSelector(Sel)
- ? EmitLegacyMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ return isVTableDispatchedSelector(Sel)
+ ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method, ObjCTypes)
- : EmitMessageSend(CGF, Return, ResultType, Sel,
+ false, CallArgs, Method)
+ : EmitMessageSend(CGF, Return, ResultType,
+ EmitSelector(CGF.Builder, Sel),
Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method);
+ false, CallArgs, Method, ObjCTypes);
}
llvm::GlobalVariable *
@@ -5773,14 +5850,14 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
- return (LegacyDispatchedSelector(Sel))
- ? EmitLegacyMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ return (isVTableDispatchedSelector(Sel))
+ ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
ObjCSuper, ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method, ObjCTypes)
- : EmitMessageSend(CGF, Return, ResultType, Sel,
+ true, CallArgs, Method)
+ : EmitMessageSend(CGF, Return, ResultType,
+ EmitSelector(CGF.Builder, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method);
+ true, CallArgs, Method, ObjCTypes);
}
llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 3d854d41acbe..21150f1f848c 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -165,9 +165,9 @@ namespace {
void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
const ObjCAtTryStmt &S,
- llvm::Function *beginCatchFn,
- llvm::Function *endCatchFn,
- llvm::Function *exceptionRethrowFn) {
+ llvm::Constant *beginCatchFn,
+ llvm::Constant *endCatchFn,
+ llvm::Constant *exceptionRethrowFn) {
// Jump destination for falling out of catch bodies.
CodeGenFunction::JumpDest Cont;
if (S.getNumCatchStmts())
@@ -233,6 +233,8 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
cast<llvm::CallInst>(Exn)->setDoesNotThrow();
}
+ CodeGenFunction::RunCleanupsScope cleanups(CGF);
+
if (endCatchFn) {
// Add a cleanup to leave the catch.
bool EndCatchMightThrow = (Handler.Variable == 0);
@@ -255,9 +257,8 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CGF.EmitStmt(Handler.Body);
CGF.ObjCEHValueStack.pop_back();
- // Leave the earlier cleanup.
- if (endCatchFn)
- CGF.PopCleanupBlock();
+ // Leave any cleanups associated with the catch.
+ cleanups.ForceCleanup();
CGF.EmitBranchThroughCleanup(Cont);
}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 0cc2d824d401..866d5d83fe60 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -95,9 +95,9 @@ protected:
/// thrown object directly.
void EmitTryCatchStmt(CodeGenFunction &CGF,
const ObjCAtTryStmt &S,
- llvm::Function *beginCatchFn,
- llvm::Function *endCatchFn,
- llvm::Function *exceptionRethrowFn);
+ llvm::Constant *beginCatchFn,
+ llvm::Constant *endCatchFn,
+ llvm::Constant *exceptionRethrowFn);
/// Emits an @synchronize() statement, using the syncEnterFn and syncExitFn
/// arguments as the functions called to lock and unlock the object. This
/// function can be called by subclasses that use zero-cost exception
@@ -243,6 +243,7 @@ public:
llvm::Value *Size) = 0;
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
+ virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0;
};
/// Creates an instance of an Objective-C runtime class.
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index a4ac390dd98c..0d72f854ba3e 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -234,7 +234,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty));
uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
- bool IsSigned = FD->getType()->isSignedIntegerType();
+ bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
if (FieldSize > TypeSizeInBits) {
// We have a wide bit-field. The extra bits are only used for padding, so
@@ -753,8 +753,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Zero-length bitfields following non-bitfield members are
// ignored:
const FieldDecl *FD = (*Field);
- if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD) ||
- Types.getContext().ZeroBitfieldFollowsBitfield(FD, LastFD)) {
+ if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD)) {
--FieldNo;
continue;
}
@@ -997,8 +996,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are
// ignored:
- if (getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD) ||
- getContext().ZeroBitfieldFollowsBitfield(FD, LastFD)) {
+ if (getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD)) {
--i;
continue;
}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 99bc3f49ce92..a982621be79a 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -773,10 +773,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
// As long as debug info is modeled with instructions, we have to ensure we
// have a place to insert here and write the stop point here.
- if (getDebugInfo()) {
- EnsureInsertPoint();
+ if (getDebugInfo() && HaveInsertPoint())
EmitStopPoint(&S);
- }
for (DeclStmt::const_decl_iterator I = S.decl_begin(), E = S.decl_end();
I != E; ++I)
@@ -999,7 +997,7 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S,
// If we're looking for the case, just see if we can skip each of the
// substatements.
for (; Case && I != E; ++I) {
- HadSkippedDecl |= isa<DeclStmt>(I);
+ HadSkippedDecl |= isa<DeclStmt>(*I);
switch (CollectStatementsForCase(*I, Case, FoundCase, ResultStmts)) {
case CSFC_Failure: return CSFC_Failure;
@@ -1224,7 +1222,7 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
while (*Constraint) {
switch (*Constraint) {
default:
- Result += Target.convertConstraint(*Constraint);
+ Result += Target.convertConstraint(Constraint);
break;
// Ignore these
case '*':
@@ -1422,8 +1420,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
const Expr *OutExpr = S.getOutputExpr(i);
OutExpr = OutExpr->IgnoreParenNoopCasts(getContext());
- OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr, Target,
- CGM, S);
+ OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr,
+ Target, CGM, S);
LValue Dest = EmitLValue(OutExpr);
if (!Constraints.empty())
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index a6849f8f3d21..aefc41e50002 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -411,6 +411,8 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
Out.flush();
llvm::StringRef Name = OutName.str();
+ ComputeVTableRelatedInformation(RD, /*VTableRequired=*/true);
+
VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
const llvm::Type *Int8PtrTy =
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 581467c53751..9ac5e67ada4d 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -21,6 +21,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
+#include "llvm/Transforms/Utils/Cloning.h"
#include <algorithm>
#include <cstdio>
@@ -2636,6 +2637,131 @@ static bool similar(const ABIArgInfo &infoL, CanQualType typeL,
}
#endif
+static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
+ QualType ResultType, RValue RV,
+ const ThunkInfo &Thunk) {
+ // Emit the return adjustment.
+ bool NullCheckValue = !ResultType->isReferenceType();
+
+ llvm::BasicBlock *AdjustNull = 0;
+ llvm::BasicBlock *AdjustNotNull = 0;
+ llvm::BasicBlock *AdjustEnd = 0;
+
+ llvm::Value *ReturnValue = RV.getScalarVal();
+
+ if (NullCheckValue) {
+ AdjustNull = CGF.createBasicBlock("adjust.null");
+ AdjustNotNull = CGF.createBasicBlock("adjust.notnull");
+ AdjustEnd = CGF.createBasicBlock("adjust.end");
+
+ llvm::Value *IsNull = CGF.Builder.CreateIsNull(ReturnValue);
+ CGF.Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull);
+ CGF.EmitBlock(AdjustNotNull);
+ }
+
+ ReturnValue = PerformTypeAdjustment(CGF, ReturnValue,
+ Thunk.Return.NonVirtual,
+ Thunk.Return.VBaseOffsetOffset);
+
+ if (NullCheckValue) {
+ CGF.Builder.CreateBr(AdjustEnd);
+ CGF.EmitBlock(AdjustNull);
+ CGF.Builder.CreateBr(AdjustEnd);
+ CGF.EmitBlock(AdjustEnd);
+
+ llvm::PHINode *PHI = CGF.Builder.CreatePHI(ReturnValue->getType(), 2);
+ PHI->addIncoming(ReturnValue, AdjustNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()),
+ AdjustNull);
+ ReturnValue = PHI;
+ }
+
+ return RValue::get(ReturnValue);
+}
+
+// This function does roughly the same thing as GenerateThunk, but in a
+// very different way, so that va_start and va_end work correctly.
+// FIXME: This function assumes "this" is the first non-sret LLVM argument of
+// a function, and that there is an alloca built in the entry block
+// for all accesses to "this".
+// FIXME: This function assumes there is only one "ret" statement per function.
+// FIXME: Cloning isn't correct in the presence of indirect goto!
+// FIXME: This implementation of thunks bloats codesize by duplicating the
+// function definition. There are alternatives:
+// 1. Add some sort of stub support to LLVM for cases where we can
+// do a this adjustment, then a sibcall.
+// 2. We could transform the definition to take a va_list instead of an
+// actual variable argument list, then have the thunks (including a
+// no-op thunk for the regular definition) call va_start/va_end.
+// There's a bit of per-call overhead for this solution, but it's
+// better for codesize if the definition is long.
+void CodeGenFunction::GenerateVarArgsThunk(
+ llvm::Function *Fn,
+ const CGFunctionInfo &FnInfo,
+ GlobalDecl GD, const ThunkInfo &Thunk) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ QualType ResultType = FPT->getResultType();
+
+ // Get the original function
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(FnInfo, /*IsVariadic*/true);
+ llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
+ llvm::Function *BaseFn = cast<llvm::Function>(Callee);
+
+ // Clone to thunk.
+ llvm::Function *NewFn = llvm::CloneFunction(BaseFn);
+ CGM.getModule().getFunctionList().push_back(NewFn);
+ Fn->replaceAllUsesWith(NewFn);
+ NewFn->takeName(Fn);
+ Fn->eraseFromParent();
+ Fn = NewFn;
+
+ // "Initialize" CGF (minimally).
+ CurFn = Fn;
+
+ // Get the "this" value
+ llvm::Function::arg_iterator AI = Fn->arg_begin();
+ if (CGM.ReturnTypeUsesSRet(FnInfo))
+ ++AI;
+
+ // Find the first store of "this", which will be to the alloca associated
+ // with "this".
+ llvm::Value *ThisPtr = &*AI;
+ llvm::BasicBlock *EntryBB = Fn->begin();
+ llvm::Instruction *ThisStore = 0;
+ for (llvm::BasicBlock::iterator I = EntryBB->begin(), E = EntryBB->end();
+ I != E; I++) {
+ if (isa<llvm::StoreInst>(I) && I->getOperand(0) == ThisPtr) {
+ ThisStore = cast<llvm::StoreInst>(I);
+ break;
+ }
+ }
+ assert(ThisStore && "Store of this should be in entry block?");
+ // Adjust "this", if necessary.
+ Builder.SetInsertPoint(ThisStore);
+ llvm::Value *AdjustedThisPtr =
+ PerformTypeAdjustment(*this, ThisPtr,
+ Thunk.This.NonVirtual,
+ Thunk.This.VCallOffsetOffset);
+ ThisStore->setOperand(0, AdjustedThisPtr);
+
+ if (!Thunk.Return.isEmpty()) {
+ // Fix up the returned value, if necessary.
+ for (llvm::Function::iterator I = Fn->begin(), E = Fn->end(); I != E; I++) {
+ llvm::Instruction *T = I->getTerminator();
+ if (isa<llvm::ReturnInst>(T)) {
+ RValue RV = RValue::get(T->getOperand(0));
+ T->eraseFromParent();
+ Builder.SetInsertPoint(&*I);
+ RV = PerformReturnAdjustment(*this, ResultType, RV, Thunk);
+ Builder.CreateRet(RV.getScalarVal());
+ break;
+ }
+ }
+ }
+}
+
void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk) {
@@ -2715,45 +2841,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
// Now emit our call.
RValue RV = EmitCall(FnInfo, Callee, Slot, CallArgs, MD);
- if (!Thunk.Return.isEmpty()) {
- // Emit the return adjustment.
- bool NullCheckValue = !ResultType->isReferenceType();
-
- llvm::BasicBlock *AdjustNull = 0;
- llvm::BasicBlock *AdjustNotNull = 0;
- llvm::BasicBlock *AdjustEnd = 0;
-
- llvm::Value *ReturnValue = RV.getScalarVal();
-
- if (NullCheckValue) {
- AdjustNull = createBasicBlock("adjust.null");
- AdjustNotNull = createBasicBlock("adjust.notnull");
- AdjustEnd = createBasicBlock("adjust.end");
-
- llvm::Value *IsNull = Builder.CreateIsNull(ReturnValue);
- Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull);
- EmitBlock(AdjustNotNull);
- }
-
- ReturnValue = PerformTypeAdjustment(*this, ReturnValue,
- Thunk.Return.NonVirtual,
- Thunk.Return.VBaseOffsetOffset);
-
- if (NullCheckValue) {
- Builder.CreateBr(AdjustEnd);
- EmitBlock(AdjustNull);
- Builder.CreateBr(AdjustEnd);
- EmitBlock(AdjustEnd);
-
- llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType(), 2);
- PHI->addIncoming(ReturnValue, AdjustNotNull);
- PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()),
- AdjustNull);
- ReturnValue = PHI;
- }
-
- RV = RValue::get(ReturnValue);
- }
+ if (!Thunk.Return.isEmpty())
+ RV = PerformReturnAdjustment(*this, ResultType, RV, Thunk);
if (!ResultType->isVoidType() && Slot.isNull())
CGM.getCXXABI().EmitReturnFromThunk(*this, RV, ResultType);
@@ -2823,8 +2912,18 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
return;
}
- // Actually generate the thunk body.
- CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
+ if (ThunkFn->isVarArg()) {
+ // Varargs thunks are special; we can't just generate a call because
+ // we can't copy the varargs. Our implementation is rather
+ // expensive/sucky at the moment, so don't generate the thunk unless
+ // we have to.
+ // FIXME: Do something better here; GenerateVarArgsThunk is extremely ugly.
+ if (!UseAvailableExternallyLinkage)
+ CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, Thunk);
+ } else {
+ // Normal thunk body generation.
+ CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
+ }
if (UseAvailableExternallyLinkage)
ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
@@ -3076,7 +3175,7 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
Out.flush();
llvm::StringRef Name = OutName.str();
- ComputeVTableRelatedInformation(RD, true);
+ ComputeVTableRelatedInformation(RD, /*VTableRequired=*/true);
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
llvm::ArrayType *ArrayType =
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 626c2b09a032..150cb69b4d1a 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -33,9 +33,9 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()),
BlockInfo(0), BlockPointer(0),
NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1),
- ExceptionSlot(0), DebugInfo(0), DisableDebugInfo(false), IndirectBranch(0),
- SwitchInsn(0), CaseRangeBlock(0),
- DidCallStackSave(false), UnreachableBlock(0),
+ ExceptionSlot(0), EHSelectorSlot(0),
+ DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
+ IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0),
OutermostConditional(0), TerminateLandingPad(0), TerminateHandler(0),
TrapBB(0) {
@@ -44,10 +44,6 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
CGM.getCXXABI().getMangleContext().startNewFunction();
}
-ASTContext &CodeGenFunction::getContext() const {
- return CGM.getContext();
-}
-
const llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) {
return CGM.getTypes().ConvertTypeForMem(T);
@@ -57,9 +53,41 @@ const llvm::Type *CodeGenFunction::ConvertType(QualType T) {
return CGM.getTypes().ConvertType(T);
}
-bool CodeGenFunction::hasAggregateLLVMType(QualType T) {
- return T->isRecordType() || T->isArrayType() || T->isAnyComplexType() ||
- T->isObjCObjectType();
+bool CodeGenFunction::hasAggregateLLVMType(QualType type) {
+ switch (type.getCanonicalType()->getTypeClass()) {
+#define TYPE(name, parent)
+#define ABSTRACT_TYPE(name, parent)
+#define NON_CANONICAL_TYPE(name, parent) case Type::name:
+#define DEPENDENT_TYPE(name, parent) case Type::name:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(name, parent) case Type::name:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("non-canonical or dependent type in IR-generation");
+
+ case Type::Builtin:
+ case Type::Pointer:
+ case Type::BlockPointer:
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::MemberPointer:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ case Type::Enum:
+ case Type::ObjCObjectPointer:
+ return false;
+
+ // Complexes, arrays, records, and Objective-C objects.
+ case Type::Complex:
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::Record:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ return true;
+ }
+ llvm_unreachable("unknown type kind!");
}
void CodeGenFunction::EmitReturnBlock() {
@@ -168,7 +196,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
bool CodeGenFunction::ShouldInstrumentFunction() {
if (!CGM.getCodeGenOpts().InstrumentFunctions)
return false;
- if (CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>())
+ if (!CurFuncDecl || CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>())
return false;
return true;
}
@@ -177,16 +205,12 @@ bool CodeGenFunction::ShouldInstrumentFunction() {
/// instrumentation function with the current function and the call site, if
/// function instrumentation is enabled.
void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
- const llvm::PointerType *PointerTy;
- const llvm::FunctionType *FunctionTy;
- std::vector<const llvm::Type*> ProfileFuncArgs;
-
// void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site);
- PointerTy = Int8PtrTy;
- ProfileFuncArgs.push_back(PointerTy);
- ProfileFuncArgs.push_back(PointerTy);
- FunctionTy = llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
- ProfileFuncArgs, false);
+ const llvm::PointerType *PointerTy = Int8PtrTy;
+ const llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy };
+ const llvm::FunctionType *FunctionTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
+ ProfileFuncArgs, false);
llvm::Constant *F = CGM.CreateRuntimeFunction(FunctionTy, Fn);
llvm::CallInst *CallSite = Builder.CreateCall(
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 169c576f1a0e..bb8fd8e24306 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -603,6 +603,10 @@ public:
/// exception pointer into this alloca.
llvm::Value *ExceptionSlot;
+ /// The selector slot. Under the MandatoryCleanup model, all
+ /// landing pads write the current selector value into this alloca.
+ llvm::AllocaInst *EHSelectorSlot;
+
/// Emits a landing pad for the current EH stack.
llvm::BasicBlock *EmitLandingPad();
@@ -951,6 +955,10 @@ private:
CGDebugInfo *DebugInfo;
bool DisableDebugInfo;
+ /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
+ /// calling llvm.stacksave for multiple VLAs in the same scope.
+ bool DidCallStackSave;
+
/// IndirectBranch - The first time an indirect goto is seen we create a block
/// with an indirect branch. Every time we see the address of a label taken,
/// we add the label to the indirect goto. Every subsequent indirect goto is
@@ -997,10 +1005,6 @@ private:
// enter/leave scopes.
llvm::DenseMap<const Expr*, llvm::Value*> VLASizeMap;
- /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
- /// calling llvm.stacksave for multiple VLAs in the same scope.
- bool DidCallStackSave;
-
/// A block containing a single 'unreachable' instruction. Created
/// lazily by getUnreachableBlock().
llvm::BasicBlock *UnreachableBlock;
@@ -1035,7 +1039,7 @@ public:
CodeGenFunction(CodeGenModule &cgm);
CodeGenTypes &getTypes() const { return CGM.getTypes(); }
- ASTContext &getContext() const;
+ ASTContext &getContext() const { return CGM.getContext(); }
CGDebugInfo *getDebugInfo() {
if (DisableDebugInfo)
return NULL;
@@ -1050,6 +1054,7 @@ public:
/// Returns a pointer to the function's exception object slot, which
/// is assigned in every landing pad.
llvm::Value *getExceptionSlot();
+ llvm::Value *getEHSelectorSlot();
llvm::Value *getNormalCleanupDestSlot();
llvm::Value *getEHCleanupDestSlot();
@@ -1076,7 +1081,8 @@ public:
void GenerateObjCMethod(const ObjCMethodDecl *OMD);
void StartObjCMethod(const ObjCMethodDecl *MD,
- const ObjCContainerDecl *CD);
+ const ObjCContainerDecl *CD,
+ SourceLocation StartLoc);
/// GenerateObjCGetter - Synthesize an Objective-C property getter function.
void GenerateObjCGetter(ObjCImplementationDecl *IMP,
@@ -1157,6 +1163,9 @@ public:
void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk);
+ void GenerateVarArgsThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
+ GlobalDecl GD, const ThunkInfo &Thunk);
+
void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type,
FunctionArgList &Args);
@@ -1701,6 +1710,7 @@ public:
void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
+ llvm::Constant *getUnwindResumeFn();
llvm::Constant *getUnwindResumeOrRethrowFn();
void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
@@ -1915,6 +1925,9 @@ public:
RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
ReturnValueSlot ReturnValue);
+ llvm::Value *EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
+ const CXXMethodDecl *MD,
+ llvm::Value *This);
RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
const CXXMethodDecl *MD,
ReturnValueSlot ReturnValue);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 83e927fcadbc..7a1a968259f3 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -90,9 +90,10 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
- Int8Ty = llvm::Type::getInt8Ty(LLVMContext);
- Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
- Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
+ VoidTy = llvm::Type::getVoidTy(LLVMContext);
+ Int8Ty = llvm::Type::getInt8Ty(LLVMContext);
+ Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
+ Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
PointerWidthInBits = C.Target.getPointerWidth(0);
PointerAlignInBytes =
C.toCharUnitsFromBits(C.Target.getPointerAlign(0)).getQuantity();
@@ -132,6 +133,9 @@ void CodeGenModule::Release() {
if (getCodeGenOpts().EmitDeclMetadata)
EmitDeclMetadata();
+
+ if (getCodeGenOpts().EmitGcovArcs || getCodeGenOpts().EmitGcovNotes)
+ EmitCoverageFile();
}
void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
@@ -339,8 +343,7 @@ void CodeGenModule::AddGlobalDtor(llvm::Function * Dtor, int Priority) {
void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
// Ctor function type is void()*.
- llvm::FunctionType* CtorFTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false);
+ llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false);
llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy);
// Get the type of a ctor entry, { i32, void ()* }.
@@ -449,6 +452,9 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
llvm::Function *F) {
+ if (CodeGenOpts.UnwindTables)
+ F->setHasUWTable();
+
if (!Features.Exceptions && !Features.ObjCNonFragileABI)
F->addFnAttr(llvm::Attribute::NoUnwind);
@@ -724,7 +730,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
}
// Forward declarations are emitted lazily on first use.
- if (!FD->isThisDeclarationADefinition())
+ if (!FD->doesThisDeclarationHaveABody())
return;
} else {
const VarDecl *VD = cast<VarDecl>(Global);
@@ -790,14 +796,19 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
return;
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ // Make sure to emit the definition(s) before we emit the thunks.
+ // This is necessary for the generation of certain thunks.
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method))
+ EmitCXXConstructor(CD, GD.getCtorType());
+ else if (const CXXDestructorDecl *DD =dyn_cast<CXXDestructorDecl>(Method))
+ EmitCXXDestructor(DD, GD.getDtorType());
+ else
+ EmitGlobalFunctionDefinition(GD);
+
if (Method->isVirtual())
getVTables().EmitThunks(GD);
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method))
- return EmitCXXConstructor(CD, GD.getCtorType());
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(Method))
- return EmitCXXDestructor(DD, GD.getDtorType());
+ return;
}
return EmitGlobalFunctionDefinition(GD);
@@ -848,7 +859,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
if (isa<llvm::FunctionType>(Ty)) {
FTy = cast<llvm::FunctionType>(Ty);
} else {
- FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false);
+ FTy = llvm::FunctionType::get(VoidTy, false);
IsIncompleteFunction = true;
}
@@ -889,7 +900,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
assert(FD->isUsed() && "Sema didn't mark implicit function as used!");
DeferredDeclsToEmit.push_back(D.getWithDecl(FD));
break;
- } else if (FD->isThisDeclarationADefinition()) {
+ } else if (FD->doesThisDeclarationHaveABody()) {
DeferredDeclsToEmit.push_back(D.getWithDecl(FD));
break;
}
@@ -930,14 +941,19 @@ CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false);
}
-static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) {
+static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D,
+ bool ConstantInit) {
if (!D->getType().isConstant(Context) && !D->getType()->isReferenceType())
return false;
- if (Context.getLangOptions().CPlusPlus &&
- Context.getBaseElementType(D->getType())->getAs<RecordType>()) {
- // FIXME: We should do something fancier here!
- return false;
+
+ if (Context.getLangOptions().CPlusPlus) {
+ if (const RecordType *Record
+ = Context.getBaseElementType(D->getType())->getAs<RecordType>())
+ return ConstantInit &&
+ cast<CXXRecordDecl>(Record->getDecl())->isPOD() &&
+ !cast<CXXRecordDecl>(Record->getDecl())->hasMutableFields();
}
+
return true;
}
@@ -994,7 +1010,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
if (D) {
// FIXME: This code is overly simple and should be merged with other global
// handling.
- GV->setConstant(DeclIsConstantGlobal(Context, D));
+ GV->setConstant(DeclIsConstantGlobal(Context, D, false));
// Set linkage and visibility in case we never see a definition.
NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility();
@@ -1109,7 +1125,7 @@ void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) {
llvm::GlobalVariable::LinkageTypes
CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
- if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
+ if (RD->getLinkage() != ExternalLinkage)
return llvm::GlobalVariable::InternalLinkage;
if (const CXXMethodDecl *KeyFunction
@@ -1276,7 +1292,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// If it is safe to mark the global 'constant', do so now.
GV->setConstant(false);
- if (!NonConstInit && DeclIsConstantGlobal(Context, D))
+ if (!NonConstInit && DeclIsConstantGlobal(Context, D, true))
GV->setConstant(true);
GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
@@ -1561,14 +1577,24 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
"isn't a lib fn");
// Get the name, skip over the __builtin_ prefix (if necessary).
- const char *Name = Context.BuiltinInfo.GetName(BuiltinID);
- if (Context.BuiltinInfo.isLibFunction(BuiltinID))
- Name += 10;
+ llvm::StringRef Name;
+ GlobalDecl D(FD);
+
+ // If the builtin has been declared explicitly with an assembler label,
+ // use the mangled name. This differs from the plain label on platforms
+ // that prefix labels.
+ if (FD->hasAttr<AsmLabelAttr>())
+ Name = getMangledName(D);
+ else if (Context.BuiltinInfo.isLibFunction(BuiltinID))
+ Name = Context.BuiltinInfo.GetName(BuiltinID) + 10;
+ else
+ Name = Context.BuiltinInfo.GetName(BuiltinID);
+
const llvm::FunctionType *Ty =
cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType()));
- return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD), /*ForVTable=*/false);
+ return GetOrCreateLLVMFunction(Name, Ty, D, /*ForVTable=*/false);
}
llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys,
@@ -1628,6 +1654,16 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
return Map.GetOrCreateValue(llvm::StringRef(AsBytes.data(), AsBytes.size()));
}
+static llvm::StringMapEntry<llvm::Constant*> &
+GetConstantStringEntry(llvm::StringMap<llvm::Constant*> &Map,
+ const StringLiteral *Literal,
+ unsigned &StringLength)
+{
+ llvm::StringRef String = Literal->getString();
+ StringLength = String.size();
+ return Map.GetOrCreateValue(String);
+}
+
llvm::Constant *
CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
unsigned StringLength = 0;
@@ -1721,11 +1757,8 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::Constant *
CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
unsigned StringLength = 0;
- bool isUTF16 = false;
llvm::StringMapEntry<llvm::Constant*> &Entry =
- GetConstantCFStringEntry(CFConstantStringMap, Literal,
- getTargetData().isLittleEndian(),
- isUTF16, StringLength);
+ GetConstantStringEntry(CFConstantStringMap, Literal, StringLength);
if (llvm::Constant *C = Entry.getValue())
return C;
@@ -1738,24 +1771,26 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
if (!ConstantStringClassRef) {
std::string StringClass(getLangOptions().ObjCConstantStringClass);
const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
- Ty = llvm::ArrayType::get(Ty, 0);
llvm::Constant *GV;
- if (StringClass.empty())
- GV = CreateRuntimeVariable(Ty,
- Features.ObjCNonFragileABI ?
- "OBJC_CLASS_$_NSConstantString" :
- "_NSConstantStringClassReference");
- else {
- std::string str;
- if (Features.ObjCNonFragileABI)
- str = "OBJC_CLASS_$_" + StringClass;
- else
- str = "_" + StringClass + "ClassReference";
- GV = CreateRuntimeVariable(Ty, str);
+ if (Features.ObjCNonFragileABI) {
+ std::string str =
+ StringClass.empty() ? "OBJC_CLASS_$_NSConstantString"
+ : "OBJC_CLASS_$_" + StringClass;
+ GV = getObjCRuntime().GetClassGlobal(str);
+ // Make sure the result is of the correct type.
+ const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
+ ConstantStringClassRef =
+ llvm::ConstantExpr::getBitCast(GV, PTy);
+ } else {
+ std::string str =
+ StringClass.empty() ? "_NSConstantStringClassReference"
+ : "_" + StringClass + "ClassReference";
+ const llvm::Type *PTy = llvm::ArrayType::get(Ty, 0);
+ GV = CreateRuntimeVariable(PTy, str);
+ // Decay array -> ptr
+ ConstantStringClassRef =
+ llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
}
- // Decay array -> ptr
- ConstantStringClassRef =
- llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
}
QualType NSTy = getContext().getNSConstantStringType();
@@ -1773,28 +1808,15 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
llvm::GlobalValue::LinkageTypes Linkage;
bool isConstant;
- if (isUTF16) {
- // FIXME: why do utf strings get "_" labels instead of "L" labels?
- Linkage = llvm::GlobalValue::InternalLinkage;
- // Note: -fwritable-strings doesn't make unicode NSStrings writable, but
- // does make plain ascii ones writable.
- isConstant = true;
- } else {
- Linkage = llvm::GlobalValue::PrivateLinkage;
- isConstant = !Features.WritableStrings;
- }
+ Linkage = llvm::GlobalValue::PrivateLinkage;
+ isConstant = !Features.WritableStrings;
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
".str");
GV->setUnnamedAddr(true);
- if (isUTF16) {
- CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
- GV->setAlignment(Align.getQuantity());
- } else {
- CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
- GV->setAlignment(Align.getQuantity());
- }
+ CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
+ GV->setAlignment(Align.getQuantity());
Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
// String length.
@@ -1877,6 +1899,7 @@ static llvm::Constant *GenerateStringLiteral(llvm::StringRef str,
new llvm::GlobalVariable(CGM.getModule(), C->getType(), constant,
llvm::GlobalValue::PrivateLinkage,
C, GlobalName);
+ GV->setAlignment(1);
GV->setUnnamedAddr(true);
return GV;
}
@@ -2057,7 +2080,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::UsingDirective:
case Decl::ClassTemplate:
case Decl::FunctionTemplate:
+ case Decl::TypeAliasTemplate:
case Decl::NamespaceAlias:
+ case Decl::Block:
break;
case Decl::CXXConstructor:
// Skip function templates
@@ -2216,6 +2241,23 @@ void CodeGenFunction::EmitDeclMetadata() {
}
}
+void CodeGenModule::EmitCoverageFile() {
+ if (!getCodeGenOpts().CoverageFile.empty()) {
+ if (llvm::NamedMDNode *CUNode = TheModule.getNamedMetadata("llvm.dbg.cu")) {
+ llvm::NamedMDNode *GCov = TheModule.getOrInsertNamedMetadata("llvm.gcov");
+ llvm::LLVMContext &Ctx = TheModule.getContext();
+ llvm::MDString *CoverageFile =
+ llvm::MDString::get(Ctx, getCodeGenOpts().CoverageFile);
+ for (int i = 0, e = CUNode->getNumOperands(); i != e; ++i) {
+ llvm::MDNode *CU = CUNode->getOperand(i);
+ llvm::Value *node[] = { CoverageFile, CU };
+ llvm::MDNode *N = llvm::MDNode::get(Ctx, node);
+ GCov->addOperand(N);
+ }
+ }
+ }
+}
+
///@name Custom Runtime Function Interfaces
///@{
//
@@ -2234,14 +2276,11 @@ llvm::Constant *CodeGenModule::getBlockObjectDispose() {
}
// Otherwise construct the function by hand.
- const llvm::FunctionType *FTy;
- std::vector<const llvm::Type*> ArgTys;
- const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
- ArgTys.push_back(Int8PtrTy);
- ArgTys.push_back(llvm::Type::getInt32Ty(VMContext));
- FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
+ const llvm::Type *args[] = { Int8PtrTy, Int32Ty };
+ const llvm::FunctionType *fty
+ = llvm::FunctionType::get(VoidTy, args, false);
return BlockObjectDispose =
- CreateRuntimeFunction(FTy, "_Block_object_dispose");
+ CreateRuntimeFunction(fty, "_Block_object_dispose");
}
llvm::Constant *CodeGenModule::getBlockObjectAssign() {
@@ -2256,15 +2295,11 @@ llvm::Constant *CodeGenModule::getBlockObjectAssign() {
}
// Otherwise construct the function by hand.
- const llvm::FunctionType *FTy;
- std::vector<const llvm::Type*> ArgTys;
- const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
- ArgTys.push_back(Int8PtrTy);
- ArgTys.push_back(Int8PtrTy);
- ArgTys.push_back(llvm::Type::getInt32Ty(VMContext));
- FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
+ const llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
+ const llvm::FunctionType *fty
+ = llvm::FunctionType::get(VoidTy, args, false);
return BlockObjectAssign =
- CreateRuntimeFunction(FTy, "_Block_object_assign");
+ CreateRuntimeFunction(fty, "_Block_object_assign");
}
llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() {
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 99c973cce628..779a3523b7f6 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -97,16 +97,20 @@ namespace CodeGen {
};
struct CodeGenTypeCache {
+ /// void
+ const llvm::Type *VoidTy;
+
/// i8, i32, and i64
const llvm::IntegerType *Int8Ty, *Int32Ty, *Int64Ty;
/// int
const llvm::IntegerType *IntTy;
- /// intptr_t and size_t, which we assume are the same
+ /// intptr_t, size_t, and ptrdiff_t, which we assume are the same size.
union {
const llvm::IntegerType *IntPtrTy;
const llvm::IntegerType *SizeTy;
+ const llvm::IntegerType *PtrDiffTy;
};
/// void* in address space 0
@@ -735,6 +739,10 @@ private:
void EmitDeclMetadata();
+ /// EmitCoverageFile - Emit the llvm.gcov metadata used to tell LLVM where
+ /// to emit the .gcno and .gcda files in a way that persists in .bc files.
+ void EmitCoverageFile();
+
/// MayDeferGeneration - Determine if the given decl can be emitted
/// lazily; this is only relevant for definitions. The given decl
/// must be either a function or var decl.
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index dc383cb4db5d..ff1eb4c45b59 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -220,8 +220,9 @@ public: // These are internal details of CGT that shouldn't be used externally.
/// GetExpandedTypes - Expand the type \arg Ty into the LLVM
/// argument types it would be passed as on the provided vector \arg
/// ArgTys. See ABIArgInfo::Expand.
- void GetExpandedTypes(QualType Ty, std::vector<const llvm::Type*> &ArgTys,
- bool IsRecursive);
+ void GetExpandedTypes(QualType type,
+ llvm::SmallVectorImpl<const llvm::Type*> &expanded,
+ bool isRecursive);
/// IsZeroInitializable - Return whether a type can be
/// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 33abf3a4aaf7..12ef9bd030bd 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -1007,11 +1007,9 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
const llvm::PointerType *GuardPtrTy) {
// int __cxa_guard_acquire(__guard *guard_object);
-
- std::vector<const llvm::Type*> Args(1, GuardPtrTy);
const llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
- Args, /*isVarArg=*/false);
+ GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire");
}
@@ -1019,12 +1017,9 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
const llvm::PointerType *GuardPtrTy) {
// void __cxa_guard_release(__guard *guard_object);
-
- std::vector<const llvm::Type*> Args(1, GuardPtrTy);
-
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- Args, /*isVarArg=*/false);
+ GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release");
}
@@ -1032,12 +1027,9 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
const llvm::PointerType *GuardPtrTy) {
// void __cxa_guard_abort(__guard *guard_object);
-
- std::vector<const llvm::Type*> Args(1, GuardPtrTy);
-
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- Args, /*isVarArg=*/false);
+ GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort");
}
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 894502864464..4a2c4abbeb03 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -79,7 +79,7 @@ namespace {
MEnd = D->decls_end();
M != MEnd; ++M)
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*M))
- if (Method->isThisDeclarationADefinition() &&
+ if (Method->doesThisDeclarationHaveABody() &&
(Method->hasAttr<UsedAttr>() ||
Method->hasAttr<ConstructorAttr>()))
Builder->EmitTopLevelDecl(Method);
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index bc2472cebbeb..043ead7e62d9 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -648,7 +648,7 @@ ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal) const {
unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
unsigned StackAlign = getTypeStackAlignInBytes(Ty, TypeAlign);
if (StackAlign == 0)
- return ABIArgInfo::getIndirect(0);
+ return ABIArgInfo::getIndirect(4);
// If the stack alignment is less than the type alignment, realign the
// argument.
@@ -1315,13 +1315,10 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const {
if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
- // Compute the byval alignment. We trust the back-end to honor the
- // minimum ABI alignment for byval, to make cleaner IR.
- const unsigned MinABIAlign = 8;
- unsigned Align = getContext().getTypeAlign(Ty) / 8;
- if (Align > MinABIAlign)
- return ABIArgInfo::getIndirect(Align);
- return ABIArgInfo::getIndirect(0);
+ // Compute the byval alignment. We specify the alignment of the byval in all
+ // cases so that the mid-level optimizer knows the alignment of the byval.
+ unsigned Align = std::max(getContext().getTypeAlign(Ty) / 8, 8U);
+ return ABIArgInfo::getIndirect(Align);
}
/// Get16ByteVectorType - The ABI specifies that a value should be passed in an
@@ -2279,6 +2276,22 @@ public:
int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
return 13;
}
+
+ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+ CodeGen::CGBuilderTy &Builder = CGF.Builder;
+ llvm::LLVMContext &Context = CGF.getLLVMContext();
+
+ const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
+
+ // 0-15 are the 16 integer registers.
+ AssignToArrayRange(Builder, Address, Four8, 0, 15);
+
+ return false;
+ }
+
+
};
}
@@ -2845,10 +2858,21 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
//===----------------------------------------------------------------------===//
namespace {
+class MipsABIInfo : public ABIInfo {
+public:
+ MipsABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy) const;
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
class MIPSTargetCodeGenInfo : public TargetCodeGenInfo {
public:
MIPSTargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
+ : TargetCodeGenInfo(new MipsABIInfo(CGT)) {}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
return 29;
@@ -2859,6 +2883,54 @@ public:
};
}
+ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty) const {
+ if (isAggregateTypeForABI(Ty)) {
+ // Ignore empty aggregates.
+ if (getContext().getTypeSize(Ty) == 0)
+ return ABIArgInfo::getIgnore();
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+}
+
+ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ if (isAggregateTypeForABI(RetTy)) {
+ if (RetTy->isAnyComplexType())
+ return ABIArgInfo::getDirect();
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
+ return (RetTy->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+}
+
+void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type);
+}
+
+llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return 0;
+}
+
bool
MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const {
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index fc4d86c861c8..eb878a3f1c5e 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -46,14 +46,14 @@
using namespace clang::driver;
using namespace clang;
-Driver::Driver(llvm::StringRef _ClangExecutable,
- llvm::StringRef _DefaultHostTriple,
- llvm::StringRef _DefaultImageName,
+Driver::Driver(llvm::StringRef ClangExecutable,
+ llvm::StringRef DefaultHostTriple,
+ llvm::StringRef DefaultImageName,
bool IsProduction, bool CXXIsProduction,
- Diagnostic &_Diags)
- : Opts(createDriverOptTable()), Diags(_Diags),
- ClangExecutable(_ClangExecutable), UseStdLib(true),
- DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName),
+ Diagnostic &Diags)
+ : Opts(createDriverOptTable()), Diags(Diags),
+ ClangExecutable(ClangExecutable), UseStdLib(true),
+ DefaultHostTriple(DefaultHostTriple), DefaultImageName(DefaultImageName),
DriverTitle("clang \"gcc-compatible\" driver"),
Host(0),
CCPrintOptionsFilename(0), CCPrintHeadersFilename(0),
@@ -398,9 +398,10 @@ void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const {
/// PrintDiagnosticCategories - Implement the --print-diagnostic-categories
/// option.
static void PrintDiagnosticCategories(llvm::raw_ostream &OS) {
- for (unsigned i = 1; // Skip the empty category.
- const char *CategoryName = DiagnosticIDs::getCategoryNameFromID(i); ++i)
- OS << i << ',' << CategoryName << '\n';
+ // Skip the empty category.
+ for (unsigned i = 1, max = DiagnosticIDs::getNumberOfCategories();
+ i != max; ++i)
+ OS << i << ',' << DiagnosticIDs::getCategoryNameFromID(i) << '\n';
}
bool Driver::HandleImmediateArgs(const Compilation &C) {
@@ -569,14 +570,14 @@ void Driver::PrintActions(const Compilation &C) const {
PrintActions1(C, *it, Ids);
}
-/// \brief Check whether the given input tree contains any compilation (or
-/// assembly) actions.
-static bool ContainsCompileAction(const Action *A) {
+/// \brief Check whether the given input tree contains any compilation or
+/// assembly actions.
+static bool ContainsCompileOrAssembleAction(const Action *A) {
if (isa<CompileJobAction>(A) || isa<AssembleJobAction>(A))
return true;
for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it)
- if (ContainsCompileAction(*it))
+ if (ContainsCompileOrAssembleAction(*it))
return true;
return false;
@@ -667,7 +668,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
Arg *A = Args.getLastArg(options::OPT_g_Group);
if (A && !A->getOption().matches(options::OPT_g0) &&
!A->getOption().matches(options::OPT_gstabs) &&
- ContainsCompileAction(Actions.back())) {
+ ContainsCompileOrAssembleAction(Actions.back())) {
ActionList Inputs;
Inputs.push_back(Actions.back());
Actions.pop_back();
diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp
index 198af54c035a..3b1c2c73fd74 100644
--- a/lib/Driver/HostInfo.cpp
+++ b/lib/Driver/HostInfo.cpp
@@ -414,15 +414,20 @@ ToolChain *NetBSDHostInfo::CreateToolChain(const ArgList &Args,
(A->getOption().matches(options::OPT_m32)) ? "powerpc" : "powerpc64";
}
}
+ llvm::Triple TargetTriple(getTriple());
+ TargetTriple.setArchName(ArchName);
- ToolChain *&TC = ToolChains[ArchName];
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArchName(ArchName);
+ ToolChain *TC;
- TC = new toolchains::NetBSD(*this, TCTriple);
+ // XXX Cache toolchain even if -m32 is used
+ if (Arch == ArchName) {
+ TC = ToolChains[ArchName];
+ if (TC)
+ return TC;
}
+ TC = new toolchains::NetBSD(*this, TargetTriple, getTriple());
+
return TC;
}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 4668d7303fc7..ca613e3d6c84 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -9,6 +9,10 @@
#include "ToolChains.h"
+#ifdef HAVE_CLANG_CONFIG_H
+# include "clang/Config/config.h"
+#endif
+
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
@@ -115,7 +119,7 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
switch (getTriple().getArch()) {
default:
return getArchName();
-
+
case llvm::Triple::thumb:
case llvm::Triple::arm: {
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
@@ -145,10 +149,10 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args) const {
// the default triple).
if (!isTargetInitialized())
return Triple.getTriple();
-
+
unsigned Version[3];
getTargetVersion(Version);
-
+
llvm::SmallString<16> Str;
llvm::raw_svector_ostream(Str)
<< (isTargetIPhoneOS() ? "ios" : "macosx")
@@ -558,7 +562,7 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
P.appendComponent("lib");
P.appendComponent("darwin");
P.appendComponent("libclang_rt.cc_kext.a");
-
+
// For now, allow missing resource libraries to support developers who may
// not have compiler-rt checked out or integrated into their build.
bool Exists;
@@ -624,7 +628,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
DAL->AddSeparateArg(OriginalArg,
Opts.getOption(options::OPT_Zlinker_input),
A->getValue(Args, i));
-
+
}
continue;
}
@@ -915,8 +919,8 @@ TCEToolChain::~TCEToolChain() {
delete it->second;
}
-bool TCEToolChain::IsMathErrnoDefault() const {
- return true;
+bool TCEToolChain::IsMathErrnoDefault() const {
+ return true;
}
bool TCEToolChain::IsUnwindTablesDefault() const {
@@ -931,7 +935,7 @@ const char *TCEToolChain::GetForcedPicModel() const {
return 0;
}
-Tool &TCEToolChain::SelectTool(const Compilation &C,
+Tool &TCEToolChain::SelectTool(const Compilation &C,
const JobAction &JA,
const ActionList &Inputs) const {
Action::ActionClass Key;
@@ -1002,7 +1006,12 @@ FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple)
llvm::Triple(getDriver().DefaultHostTriple).getArch() ==
llvm::Triple::x86_64)
Lib32 = true;
-
+
+ if (Triple.getArch() == llvm::Triple::ppc &&
+ llvm::Triple(getDriver().DefaultHostTriple).getArch() ==
+ llvm::Triple::ppc64)
+ Lib32 = true;
+
if (Lib32) {
getFilePaths().push_back("/usr/lib32");
} else {
@@ -1043,14 +1052,14 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA,
/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
-NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple)
- : Generic_ELF(Host, Triple) {
+NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple,
+ const llvm::Triple& ToolTriple)
+ : Generic_ELF(Host, Triple), ToolTriple(ToolTriple) {
// Determine if we are compiling 32-bit code on an x86_64 platform.
bool Lib32 = false;
- if (Triple.getArch() == llvm::Triple::x86 &&
- llvm::Triple(getDriver().DefaultHostTriple).getArch() ==
- llvm::Triple::x86_64)
+ if (ToolTriple.getArch() == llvm::Triple::x86_64 &&
+ Triple.getArch() == llvm::Triple::x86)
Lib32 = true;
if (getDriver().UseStdLib) {
@@ -1080,10 +1089,11 @@ Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA,
if (UseIntegratedAs)
T = new tools::ClangAs(*this);
else
- T = new tools::netbsd::Assemble(*this);
+ T = new tools::netbsd::Assemble(*this, ToolTriple);
break;
case Action::LinkJobClass:
- T = new tools::netbsd::Link(*this); break;
+ T = new tools::netbsd::Link(*this, ToolTriple);
+ break;
default:
T = &Generic_GCC::SelectTool(C, JA, Inputs);
}
@@ -1172,12 +1182,18 @@ enum LinuxDistro {
ArchLinux,
DebianLenny,
DebianSqueeze,
+ DebianWheezy,
Exherbo,
+ RHEL4,
+ RHEL5,
+ RHEL6,
Fedora13,
Fedora14,
Fedora15,
FedoraRawhide,
OpenSuse11_3,
+ OpenSuse11_4,
+ OpenSuse12_1,
UbuntuHardy,
UbuntuIntrepid,
UbuntuJaunty,
@@ -1185,27 +1201,31 @@ enum LinuxDistro {
UbuntuLucid,
UbuntuMaverick,
UbuntuNatty,
+ UbuntuOneiric,
UnknownDistro
};
-static bool IsFedora(enum LinuxDistro Distro) {
+static bool IsRedhat(enum LinuxDistro Distro) {
return Distro == Fedora13 || Distro == Fedora14 ||
- Distro == Fedora15 || Distro == FedoraRawhide;
+ Distro == Fedora15 || Distro == FedoraRawhide ||
+ Distro == RHEL4 || Distro == RHEL5 || Distro == RHEL6;
}
static bool IsOpenSuse(enum LinuxDistro Distro) {
- return Distro == OpenSuse11_3;
+ return Distro == OpenSuse11_3 || Distro == OpenSuse11_4 ||
+ Distro == OpenSuse12_1;
}
static bool IsDebian(enum LinuxDistro Distro) {
- return Distro == DebianLenny || Distro == DebianSqueeze;
+ return Distro == DebianLenny || Distro == DebianSqueeze ||
+ Distro == DebianWheezy;
}
static bool IsUbuntu(enum LinuxDistro Distro) {
return Distro == UbuntuHardy || Distro == UbuntuIntrepid ||
- Distro == UbuntuLucid || Distro == UbuntuMaverick ||
+ Distro == UbuntuLucid || Distro == UbuntuMaverick ||
Distro == UbuntuJaunty || Distro == UbuntuKarmic ||
- Distro == UbuntuNatty;
+ Distro == UbuntuNatty || Distro == UbuntuOneiric;
}
static bool IsDebianBased(enum LinuxDistro Distro) {
@@ -1223,7 +1243,8 @@ static bool HasMultilib(llvm::Triple::ArchType Arch, enum LinuxDistro Distro) {
}
if (Arch == llvm::Triple::ppc64)
return true;
- if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) && IsDebianBased(Distro))
+ if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) &&
+ IsDebianBased(Distro))
return true;
return false;
}
@@ -1249,6 +1270,8 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
return UbuntuMaverick;
else if (Lines[i] == "DISTRIB_CODENAME=natty")
return UbuntuNatty;
+ else if (Lines[i] == "DISTRIB_CODENAME=oneiric")
+ return UbuntuOneiric;
}
return UnknownDistro;
}
@@ -1264,6 +1287,17 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
else if (Data.startswith("Fedora release") &&
Data.find("Rawhide") != llvm::StringRef::npos)
return FedoraRawhide;
+ else if (Data.startswith("Red Hat Enterprise Linux") &&
+ Data.find("release 6") != llvm::StringRef::npos)
+ return RHEL6;
+ else if ((Data.startswith("Red Hat Enterprise Linux") ||
+ Data.startswith("CentOS")) &&
+ Data.find("release 5") != llvm::StringRef::npos)
+ return RHEL5;
+ else if ((Data.startswith("Red Hat Enterprise Linux") ||
+ Data.startswith("CentOS")) &&
+ Data.find("release 4") != llvm::StringRef::npos)
+ return RHEL4;
return UnknownDistro;
}
@@ -1273,6 +1307,8 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
return DebianLenny;
else if (Data.startswith("squeeze/sid"))
return DebianSqueeze;
+ else if (Data.startswith("wheezy/sid"))
+ return DebianWheezy;
return UnknownDistro;
}
@@ -1280,6 +1316,10 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
llvm::StringRef Data = File.get()->getBuffer();
if (Data.startswith("openSUSE 11.3"))
return OpenSuse11_3;
+ else if (Data.startswith("openSUSE 11.4"))
+ return OpenSuse11_4;
+ else if (Data.startswith("openSUSE 12.1"))
+ return OpenSuse12_1;
return UnknownDistro;
}
@@ -1293,6 +1333,54 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
return UnknownDistro;
}
+static std::string findGCCBaseLibDir(const std::string &GccTriple) {
+ // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but
+ // avoids adding yet another option to configure/cmake.
+ // It would probably be cleaner to break it in two variables
+ // CXX_GCC_ROOT with just /foo/bar
+ // CXX_GCC_VER with 4.5.2
+ // Then we would have
+ // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER
+ // and this function would return
+ // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER
+ llvm::SmallString<128> CxxIncludeRoot(CXX_INCLUDE_ROOT);
+ if (CxxIncludeRoot != "") {
+ // This is of the form /foo/bar/include/c++/4.5.2/
+ if (CxxIncludeRoot.back() == '/')
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the /
+ llvm::StringRef Version = llvm::sys::path::filename(CxxIncludeRoot);
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include
+ std::string ret(CxxIncludeRoot.c_str());
+ ret.append("/lib/gcc/");
+ ret.append(CXX_INCLUDE_ARCH);
+ ret.append("/");
+ ret.append(Version);
+ return ret;
+ }
+ static const char* GccVersions[] = {"4.6.0", "4.6",
+ "4.5.2", "4.5.1", "4.5",
+ "4.4.5", "4.4.4", "4.4.3", "4.4",
+ "4.3.4", "4.3.3", "4.3.2", "4.3",
+ "4.2.4", "4.2.3", "4.2.2", "4.2.1",
+ "4.2", "4.1.1"};
+ bool Exists;
+ for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) {
+ std::string Suffix = GccTriple + "/" + GccVersions[i];
+ std::string t1 = "/usr/lib/gcc/" + Suffix;
+ if (!llvm::sys::fs::exists(t1 + "/crtbegin.o", Exists) && Exists)
+ return t1;
+ std::string t2 = "/usr/lib64/gcc/" + Suffix;
+ if (!llvm::sys::fs::exists(t2 + "/crtbegin.o", Exists) && Exists)
+ return t2;
+ std::string t3 = "/usr/lib/" + GccTriple + "/gcc/" + Suffix;
+ if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists)
+ return t3;
+ }
+ return "";
+}
+
Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
: Generic_ELF(Host, Triple) {
llvm::Triple::ArchType Arch =
@@ -1366,42 +1454,23 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
} else if (Arch == llvm::Triple::ppc) {
if (!llvm::sys::fs::exists("/usr/lib/powerpc-linux-gnu", Exists) && Exists)
GccTriple = "powerpc-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu", Exists) && Exists)
+ else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu",
+ Exists) && Exists)
GccTriple = "powerpc-unknown-linux-gnu";
} else if (Arch == llvm::Triple::ppc64) {
- if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu", Exists) && Exists)
+ if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu",
+ Exists) && Exists)
GccTriple = "powerpc64-unknown-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib64/gcc/powerpc64-unknown-linux-gnu", Exists) && Exists)
+ else if (!llvm::sys::fs::exists("/usr/lib64/gcc/"
+ "powerpc64-unknown-linux-gnu", Exists) &&
+ Exists)
GccTriple = "powerpc64-unknown-linux-gnu";
}
- const char* GccVersions[] = {"4.6.0",
- "4.5.2", "4.5.1", "4.5",
- "4.4.5", "4.4.4", "4.4.3", "4.4",
- "4.3.4", "4.3.3", "4.3.2", "4.3",
- "4.2.4", "4.2.3", "4.2.2", "4.2.1", "4.2"};
- std::string Base = "";
- for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) {
- std::string Suffix = GccTriple + "/" + GccVersions[i];
- std::string t1 = "/usr/lib/gcc/" + Suffix;
- if (!llvm::sys::fs::exists(t1 + "/crtbegin.o", Exists) && Exists) {
- Base = t1;
- break;
- }
- std::string t2 = "/usr/lib64/gcc/" + Suffix;
- if (!llvm::sys::fs::exists(t2 + "/crtbegin.o", Exists) && Exists) {
- Base = t2;
- break;
- }
- std::string t3 = "/usr/lib/" + GccTriple + "/gcc/" + Suffix;
- if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists) {
- Base = t3;
- break;
- }
- }
-
+ std::string Base = findGCCBaseLibDir(GccTriple);
path_list &Paths = getFilePaths();
- bool Is32Bits = (getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::ppc);
+ bool Is32Bits = (getArch() == llvm::Triple::x86 ||
+ getArch() == llvm::Triple::ppc);
std::string Suffix;
std::string Lib;
@@ -1422,7 +1491,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
LinuxDistro Distro = DetectLinuxDistro(Arch);
- if (IsUbuntu(Distro)) {
+ if (IsOpenSuse(Distro) || IsUbuntu(Distro)) {
ExtraOpts.push_back("-z");
ExtraOpts.push_back("relro");
}
@@ -1430,21 +1499,28 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
ExtraOpts.push_back("-X");
- if (IsFedora(Distro) || Distro == UbuntuMaverick || Distro == UbuntuNatty)
+ if (IsRedhat(Distro) || IsOpenSuse(Distro) || Distro == UbuntuMaverick ||
+ Distro == UbuntuNatty || Distro == UbuntuOneiric)
ExtraOpts.push_back("--hash-style=gnu");
- if (IsDebian(Distro) || Distro == UbuntuLucid || Distro == UbuntuJaunty ||
- Distro == UbuntuKarmic)
+ if (IsDebian(Distro) || IsOpenSuse(Distro) || Distro == UbuntuLucid ||
+ Distro == UbuntuJaunty || Distro == UbuntuKarmic)
ExtraOpts.push_back("--hash-style=both");
- if (IsFedora(Distro))
+ if (IsRedhat(Distro))
ExtraOpts.push_back("--no-add-needed");
- if (Distro == DebianSqueeze || IsOpenSuse(Distro) ||
- IsFedora(Distro) || Distro == UbuntuLucid || Distro == UbuntuMaverick ||
- Distro == UbuntuKarmic || Distro == UbuntuNatty)
+ if (Distro == DebianSqueeze || Distro == DebianWheezy ||
+ IsOpenSuse(Distro) ||
+ (IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) ||
+ Distro == UbuntuLucid ||
+ Distro == UbuntuMaverick || Distro == UbuntuKarmic ||
+ Distro == UbuntuNatty || Distro == UbuntuOneiric)
ExtraOpts.push_back("--build-id");
+ if (IsOpenSuse(Distro))
+ ExtraOpts.push_back("--enable-new-dtags");
+
if (Distro == ArchLinux)
Lib = "lib";
@@ -1453,9 +1529,14 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
if (IsOpenSuse(Distro) && Is32Bits)
Paths.push_back(Base + "/../../../../" + GccTriple + "/lib/../lib");
Paths.push_back(Base + "/../../../../" + Lib);
- Paths.push_back("/lib/../" + Lib);
- Paths.push_back("/usr/lib/../" + Lib);
}
+
+ // FIXME: This is in here to find crt1.o. It is provided by libc, and
+ // libc (like gcc), can be installed in any directory. Once we are
+ // fetching this from a config file, we should have a libc prefix.
+ Paths.push_back("/lib/../" + Lib);
+ Paths.push_back("/usr/lib/../" + Lib);
+
if (!Suffix.empty())
Paths.push_back(Base);
if (IsOpenSuse(Distro))
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 7a1a05025296..ace9b847919f 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -308,8 +308,11 @@ public:
};
class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF {
+ const llvm::Triple ToolTriple;
+
public:
- NetBSD(const HostInfo &Host, const llvm::Triple& Triple);
+ NetBSD(const HostInfo &Host, const llvm::Triple& Triple,
+ const llvm::Triple& ToolTriple);
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 60803ddf93c8..8cd7adc42e84 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -47,8 +47,9 @@ using namespace clang::driver::tools;
/// FindTargetProgramPath - Return path of the target specific version of
/// ProgName. If it doesn't exist, return path of ProgName itself.
static std::string FindTargetProgramPath(const ToolChain &TheToolChain,
+ const std::string TripleString,
const char *ProgName) {
- std::string Executable(TheToolChain.getTripleString() + "-" + ProgName);
+ std::string Executable(TripleString + "-" + ProgName);
std::string Path(TheToolChain.GetProgramPath(Executable.c_str()));
if (Path != Executable)
return Path;
@@ -146,6 +147,22 @@ static void AddLinkerInputs(const ToolChain &TC,
}
}
+static void addProfileRT(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (Args.hasArg(options::OPT_fprofile_arcs) ||
+ Args.hasArg(options::OPT_fprofile_generate) ||
+ Args.hasArg(options::OPT_fcreate_profile) ||
+ Args.hasArg(options::OPT_coverage)) {
+ // GCC links libgcov.a by adding -L<inst>/gcc/lib/gcc/<triple>/<ver> -lgcov
+ // to the link line. We cannot do the same thing because unlike gcov
+ // there is a libprofile_rt.so. We used to use the -l:libprofile_rt.a
+ // syntax, but that is not supported by old linkers.
+ const char *lib = Args.MakeArgString(TC.getDriver().Dir + "/../lib/" +
+ "libprofile_rt.a");
+ CmdArgs.push_back(lib);
+ }
+}
+
void Clang::AddPreprocessingOptions(const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -428,6 +445,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
default:
return true;
+ case llvm::Triple::arm:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
if (Triple.getOS() == llvm::Triple::Darwin)
@@ -652,7 +670,7 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
else if (MArch == "r6000")
CmdArgs.push_back("mips2");
else
- CmdArgs.push_back(MArch.str().c_str());
+ CmdArgs.push_back(Args.MakeArgString(MArch));
}
// Select the float ABI as determined by -msoft-float, -mhard-float, and
@@ -761,34 +779,34 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
if (!CPUName) {
// FIXME: Need target hooks.
if (getToolChain().getOS().startswith("darwin")) {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "core2";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "yonah";
} else if (getToolChain().getOS().startswith("haiku")) {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "i586";
} else if (getToolChain().getOS().startswith("openbsd")) {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "i486";
} else if (getToolChain().getOS().startswith("freebsd")) {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "i486";
} else if (getToolChain().getOS().startswith("netbsd")) {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "i486";
} else {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "pentium4";
}
}
@@ -907,21 +925,63 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
static bool ShouldDisableCFI(const ArgList &Args,
const ToolChain &TC) {
+ if (TC.getTriple().getOS() == llvm::Triple::Darwin) {
+ // The native darwin assembler doesn't support cfi directives, so
+ // we disable them if we think the .s file will be passed to it.
+
+ // FIXME: Duplicated code with ToolChains.cpp
+ // FIXME: This doesn't belong here, but ideally we will support static soon
+ // anyway.
+ bool HasStatic = (Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_fapple_kext));
+ bool IsIADefault = TC.IsIntegratedAssemblerDefault() && !HasStatic;
+ bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ IsIADefault);
+ bool UseCFI = Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
+ options::OPT_fno_dwarf2_cfi_asm,
+ UseIntegratedAs);
+ return !UseCFI;
+ }
+
+ // For now we assume that every other assembler support CFI.
+ return false;
+}
+
+/// \brief Check whether the given input tree contains any compilation actions.
+static bool ContainsCompileAction(const Action *A) {
+ if (isa<CompileJobAction>(A))
+ return true;
+
+ for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it)
+ if (ContainsCompileAction(*it))
+ return true;
- // FIXME: Duplicated code with ToolChains.cpp
- // FIXME: This doesn't belong here, but ideally we will support static soon
- // anyway.
- bool HasStatic = (Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_fapple_kext));
- bool IsIADefault = TC.IsIntegratedAssemblerDefault() && !HasStatic;
- bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIADefault);
- bool UseCFI = Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
- options::OPT_fno_dwarf2_cfi_asm,
- UseIntegratedAs);
- return !UseCFI;
+ return false;
+}
+
+/// \brief Check if -relax-all should be passed to the internal assembler.
+/// This is done by default when compiling non-assembler source with -O0.
+static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
+ bool RelaxDefault = true;
+
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ RelaxDefault = A->getOption().matches(options::OPT_O0);
+
+ if (RelaxDefault) {
+ RelaxDefault = false;
+ for (ActionList::const_iterator it = C.getActions().begin(),
+ ie = C.getActions().end(); it != ie; ++it) {
+ if (ContainsCompileAction(*it)) {
+ RelaxDefault = true;
+ break;
+ }
+ }
+ }
+
+ return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all,
+ RelaxDefault);
}
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
@@ -959,13 +1019,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (isa<AssembleJobAction>(JA)) {
CmdArgs.push_back("-emit-obj");
- // At -O0, we use -mrelax-all by default.
- bool IsOpt = false;
- if (Arg *A = Args.getLastArg(options::OPT_O_Group))
- IsOpt = !A->getOption().matches(options::OPT_O0);
- if (Args.hasFlag(options::OPT_mrelax_all,
- options::OPT_mno_relax_all,
- !IsOpt))
+ if (UseRelaxAll(C, Args))
CmdArgs.push_back("-mrelax-all");
// When using an integrated assembler, translate -Wa, and -Xassembler
@@ -983,6 +1037,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Do nothing, this is the default and we don't support anything else.
} else if (Value == "-L") {
CmdArgs.push_back("-msave-temp-labels");
+ } else if (Value == "--fatal-warnings") {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-fatal-assembler-warnings");
} else {
D.Diag(clang::diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
@@ -1303,6 +1360,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.hasArg(options::OPT_coverage))
CmdArgs.push_back("-femit-coverage-data");
+ if (C.getArgs().hasArg(options::OPT_c) ||
+ C.getArgs().hasArg(options::OPT_S)) {
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-coverage-file");
+ CmdArgs.push_back(Args.MakeArgString(Output.getFilename()));
+ }
+ }
+
Args.AddLastArg(CmdArgs, options::OPT_nostdinc);
Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
@@ -1477,6 +1542,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_lax_vector_conversions))
CmdArgs.push_back("-fno-lax-vector-conversions");
+ // -fobjc-infer-related-result-type is the default.
+ if (Args.hasFlag(options::OPT_fobjc_infer_related_result_type,
+ options::OPT_fno_objc_infer_related_result_type,
+ /*Default=*/true))
+ CmdArgs.push_back("-fobjc-infer-related-result-type");
+
// Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
// takes precedence.
const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);
@@ -1495,7 +1566,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.getLastArg(options::OPT_fapple_kext))
CmdArgs.push_back("-fapple-kext");
- Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
@@ -1546,6 +1616,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(llvm::Twine(StackProtectorLevel)));
}
+ // Translate -mstackrealign
+ if (Args.hasArg(options::OPT_mstackrealign)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-force-align-stack");
+ }
+
// Forward -f options with positive and negative forms; we translate
// these by hand.
@@ -1653,6 +1729,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_gnu_keywords))
A->render(Args, CmdArgs);
+ if (Args.hasFlag(options::OPT_fgnu89_inline,
+ options::OPT_fno_gnu89_inline,
+ false))
+ CmdArgs.push_back("-fgnu89-inline");
+
// -fnext-runtime defaults to on Darwin and when rewriting Objective-C, and is
// -the -cc1 default.
bool NeXTRuntimeIsDefault =
@@ -1815,6 +1896,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
+ CmdArgs.push_back("-fdiagnostics-format");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
if (Arg *A = Args.getLastArg(
options::OPT_fdiagnostics_show_note_include_stack,
options::OPT_fno_diagnostics_show_note_include_stack)) {
@@ -1836,6 +1923,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_show_source_location))
CmdArgs.push_back("-fno-show-source-location");
+ if (!Args.hasFlag(options::OPT_fshow_column,
+ options::OPT_fno_show_column,
+ true))
+ CmdArgs.push_back("-fno-show-column");
+
if (!Args.hasFlag(options::OPT_fspell_checking,
options::OPT_fno_spell_checking))
CmdArgs.push_back("-fno-spell-checking");
@@ -2005,13 +2097,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-filetype");
CmdArgs.push_back("obj");
- // At -O0, we use -mrelax-all by default.
- bool IsOpt = false;
- if (Arg *A = Args.getLastArg(options::OPT_O_Group))
- IsOpt = !A->getOption().matches(options::OPT_O0);
- if (Args.hasFlag(options::OPT_mrelax_all,
- options::OPT_mno_relax_all,
- !IsOpt))
+ if (UseRelaxAll(C, Args))
CmdArgs.push_back("-relax-all");
// Ignore explicit -force_cpusubtype_ALL option.
@@ -2893,12 +2979,17 @@ void darwin::Link::AddLinkArgs(Compilation &C,
Args.AddAllArgs(CmdArgs, options::OPT_sub__library);
Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella);
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_isysroot, "-syslibroot");
- if (getDarwinToolChain().isTargetIPhoneOS()) {
- if (!Args.hasArg(options::OPT_isysroot)) {
- CmdArgs.push_back("-syslibroot");
- CmdArgs.push_back("/Developer/SDKs/Extra");
- }
+ // Give --sysroot= preference, over the Apple specific behavior to also use
+ // --isysroot as the syslibroot.
+ if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) {
+ CmdArgs.push_back("-syslibroot");
+ CmdArgs.push_back(A->getValue(Args));
+ } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ CmdArgs.push_back("-syslibroot");
+ CmdArgs.push_back(A->getValue(Args));
+ } else if (getDarwinToolChain().isTargetIPhoneOS()) {
+ CmdArgs.push_back("-syslibroot");
+ CmdArgs.push_back("/Developer/SDKs/Extra");
}
Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace);
@@ -3059,12 +3150,6 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(LinkingOutput);
}
- if (Args.hasArg(options::OPT_fprofile_arcs) ||
- Args.hasArg(options::OPT_fprofile_generate) ||
- Args.hasArg(options::OPT_fcreate_profile) ||
- Args.hasArg(options::OPT_coverage))
- CmdArgs.push_back("-lgcov");
-
if (Args.hasArg(options::OPT_fnested_functions))
CmdArgs.push_back("-allow_stack_execute");
@@ -3085,6 +3170,8 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// endfile_spec is empty.
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_F);
@@ -3124,14 +3211,14 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
const InputInfo &Input = Inputs[0];
assert(Input.isFilename() && "Unexpected dsymutil input.");
CmdArgs.push_back(Input.getFilename());
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("dsymutil"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -3242,6 +3329,8 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().GetFilePath("crtend.o")));
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -3377,6 +3466,8 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().getArchName() == "i386")
CmdArgs.push_back("--32");
+ if (getToolChain().getArchName() == "powerpc")
+ CmdArgs.push_back("-a32");
// Set byte order explicitly
if (getToolChain().getArchName() == "mips")
@@ -3433,6 +3524,11 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("elf_i386_fbsd");
}
+ if (getToolChain().getArchName() == "powerpc") {
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf32ppc");
+ }
+
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -3541,6 +3637,8 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
"crtn.o")));
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -3555,7 +3653,8 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on NetBSD/amd64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
- if (getToolChain().getArchName() == "i386")
+ if (ToolTriple.getArch() == llvm::Triple::x86_64 &&
+ getToolChain().getArch() == llvm::Triple::x86)
CmdArgs.push_back("--32");
@@ -3578,7 +3677,8 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(),
- "as"));
+ ToolTriple.getTriple(),
+ "as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -3609,7 +3709,8 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on NetBSD/amd64, we have to explicitly
// instruct ld in the base system to link 32-bit code.
- if (getToolChain().getArchName() == "i386") {
+ if (ToolTriple.getArch() == llvm::Triple::x86_64 &&
+ getToolChain().getArch() == llvm::Triple::x86) {
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386");
}
@@ -3656,7 +3757,6 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
// FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
// the default system libraries. Just mimic this for now.
- CmdArgs.push_back("-lgcc");
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-lgcc_eh");
} else {
@@ -3664,6 +3764,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lgcc_s");
CmdArgs.push_back("--no-as-needed");
}
+ CmdArgs.push_back("-lgcc");
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-lpthread");
@@ -3691,8 +3792,11 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
"crtn.o")));
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(),
- "ld"));
+ ToolTriple.getTriple(),
+ "ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -3854,10 +3958,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lm");
}
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("--start-group");
-
if (!Args.hasArg(options::OPT_nostdlib)) {
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("--start-group");
+
if (!D.CCCIsCXX)
CmdArgs.push_back("-lgcc");
@@ -3912,6 +4016,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
if (Args.hasArg(options::OPT_use_gold_plugin)) {
CmdArgs.push_back("-plugin");
std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
@@ -3994,6 +4100,8 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
"/usr/gnu/lib/libend.a")));
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("/usr/gnu/bin/gld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -4149,6 +4257,8 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().GetFilePath("crtn.o")));
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 93abf75722eb..4a5a7e474526 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -14,6 +14,7 @@
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
namespace clang {
@@ -338,9 +339,12 @@ namespace freebsd {
/// netbsd -- Directly call GNU Binutils assembler and linker
namespace netbsd {
class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ private:
+ const llvm::Triple ToolTriple;
+
public:
- Assemble(const ToolChain &TC) : Tool("netbsd::Assemble", "assembler",
- TC) {}
+ Assemble(const ToolChain &TC, const llvm::Triple &ToolTriple)
+ : Tool("netbsd::Assemble", "assembler", TC), ToolTriple(ToolTriple) {}
virtual bool hasIntegratedCPP() const { return false; }
@@ -351,8 +355,12 @@ namespace netbsd {
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ private:
+ const llvm::Triple ToolTriple;
+
public:
- Link(const ToolChain &TC) : Tool("netbsd::Link", "linker", TC) {}
+ Link(const ToolChain &TC, const llvm::Triple &ToolTriple)
+ : Tool("netbsd::Ling", "linker", TC), ToolTriple(ToolTriple) {}
virtual bool hasIntegratedCPP() const { return false; }
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index ecd6ef442aea..28d312a2219b 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -173,7 +173,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
break;
case Decl::Function: {
const FunctionDecl* FD = cast<FunctionDecl>(DC);
- if (FD->isThisDeclarationADefinition())
+ if (FD->doesThisDeclarationHaveABody())
Out << "[function] ";
else
Out << "<function> ";
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 2a1244841e3b..8827116f2e40 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -102,6 +102,7 @@ ASTUnit::ASTUnit(bool _MainFileIsAST)
ConcurrencyCheckValue(CheckUnlocked),
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
ShouldCacheCodeCompletionResults(false),
+ NestedMacroInstantiations(true),
CompletionCacheTopLevelHashValue(0),
PreambleTopLevelHashValue(0),
CurrentTopLevelHashValue(0),
@@ -579,6 +580,11 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
Reader.reset(new ASTReader(AST->getSourceManager(), AST->getFileManager(),
AST->getDiagnostics()));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<ASTReader>
+ ReaderCleanup(Reader.get());
+
Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple,
Predefines, Counter));
@@ -633,6 +639,11 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// AST file as needed.
ASTReader *ReaderPtr = Reader.get();
llvm::OwningPtr<ExternalASTSource> Source(Reader.take());
+
+ // Unregister the cleanup for ASTReader. It will get cleaned up
+ // by the ASTUnit cleanup.
+ ReaderCleanup.unregister();
+
Context.setExternalSource(Source);
// Create an AST consumer, even though it isn't used.
@@ -917,6 +928,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
+ PreprocessorOpts.DetailedRecordIncludesNestedMacroInstantiations
+ = NestedMacroInstantiations;
std::string PriorImplicitPCHInclude;
if (OverrideMainBuffer) {
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
@@ -1554,6 +1567,119 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI,
return AST.take();
}
+ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ ASTFrontendAction *Action) {
+ assert(CI && "A CompilerInvocation is required");
+
+ // Create the AST unit.
+ llvm::OwningPtr<ASTUnit> AST;
+ AST.reset(new ASTUnit(false));
+ ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics*/false);
+ AST->Diagnostics = Diags;
+ AST->OnlyLocalDecls = false;
+ AST->CaptureDiagnostics = false;
+ AST->CompleteTranslationUnit = Action ? Action->usesCompleteTranslationUnit()
+ : true;
+ AST->ShouldCacheCodeCompletionResults = false;
+ AST->Invocation = CI;
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
+ ASTUnitCleanup(AST.get());
+ llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
+ llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ DiagCleanup(Diags.getPtr());
+
+ // We'll manage file buffers ourselves.
+ CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
+ CI->getFrontendOpts().DisableFree = false;
+ ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts());
+
+ // Save the target features.
+ AST->TargetFeatures = CI->getTargetOpts().Features;
+
+ // Create the compiler instance to use for building the AST.
+ llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
+ CICleanup(Clang.get());
+
+ Clang->setInvocation(CI);
+ AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
+
+ // Set up diagnostics, capturing any diagnostics that would
+ // otherwise be dropped.
+ Clang->setDiagnostics(&AST->getDiagnostics());
+
+ // Create the target instance.
+ Clang->getTargetOpts().Features = AST->TargetFeatures;
+ Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
+ Clang->getTargetOpts()));
+ if (!Clang->hasTarget())
+ return 0;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
+
+ assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
+ "Invocation must have exactly one source file!");
+ assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST &&
+ "FIXME: AST inputs not yet supported here!");
+ assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+ "IR inputs not supported here!");
+
+ // Configure the various subsystems.
+ AST->FileSystemOpts = Clang->getFileSystemOpts();
+ AST->FileMgr = new FileManager(AST->FileSystemOpts);
+ AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr);
+ AST->TheSema.reset();
+ AST->Ctx = 0;
+ AST->PP = 0;
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ Clang->setFileManager(&AST->getFileManager());
+
+ // Create the source manager.
+ Clang->setSourceManager(&AST->getSourceManager());
+
+ ASTFrontendAction *Act = Action;
+
+ llvm::OwningPtr<TopLevelDeclTrackerAction> TrackerAct;
+ if (!Act) {
+ TrackerAct.reset(new TopLevelDeclTrackerAction(*AST));
+ Act = TrackerAct.get();
+ }
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction>
+ ActCleanup(TrackerAct.get());
+
+ if (!Act->BeginSourceFile(*Clang.get(),
+ Clang->getFrontendOpts().Inputs[0].second,
+ Clang->getFrontendOpts().Inputs[0].first))
+ return 0;
+
+ Act->Execute();
+
+ // Steal the created target, context, and preprocessor.
+ AST->TheSema.reset(Clang->takeSema());
+ AST->Consumer.reset(Clang->takeASTConsumer());
+ AST->Ctx = &Clang->getASTContext();
+ AST->PP = &Clang->getPreprocessor();
+ Clang->setSourceManager(0);
+ Clang->setFileManager(0);
+ AST->Target = &Clang->getTarget();
+
+ Act->EndSourceFile();
+
+ return AST.take();
+}
+
bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
if (!Invocation)
return true;
@@ -1589,7 +1715,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
bool CaptureDiagnostics,
bool PrecompilePreamble,
bool CompleteTranslationUnit,
- bool CacheCodeCompletionResults) {
+ bool CacheCodeCompletionResults,
+ bool NestedMacroInstantiations) {
// Create the AST unit.
llvm::OwningPtr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
@@ -1600,6 +1727,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
AST->CompleteTranslationUnit = CompleteTranslationUnit;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->Invocation = CI;
+ AST->NestedMacroInstantiations = NestedMacroInstantiations;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
@@ -1624,7 +1752,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
bool CompleteTranslationUnit,
bool CacheCodeCompletionResults,
bool CXXPrecompilePreamble,
- bool CXXChainedPCH) {
+ bool CXXChainedPCH,
+ bool NestedMacroInstantiations) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -1691,6 +1820,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
AST->StoredDiagnostics.swap(StoredDiagnostics);
AST->Invocation = CI;
+ AST->NestedMacroInstantiations = NestedMacroInstantiations;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
@@ -2142,6 +2272,9 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
}
+ // Disable the preprocessing record
+ PreprocessorOpts.DetailedRecord = false;
+
llvm::OwningPtr<SyntaxOnlyAction> Act;
Act.reset(new SyntaxOnlyAction);
if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 9d49e9039d91..7dcbebff39b8 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -18,7 +18,6 @@ add_clang_library(clangFrontend
CompilerInvocation.cpp
CreateInvocationFromCommandLine.cpp
DependencyFile.cpp
- DiagChecker.cpp
FrontendAction.cpp
FrontendActions.cpp
FrontendOptions.cpp
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index ace3c5adb100..38fcfe3c4711 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -227,7 +227,8 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
}
if (PPOpts.DetailedRecord)
- PP->createPreprocessingRecord();
+ PP->createPreprocessingRecord(
+ PPOpts.DetailedRecordIncludesNestedMacroInstantiations);
InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 1d4cd15ac480..536512a121e9 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -277,6 +277,14 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fdiagnostics-show-category=id");
else if (Opts.ShowCategories == 2)
Res.push_back("-fdiagnostics-show-category=name");
+ switch (Opts.Format) {
+ case DiagnosticOptions::Clang:
+ Res.push_back("-fdiagnostics-format=clang"); break;
+ case DiagnosticOptions::Msvc:
+ Res.push_back("-fdiagnostics-format=msvc"); break;
+ case DiagnosticOptions::Vi:
+ Res.push_back("-fdiagnostics-format=vi"); break;
+ }
if (Opts.ErrorLimit) {
Res.push_back("-ferror-limit");
Res.push_back(llvm::utostr(Opts.ErrorLimit));
@@ -662,6 +670,9 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fobjc-gc-only");
}
}
+ if (Opts.ObjCInferRelatedResultType)
+ Res.push_back("-fobjc-infer-related-result-type");
+
if (Opts.AppleKext)
Res.push_back("-fapple-kext");
@@ -974,6 +985,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data);
Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes);
+ Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
llvm::StringRef Name = A->getValue(Args);
@@ -1010,7 +1022,9 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors);
Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics);
Opts.ShowColors = Args.hasArg(OPT_fcolor_diagnostics);
- Opts.ShowColumn = !Args.hasArg(OPT_fno_show_column);
+ Opts.ShowColumn = Args.hasFlag(OPT_fshow_column,
+ OPT_fno_show_column,
+ /*Default=*/true);
Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info);
Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location);
Opts.ShowNames = Args.hasArg(OPT_fdiagnostics_show_name);
@@ -1047,6 +1061,19 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
<< Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args)
<< ShowCategory;
+ llvm::StringRef Format =
+ Args.getLastArgValue(OPT_fdiagnostics_format, "clang");
+ if (Format == "clang")
+ Opts.Format = DiagnosticOptions::Clang;
+ else if (Format == "msvc")
+ Opts.Format = DiagnosticOptions::Msvc;
+ else if (Format == "vi")
+ Opts.Format = DiagnosticOptions::Vi;
+ else
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_fdiagnostics_format)->getAsString(Args)
+ << Format;
+
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
@@ -1397,6 +1424,40 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (LangStd == LangStandard::lang_unspecified)
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue(Args);
+ else {
+ // Valid standard, check to make sure language and standard are compatable.
+ const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
+ switch (IK) {
+ case IK_C:
+ case IK_ObjC:
+ case IK_PreprocessedC:
+ case IK_PreprocessedObjC:
+ if (!(Std.isC89() || Std.isC99()))
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "C/ObjC";
+ break;
+ case IK_CXX:
+ case IK_ObjCXX:
+ case IK_PreprocessedCXX:
+ case IK_PreprocessedObjCXX:
+ if (!Std.isCPlusPlus())
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "C++/ObjC++";
+ break;
+ case IK_OpenCL:
+ if (!Std.isC99())
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "OpenCL";
+ break;
+ case IK_CUDA:
+ if (!Std.isCPlusPlus())
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "CUDA";
+ break;
+ default:
+ break;
+ }
+ }
}
if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) {
@@ -1419,11 +1480,17 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fno_operator_names))
Opts.CXXOperatorNames = 0;
+ if (Args.hasArg(OPT_fgnu89_inline))
+ Opts.GNUInline = 1;
+
if (Args.hasArg(OPT_fobjc_gc_only))
Opts.setGCMode(LangOptions::GCOnly);
else if (Args.hasArg(OPT_fobjc_gc))
Opts.setGCMode(LangOptions::HybridGC);
+ if (Args.hasArg(OPT_fobjc_infer_related_result_type))
+ Opts.ObjCInferRelatedResultType = 1;
+
if (Args.hasArg(OPT_fapple_kext)) {
if (!Opts.CPlusPlus)
Diags.Report(diag::warn_c_kext);
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 0005f910d214..42b648aa6411 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -65,7 +65,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList,
// We expect to get back exactly one command job, if we didn't something
// failed.
const driver::JobList &Jobs = C->getJobs();
- if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
+ if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
llvm::SmallString<256> Msg;
llvm::raw_svector_ostream OS(Msg);
C->PrintJob(OS, C->getJobs(), "; ", true);
diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp
deleted file mode 100644
index 66d7ed7cf40a..000000000000
--- a/lib/Frontend/DiagChecker.cpp
+++ /dev/null
@@ -1,301 +0,0 @@
-//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Process the input files and check that the diagnostic messages are expected.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/Utils.h"
-#include "clang/Frontend/TextDiagnosticBuffer.h"
-#include "clang/Parse/ParseAST.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-
-typedef TextDiagnosticBuffer::DiagList DiagList;
-typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
-
-static void EmitError(Preprocessor &PP, SourceLocation Pos, const char *String){
- unsigned ID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, String);
- PP.Diag(Pos, ID);
-}
-
-
-// USING THE DIAGNOSTIC CHECKER:
-//
-// Indicating that a line expects an error or a warning is simple. Put a comment
-// on the line that has the diagnostic, use "expected-{error,warning}" to tag
-// if it's an expected error or warning, and place the expected text between {{
-// and }} markers. The full text doesn't have to be included, only enough to
-// ensure that the correct diagnostic was emitted.
-//
-// Here's an example:
-//
-// int A = B; // expected-error {{use of undeclared identifier 'B'}}
-//
-// You can place as many diagnostics on one line as you wish. To make the code
-// more readable, you can use slash-newline to separate out the diagnostics.
-//
-// The simple syntax above allows each specification to match exactly one error.
-// You can use the extended syntax to customize this. The extended syntax is
-// "expected-<type> <n> {{diag text}}", where <type> is one of "error",
-// "warning" or "note", and <n> is a positive integer. This allows the
-// diagnostic to appear as many times as specified. Example:
-//
-// void f(); // expected-note 2 {{previous declaration is here}}
-//
-
-/// FindDiagnostics - Go through the comment and see if it indicates expected
-/// diagnostics. If so, then put them in a diagnostic list.
-///
-static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
- DiagList &ExpectedDiags,
- Preprocessor &PP, SourceLocation Pos,
- const char *ExpectedStr) {
- const char *CommentEnd = CommentStart+CommentLen;
- unsigned ExpectedStrLen = strlen(ExpectedStr);
-
- // Find all expected-foo diagnostics in the string and add them to
- // ExpectedDiags.
- while (CommentStart != CommentEnd) {
- CommentStart = std::find(CommentStart, CommentEnd, 'e');
- if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return;
-
- // If this isn't expected-foo, ignore it.
- if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) {
- ++CommentStart;
- continue;
- }
-
- CommentStart += ExpectedStrLen;
-
- // Skip whitespace.
- while (CommentStart != CommentEnd &&
- isspace(CommentStart[0]))
- ++CommentStart;
-
- // Default, if we find the '{' now, is 1 time.
- int Times = 1;
- int Temp = 0;
- // In extended syntax, there could be a digit now.
- while (CommentStart != CommentEnd &&
- CommentStart[0] >= '0' && CommentStart[0] <= '9') {
- Temp *= 10;
- Temp += CommentStart[0] - '0';
- ++CommentStart;
- }
- if (Temp > 0)
- Times = Temp;
-
- // Skip whitespace again.
- while (CommentStart != CommentEnd &&
- isspace(CommentStart[0]))
- ++CommentStart;
-
- // We should have a {{ now.
- if (CommentEnd-CommentStart < 2 ||
- CommentStart[0] != '{' || CommentStart[1] != '{') {
- if (std::find(CommentStart, CommentEnd, '{') != CommentEnd)
- EmitError(PP, Pos, "bogus characters before '{{' in expected string");
- else
- EmitError(PP, Pos, "cannot find start ('{{') of expected string");
- return;
- }
- CommentStart += 2;
-
- // Find the }}.
- const char *ExpectedEnd = CommentStart;
- while (1) {
- ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}');
- if (CommentEnd-ExpectedEnd < 2) {
- EmitError(PP, Pos, "cannot find end ('}}') of expected string");
- return;
- }
-
- if (ExpectedEnd[1] == '}')
- break;
-
- ++ExpectedEnd; // Skip over singular }'s
- }
-
- std::string Msg(CommentStart, ExpectedEnd);
- std::string::size_type FindPos;
- while ((FindPos = Msg.find("\\n")) != std::string::npos)
- Msg.replace(FindPos, 2, "\n");
- // Add is possibly multiple times.
- for (int i = 0; i < Times; ++i)
- ExpectedDiags.push_back(std::make_pair(Pos, Msg));
-
- CommentStart = ExpectedEnd;
- }
-}
-
-/// FindExpectedDiags - Lex the main source file to find all of the
-// expected errors and warnings.
-static void FindExpectedDiags(Preprocessor &PP,
- DiagList &ExpectedErrors,
- DiagList &ExpectedWarnings,
- DiagList &ExpectedNotes) {
- // Create a raw lexer to pull all the comments out of the main file. We don't
- // want to look in #include'd headers for expected-error strings.
- FileID FID = PP.getSourceManager().getMainFileID();
-
- // Create a lexer to lex all the tokens of the main file in raw mode.
- const llvm::MemoryBuffer *FromFile = PP.getSourceManager().getBuffer(FID);
- Lexer RawLex(FID, FromFile, PP.getSourceManager(), PP.getLangOptions());
-
- // Return comments as tokens, this is how we find expected diagnostics.
- RawLex.SetCommentRetentionState(true);
-
- Token Tok;
- Tok.setKind(tok::comment);
- while (Tok.isNot(tok::eof)) {
- RawLex.Lex(Tok);
- if (!Tok.is(tok::comment)) continue;
-
- std::string Comment = PP.getSpelling(Tok);
- if (Comment.empty()) continue;
-
-
- // Find all expected errors.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP,
- Tok.getLocation(), "expected-error");
-
- // Find all expected warnings.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP,
- Tok.getLocation(), "expected-warning");
-
- // Find all expected notes.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP,
- Tok.getLocation(), "expected-note");
- };
-}
-
-/// PrintProblem - This takes a diagnostic map of the delta between expected and
-/// seen diagnostics. If there's anything in it, then something unexpected
-/// happened. Print the map out in a nice format and return "true". If the map
-/// is empty and we're not going to print things, then return "false".
-///
-static bool PrintProblem(SourceManager &SourceMgr,
- const_diag_iterator diag_begin,
- const_diag_iterator diag_end,
- const char *Msg) {
- if (diag_begin == diag_end) return false;
-
- llvm::errs() << Msg << "\n";
- for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
- llvm::errs() << " Line " << SourceMgr.getInstantiationLineNumber(I->first)
- << " " << I->second << "\n";
-
- return true;
-}
-
-/// CompareDiagLists - Compare two diagnostic lists and return the difference
-/// between them.
-///
-static bool CompareDiagLists(SourceManager &SourceMgr,
- const_diag_iterator d1_begin,
- const_diag_iterator d1_end,
- const_diag_iterator d2_begin,
- const_diag_iterator d2_end,
- const char *MsgLeftOnly,
- const char *MsgRightOnly) {
- DiagList LeftOnly;
- DiagList Left(d1_begin, d1_end);
- DiagList Right(d2_begin, d2_end);
-
- for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
- unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first);
- const std::string &Diag1 = I->second;
-
- DiagList::iterator II, IE;
- for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
- unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
- if (LineNo1 != LineNo2) continue;
-
- const std::string &Diag2 = II->second;
- if (Diag2.find(Diag1) != std::string::npos ||
- Diag1.find(Diag2) != std::string::npos) {
- break;
- }
- }
- if (II == IE) {
- // Not found.
- LeftOnly.push_back(*I);
- } else {
- // Found. The same cannot be found twice.
- Right.erase(II);
- }
- }
- // Now all that's left in Right are those that were not matched.
-
- return PrintProblem(SourceMgr, LeftOnly.begin(), LeftOnly.end(), MsgLeftOnly)
- | PrintProblem(SourceMgr, Right.begin(), Right.end(), MsgRightOnly);
-}
-
-/// CheckResults - This compares the expected results to those that
-/// were actually reported. It emits any discrepencies. Return "true" if there
-/// were problems. Return "false" otherwise.
-///
-static bool CheckResults(Preprocessor &PP,
- const DiagList &ExpectedErrors,
- const DiagList &ExpectedWarnings,
- const DiagList &ExpectedNotes) {
- const DiagnosticClient *DiagClient = PP.getDiagnostics().getClient();
- assert(DiagClient != 0 &&
- "DiagChecker requires a valid TextDiagnosticBuffer");
- const TextDiagnosticBuffer &Diags =
- static_cast<const TextDiagnosticBuffer&>(*DiagClient);
- SourceManager &SourceMgr = PP.getSourceManager();
-
- // We want to capture the delta between what was expected and what was
- // seen.
- //
- // Expected \ Seen - set expected but not seen
- // Seen \ Expected - set seen but not expected
- bool HadProblem = false;
-
- // See if there are error mismatches.
- HadProblem |= CompareDiagLists(SourceMgr,
- ExpectedErrors.begin(), ExpectedErrors.end(),
- Diags.err_begin(), Diags.err_end(),
- "Errors expected but not seen:",
- "Errors seen but not expected:");
-
- // See if there are warning mismatches.
- HadProblem |= CompareDiagLists(SourceMgr,
- ExpectedWarnings.begin(),
- ExpectedWarnings.end(),
- Diags.warn_begin(), Diags.warn_end(),
- "Warnings expected but not seen:",
- "Warnings seen but not expected:");
-
- // See if there are note mismatches.
- HadProblem |= CompareDiagLists(SourceMgr,
- ExpectedNotes.begin(),
- ExpectedNotes.end(),
- Diags.note_begin(), Diags.note_end(),
- "Notes expected but not seen:",
- "Notes seen but not expected:");
-
- return HadProblem;
-}
-
-
-/// CheckDiagnostics - Gather the expected diagnostics and check them.
-bool clang::CheckDiagnostics(Preprocessor &PP) {
- // Gather the set of expected diagnostics.
- DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes;
- FindExpectedDiags(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
-
- // Check that the expected diagnostics occurred.
- return CheckResults(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
-}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index c552512dc957..ad931166b8fc 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -559,6 +559,19 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath("/mingw/include", System, true, false, false);
AddPath("c:/mingw/include", System, true, false, false);
break;
+ case llvm::Triple::Linux:
+ // Generic Debian multiarch support:
+ if (triple.getArch() == llvm::Triple::x86_64) {
+ AddPath("/usr/include/x86_64-linux-gnu", System, false, false, false);
+ AddPath("/usr/include/i686-linux-gnu/64", System, false, false, false);
+ AddPath("/usr/include/i486-linux-gnu/64", System, false, false, false);
+ } else if (triple.getArch() == llvm::Triple::x86) {
+ AddPath("/usr/include/x86_64-linux-gnu/32", System, false, false, false);
+ AddPath("/usr/include/i686-linux-gnu", System, false, false, false);
+ AddPath("/usr/include/i486-linux-gnu", System, false, false, false);
+ } else if (triple.getArch() == llvm::Triple::arm) {
+ AddPath("/usr/include/arm-linux-gnueabi", System, false, false, false);
+ }
default:
break;
}
@@ -651,6 +664,27 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
// Debian based distros.
// Note: these distros symlink /usr/include/c++/X.Y.Z -> X.Y
//===------------------------------------------------------------------===//
+
+ // Ubuntu 11.11 "Oneiric Ocelot" -- gcc-4.6.0
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "x86_64-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "i686-linux-gnu", "", "64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "i486-linux-gnu", "", "64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "arm-linux-gnueabi", "", "", triple);
+
+ // Ubuntu 11.04 "Natty Narwhal" -- gcc-4.5.2
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
+ "x86_64-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
+ "i686-linux-gnu", "", "64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
+ "i486-linux-gnu", "", "64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
+ "arm-linux-gnueabi", "", "", triple);
+
// Ubuntu 10.10 "Maverick Meerkat" -- gcc-4.4.5
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
"i686-linux-gnu", "", "64", triple);
@@ -734,6 +768,13 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
"x86_64-redhat-linux", "", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2",
"i386-redhat-linux", "", "", triple);
+
+ // RHEL 5
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.1",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.1",
+ "i386-redhat-linux", "", "", triple);
+
//===------------------------------------------------------------------===//
@@ -761,6 +802,11 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
"x86_64-suse-linux", "", "", triple);
+ // openSUSE 12.1
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "i586-suse-linux", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "x86_64-suse-linux", "", "", triple);
// Arch Linux 2008-06-24
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
"i686-pc-linux-gnu", "", "", triple);
@@ -986,6 +1032,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
if (it->first == Angled)
SearchList.push_back(it->second);
}
+ RemoveDuplicates(SearchList, quoted, Verbose);
+ unsigned angled = SearchList.size();
for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
it != ie; ++it) {
@@ -999,10 +1047,10 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
SearchList.push_back(it->second);
}
- RemoveDuplicates(SearchList, quoted, Verbose);
+ RemoveDuplicates(SearchList, angled, Verbose);
bool DontSearchCurDir = false; // TODO: set to true if -I- is set?
- Headers.SetSearchPaths(SearchList, quoted, DontSearchCurDir);
+ Headers.SetSearchPaths(SearchList, quoted, angled, DontSearchCurDir);
// If verbose, print the list of directories that will be searched.
if (Verbose) {
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index abe251d67df2..147a8df03760 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -221,6 +221,40 @@ static void DefineExactWidthIntType(TargetInfo::IntType Ty,
ConstSuffix);
}
+static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
+ const LangOptions &LangOpts,
+ const FrontendOptions &FEOpts,
+ MacroBuilder &Builder) {
+ if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP)
+ Builder.defineMacro("__STDC__");
+ if (LangOpts.Freestanding)
+ Builder.defineMacro("__STDC_HOSTED__", "0");
+ else
+ Builder.defineMacro("__STDC_HOSTED__");
+
+ if (!LangOpts.CPlusPlus) {
+ if (LangOpts.C99)
+ Builder.defineMacro("__STDC_VERSION__", "199901L");
+ else if (!LangOpts.GNUMode && LangOpts.Digraphs)
+ Builder.defineMacro("__STDC_VERSION__", "199409L");
+ } else {
+ if (LangOpts.GNUMode)
+ Builder.defineMacro("__cplusplus");
+ else
+ // C++ [cpp.predefined]p1:
+ // The name_ _cplusplus is defined to the value 199711L when compiling a
+ // C++ translation unit.
+ Builder.defineMacro("__cplusplus", "199711L");
+ }
+
+ if (LangOpts.ObjC1)
+ Builder.defineMacro("__OBJC__");
+
+ // Not "standard" per se, but available even with the -undef flag.
+ if (LangOpts.AsmPreprocessor)
+ Builder.defineMacro("__ASSEMBLER__");
+}
+
static void InitializePredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
@@ -256,20 +290,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Initialize language-specific preprocessor defines.
- // These should all be defined in the preprocessor according to the
- // current language configuration.
- if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP)
- Builder.defineMacro("__STDC__");
- if (LangOpts.AsmPreprocessor)
- Builder.defineMacro("__ASSEMBLER__");
-
- if (!LangOpts.CPlusPlus) {
- if (LangOpts.C99)
- Builder.defineMacro("__STDC_VERSION__", "199901L");
- else if (!LangOpts.GNUMode && LangOpts.Digraphs)
- Builder.defineMacro("__STDC_VERSION__", "199409L");
- }
-
// Standard conforming mode?
if (!LangOpts.GNUMode)
Builder.defineMacro("__STRICT_ANSI__");
@@ -277,13 +297,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.CPlusPlus0x)
Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__");
- if (LangOpts.Freestanding)
- Builder.defineMacro("__STDC_HOSTED__", "0");
- else
- Builder.defineMacro("__STDC_HOSTED__");
-
if (LangOpts.ObjC1) {
- Builder.defineMacro("__OBJC__");
if (LangOpts.ObjCNonFragileABI) {
Builder.defineMacro("__OBJC2__");
Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS");
@@ -324,13 +338,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.CPlusPlus) {
Builder.defineMacro("__GNUG__", "4");
Builder.defineMacro("__GXX_WEAK__");
- if (LangOpts.GNUMode)
- Builder.defineMacro("__cplusplus");
- else
- // C++ [cpp.predefined]p1:
- // The name_ _cplusplusis defined to the value 199711L when compiling a
- // C++ translation unit.
- Builder.defineMacro("__cplusplus", "199711L");
Builder.defineMacro("__private_extern__", "extern");
}
@@ -343,6 +350,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Since we define wchar_t in C++ mode.
Builder.defineMacro("_WCHAR_T_DEFINED");
Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
+ // FIXME: Support Microsoft's __identifier extension in the lexer.
+ Builder.append("#define __identifier(x) x");
Builder.append("class type_info;");
}
@@ -570,6 +579,12 @@ void clang::InitializePreprocessor(Preprocessor &PP,
InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
FEOpts, Builder);
+ // Even with predefines off, some macros are still predefined.
+ // These should all be defined in the preprocessor according to the
+ // current language configuration.
+ InitializeStandardPredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
+ FEOpts, Builder);
+
// Add on the predefines from the driver. Wrap in a #line directive to report
// that they come from the command line.
if (!PP.getLangOptions().AsmPreprocessor)
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
index 954bad4e7c54..78eb1b212836 100644
--- a/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -99,7 +99,7 @@ void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
DiagnosticClient::HandleDiagnostic(Level, Info);
// Initialize the main file name, if we haven't already fetched it.
- if (MainFilename.empty()) {
+ if (MainFilename.empty() && Info.hasSourceManager()) {
const SourceManager &SM = Info.getSourceManager();
FileID FID = SM.getMainFileID();
if (!FID.isInvalid()) {
@@ -122,7 +122,7 @@ void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
// Set the location information.
DE.Filename = "";
DE.Line = DE.Column = 0;
- if (Info.getLocation().isValid()) {
+ if (Info.getLocation().isValid() && Info.hasSourceManager()) {
const SourceManager &SM = Info.getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 47c942ca8dfa..1c47bf7bee93 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -343,7 +343,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(Diagnostic::Level Level,
// "included from" lines.
if (LastWarningLoc != PLoc.getIncludeLoc()) {
LastWarningLoc = PLoc.getIncludeLoc();
- PrintIncludeStack(Level, LastWarningLoc, SM);
+ PrintIncludeStack(Diagnostic::Note, LastWarningLoc, SM);
}
if (DiagOpts->ShowLocation) {
@@ -819,16 +819,28 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
- // Emit a Visual Studio compatible line number syntax.
- if (LangOpts && LangOpts->Microsoft) {
- OS << PLoc.getFilename() << '(' << LineNo << ')';
- OS << " : ";
- } else {
- OS << PLoc.getFilename() << ':' << LineNo << ':';
- if (DiagOpts->ShowColumn)
- if (unsigned ColNo = PLoc.getColumn())
- OS << ColNo << ':';
+ OS << PLoc.getFilename();
+ switch (DiagOpts->Format) {
+ case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
+ case DiagnosticOptions::Msvc: OS << '(' << LineNo; break;
+ case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
+ }
+ if (DiagOpts->ShowColumn)
+ if (unsigned ColNo = PLoc.getColumn()) {
+ if (DiagOpts->Format == DiagnosticOptions::Msvc) {
+ OS << ',';
+ ColNo--;
+ } else
+ OS << ':';
+ OS << ColNo;
+ }
+ switch (DiagOpts->Format) {
+ case DiagnosticOptions::Clang:
+ case DiagnosticOptions::Vi: OS << ':'; break;
+ case DiagnosticOptions::Msvc: OS << ") : "; break;
}
+
+
if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
FileID CaretFileID =
SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
@@ -927,8 +939,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
OptionName += "-Werror";
}
- if (const char *
- Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID())) {
+ llvm::StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
+ if (!Opt.empty()) {
if (!OptionName.empty())
OptionName += ',';
OptionName += "-W";
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index 8cc56168e0f8..f12b484c05e6 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -55,17 +55,14 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore);
for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
- const std::string &Opt = Opts.Warnings[i];
- const char *OptStart = &Opt[0];
- const char *OptEnd = OptStart+Opt.size();
- assert(*OptEnd == 0 && "Expect null termination for lower-bound search");
+ llvm::StringRef Opt = Opts.Warnings[i];
// Check to see if this warning starts with "no-", if so, this is a negative
// form of the option.
bool isPositive = true;
- if (OptEnd-OptStart > 3 && memcmp(OptStart, "no-", 3) == 0) {
+ if (Opt.startswith("no-")) {
isPositive = false;
- OptStart += 3;
+ Opt = Opt.substr(3);
}
// Figure out how this option affects the warning. If -Wfoo, map the
@@ -74,49 +71,47 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
// -Wsystem-headers is a special case, not driven by the option table. It
// cannot be controlled with -Werror.
- if (OptEnd-OptStart == 14 && memcmp(OptStart, "system-headers", 14) == 0) {
+ if (Opt == "system-headers") {
Diags.setSuppressSystemWarnings(!isPositive);
continue;
}
// -Werror/-Wno-error is a special case, not controlled by the option table.
// It also has the "specifier" form of -Werror=foo and -Werror-foo.
- if (OptEnd-OptStart >= 5 && memcmp(OptStart, "error", 5) == 0) {
- const char *Specifier = 0;
- if (OptEnd-OptStart != 5) { // Specifier must be present.
- if ((OptStart[5] != '=' && OptStart[5] != '-') ||
- OptEnd-OptStart == 6) {
+ if (Opt.startswith("error")) {
+ llvm::StringRef Specifier;
+ if (Opt.size() > 5) { // Specifier must be present.
+ if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) {
Diags.Report(diag::warn_unknown_warning_specifier)
- << "-Werror" << ("-W" + Opt);
+ << "-Werror" << ("-W" + Opt.str());
continue;
}
- Specifier = OptStart+6;
+ Specifier = Opt.substr(6);
}
- if (Specifier == 0) {
+ if (Specifier.empty()) {
Diags.setWarningsAsErrors(isPositive);
continue;
}
// -Werror=foo maps foo to Error, -Wno-error=foo maps it to Warning.
Mapping = isPositive ? diag::MAP_ERROR : diag::MAP_WARNING_NO_WERROR;
- OptStart = Specifier;
+ Opt = Specifier;
}
// -Wfatal-errors is yet another special case.
- if (OptEnd-OptStart >= 12 && memcmp(OptStart, "fatal-errors", 12) == 0) {
- const char* Specifier = 0;
- if (OptEnd-OptStart != 12) {
- if ((OptStart[12] != '=' && OptStart[12] != '-') ||
- OptEnd-OptStart == 13) {
+ if (Opt.startswith("fatal-errors")) {
+ llvm::StringRef Specifier;
+ if (Opt.size() != 12) {
+ if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) {
Diags.Report(diag::warn_unknown_warning_specifier)
- << "-Wfatal-errors" << ("-W" + Opt);
+ << "-Wfatal-errors" << ("-W" + Opt.str());
continue;
}
- Specifier = OptStart + 13;
+ Specifier = Opt.substr(13);
}
- if (Specifier == 0) {
+ if (Specifier.empty()) {
Diags.setErrorsAsFatal(isPositive);
continue;
}
@@ -124,10 +119,12 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
// -Wfatal-errors=foo maps foo to Fatal, -Wno-fatal-errors=foo
// maps it to Error.
Mapping = isPositive ? diag::MAP_FATAL : diag::MAP_ERROR_NO_WFATAL;
- OptStart = Specifier;
+ Opt = Specifier;
}
- if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
- Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt);
+ if (Diags.setDiagnosticGroupMapping(Opt, Mapping))
+ Diags.Report(isPositive ? diag::warn_unknown_warning_option :
+ diag::warn_unknown_negative_warning_option)
+ << ("-W" + Opt.str());
}
}
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 0c1d730f015d..ee12d3caef9c 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -466,7 +466,10 @@ _mm_loadr_pd(double const *dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadu_pd(double const *dp)
{
- return (__m128d){ dp[0], dp[1] };
+ struct __loadu_pd {
+ __m128d v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_pd*)dp)->v;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
@@ -478,13 +481,13 @@ _mm_load_sd(double const *dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadh_pd(__m128d a, double const *dp)
{
- return __builtin_shufflevector(a, *(__m128d *)dp, 0, 2);
+ return (__m128d){ a[0], *dp };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadl_pd(__m128d a, double const *dp)
{
- return __builtin_shufflevector(a, *(__m128d *)dp, 2, 1);
+ return (__m128d){ *dp, a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
@@ -1011,7 +1014,10 @@ _mm_load_si128(__m128i const *p)
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_loadu_si128(__m128i const *p)
{
- return (__m128i)__builtin_ia32_loaddqu((char const *)p);
+ struct __loadu_si128 {
+ __m128i v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_si128*)p)->v;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h
index fefb42fd74e3..986870a96883 100644
--- a/lib/Headers/mmintrin.h
+++ b/lib/Headers/mmintrin.h
@@ -421,20 +421,20 @@ _mm_set1_pi8(char __b)
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_setr_pi32(int __i1, int __i0)
+_mm_setr_pi32(int __i0, int __i1)
{
return _mm_set_pi32(__i1, __i0);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_setr_pi16(short __w3, short __w2, short __w1, short __w0)
+_mm_setr_pi16(short __w0, short __w1, short __w2, short __w3)
{
return _mm_set_pi16(__w3, __w2, __w1, __w0);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_setr_pi8(char __b7, char __b6, char __b5, char __b4, char __b3, char __b2,
- char __b1, char __b0)
+_mm_setr_pi8(char __b0, char __b1, char __b2, char __b3, char __b4, char __b5,
+ char __b6, char __b7)
{
return _mm_set_pi8(__b7, __b6, __b5, __b4, __b3, __b2, __b1, __b0);
}
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 00760ed6d1ef..50f275dce054 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -539,7 +539,10 @@ _mm_load_ps(const float *p)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_loadu_ps(const float *p)
{
- return (__m128){ p[0], p[1], p[2], p[3] };
+ struct __loadu_ps {
+ __m128 v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_ps*)p)->v;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Index/CallGraph.cpp b/lib/Index/CallGraph.cpp
index bf3f5a8a8d24..94790b8fbc17 100644
--- a/lib/Index/CallGraph.cpp
+++ b/lib/Index/CallGraph.cpp
@@ -74,7 +74,7 @@ void CallGraph::addTU(ASTContext& Ctx) {
I != E; ++I) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
- if (FD->isThisDeclarationADefinition()) {
+ if (FD->doesThisDeclarationHaveABody()) {
// Set caller's ASTContext.
Entity Ent = Entity::get(FD, Prog);
CallGraphNode *Node = getOrInsertFunction(Ent);
diff --git a/lib/Index/Indexer.cpp b/lib/Index/Indexer.cpp
index 7f21c4f3035a..ebba43c4747e 100644
--- a/lib/Index/Indexer.cpp
+++ b/lib/Index/Indexer.cpp
@@ -39,7 +39,7 @@ public:
Decl *D = Ent.getDecl(TU->getASTContext());
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isThisDeclarationADefinition())
+ if (FD->doesThisDeclarationHaveABody())
DefMap[Ent] = std::make_pair(FD, TU);
}
};
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 372078c60d20..bb4388195a32 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -37,6 +37,7 @@ ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
HeaderSearch::HeaderSearch(FileManager &FM)
: FileMgr(FM), FrameworkMap(64) {
+ AngledDirIdx = 0;
SystemDirIdx = 0;
NoCurDirSearch = false;
@@ -317,7 +318,7 @@ const FileEntry *HeaderSearch::LookupFile(
CurDir = 0;
// If this is a system #include, ignore the user #include locs.
- unsigned i = isAngled ? SystemDirIdx : 0;
+ unsigned i = isAngled ? AngledDirIdx : 0;
// If this is a #include_next request, start searching after the directory the
// file was found in.
@@ -482,6 +483,21 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
return HFI;
}
+bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
+ // Check if we've ever seen this file as a header.
+ if (File->getUID() >= FileInfo.size())
+ return false;
+
+ // Resolve header file info from the external source, if needed.
+ HeaderFileInfo &HFI = FileInfo[File->getUID()];
+ if (ExternalSource && !HFI.Resolved) {
+ HFI = ExternalSource->GetHeaderFileInfo(File);
+ HFI.Resolved = true;
+ }
+
+ return HFI.isPragmaOnce || HFI.ControllingMacro || HFI.ControllingMacroID;
+}
+
void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
if (UID >= FileInfo.size())
FileInfo.resize(UID+1);
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 16cc4f8fd54f..3b1149c08af3 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -76,7 +76,8 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
// skip the UTF-8 BOM if it's present.
if (BufferStart == BufferPtr) {
// Determine the size of the BOM.
- size_t BOMLength = llvm::StringSwitch<size_t>(BufferStart)
+ llvm::StringRef Buf(BufferStart, BufferEnd - BufferStart);
+ size_t BOMLength = llvm::StringSwitch<size_t>(Buf)
.StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM
.Default(0);
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 37e7bf4d628e..2c96c4d4ee24 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -840,16 +840,27 @@ StringLiteralParser::
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
Preprocessor &PP, bool Complain)
: SM(PP.getSourceManager()), Features(PP.getLangOptions()),
- Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() : 0) {
+ Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() : 0),
+ MaxTokenLength(0), SizeBound(0), wchar_tByteWidth(0),
+ ResultPtr(ResultBuf.data()), hadError(false), AnyWide(false), Pascal(false) {
init(StringToks, NumStringToks);
}
void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
+ // The literal token may have come from an invalid source location (e.g. due
+ // to a PCH error), in which case the token length will be 0.
+ if (NumStringToks == 0 || StringToks[0].getLength() < 2) {
+ hadError = true;
+ return;
+ }
+
// Scan all of the string portions, remember the max individual token length,
// computing a bound on the concatenated string length, and see whether any
// piece is a wide-string. If any of the string portions is a wide-string
// literal, the result is a wide-string literal [C99 6.4.5p4].
+ assert(NumStringToks && "expected at least one token");
MaxTokenLength = StringToks[0].getLength();
+ assert(StringToks[0].getLength() >= 2 && "literal token is invalid!");
SizeBound = StringToks[0].getLength()-2; // -2 for "".
AnyWide = StringToks[0].is(tok::wide_string_literal);
@@ -858,8 +869,14 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
// Implement Translation Phase #6: concatenation of string literals
/// (C99 5.1.1.2p1). The common case is only one string fragment.
for (unsigned i = 1; i != NumStringToks; ++i) {
+ if (StringToks[i].getLength() < 2) {
+ hadError = true;
+ return;
+ }
+
// The string could be shorter than this if it needs cleaning, but this is a
// reasonable bound, which is all we need.
+ assert(StringToks[i].getLength() >= 2 && "literal token is invalid!");
SizeBound += StringToks[i].getLength()-2; // -2 for "".
// Remember maximum string piece length.
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index c819011338e8..66d87a19386a 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -42,6 +42,7 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) {
IsDisabled = MI.IsDisabled;
IsUsed = MI.IsUsed;
IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning;
+ IsWarnIfUnused = MI.IsWarnIfUnused;
ArgumentList = 0;
NumArguments = 0;
setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator);
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index af3fa6e2add7..66e44bbc6dd0 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -323,7 +323,6 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// #else directive in a skipping conditional. If not in some other
// skipping conditional, and if #else hasn't already been seen, enter it
// as a non-skipping conditional.
- DiscardUntilEndOfDirective(); // C99 6.10p4.
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
// If this is a #else with a #else before it, report the error.
@@ -339,7 +338,10 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// entered, enter the #else block now.
if (!CondInfo.WasSkipping && !CondInfo.FoundNonSkip) {
CondInfo.FoundNonSkip = true;
+ CheckEndOfDirective("else");
break;
+ } else {
+ DiscardUntilEndOfDirective(); // C99 6.10p4.
}
} else if (Sub == "lif") { // "elif".
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index d6e0d3a1c08b..01cd75fa8485 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -85,6 +85,7 @@ void Preprocessor::RegisterBuiltinMacros() {
// Clang Extensions.
Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature");
+ Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension");
Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin");
Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute");
Ident__has_include = RegisterBuiltinMacro(*this, "__has_include");
@@ -525,8 +526,8 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
}
-/// HasFeature - Return true if we recognize and implement the specified feature
-/// specified by the identifier.
+/// HasFeature - Return true if we recognize and implement the feature
+/// specified by the identifier as a standard language feature.
static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
const LangOptions &LangOpts = PP.getLangOptions();
@@ -550,13 +551,17 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
- .Case("generic_selections", true)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
.Case("ownership_holds", true)
.Case("ownership_returns", true)
.Case("ownership_takes", true)
+ // C1X features
+ .Case("c_generic_selections", LangOpts.C1X)
+ .Case("c_static_assert", LangOpts.C1X)
// C++0x features
+ .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus0x)
+ .Case("cxx_alias_templates", LangOpts.CPlusPlus0x)
.Case("cxx_attributes", LangOpts.CPlusPlus0x)
.Case("cxx_auto_type", LangOpts.CPlusPlus0x)
.Case("cxx_decltype", LangOpts.CPlusPlus0x)
@@ -566,7 +571,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x)
//.Case("cxx_lambdas", false)
.Case("cxx_noexcept", LangOpts.CPlusPlus0x)
- //.Case("cxx_nullptr", false)
+ .Case("cxx_nullptr", LangOpts.CPlusPlus0x)
.Case("cxx_override_control", LangOpts.CPlusPlus0x)
.Case("cxx_range_for", LangOpts.CPlusPlus0x)
.Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x)
@@ -591,14 +596,45 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("is_empty", LangOpts.CPlusPlus)
.Case("is_enum", LangOpts.CPlusPlus)
.Case("is_literal", LangOpts.CPlusPlus)
+ .Case("is_standard_layout", LangOpts.CPlusPlus)
.Case("is_pod", LangOpts.CPlusPlus)
.Case("is_polymorphic", LangOpts.CPlusPlus)
.Case("is_trivial", LangOpts.CPlusPlus)
+ .Case("is_trivially_copyable", LangOpts.CPlusPlus)
.Case("is_union", LangOpts.CPlusPlus)
.Case("tls", PP.getTargetInfo().isTLSSupported())
.Default(false);
}
+/// HasExtension - Return true if we recognize and implement the feature
+/// specified by the identifier, either as an extension or a standard language
+/// feature.
+static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
+ if (HasFeature(PP, II))
+ return true;
+
+ // If the use of an extension results in an error diagnostic, extensions are
+ // effectively unavailable, so just return false here.
+ if (PP.getDiagnostics().getExtensionHandlingBehavior()==Diagnostic::Ext_Error)
+ return false;
+
+ const LangOptions &LangOpts = PP.getLangOptions();
+
+ // Because we inherit the feature list from HasFeature, this string switch
+ // must be less restrictive than HasFeature's.
+ return llvm::StringSwitch<bool>(II->getName())
+ // C1X features supported by other languages as extensions.
+ .Case("c_generic_selections", true)
+ .Case("c_static_assert", true)
+ // C++0x features supported by other languages as extensions.
+ .Case("cxx_deleted_functions", LangOpts.CPlusPlus)
+ .Case("cxx_inline_namespaces", LangOpts.CPlusPlus)
+ .Case("cxx_override_control", LangOpts.CPlusPlus)
+ .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus)
+ .Case("cxx_rvalue_references", LangOpts.CPlusPlus)
+ .Default(false);
+}
+
/// HasAttribute - Return true if we recognize and implement the attribute
/// specified by the given identifier.
static bool HasAttribute(const IdentifierInfo *II) {
@@ -847,10 +883,11 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// __COUNTER__ expands to a simple numeric value.
OS << CounterValue++;
Tok.setKind(tok::numeric_constant);
- } else if (II == Ident__has_feature ||
- II == Ident__has_builtin ||
+ } else if (II == Ident__has_feature ||
+ II == Ident__has_extension ||
+ II == Ident__has_builtin ||
II == Ident__has_attribute) {
- // The argument to these two builtins should be a parenthesized identifier.
+ // The argument to these builtins should be a parenthesized identifier.
SourceLocation StartLoc = Tok.getLocation();
bool IsValid = false;
@@ -879,6 +916,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Value = FeatureII->getBuiltinID() != 0;
} else if (II == Ident__has_attribute)
Value = HasAttribute(FeatureII);
+ else if (II == Ident__has_extension)
+ Value = HasExtension(*this, FeatureII);
else {
assert(II == Ident__has_feature && "Must be feature check");
Value = HasFeature(*this, FeatureII);
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 0c180918dc26..23855d4a4748 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -330,16 +330,16 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
unsigned FilenameID = SourceMgr.getLineTableFilenameID(PLoc.getFilename(),
FilenameLen);
+ // Notify the client, if desired, that we are in a new source file.
+ if (Callbacks)
+ Callbacks->FileChanged(SysHeaderTok.getLocation(),
+ PPCallbacks::SystemHeaderPragma, SrcMgr::C_System);
+
// Emit a line marker. This will change any source locations from this point
// forward to realize they are in a system header.
// Create a line note with this information.
SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine(), FilenameID,
false, false, true, false);
-
- // Notify the client, if desired, that we are in a new source file.
- if (Callbacks)
- Callbacks->FileChanged(SysHeaderTok.getLocation(),
- PPCallbacks::SystemHeaderPragma, SrcMgr::C_System);
}
/// HandlePragmaDependency - Handle #pragma GCC dependency "foo" blah.
@@ -824,9 +824,17 @@ struct PragmaDebugHandler : public PragmaHandler {
}
}
+// Disable MSVC warning about runtime stack overflow.
+#ifdef _MSC_VER
+ #pragma warning(disable : 4717)
+#endif
void DebugOverflowStack() {
DebugOverflowStack();
}
+#ifdef _MSC_VER
+ #pragma warning(default : 4717)
+#endif
+
};
/// PragmaDiagnosticHandler - e.g. '#pragma GCC diagnostic ignored "-Wformat"'
@@ -898,8 +906,7 @@ public:
return;
}
- std::string WarningName(Literal.GetString(),
- Literal.GetString()+Literal.GetStringLength());
+ llvm::StringRef WarningName(Literal.GetString(), Literal.GetStringLength());
if (WarningName.size() < 3 || WarningName[0] != '-' ||
WarningName[1] != 'W') {
@@ -908,7 +915,7 @@ public:
return;
}
- if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.c_str()+2,
+ if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.substr(2),
Map, DiagLoc))
PP.Diag(StrToks[0].getLocation(),
diag::warn_pragma_diagnostic_unknown_warning) << WarningName;
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 9555611dc59d..0c8d948ce0a7 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -45,8 +45,9 @@ void PreprocessingRecord::MaybeLoadPreallocatedEntities() const {
ExternalSource->ReadPreprocessedEntities();
}
-PreprocessingRecord::PreprocessingRecord()
- : ExternalSource(0), NumPreallocatedEntities(0),
+PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroInstantiations)
+ : IncludeNestedMacroInstantiations(IncludeNestedMacroInstantiations),
+ ExternalSource(0), NumPreallocatedEntities(0),
LoadedPreallocatedEntities(false)
{
}
@@ -120,6 +121,9 @@ MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
}
void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) {
+ if (!IncludeNestedMacroInstantiations && Id.getLocation().isMacroID())
+ return;
+
if (MacroDefinition *Def = findMacroDefinition(MI))
PreprocessedEntities.push_back(
new (*this) MacroInstantiation(Id.getIdentifierInfo(),
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 31fd667a651d..fdc18f878180 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -527,10 +527,11 @@ CommentHandler::~CommentHandler() { }
CodeCompletionHandler::~CodeCompletionHandler() { }
-void Preprocessor::createPreprocessingRecord() {
+void Preprocessor::createPreprocessingRecord(
+ bool IncludeNestedMacroInstantiations) {
if (Record)
return;
- Record = new PreprocessingRecord;
+ Record = new PreprocessingRecord(IncludeNestedMacroInstantiations);
addPPCallbacks(Record);
}
diff --git a/lib/Makefile b/lib/Makefile
index eda7017bb8bf..924819c81807 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -10,7 +10,7 @@ CLANG_LEVEL := ..
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
StaticAnalyzer Rewrite Serialization Frontend FrontendTool \
- Index Driver Tooling
+ Index Driver
include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 87e2f343748e..f5c69981ca35 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -23,10 +23,11 @@ using namespace clang;
/// and store its tokens for parsing after the C++ class is complete.
Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
- const VirtSpecifiers& VS) {
+ const VirtSpecifiers& VS, ExprResult& Init) {
assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
- assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) &&
- "Current token not a '{', ':' or 'try'!");
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) ||
+ Tok.is(tok::equal)) &&
+ "Current token not a '{', ':', '=', or 'try'!");
MultiTemplateParamsArg TemplateParams(Actions,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
@@ -40,13 +41,49 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
else { // FIXME: pass template information through
FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
move(TemplateParams), 0,
- VS, 0, /*IsDefinition*/true);
+ VS, Init.release(),
+ /*HasInit=*/false,
+ /*IsDefinition*/true);
}
HandleMemberFunctionDefaultArgs(D, FnD);
D.complete(FnD);
+ if (Tok.is(tok::equal)) {
+ ConsumeToken();
+
+ bool Delete = false;
+ SourceLocation KWLoc;
+ if (Tok.is(tok::kw_delete)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDeleted(FnD, KWLoc);
+ Delete = true;
+ } else if (Tok.is(tok::kw_default)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDefaulted(FnD, KWLoc);
+ } else {
+ llvm_unreachable("function definition after = not 'delete' or 'default'");
+ }
+
+ if (Tok.is(tok::comma)) {
+ Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
+ << Delete;
+ SkipUntil(tok::semi);
+ } else {
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ Delete ? "delete" : "default", tok::semi);
+ }
+
+ return FnD;
+ }
+
// In delayed template parsing mode, if we are within a class template
// or if we are about to parse function member template then consume
// the tokens and store them for parsing at the end of the translation unit.
@@ -130,8 +167,50 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
return FnD;
}
+/// ParseCXXNonStaticMemberInitializer - We parsed and verified that the
+/// specified Declarator is a well formed C++ non-static data member
+/// declaration. Now lex its initializer and store its tokens for parsing
+/// after the class is complete.
+void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) {
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::equal)) &&
+ "Current token not a '{' or '='!");
+
+ LateParsedMemberInitializer *MI =
+ new LateParsedMemberInitializer(this, VarD);
+ getCurrentClass().LateParsedDeclarations.push_back(MI);
+ CachedTokens &Toks = MI->Toks;
+
+ tok::TokenKind kind = Tok.getKind();
+ if (kind == tok::equal) {
+ Toks.push_back(Tok);
+ ConsumeAnyToken();
+ }
+
+ if (kind == tok::l_brace) {
+ // Begin by storing the '{' token.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/true);
+ } else {
+ // Consume everything up to (but excluding) the comma or semicolon.
+ ConsumeAndStoreUntil(tok::comma, Toks, /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/false);
+ }
+
+ // Store an artificial EOF token to ensure that we don't run off the end of
+ // the initializer when we come to parse it.
+ Token Eof;
+ Eof.startToken();
+ Eof.setKind(tok::eof);
+ Eof.setLocation(Tok.getLocation());
+ Toks.push_back(Eof);
+}
+
Parser::LateParsedDeclaration::~LateParsedDeclaration() {}
void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
+void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {}
void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
@@ -145,6 +224,10 @@ void Parser::LateParsedClass::ParseLexedMethodDeclarations() {
Self->ParseLexedMethodDeclarations(*Class);
}
+void Parser::LateParsedClass::ParseLexedMemberInitializers() {
+ Self->ParseLexedMemberInitializers(*Class);
+}
+
void Parser::LateParsedClass::ParseLexedMethodDefs() {
Self->ParseLexedMethodDefs(*Class);
}
@@ -157,6 +240,10 @@ void Parser::LexedMethod::ParseLexedMethodDefs() {
Self->ParseLexedMethodDef(*this);
}
+void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() {
+ Self->ParseLexedMemberInitializer(*this);
+}
+
/// ParseLexedMethodDeclarations - We finished parsing the member
/// specification of a top (non-nested) C++ class. Now go over the
/// stack of method declarations with some parts for which parsing was
@@ -328,8 +415,70 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
origLoc))
while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
ConsumeAnyToken();
+ }
+}
+
+/// ParseLexedMemberInitializers - We finished parsing the member specification
+/// of a top (non-nested) C++ class. Now go over the stack of lexed data member
+/// initializers that were collected during its parsing and parse them all.
+void Parser::ParseLexedMemberInitializers(ParsingClass &Class) {
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
+ HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
+ // Set or update the scope flags to include Scope::ThisScope.
+ bool AlreadyHasClassScope = Class.TopLevelClass;
+ unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope;
+ ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
+ ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
+
+ if (!AlreadyHasClassScope)
+ Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
+ Class.TagOrTemplate);
+
+ for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) {
+ Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers();
}
+
+ if (!AlreadyHasClassScope)
+ Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(),
+ Class.TagOrTemplate);
+
+ Actions.ActOnFinishDelayedMemberInitializers(Class.TagOrTemplate);
+}
+
+void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
+ if (MI.Field->isInvalidDecl())
+ return;
+
+ // Append the current token at the end of the new token stream so that it
+ // doesn't get lost.
+ MI.Toks.push_back(Tok);
+ PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false);
+
+ // Consume the previously pushed token.
+ ConsumeAnyToken();
+
+ SourceLocation EqualLoc;
+ ExprResult Init = ParseCXXMemberInitializer(/*IsFunction=*/false, EqualLoc);
+
+ Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release());
+
+ // The next token should be our artificial terminating EOF token.
+ if (Tok.isNot(tok::eof)) {
+ SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
+ if (!EndLoc.isValid())
+ EndLoc = Tok.getLocation();
+ // No fixit; we can't recover as if there were a semicolon here.
+ Diag(EndLoc, diag::err_expected_semi_decl_list);
+
+ // Consume tokens until we hit the artificial EOF.
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+ }
+ ConsumeAnyToken();
}
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index a20e90bd0ea3..ad3fcfe0d369 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -253,9 +253,17 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) {
SkipUntil(tok::r_paren, true); // skip until ) or ;
return;
}
+
while (Tok.getIdentifierInfo()) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
+
+ // FIXME: Remove this when we have proper __declspec(property()) support.
+ // Just skip everything inside property().
+ if (AttrName->getName() == "property") {
+ ConsumeParen();
+ SkipUntil(tok::r_paren);
+ }
if (Tok.is(tok::l_paren)) {
ConsumeParen();
// FIXME: This doesn't parse __declspec(property(get=get_func_name))
@@ -806,8 +814,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// analyzed.
if (FRI && Tok.is(tok::colon)) {
FRI->ColonLoc = ConsumeToken();
- // FIXME: handle braced-init-list here.
- FRI->RangeExpr = ParseExpression();
+ if (Tok.is(tok::l_brace))
+ FRI->RangeExpr = ParseBraceInitializer();
+ else
+ FRI->RangeExpr = ParseExpression();
Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
Actions.ActOnCXXForRangeDecl(ThisDecl);
Actions.FinalizeDeclaration(ThisDecl);
@@ -906,6 +916,7 @@ bool Parser::ParseAttributesAfterDeclarator(Declarator &D) {
/// [C++] '(' expression-list ')'
/// [C++0x] '=' 'default' [TODO]
/// [C++0x] '=' 'delete'
+/// [C++0x] braced-init-list
///
/// According to the standard grammar, =default and =delete are function
/// definitions, but that definitely doesn't fit with the parser here.
@@ -960,12 +971,17 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
diag::err_invalid_equalequal_after_declarator)) {
ConsumeToken();
if (Tok.is(tok::kw_delete)) {
- SourceLocation DelLoc = ConsumeToken();
-
- if (!getLang().CPlusPlus0x)
- Diag(DelLoc, diag::warn_deleted_function_accepted_as_extension);
-
- Actions.SetDeclDeleted(ThisDecl, DelLoc);
+ if (D.isFunctionDeclarator())
+ Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_deleted_non_function);
+ } else if (Tok.is(tok::kw_default)) {
+ if (D.isFunctionDeclarator())
+ Diag(Tok, diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_default_special_members);
} else {
if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
EnterScope(0);
@@ -1028,6 +1044,26 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
RParenLoc,
TypeContainsAuto);
}
+ } else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ // Parse C++0x braced-init-list.
+ if (D.getCXXScopeSpec().isSet()) {
+ EnterScope(0);
+ Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
+ }
+
+ ExprResult Init(ParseBraceInitializer());
+
+ if (D.getCXXScopeSpec().isSet()) {
+ Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
+ ExitScope();
+ }
+
+ if (Init.isInvalid()) {
+ Actions.ActOnInitializerError(ThisDecl);
+ } else
+ Actions.AddInitializerToDecl(ThisDecl, Init.take(),
+ /*DirectInit=*/true, TypeContainsAuto);
+
} else {
Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto);
}
@@ -1846,6 +1882,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ParseDecltypeSpecifier(DS);
continue;
+ case tok::kw___underlying_type:
+ ParseUnderlyingTypeSpecifier(DS);
+
// OpenCL qualifiers:
case tok::kw_private:
if (!getLang().OpenCL)
@@ -2116,6 +2155,11 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
ParseDecltypeSpecifier(DS);
return true;
+ // C++0x type traits support.
+ case tok::kw___underlying_type:
+ ParseUnderlyingTypeSpecifier(DS);
+ return true;
+
// OpenCL qualifiers:
case tok::kw_private:
if (!getLang().OpenCL)
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 8c0aa1ba694c..51aa01091e73 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -60,12 +60,20 @@ Decl *Parser::ParseNamespace(unsigned Context,
SourceLocation IdentLoc;
IdentifierInfo *Ident = 0;
+ std::vector<SourceLocation> ExtraIdentLoc;
+ std::vector<IdentifierInfo*> ExtraIdent;
+ std::vector<SourceLocation> ExtraNamespaceLoc;
Token attrTok;
if (Tok.is(tok::identifier)) {
Ident = Tok.getIdentifierInfo();
IdentLoc = ConsumeToken(); // eat the identifier.
+ while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) {
+ ExtraNamespaceLoc.push_back(ConsumeToken());
+ ExtraIdent.push_back(Tok.getIdentifierInfo());
+ ExtraIdentLoc.push_back(ConsumeToken());
+ }
}
// Read label attributes, if present.
@@ -85,7 +93,12 @@ Decl *Parser::ParseNamespace(unsigned Context,
return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
}
+
if (Tok.isNot(tok::l_brace)) {
+ if (!ExtraIdent.empty()) {
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
+ }
Diag(Tok, Ident ? diag::err_expected_lbrace :
diag::err_expected_ident_lbrace);
return 0;
@@ -96,11 +109,44 @@ Decl *Parser::ParseNamespace(unsigned Context,
if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() ||
getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() ||
getCurScope()->getFnParent()) {
+ if (!ExtraIdent.empty()) {
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
+ }
Diag(LBrace, diag::err_namespace_nonnamespace_scope);
SkipUntil(tok::r_brace, false);
return 0;
}
+ if (!ExtraIdent.empty()) {
+ TentativeParsingAction TPA(*this);
+ SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true);
+ Token rBraceToken = Tok;
+ TPA.Revert();
+
+ if (!rBraceToken.is(tok::r_brace)) {
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
+ } else {
+ std::string NamespaceFix;
+ for (std::vector<IdentifierInfo*>::iterator I = ExtraIdent.begin(),
+ E = ExtraIdent.end(); I != E; ++I) {
+ NamespaceFix += " { namespace ";
+ NamespaceFix += (*I)->getName();
+ }
+
+ std::string RBraces;
+ for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i)
+ RBraces += "} ";
+
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(),
+ ExtraIdentLoc.back()),
+ NamespaceFix)
+ << FixItHint::CreateInsertion(rBraceToken.getLocation(), RBraces);
+ }
+ }
+
// If we're still good, complain about inline namespaces in non-C++0x now.
if (!getLang().CPlusPlus0x && InlineLoc.isValid())
Diag(InlineLoc, diag::ext_inline_namespace);
@@ -115,23 +161,56 @@ Decl *Parser::ParseNamespace(unsigned Context,
PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc,
"parsing namespace");
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
- MaybeParseMicrosoftAttributes(attrs);
- ParseExternalDeclaration(attrs);
- }
+ SourceLocation RBraceLoc;
+ // Parse the contents of the namespace. This includes parsing recovery on
+ // any improperly nested namespaces.
+ ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0,
+ InlineLoc, LBrace, attrs, RBraceLoc);
// Leave the namespace scope.
NamespaceScope.Exit();
- SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace);
Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
DeclEnd = RBraceLoc;
return NamespcDecl;
}
+/// ParseInnerNamespace - Parse the contents of a namespace.
+void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
+ std::vector<IdentifierInfo*>& Ident,
+ std::vector<SourceLocation>& NamespaceLoc,
+ unsigned int index, SourceLocation& InlineLoc,
+ SourceLocation& LBrace,
+ ParsedAttributes& attrs,
+ SourceLocation& RBraceLoc) {
+ if (index == Ident.size()) {
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(attrs);
+ MaybeParseMicrosoftAttributes(attrs);
+ ParseExternalDeclaration(attrs);
+ }
+ RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace);
+
+ return;
+ }
+
+ // Parse improperly nested namespaces.
+ ParseScope NamespaceScope(this, Scope::DeclScope);
+ Decl *NamespcDecl =
+ Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(),
+ NamespaceLoc[index], IdentLoc[index],
+ Ident[index], LBrace, attrs.getList());
+
+ ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc,
+ LBrace, attrs, RBraceLoc);
+
+ NamespaceScope.Exit();
+
+ Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
+}
+
/// ParseNamespaceAlias - Parse the part after the '=' in a namespace
/// alias definition.
///
@@ -387,13 +466,35 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
bool IsAliasDecl = Tok.is(tok::equal);
TypeResult TypeAlias;
if (IsAliasDecl) {
- // TODO: Do we want to support attributes somewhere in an alias declaration?
- // Can't follow GCC since it doesn't support them yet!
+ // TODO: Attribute support. C++0x attributes may appear before the equals.
+ // Where can GNU attributes appear?
ConsumeToken();
if (!getLang().CPlusPlus0x)
Diag(Tok.getLocation(), diag::ext_alias_declaration);
+ // Type alias templates cannot be specialized.
+ int SpecKind = -1;
+ if (TemplateInfo.Kind == ParsedTemplateInfo::Template &&
+ Name.getKind() == UnqualifiedId::IK_TemplateId)
+ SpecKind = 0;
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization)
+ SpecKind = 1;
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+ SpecKind = 2;
+ if (SpecKind != -1) {
+ SourceRange Range;
+ if (SpecKind == 0)
+ Range = SourceRange(Name.TemplateId->LAngleLoc,
+ Name.TemplateId->RAngleLoc);
+ else
+ Range = TemplateInfo.getSourceRange();
+ Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
+ << SpecKind << Range;
+ SkipUntil(tok::semi);
+ return 0;
+ }
+
// Name must be an identifier.
if (Name.getKind() != UnqualifiedId::IK_Identifier) {
Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier);
@@ -408,7 +509,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
<< FixItHint::CreateRemoval(SS.getRange());
- TypeAlias = ParseTypeName(0, Declarator::AliasDeclContext);
+ TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
+ Declarator::AliasTemplateContext :
+ Declarator::AliasDeclContext);
} else
// Parse (optional) attributes (most likely GNU strong-using extension).
MaybeParseGNUAttributes(attrs);
@@ -421,9 +524,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
tok::semi);
// Diagnose an attempt to declare a templated using-declaration.
- // TODO: in C++0x, alias-declarations can be templates:
+ // In C++0x, alias-declarations can be templates:
// template <...> using id = type;
- if (TemplateInfo.Kind) {
+ if (TemplateInfo.Kind && !IsAliasDecl) {
SourceRange R = TemplateInfo.getSourceRange();
Diag(UsingLoc, diag::err_templated_using_declaration)
<< R << FixItHint::CreateRemoval(R);
@@ -434,9 +537,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return 0;
}
- if (IsAliasDecl)
- return Actions.ActOnAliasDeclaration(getCurScope(), AS, UsingLoc, Name,
- TypeAlias);
+ if (IsAliasDecl) {
+ TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
+ MultiTemplateParamsArg TemplateParamsArg(Actions,
+ TemplateParams ? TemplateParams->data() : 0,
+ TemplateParams ? TemplateParams->size() : 0);
+ return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
+ UsingLoc, Name, TypeAlias);
+ }
return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS,
Name, attrs.getList(),
@@ -543,6 +651,42 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
Diag(StartLoc, DiagID) << PrevSpec;
}
+void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
+ assert(Tok.is(tok::kw___underlying_type) &&
+ "Not an underlying type specifier");
+
+ SourceLocation StartLoc = ConsumeToken();
+ SourceLocation LParenLoc = Tok.getLocation();
+
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "__underlying_type")) {
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ TypeResult Result = ParseTypeName();
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ // Match the ')'
+ SourceLocation RParenLoc;
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (RParenLoc.isInvalid())
+ return;
+
+ const char *PrevSpec = 0;
+ unsigned DiagID;
+ if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec,
+ DiagID, Result.release()))
+ Diag(StartLoc, DiagID) << PrevSpec;
+}
+
/// ParseClassName - Parse a C++ class-name, which names a class. Note
/// that we only check that the result names a type; semantic analysis
/// will need to verify that the type names a class. The result is
@@ -1409,6 +1553,7 @@ bool Parser::isCXX0XFinalKeyword() const {
/// member-declarator:
/// declarator virt-specifier-seq[opt] pure-specifier[opt]
/// declarator constant-initializer[opt]
+/// [C++11] declarator brace-or-equal-initializer[opt]
/// identifier[opt] ':' constant-expression
///
/// virt-specifier-seq:
@@ -1515,8 +1660,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
MaybeParseMicrosoftAttributes(attrs);
if (Tok.is(tok::kw_using)) {
- // FIXME: Check for template aliases
-
ProhibitAttributes(attrs);
// Eat 'using'.
@@ -1527,7 +1670,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SkipUntil(tok::semi, true, true);
} else {
SourceLocation DeclEnd;
- // Otherwise, it must be using-declaration.
+ // Otherwise, it must be a using-declaration or an alias-declaration.
ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
UsingLoc, DeclEnd, AS);
}
@@ -1547,13 +1690,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::semi)) {
ConsumeToken();
Decl *TheDecl =
- Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS);
+ Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams);
DS.complete(TheDecl);
return;
}
ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext);
VirtSpecifiers VS;
+ ExprResult Init;
if (Tok.isNot(tok::colon)) {
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
@@ -1575,10 +1719,36 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// If attributes exist after the declarator, but before an '{', parse them.
MaybeParseGNUAttributes(DeclaratorInfo);
+ // MSVC permits pure specifier on inline functions declared at class scope.
+ // Hence check for =0 before checking for function definition.
+ if (getLang().Microsoft && Tok.is(tok::equal) &&
+ DeclaratorInfo.isFunctionDeclarator() &&
+ NextToken().is(tok::numeric_constant)) {
+ ConsumeToken();
+ Init = ParseInitializer();
+ if (Init.isInvalid())
+ SkipUntil(tok::comma, true, true);
+ }
+
+ bool IsDefinition = false;
// function-definition:
- if (Tok.is(tok::l_brace)
- || (DeclaratorInfo.isFunctionDeclarator() &&
- (Tok.is(tok::colon) || Tok.is(tok::kw_try)))) {
+ //
+ // In C++11, a non-function declarator followed by an open brace is a
+ // braced-init-list for an in-class member initialization, not an
+ // erroneous function definition.
+ if (Tok.is(tok::l_brace) && !getLang().CPlusPlus0x) {
+ IsDefinition = true;
+ } else if (DeclaratorInfo.isFunctionDeclarator()) {
+ if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
+ IsDefinition = true;
+ } else if (Tok.is(tok::equal)) {
+ const Token &KW = NextToken();
+ if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
+ IsDefinition = true;
+ }
+ }
+
+ if (IsDefinition) {
if (!DeclaratorInfo.isFunctionDeclarator()) {
Diag(Tok, diag::err_func_def_no_params);
ConsumeBrace();
@@ -1604,10 +1774,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
- ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS);
- // Consume the optional ';'
- if (Tok.is(tok::semi))
+ ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init);
+
+ // Consume the ';' - it's optional unless we have a delete or default
+ if (Tok.is(tok::semi)) {
ConsumeToken();
+ }
return;
}
@@ -1619,13 +1791,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
llvm::SmallVector<Decl *, 8> DeclsInGroup;
ExprResult BitfieldSize;
- ExprResult Init;
- bool Deleted = false;
while (1) {
// member-declarator:
// declarator pure-specifier[opt]
- // declarator constant-initializer[opt]
+ // declarator brace-or-equal-initializer[opt]
// identifier[opt] ':' constant-expression
if (Tok.is(tok::colon)) {
ConsumeToken();
@@ -1634,31 +1804,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SkipUntil(tok::comma, true, true);
}
- ParseOptionalCXX0XVirtSpecifierSeq(VS);
-
- // pure-specifier:
- // '= 0'
- //
- // constant-initializer:
- // '=' constant-expression
- //
- // defaulted/deleted function-definition:
- // '=' 'default' [TODO]
- // '=' 'delete'
- if (Tok.is(tok::equal)) {
- ConsumeToken();
- if (Tok.is(tok::kw_delete)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
- ConsumeToken();
- Deleted = true;
- } else {
- Init = ParseInitializer();
- if (Init.isInvalid())
- SkipUntil(tok::comma, true, true);
- }
- }
-
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
@@ -1673,6 +1818,30 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// If attributes exist after the declarator, parse them.
MaybeParseGNUAttributes(DeclaratorInfo);
+ // FIXME: When g++ adds support for this, we'll need to check whether it
+ // goes before or after the GNU attributes and __asm__.
+ ParseOptionalCXX0XVirtSpecifierSeq(VS);
+
+ bool HasDeferredInitializer = false;
+ if (Tok.is(tok::equal) || Tok.is(tok::l_brace)) {
+ if (BitfieldSize.get()) {
+ Diag(Tok, diag::err_bitfield_member_init);
+ SkipUntil(tok::comma, true, true);
+ } else {
+ HasDeferredInitializer = !DeclaratorInfo.isFunctionDeclarator() &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_static;
+
+ if (!HasDeferredInitializer) {
+ SourceLocation EqualLoc;
+ Init = ParseCXXMemberInitializer(
+ DeclaratorInfo.isFunctionDeclarator(), EqualLoc);
+ if (Init.isInvalid())
+ SkipUntil(tok::comma, true, true);
+ }
+ }
+ }
+
// NOTE: If Sema is the Action module and declarator is an instance field,
// this call will *not* return the created decl; It will return null.
// See Sema::ActOnCXXMemberDeclarator for details.
@@ -1689,8 +1858,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
move(TemplateParams),
BitfieldSize.release(),
VS, Init.release(),
- /*IsDefinition*/Deleted,
- Deleted);
+ HasDeferredInitializer,
+ /*IsDefinition*/ false);
}
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);
@@ -1703,6 +1872,24 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DeclaratorInfo.complete(ThisDecl);
+ if (HasDeferredInitializer) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension);
+
+ if (DeclaratorInfo.isArrayOfUnknownBound()) {
+ // C++0x [dcl.array]p3: An array bound may also be omitted when the
+ // declarator is followed by an initializer.
+ //
+ // A brace-or-equal-initializer for a member-declarator is not an
+ // initializer in the gramamr, so this is ill-formed.
+ Diag(Tok, diag::err_incomplete_array_member_init);
+ SkipUntil(tok::comma, true, true);
+ // Avoid later warnings about a class member of incomplete type.
+ ThisDecl->setInvalidDecl();
+ } else
+ ParseCXXNonStaticMemberInitializer(ThisDecl);
+ }
+
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
if (Tok.isNot(tok::comma))
@@ -1716,7 +1903,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
VS.clear();
BitfieldSize = 0;
Init = 0;
- Deleted = false;
// Attributes are only allowed on the second declarator.
MaybeParseGNUAttributes(DeclaratorInfo);
@@ -1737,6 +1923,66 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DeclsInGroup.size());
}
+/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or
+/// pure-specifier. Also detect and reject any attempted defaulted/deleted
+/// function definition. The location of the '=', if any, will be placed in
+/// EqualLoc.
+///
+/// pure-specifier:
+/// '= 0'
+///
+/// brace-or-equal-initializer:
+/// '=' initializer-expression
+/// braced-init-list [TODO]
+///
+/// initializer-clause:
+/// assignment-expression
+/// braced-init-list [TODO]
+///
+/// defaulted/deleted function-definition:
+/// '=' 'default'
+/// '=' 'delete'
+///
+/// Prior to C++0x, the assignment-expression in an initializer-clause must
+/// be a constant-expression.
+ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction,
+ SourceLocation &EqualLoc) {
+ assert((Tok.is(tok::equal) || Tok.is(tok::l_brace))
+ && "Data member initializer not starting with '=' or '{'");
+
+ if (Tok.is(tok::equal)) {
+ EqualLoc = ConsumeToken();
+ if (Tok.is(tok::kw_delete)) {
+ // In principle, an initializer of '= delete p;' is legal, but it will
+ // never type-check. It's better to diagnose it as an ill-formed expression
+ // than as an ill-formed deleted non-function member.
+ // An initializer of '= delete p, foo' will never be parsed, because
+ // a top-level comma always ends the initializer expression.
+ const Token &Next = NextToken();
+ if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) ||
+ Next.is(tok::eof)) {
+ if (IsFunction)
+ Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_deleted_non_function);
+ return ExprResult();
+ }
+ } else if (Tok.is(tok::kw_default)) {
+ Diag(ConsumeToken(), diag::err_default_special_members);
+ if (IsFunction)
+ Diag(Tok, diag::err_default_delete_in_multiple_declaration)
+ << 0 /* default */;
+ else
+ Diag(ConsumeToken(), diag::err_default_special_members);
+ return ExprResult();
+ }
+
+ return ParseInitializer();
+ } else
+ return ExprError(Diag(Tok, diag::err_generalized_initializer_lists));
+}
+
/// ParseCXXMemberSpecification - Parse the class definition.
///
/// member-specification:
@@ -1839,6 +2085,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
// Each iteration of this loop reads one member-declaration.
+ if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) ||
+ Tok.is(tok::kw___if_not_exists))) {
+ ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
+ continue;
+ }
+
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
Diag(Tok, diag::ext_extra_struct_semi)
@@ -1882,19 +2134,20 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
LBraceLoc, RBraceLoc,
attrs.getList());
- // C++ 9.2p2: Within the class member-specification, the class is regarded as
- // complete within function bodies, default arguments,
- // exception-specifications, and constructor ctor-initializers (including
- // such things in nested classes).
+ // C++0x [class.mem]p2: Within the class member-specification, the class is
+ // regarded as complete within function bodies, default arguments, exception-
+ // specifications, and brace-or-equal-initializers for non-static data
+ // members (including such things in nested classes).
//
- // FIXME: Only function bodies and constructor ctor-initializers are
- // parsed correctly, fix the rest.
+ // FIXME: Only function bodies and brace-or-equal-initializers are currently
+ // handled. Fix the others!
if (TagDecl && NonNestedClass) {
// We are not inside a nested class. This class and its nested classes
// are complete and we can parse the delayed portions of method
// declarations and the lexed inline method definitions.
SourceLocation SavedPrevTokLocation = PrevTokLocation;
ParseLexedMethodDeclarations(getCurrentClass());
+ ParseLexedMemberInitializers(getCurrentClass());
ParseLexedMethodDefs(getCurrentClass());
PrevTokLocation = SavedPrevTokLocation;
}
@@ -1982,6 +2235,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
///
/// [C++] mem-initializer:
/// mem-initializer-id '(' expression-list[opt] ')'
+/// [C++0x] mem-initializer-id braced-init-list
///
/// [C++] mem-initializer-id:
/// '::'[opt] nested-name-specifier[opt] class-name
@@ -2012,31 +2266,37 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
SourceLocation IdLoc = ConsumeToken();
// Parse the '('.
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected_lparen);
+ if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ // FIXME: Do something with the braced-init-list.
+ ParseBraceInitializer();
return true;
- }
- SourceLocation LParenLoc = ConsumeParen();
+ } else if(Tok.is(tok::l_paren)) {
+ SourceLocation LParenLoc = ConsumeParen();
- // Parse the optional expression-list.
- ExprVector ArgExprs(Actions);
- CommaLocsTy CommaLocs;
- if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
- SkipUntil(tok::r_paren);
- return true;
- }
+ // Parse the optional expression-list.
+ ExprVector ArgExprs(Actions);
+ CommaLocsTy CommaLocs;
+ if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ return true;
+ }
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- SourceLocation EllipsisLoc;
- if (Tok.is(tok::ellipsis))
- EllipsisLoc = ConsumeToken();
-
- return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
- TemplateTypeTy, IdLoc,
- LParenLoc, ArgExprs.take(),
- ArgExprs.size(), RParenLoc,
- EllipsisLoc);
+ SourceLocation EllipsisLoc;
+ if (Tok.is(tok::ellipsis))
+ EllipsisLoc = ConsumeToken();
+
+ return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
+ TemplateTypeTy, IdLoc,
+ LParenLoc, ArgExprs.take(),
+ ArgExprs.size(), RParenLoc,
+ EllipsisLoc);
+ }
+
+ Diag(Tok, getLang().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace
+ : diag::err_expected_lparen);
+ return true;
}
/// \brief Parse a C++ exception-specification if present (C++0x [except.spec]).
@@ -2438,3 +2698,64 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs,
ExpectAndConsume(tok::r_square, diag::err_expected_rsquare);
}
}
+
+void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
+ AccessSpecifier& CurAS) {
+ bool Result;
+ if (ParseMicrosoftIfExistsCondition(Result))
+ return;
+
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return;
+ }
+ ConsumeBrace();
+
+ // Condition is false skip all inside the {}.
+ if (!Result) {
+ SkipUntil(tok::r_brace, false);
+ return;
+ }
+
+ // Condition is true, parse the declaration.
+ while (Tok.isNot(tok::r_brace)) {
+
+ // __if_exists, __if_not_exists can nest.
+ if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) {
+ ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
+ continue;
+ }
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.is(tok::semi)) {
+ Diag(Tok, diag::ext_extra_struct_semi)
+ << DeclSpec::getSpecifierName((DeclSpec::TST)TagType)
+ << FixItHint::CreateRemoval(Tok.getLocation());
+ ConsumeToken();
+ continue;
+ }
+
+ AccessSpecifier AS = getAccessSpecifierIfPresent();
+ if (AS != AS_none) {
+ // Current token is a C++ access specifier.
+ CurAS = AS;
+ SourceLocation ASLoc = Tok.getLocation();
+ ConsumeToken();
+ if (Tok.is(tok::colon))
+ Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation());
+ else
+ Diag(Tok, diag::err_expected_colon);
+ ConsumeToken();
+ continue;
+ }
+
+ // Parse all the comma separated declarators.
+ ParseCXXClassMemberDeclaration(CurAS);
+ }
+
+ if (Tok.isNot(tok::r_brace)) {
+ Diag(Tok, diag::err_expected_rbrace);
+ return;
+ }
+ ConsumeBrace();
+}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 91fe1e1935e9..4e94ed9323b8 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -480,7 +480,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// [OBJC] '@encode' '(' type-name ')'
/// [OBJC] objc-string-literal
/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
+/// [C++0x] simple-type-specifier braced-init-list [C++ 5.2.3]
/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
+/// [C++0x] typename-specifier braced-init-list [C++ 5.2.3]
/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
@@ -566,6 +568,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// '__is_trivial'
/// '__is_union'
///
+/// [Clang] unary-type-trait:
+/// '__trivially_copyable'
+///
/// binary-type-trait:
/// [GNU] '__is_base_of'
/// [MS] '__is_convertible_to'
@@ -782,6 +787,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___builtin_va_arg:
case tok::kw___builtin_offsetof:
case tok::kw___builtin_choose_expr:
+ case tok::kw___builtin_astype: // primary-expression: [OCL] as_type()
return ParseBuiltinPrimaryExpression();
case tok::kw___null:
return Actions.ActOnGNUNullExpr(ConsumeToken());
@@ -919,15 +925,18 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (SavedKind == tok::kw_typename) {
// postfix-expression: typename-specifier '(' expression-list[opt] ')'
+ // typename-specifier braced-init-list
if (TryAnnotateTypeOrScopeToken())
return ExprError();
}
// postfix-expression: simple-type-specifier '(' expression-list[opt] ')'
+ // simple-type-specifier braced-init-list
//
DeclSpec DS(AttrFactory);
ParseCXXSimpleTypeSpecifier(DS);
- if (Tok.isNot(tok::l_paren))
+ if (Tok.isNot(tok::l_paren) &&
+ (!getLang().CPlusPlus0x || Tok.isNot(tok::l_brace)))
return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
<< DS.getSourceRange());
@@ -1060,6 +1069,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___is_pod:
case tok::kw___is_polymorphic:
case tok::kw___is_trivial:
+ case tok::kw___is_trivially_copyable:
case tok::kw___is_union:
case tok::kw___has_trivial_constructor:
case tok::kw___has_trivial_copy:
@@ -1117,6 +1127,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// postfix-expression: [C99 6.5.2]
/// primary-expression
/// postfix-expression '[' expression ']'
+/// postfix-expression '[' braced-init-list ']'
/// postfix-expression '(' argument-expression-list[opt] ')'
/// postfix-expression '.' identifier
/// postfix-expression '->' identifier
@@ -1172,7 +1183,11 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
return move(LHS);
Loc = ConsumeBracket();
- ExprResult Idx(ParseExpression());
+ ExprResult Idx;
+ if (getLang().CPlusPlus0x && Tok.is(tok::l_brace))
+ Idx = ParseBraceInitializer();
+ else
+ Idx = ParseExpression();
SourceLocation RLoc = Tok.getLocation();
@@ -1529,6 +1544,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
/// assign-expr ')'
/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
+/// [OCL] '__builtin_astype' '(' type-name expr ')'
///
/// [GNU] offsetof-member-designator:
/// [GNU] identifier
@@ -1673,7 +1689,35 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
Expr2.take(), ConsumeParen());
break;
}
+ case tok::kw___builtin_astype: {
+ // The first argument is an expression to be converted, followed by a comma.
+ ExprResult Expr(ParseAssignmentExpression());
+ if (Expr.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",
+ tok::r_paren))
+ return ExprError();
+
+ // Second argument is the type to bitcast to.
+ TypeResult DestTy = ParseTypeName();
+ if (DestTy.isInvalid())
+ return ExprError();
+
+ // Attempt to consume the r-paren.
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ Res = Actions.ActOnAsTypeExpr(Expr.take(), DestTy.get(), StartLoc,
+ ConsumeParen());
+ break;
}
+}
if (Res.isInvalid())
return ExprError();
@@ -1987,8 +2031,19 @@ ExprResult Parser::ParseGenericSelectionExpression() {
/// argument-expression-list , assignment-expression
///
/// [C++] expression-list:
-/// [C++] assignment-expression ...[opt]
-/// [C++] expression-list , assignment-expression ...[opt]
+/// [C++] assignment-expression
+/// [C++] expression-list , assignment-expression
+///
+/// [C++0x] expression-list:
+/// [C++0x] initializer-list
+///
+/// [C++0x] initializer-list
+/// [C++0x] initializer-clause ...[opt]
+/// [C++0x] initializer-list , initializer-clause ...[opt]
+///
+/// [C++0x] initializer-clause:
+/// [C++0x] assignment-expression
+/// [C++0x] braced-init-list
///
bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs,
llvm::SmallVectorImpl<SourceLocation> &CommaLocs,
@@ -2005,8 +2060,13 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs,
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
ConsumeCodeCompletionToken();
}
-
- ExprResult Expr(ParseAssignmentExpression());
+
+ ExprResult Expr;
+ if (getLang().CPlusPlus0x && Tok.is(tok::l_brace))
+ Expr = ParseBraceInitializer();
+ else
+ Expr = ParseAssignmentExpression();
+
if (Tok.is(tok::ellipsis))
Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
if (Expr.isInvalid())
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 8bf6f63d3ecd..eab7114284de 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -280,8 +280,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
: TemplateId->TemplateNameLoc;
SS.SetInvalid(SourceRange(StartLoc, CCLoc));
}
-
- TemplateId->Destroy();
+
+ // If we are caching tokens we will process the TemplateId again,
+ // otherwise destroy it.
+ if (!PP.isBacktrackEnabled())
+ TemplateId->Destroy();
continue;
}
@@ -806,42 +809,55 @@ ExprResult Parser::ParseCXXThis() {
/// Can be interpreted either as function-style casting ("int(x)")
/// or class type construction ("ClassType(x,y,z)")
/// or creation of a value-initialized type ("int()").
+/// See [C++ 5.2.3].
///
/// postfix-expression: [C++ 5.2p1]
-/// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
-/// typename-specifier '(' expression-list[opt] ')' [TODO]
+/// simple-type-specifier '(' expression-list[opt] ')'
+/// [C++0x] simple-type-specifier braced-init-list
+/// typename-specifier '(' expression-list[opt] ')'
+/// [C++0x] typename-specifier braced-init-list
///
ExprResult
Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
- assert(Tok.is(tok::l_paren) && "Expected '('!");
- GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
+ assert((Tok.is(tok::l_paren) ||
+ (getLang().CPlusPlus0x && Tok.is(tok::l_brace)))
+ && "Expected '(' or '{'!");
- SourceLocation LParenLoc = ConsumeParen();
+ if (Tok.is(tok::l_brace)) {
- ExprVector Exprs(Actions);
- CommaLocsTy CommaLocs;
+ // FIXME: Convert to a proper type construct expression.
+ return ParseBraceInitializer();
- if (Tok.isNot(tok::r_paren)) {
- if (ParseExpressionList(Exprs, CommaLocs)) {
- SkipUntil(tok::r_paren);
- return ExprError();
+ } else {
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
+
+ SourceLocation LParenLoc = ConsumeParen();
+
+ ExprVector Exprs(Actions);
+ CommaLocsTy CommaLocs;
+
+ if (Tok.isNot(tok::r_paren)) {
+ if (ParseExpressionList(Exprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
}
- }
- // Match the ')'.
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ // Match the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- // TypeRep could be null, if it references an invalid typedef.
- if (!TypeRep)
- return ExprError();
+ // TypeRep could be null, if it references an invalid typedef.
+ if (!TypeRep)
+ return ExprError();
- assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
- "Unexpected number of commas!");
- return Actions.ActOnCXXTypeConstructExpr(TypeRep, LParenLoc, move_arg(Exprs),
- RParenLoc);
+ assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
+ "Unexpected number of commas!");
+ return Actions.ActOnCXXTypeConstructExpr(TypeRep, LParenLoc, move_arg(Exprs),
+ RParenLoc);
+ }
}
/// ParseCXXCondition - if/switch/while condition expression.
@@ -959,6 +975,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const {
case tok::kw_bool:
case tok::kw_decltype:
case tok::kw_typeof:
+ case tok::kw___underlying_type:
return true;
default:
@@ -1723,7 +1740,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
///
/// new-initializer:
/// '(' expression-list[opt] ')'
-/// [C++0x] braced-init-list [TODO]
+/// [C++0x] braced-init-list
///
ExprResult
Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
@@ -1812,6 +1829,9 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return ExprError();
}
+ } else if (Tok.is(tok::l_brace)) {
+ // FIXME: Have to communicate the init-list to ActOnCXXNew.
+ ParseBraceInitializer();
}
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
@@ -1921,7 +1941,8 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign;
- case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor;
+ case tok::kw___has_trivial_constructor:
+ return UTT_HasTrivialDefaultConstructor;
case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor;
case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor;
@@ -1954,6 +1975,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
case tok::kw___is_signed: return UTT_IsSigned;
case tok::kw___is_standard_layout: return UTT_IsStandardLayout;
case tok::kw___is_trivial: return UTT_IsTrivial;
+ case tok::kw___is_trivially_copyable: return UTT_IsTriviallyCopyable;
case tok::kw___is_union: return UTT_IsUnion;
case tok::kw___is_unsigned: return UTT_IsUnsigned;
case tok::kw___is_void: return UTT_IsVoid;
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index fdbedc54d1cd..a8c18c01a291 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -874,8 +874,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
Decl *Result
= Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
- mType, IDecl, DSRet, ReturnType, Sel,
- 0,
+ mType, IDecl, DSRet, ReturnType,
+ selLoc, Sel, 0,
CParamInfo.data(), CParamInfo.size(),
methodAttrs.getList(), MethodImplKind,
false, MethodDefinition);
@@ -1000,8 +1000,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
&KeyIdents[0]);
Decl *Result
= Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
- mType, IDecl, DSRet, ReturnType, Sel,
- &ArgInfos[0],
+ mType, IDecl, DSRet, ReturnType,
+ selLoc, Sel, &ArgInfos[0],
CParamInfo.data(), CParamInfo.size(),
methodAttrs.getList(),
MethodImplKind, isVariadic, MethodDefinition);
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 46225c8e7910..c30ab75b76e8 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -295,7 +295,6 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
return;
}
- SourceLocation LParenLoc = Tok.getLocation();
// Lex the declaration reference(s).
llvm::SmallVector<Token, 5> Identifiers;
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index f0ab53108033..6cc8b57b61fe 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -741,6 +741,12 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
continue;
}
+ if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) ||
+ Tok.is(tok::kw___if_not_exists))) {
+ ParseMicrosoftIfExistsStatement(Stmts);
+ continue;
+ }
+
StmtResult R;
if (Tok.isNot(tok::kw___extension__)) {
R = ParseStatementOrDeclaration(Stmts, false);
@@ -2000,3 +2006,34 @@ StmtResult Parser::ParseCXXCatchBlock() {
return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take());
}
+
+void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
+ bool Result;
+ if (ParseMicrosoftIfExistsCondition(Result))
+ return;
+
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return;
+ }
+ ConsumeBrace();
+
+ // Condition is false skip all inside the {}.
+ if (!Result) {
+ SkipUntil(tok::r_brace, false);
+ return;
+ }
+
+ // Condition is true, parse the statements.
+ while (Tok.isNot(tok::r_brace)) {
+ StmtResult R = ParseStatementOrDeclaration(Stmts, false);
+ if (R.isUsable())
+ Stmts.push_back(R.release());
+ }
+
+ if (Tok.isNot(tok::r_brace)) {
+ Diag(Tok, diag::err_expected_rbrace);
+ return;
+ }
+ ConsumeBrace();
+}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 12e38daf0029..aa89d75c6d1b 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -905,10 +905,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
// C++0x [temp.arg.template]p1:
// A template-argument for a template template-parameter shall be the name
- // of a class template or a template alias, expressed as id-expression.
+ // of a class template or an alias template, expressed as id-expression.
//
- // We parse an id-expression that refers to a class template or template
- // alias. The grammar we parse is:
+ // We parse an id-expression that refers to a class template or alias
+ // template. The grammar we parse is:
//
// nested-name-specifier[opt] template[opt] identifier ...[opt]
//
@@ -969,7 +969,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
MemberOfUnknownSpecialization);
if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) {
// We have an id-expression that refers to a class template or
- // (C++0x) template alias.
+ // (C++0x) alias template.
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
}
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 1c4e2b3ddc8b..78d2c9091b1b 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -664,6 +664,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___is_pod:
case tok::kw___is_polymorphic:
case tok::kw___is_trivial:
+ case tok::kw___is_trivially_copyable:
case tok::kw___is_union:
case tok::kw___uuidof:
return TPResult::True();
@@ -693,6 +694,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_decltype:
+ case tok::kw___underlying_type:
case tok::kw_thread_local:
case tok::kw__Decimal32:
case tok::kw__Decimal64:
@@ -1011,6 +1013,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw_decltype:
return TPResult::True();
+ // C++0x type traits support
+ case tok::kw___underlying_type:
+ return TPResult::True();
+
default:
return TPResult::False();
}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 4d08699bdd39..f19472ccdc04 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -20,6 +20,7 @@
#include "RAIIObjectsForParser.h"
#include "ParsePragma.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTConsumer.h"
using namespace clang;
Parser::Parser(Preprocessor &pp, Sema &actions)
@@ -350,7 +351,23 @@ void Parser::ExitScope() {
ScopeCache[NumCachedScopes++] = OldScope;
}
+/// Set the flags for the current scope to ScopeFlags. If ManageFlags is false,
+/// this object does nothing.
+Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags,
+ bool ManageFlags)
+ : CurScope(ManageFlags ? Self->getCurScope() : 0) {
+ if (CurScope) {
+ OldFlags = CurScope->getFlags();
+ CurScope->setFlags(ScopeFlags);
+ }
+}
+/// Restore the flags for the current scope to what they were before this
+/// object overrode them.
+Parser::ParseScopeFlags::~ParseScopeFlags() {
+ if (CurScope)
+ CurScope->setFlags(OldFlags);
+}
//===----------------------------------------------------------------------===//
@@ -653,6 +670,11 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// FIXME: Detect C++ linkage specifications here?
goto dont_know;
+ case tok::kw___if_exists:
+ case tok::kw___if_not_exists:
+ ParseMicrosoftIfExistsExternalDeclaration();
+ return DeclGroupPtrTy();
+
default:
dont_know:
// We can't tell whether this is a function-definition or declaration yet.
@@ -671,7 +693,14 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
/// \brief Determine whether the current token, if it occurs after a
/// declarator, continues a declaration or declaration list.
-bool Parser::isDeclarationAfterDeclarator() const {
+bool Parser::isDeclarationAfterDeclarator() {
+ // Check for '= delete' or '= default'
+ if (getLang().CPlusPlus && Tok.is(tok::equal)) {
+ const Token &KW = NextToken();
+ if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
+ return false;
+ }
+
return Tok.is(tok::equal) || // int X()= -> not a function def
Tok.is(tok::comma) || // int X(), -> not a function def
Tok.is(tok::semi) || // int X(); -> not a function def
@@ -692,6 +721,11 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
if (!getLang().CPlusPlus &&
Declarator.getFunctionTypeInfo().isKNRPrototype())
return isDeclarationSpecifier();
+
+ if (getLang().CPlusPlus && Tok.is(tok::equal)) {
+ const Token &KW = NextToken();
+ return KW.is(tok::kw_default) || KW.is(tok::kw_delete);
+ }
return Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
Tok.is(tok::kw_try); // X() try { ... }
@@ -814,11 +848,13 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (FTI.isKNRPrototype())
ParseKNRParamDeclarations(D);
+
// We should have either an opening brace or, in a C++ constructor,
// we may have a colon.
if (Tok.isNot(tok::l_brace) &&
(!getLang().CPlusPlus ||
- (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try)))) {
+ (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try) &&
+ Tok.isNot(tok::equal)))) {
Diag(Tok, diag::err_expected_fn_body);
// Skip over garbage, until we get to '{'. Don't eat the '{'.
@@ -866,7 +902,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
return DP;
}
-
// Enter a scope for the function body.
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
@@ -887,6 +922,43 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// safe because we're always the sole owner.
D.getMutableDeclSpec().abort();
+ if (Tok.is(tok::equal)) {
+ assert(getLang().CPlusPlus && "Only C++ function definitions have '='");
+ ConsumeToken();
+
+ Actions.ActOnFinishFunctionBody(Res, 0, false);
+
+ bool Delete = false;
+ SourceLocation KWLoc;
+ if (Tok.is(tok::kw_delete)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDeleted(Res, KWLoc);
+ Delete = true;
+ } else if (Tok.is(tok::kw_default)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDefaulted(Res, KWLoc);
+ } else {
+ llvm_unreachable("function definition after = not 'delete' or 'default'");
+ }
+
+ if (Tok.is(tok::comma)) {
+ Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
+ << Delete;
+ SkipUntil(tok::semi);
+ } else {
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ Delete ? "delete" : "default", tok::semi);
+ }
+
+ return Res;
+ }
+
if (Tok.is(tok::kw_try))
return ParseFunctionTryBlock(Res, BodyScope);
@@ -1374,3 +1446,80 @@ void Parser::CodeCompleteMacroArgument(IdentifierInfo *Macro,
void Parser::CodeCompleteNaturalLanguage() {
Actions.CodeCompleteNaturalLanguage();
}
+
+bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) {
+ assert((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists)) &&
+ "Expected '__if_exists' or '__if_not_exists'");
+ Token Condition = Tok;
+ SourceLocation IfExistsLoc = ConsumeToken();
+
+ SourceLocation LParenLoc = Tok.getLocation();
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << IfExistsLoc;
+ SkipUntil(tok::semi);
+ return true;
+ }
+ ConsumeParen(); // eat the '('.
+
+ // Parse nested-name-specifier.
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
+
+ // Check nested-name specifier.
+ if (SS.isInvalid()) {
+ SkipUntil(tok::semi);
+ return true;
+ }
+
+ // Parse the unqualified-id.
+ UnqualifiedId Name;
+ if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), Name)) {
+ SkipUntil(tok::semi);
+ return true;
+ }
+
+ if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid())
+ return true;
+
+ // Check if the symbol exists.
+ bool Exist = Actions.CheckMicrosoftIfExistsSymbol(SS, Name);
+
+ Result = ((Condition.is(tok::kw___if_exists) && Exist) ||
+ (Condition.is(tok::kw___if_not_exists) && !Exist));
+
+ return false;
+}
+
+void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
+ bool Result;
+ if (ParseMicrosoftIfExistsCondition(Result))
+ return;
+
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return;
+ }
+ ConsumeBrace();
+
+ // Condition is false skip all inside the {}.
+ if (!Result) {
+ SkipUntil(tok::r_brace, false);
+ return;
+ }
+
+ // Condition is true, parse the declaration.
+ while (Tok.isNot(tok::r_brace)) {
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(attrs);
+ MaybeParseMicrosoftAttributes(attrs);
+ DeclGroupPtrTy Result = ParseExternalDeclaration(attrs);
+ if (Result && !getCurScope()->getParent())
+ Actions.getASTConsumer().HandleTopLevelDecl(Result.get());
+ }
+
+ if (Tok.isNot(tok::r_brace)) {
+ Diag(Tok, diag::err_expected_rbrace);
+ return;
+ }
+ ConsumeBrace();
+}
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index d6e34ef8fa46..8cdb55a0c1c6 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -2695,7 +2695,8 @@ QualType RewriteObjC::getSuperStructType() {
SourceLocation(), 0,
FieldTypes[i], 0,
/*BitWidth=*/0,
- /*Mutable=*/false));
+ /*Mutable=*/false,
+ /*HasInit=*/false));
}
SuperStructDecl->completeDefinition();
@@ -2727,7 +2728,8 @@ QualType RewriteObjC::getConstantStringStructType() {
SourceLocation(), 0,
FieldTypes[i], 0,
/*BitWidth=*/0,
- /*Mutable=*/true));
+ /*Mutable=*/true,
+ /*HasInit=*/false));
}
ConstantStringDecl->completeDefinition();
@@ -4709,7 +4711,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
SourceLocation(),
&Context->Idents.get("FuncPtr"),
Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true);
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
FD->getType(), VK_LValue,
OK_Ordinary);
@@ -4763,7 +4766,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
SourceLocation(),
&Context->Idents.get("__forwarding"),
Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true);
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
FD, SourceLocation(),
FD->getType(), VK_LValue,
@@ -4773,7 +4777,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
&Context->Idents.get(Name),
Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true);
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
DeclRefExp->getType(), VK_LValue, OK_Ordinary);
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index e482172ca3eb..9efae6103a4a 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -196,7 +196,12 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
continue;
}
Expr *CEE = C->getCallee()->IgnoreParenCasts();
- if (getFunctionExtInfo(CEE->getType()).getNoReturn()) {
+ QualType calleeType = CEE->getType();
+ if (calleeType == AC.getASTContext().BoundMemberTy) {
+ calleeType = Expr::findBoundMemberType(CEE);
+ assert(!calleeType.isNull() && "analyzing unresolved call?");
+ }
+ if (getFunctionExtInfo(calleeType).getNoReturn()) {
NoReturnEdge = true;
HasFakeEdge = true;
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 0f20d10b076a..5be16e7431c1 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -309,6 +309,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_typeofExpr: return "typeof";
case DeclSpec::TST_auto: return "auto";
case DeclSpec::TST_decltype: return "(decltype)";
+ case DeclSpec::TST_underlyingType: return "__underlying_type";
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_error: return "(error)";
}
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 867d78fef6a7..ae154aae2062 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
#include "llvm/ADT/BitVector.h"
@@ -126,18 +127,45 @@ static std::pair<unsigned,unsigned>
InDiag = diag::note_protected_by_cleanup;
OutDiag = diag::note_exits_cleanup;
} else if (isCPlusPlus) {
- // FIXME: In C++0x, we have to check more conditions than "did we
- // just give it an initializer?". See 6.7p3.
- if (VD->hasLocalStorage() && VD->hasInit())
- InDiag = diag::note_protected_by_variable_init;
-
- CanQualType T = VD->getType()->getCanonicalTypeUnqualified();
+ if (!VD->hasLocalStorage())
+ return std::make_pair(InDiag, OutDiag);
+
+ ASTContext &Context = D->getASTContext();
+ QualType T = Context.getBaseElementType(VD->getType());
if (!T->isDependentType()) {
- while (CanQual<ArrayType> AT = T->getAs<ArrayType>())
- T = AT->getElementType();
- if (CanQual<RecordType> RT = T->getAs<RecordType>())
- if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor())
- OutDiag = diag::note_exits_dtor;
+ // C++0x [stmt.dcl]p3:
+ // A program that jumps from a point where a variable with automatic
+ // storage duration is not in scope to a point where it is in scope
+ // is ill-formed unless the variable has scalar type, class type with
+ // a trivial default constructor and a trivial destructor, a
+ // cv-qualified version of one of these types, or an array of one of
+ // the preceding types and is declared without an initializer (8.5).
+ // Check whether this is a C++ class.
+ CXXRecordDecl *Record = T->getAsCXXRecordDecl();
+
+ if (const Expr *Init = VD->getInit()) {
+ bool CallsTrivialConstructor = false;
+ if (Record) {
+ // FIXME: With generalized initializer lists, this may
+ // classify "X x{};" as having no initializer.
+ if (const CXXConstructExpr *Construct
+ = dyn_cast<CXXConstructExpr>(Init))
+ if (const CXXConstructorDecl *Constructor
+ = Construct->getConstructor())
+ if ((Context.getLangOptions().CPlusPlus0x
+ ? Record->hasTrivialDefaultConstructor()
+ : Record->isPOD()) &&
+ Constructor->isDefaultConstructor())
+ CallsTrivialConstructor = true;
+ }
+
+ if (!CallsTrivialConstructor)
+ InDiag = diag::note_protected_by_variable_init;
+ }
+
+ // Note whether we have a class with a non-trivial destructor.
+ if (Record && !Record->hasTrivialDestructor())
+ OutDiag = diag::note_exits_dtor;
}
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 7707fb1104be..8297b3155a8c 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -31,6 +31,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -377,30 +378,22 @@ void Sema::ActOnEndOfTranslationUnit() {
}
}
- bool SomethingChanged;
- do {
- SomethingChanged = false;
-
- // If DefinedUsedVTables ends up marking any virtual member functions it
- // might lead to more pending template instantiations, which we then need
- // to instantiate.
- if (DefineUsedVTables())
- SomethingChanged = true;
-
- // C++: Perform implicit template instantiations.
- //
- // FIXME: When we perform these implicit instantiations, we do not
- // carefully keep track of the point of instantiation (C++ [temp.point]).
- // This means that name lookup that occurs within the template
- // instantiation will always happen at the end of the translation unit,
- // so it will find some names that should not be found. Although this is
- // common behavior for C++ compilers, it is technically wrong. In the
- // future, we either need to be able to filter the results of name lookup
- // or we need to perform template instantiations earlier.
- if (PerformPendingInstantiations())
- SomethingChanged = true;
-
- } while (SomethingChanged);
+ // If DefinedUsedVTables ends up marking any virtual member functions it
+ // might lead to more pending template instantiations, which we then need
+ // to instantiate.
+ DefineUsedVTables();
+
+ // C++: Perform implicit template instantiations.
+ //
+ // FIXME: When we perform these implicit instantiations, we do not
+ // carefully keep track of the point of instantiation (C++ [temp.point]).
+ // This means that name lookup that occurs within the template
+ // instantiation will always happen at the end of the translation unit,
+ // so it will find some names that should not be found. Although this is
+ // common behavior for C++ compilers, it is technically wrong. In the
+ // future, we either need to be able to filter the results of name lookup
+ // or we need to perform template instantiations earlier.
+ PerformPendingInstantiations();
}
// Remove file scoped decls that turned out to be used.
@@ -473,6 +466,12 @@ void Sema::ActOnEndOfTranslationUnit() {
}
+ if (LangOpts.CPlusPlus0x &&
+ Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle,
+ SourceLocation())
+ != Diagnostic::Ignored)
+ CheckDelegatingCtorCycles();
+
// If there were errors, disable 'unused' warnings since they will mostly be
// noise.
if (!Diags.hasErrorOccurred()) {
@@ -570,9 +569,12 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
break;
case DiagnosticIDs::SFINAE_AccessControl:
- // Unless access checking is specifically called out as a SFINAE
- // error, report this diagnostic.
- if (!SemaRef.AccessCheckingSFINAE)
+ // Per C++ Core Issue 1170, access control is part of SFINAE.
+ // Additionally, the AccessCheckingSFINAE flag can be used to temporary
+ // make access control a part of SFINAE for the purposes of checking
+ // type traits.
+ if (!SemaRef.AccessCheckingSFINAE &&
+ !SemaRef.getLangOptions().CPlusPlus0x)
break;
case DiagnosticIDs::SFINAE_SubstitutionFailure:
@@ -763,3 +765,101 @@ void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const {
OS << '\n';
}
+
+/// \brief Figure out if an expression could be turned into a call.
+///
+/// Use this when trying to recover from an error where the programmer may have
+/// written just the name of a function instead of actually calling it.
+///
+/// \param E - The expression to examine.
+/// \param ZeroArgCallReturnTy - If the expression can be turned into a call
+/// with no arguments, this parameter is set to the type returned by such a
+/// call; otherwise, it is set to an empty QualType.
+/// \param NonTemplateOverloads - If the expression is an overloaded function
+/// name, this parameter is populated with the decls of the various overloads.
+bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
+ UnresolvedSetImpl &NonTemplateOverloads) {
+ ZeroArgCallReturnTy = QualType();
+ NonTemplateOverloads.clear();
+ if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(&E)) {
+ for (OverloadExpr::decls_iterator it = Overloads->decls_begin(),
+ DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) {
+ // Our overload set may include TemplateDecls, which we'll ignore for our
+ // present purpose.
+ if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) {
+ NonTemplateOverloads.addDecl(*it);
+ if (OverloadDecl->getMinRequiredArguments() == 0)
+ ZeroArgCallReturnTy = OverloadDecl->getResultType();
+ }
+ }
+ return true;
+ }
+
+ if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(&E)) {
+ if (const FunctionDecl *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
+ if (Fun->getMinRequiredArguments() == 0)
+ ZeroArgCallReturnTy = Fun->getResultType();
+ return true;
+ }
+ }
+
+ // We don't have an expression that's convenient to get a FunctionDecl from,
+ // but we can at least check if the type is "function of 0 arguments".
+ QualType ExprTy = E.getType();
+ const FunctionType *FunTy = NULL;
+ QualType PointeeTy = ExprTy->getPointeeType();
+ if (!PointeeTy.isNull())
+ FunTy = PointeeTy->getAs<FunctionType>();
+ if (!FunTy)
+ FunTy = ExprTy->getAs<FunctionType>();
+ if (!FunTy && ExprTy == Context.BoundMemberTy) {
+ // Look for the bound-member type. If it's still overloaded, give up,
+ // although we probably should have fallen into the OverloadExpr case above
+ // if we actually have an overloaded bound member.
+ QualType BoundMemberTy = Expr::findBoundMemberType(&E);
+ if (!BoundMemberTy.isNull())
+ FunTy = BoundMemberTy->castAs<FunctionType>();
+ }
+
+ if (const FunctionProtoType *FPT =
+ dyn_cast_or_null<FunctionProtoType>(FunTy)) {
+ if (FPT->getNumArgs() == 0)
+ ZeroArgCallReturnTy = FunTy->getResultType();
+ return true;
+ }
+ return false;
+}
+
+/// \brief Give notes for a set of overloads.
+///
+/// A companion to isExprCallable. In cases when the name that the programmer
+/// wrote was an overloaded function, we may be able to make some guesses about
+/// plausible overloads based on their return types; such guesses can be handed
+/// off to this method to be emitted as notes.
+///
+/// \param Overloads - The overloads to note.
+/// \param FinalNoteLoc - If we've suppressed printing some overloads due to
+/// -fshow-overloads=best, this is the location to attach to the note about too
+/// many candidates. Typically this will be the location of the original
+/// ill-formed expression.
+void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads,
+ const SourceLocation FinalNoteLoc) {
+ int ShownOverloads = 0;
+ int SuppressedOverloads = 0;
+ for (UnresolvedSetImpl::iterator It = Overloads.begin(),
+ DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
+ // FIXME: Magic number for max shown overloads stolen from
+ // OverloadCandidateSet::NoteCandidates.
+ if (ShownOverloads >= 4 &&
+ Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
+ ++SuppressedOverloads;
+ continue;
+ }
+ Diag(cast<FunctionDecl>(*It)->getSourceRange().getBegin(),
+ diag::note_member_ref_possible_intended_overload);
+ ++ShownOverloads;
+ }
+ if (SuppressedOverloads)
+ Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates)
+ << SuppressedOverloads;
+}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 411d424dd8df..a26737e00e4d 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -146,8 +146,10 @@ struct AccessTarget : public AccessedEntity {
MemberNonce _,
CXXRecordDecl *NamingClass,
DeclAccessPair FoundDecl,
- QualType BaseObjectType)
- : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) {
+ QualType BaseObjectType,
+ bool IsUsingDecl = false)
+ : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType),
+ IsUsingDeclaration(IsUsingDecl) {
initialize();
}
@@ -216,6 +218,7 @@ private:
DeclaringClass = DeclaringClass->getCanonicalDecl();
}
+ bool IsUsingDeclaration : 1;
bool HasInstanceContext : 1;
mutable bool CalculatedInstanceContext : 1;
mutable const CXXRecordDecl *InstanceContext;
@@ -445,8 +448,8 @@ static AccessResult MatchesFriend(Sema &S,
continue;
// If the template names don't match, it can't be a dependent
- // match. This isn't true in C++0x because of template aliases.
- if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
+ // match.
+ if (CTD->getDeclName() != Friend->getDeclName())
continue;
// If the class's context can't instantiate to the friend's
@@ -1129,6 +1132,44 @@ static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
DiagnoseAccessPath(S, EC, Entity);
}
+/// MSVC has a bug where if during an using declaration name lookup,
+/// the declaration found is unaccessible (private) and that declaration
+/// was bring into scope via another using declaration whose target
+/// declaration is accessible (public) then no error is generated.
+/// Example:
+/// class A {
+/// public:
+/// int f();
+/// };
+/// class B : public A {
+/// private:
+/// using A::f;
+/// };
+/// class C : public B {
+/// private:
+/// using B::f;
+/// };
+///
+/// Here, B::f is private so this should fail in Standard C++, but
+/// because B::f refers to A::f which is public MSVC accepts it.
+static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
+ SourceLocation AccessLoc,
+ AccessTarget &Entity) {
+ if (UsingShadowDecl *Shadow =
+ dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) {
+ const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl();
+ if (Entity.getTargetDecl()->getAccess() == AS_private &&
+ (OrigDecl->getAccess() == AS_public ||
+ OrigDecl->getAccess() == AS_protected)) {
+ S.Diag(AccessLoc, diag::war_ms_using_declaration_inaccessible)
+ << Shadow->getUsingDecl()->getQualifiedNameAsString()
+ << OrigDecl->getQualifiedNameAsString();
+ return true;
+ }
+ }
+ return false;
+}
+
/// Determines whether the accessed entity is accessible. Public members
/// have been weeded out by this point.
static AccessResult IsAccessible(Sema &S,
@@ -1232,6 +1273,10 @@ static AccessResult CheckEffectiveAccess(Sema &S,
AccessTarget &Entity) {
assert(Entity.getAccess() != AS_public && "called for public access!");
+ if (S.getLangOptions().Microsoft &&
+ IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
+ return AR_accessible;
+
switch (IsAccessible(S, EC, Entity)) {
case AR_dependent:
DelayDependentAccess(S, EC, Loc, Entity);
@@ -1415,30 +1460,48 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
DeclAccessPair::make(Constructor, Access),
QualType());
+ PartialDiagnostic PD(PDiag());
switch (Entity.getKind()) {
default:
- AccessEntity.setDiag(IsCopyBindingRefToTemp
- ? diag::ext_rvalue_to_reference_access_ctor
- : diag::err_access_ctor);
+ PD = PDiag(IsCopyBindingRefToTemp
+ ? diag::ext_rvalue_to_reference_access_ctor
+ : diag::err_access_ctor);
+
break;
case InitializedEntity::EK_Base:
- AccessEntity.setDiag(PDiag(diag::err_access_base)
- << Entity.isInheritedVirtualBase()
- << Entity.getBaseSpecifier()->getType()
- << getSpecialMember(Constructor));
+ PD = PDiag(diag::err_access_base_ctor);
+ PD << Entity.isInheritedVirtualBase()
+ << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor);
break;
case InitializedEntity::EK_Member: {
const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
- AccessEntity.setDiag(PDiag(diag::err_access_field)
- << Field->getType()
- << getSpecialMember(Constructor));
+ PD = PDiag(diag::err_access_field_ctor);
+ PD << Field->getType() << getSpecialMember(Constructor);
break;
}
}
+ return CheckConstructorAccess(UseLoc, Constructor, Access, PD);
+}
+
+/// Checks access to a constructor.
+Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
+ CXXConstructorDecl *Constructor,
+ AccessSpecifier Access,
+ PartialDiagnostic PD) {
+ if (!getLangOptions().AccessControl ||
+ Access == AS_public)
+ return AR_accessible;
+
+ CXXRecordDecl *NamingClass = Constructor->getParent();
+ AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
+ DeclAccessPair::make(Constructor, Access),
+ QualType());
+ AccessEntity.setDiag(PD);
+
return CheckAccess(*this, UseLoc, AccessEntity);
}
@@ -1465,7 +1528,8 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
SourceRange PlacementRange,
CXXRecordDecl *NamingClass,
- DeclAccessPair Found) {
+ DeclAccessPair Found,
+ bool Diagnose) {
if (!getLangOptions().AccessControl ||
!NamingClass ||
Found.getAccess() == AS_public)
@@ -1473,8 +1537,9 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
QualType());
- Entity.setDiag(diag::err_access)
- << PlacementRange;
+ if (Diagnose)
+ Entity.setDiag(diag::err_access)
+ << PlacementRange;
return CheckAccess(*this, OpLoc, Entity);
}
@@ -1573,9 +1638,8 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
if (I.getAccess() != AS_public) {
AccessTarget Entity(Context, AccessedEntity::Member,
R.getNamingClass(), I.getPair(),
- R.getBaseObjectType());
+ R.getBaseObjectType(), R.isUsingDeclaration());
Entity.setDiag(diag::err_access);
-
CheckAccess(*this, R.getNameLoc(), Entity);
}
}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index ed54f0f54425..e46ad5bcfeb5 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -252,8 +252,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
(CT == CT_CStyle || CT == CT_Functional));
InitializationSequence sequence(S, entity, initKind, &src, 1);
- assert(sequence.getKind() == InitializationSequence::FailedSequence &&
- "initialization succeeded on second try?");
+ assert(sequence.Failed() && "initialization succeeded on second try?");
switch (sequence.getFailureKind()) {
default: return false;
@@ -1195,8 +1194,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
// On the other hand, if we're checking a C-style cast, we've still got
// the reinterpret_cast way.
- if (InitSeq.getKind() == InitializationSequence::FailedSequence &&
- (CStyle || !DestType->isReferenceType()))
+ if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;
ExprResult Result
@@ -1288,6 +1286,62 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
return TC_Success;
}
+// Checks for undefined behavior in reinterpret_cast.
+// The cases that is checked for is:
+// *reinterpret_cast<T*>(&a)
+// reinterpret_cast<T&>(a)
+// where accessing 'a' as type 'T' will result in undefined behavior.
+void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
+ bool IsDereference,
+ SourceRange Range) {
+ unsigned DiagID = IsDereference ?
+ diag::warn_pointer_indirection_from_incompatible_type :
+ diag::warn_undefined_reinterpret_cast;
+
+ if (Diags.getDiagnosticLevel(DiagID, Range.getBegin()) ==
+ Diagnostic::Ignored) {
+ return;
+ }
+
+ QualType SrcTy, DestTy;
+ if (IsDereference) {
+ if (!SrcType->getAs<PointerType>() || !DestType->getAs<PointerType>()) {
+ return;
+ }
+ SrcTy = SrcType->getPointeeType();
+ DestTy = DestType->getPointeeType();
+ } else {
+ if (!DestType->getAs<ReferenceType>()) {
+ return;
+ }
+ SrcTy = SrcType;
+ DestTy = DestType->getPointeeType();
+ }
+
+ // Cast is compatible if the types are the same.
+ if (Context.hasSameUnqualifiedType(DestTy, SrcTy)) {
+ return;
+ }
+ // or one of the types is a char or void type
+ if (DestTy->isAnyCharacterType() || DestTy->isVoidType() ||
+ SrcTy->isAnyCharacterType() || SrcTy->isVoidType()) {
+ return;
+ }
+ // or one of the types is a tag type.
+ if (SrcTy->getAs<TagType>() || DestTy->getAs<TagType>()) {
+ return;
+ }
+
+ // FIXME: Scoped enums?
+ if ((SrcTy->isUnsignedIntegerType() && DestTy->isSignedIntegerType()) ||
+ (SrcTy->isSignedIntegerType() && DestTy->isUnsignedIntegerType())) {
+ if (Context.getTypeSize(DestTy) == Context.getTypeSize(SrcTy)) {
+ return;
+ }
+ }
+
+ Diag(Range.getBegin(), DiagID) << SrcType << DestType << Range;
+}
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
@@ -1324,6 +1378,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_NotApplicable;
}
+ if (!CStyle) {
+ Self.CheckCompatibleReinterpretCast(SrcType, DestType,
+ /*isDereference=*/false, OpRange);
+ }
+
// C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the
// same effect as the conversion *reinterpret_cast<T*>(&x) with the
// built-in & and * operators.
@@ -1454,9 +1513,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
if (DestType->isIntegralType(Self.Context)) {
assert(srcIsPtr && "One type must be a pointer");
// C++ 5.2.10p4: A pointer can be explicitly converted to any integral
- // type large enough to hold it.
- if (Self.Context.getTypeSize(SrcType) >
- Self.Context.getTypeSize(DestType)) {
+ // type large enough to hold it; except in Microsoft mode, where the
+ // integral type size doesn't matter.
+ if ((Self.Context.getTypeSize(SrcType) >
+ Self.Context.getTypeSize(DestType)) &&
+ !Self.getLangOptions().Microsoft) {
msg = diag::err_bad_reinterpret_cast_small_int;
return TC_Failed;
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 7049f6b01d26..61d9e93f2ff5 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -94,9 +94,13 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
if (EnteringContext) {
const Type *NNSType = NNS->getAsType();
if (!NNSType) {
- // do nothing, fall out
- } else if (const TemplateSpecializationType *SpecType
- = NNSType->getAs<TemplateSpecializationType>()) {
+ return 0;
+ }
+
+ // Look through type alias templates, per C++0x [temp.dep.type]p1.
+ NNSType = Context.getCanonicalType(NNSType);
+ if (const TemplateSpecializationType *SpecType
+ = NNSType->getAs<TemplateSpecializationType>()) {
// We are entering the context of the nested name specifier, so try to
// match the nested name specifier to either a primary class template
// or a class template partial specialization.
@@ -382,7 +386,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
isDependent = ObjectType->isDependentType();
} else if (SS.isSet()) {
// This nested-name-specifier occurs after another nested-name-specifier,
- // so long into the context associated with the prior nested-name-specifier.
+ // so look into the context associated with the prior nested-name-specifier.
LookupCtx = computeDeclContext(SS, EnteringContext);
isDependent = isDependentScopeSpecifier(SS);
Found.setContextRange(SS.getRange());
@@ -419,7 +423,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// class-name or namespace-name. [...]
//
// Qualified name lookup into a class will not find a namespace-name,
- // so we do not need to diagnoste that case specifically. However,
+ // so we do not need to diagnose that case specifically. However,
// this qualified name lookup may find nothing. In that case, perform
// unqualified name lookup in the given scope (if available) or
// reconstruct the result from when name lookup was performed at template
@@ -546,25 +550,33 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
InjectedClassNameTypeLoc InjectedTL
= TLB.push<InjectedClassNameTypeLoc>(T);
InjectedTL.setNameLoc(IdentifierLoc);
- } else if (isa<RecordDecl>(SD)) {
+ } else if (isa<RecordType>(T)) {
RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T);
RecordTL.setNameLoc(IdentifierLoc);
- } else if (isa<TypedefNameDecl>(SD)) {
+ } else if (isa<TypedefType>(T)) {
TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T);
TypedefTL.setNameLoc(IdentifierLoc);
- } else if (isa<EnumDecl>(SD)) {
+ } else if (isa<EnumType>(T)) {
EnumTypeLoc EnumTL = TLB.push<EnumTypeLoc>(T);
EnumTL.setNameLoc(IdentifierLoc);
- } else if (isa<TemplateTypeParmDecl>(SD)) {
+ } else if (isa<TemplateTypeParmType>(T)) {
TemplateTypeParmTypeLoc TemplateTypeTL
= TLB.push<TemplateTypeParmTypeLoc>(T);
TemplateTypeTL.setNameLoc(IdentifierLoc);
- } else {
- assert(isa<UnresolvedUsingTypenameDecl>(SD) &&
- "Unhandled TypeDecl node in nested-name-specifier");
+ } else if (isa<UnresolvedUsingType>(T)) {
UnresolvedUsingTypeLoc UnresolvedTL
= TLB.push<UnresolvedUsingTypeLoc>(T);
UnresolvedTL.setNameLoc(IdentifierLoc);
+ } else if (isa<SubstTemplateTypeParmType>(T)) {
+ SubstTemplateTypeParmTypeLoc TL
+ = TLB.push<SubstTemplateTypeParmTypeLoc>(T);
+ TL.setNameLoc(IdentifierLoc);
+ } else if (isa<SubstTemplateTypeParmPackType>(T)) {
+ SubstTemplateTypeParmPackTypeLoc TL
+ = TLB.push<SubstTemplateTypeParmPackTypeLoc>(T);
+ TL.setNameLoc(IdentifierLoc);
+ } else {
+ llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier");
}
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
@@ -704,8 +716,13 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
if (T.isNull())
return true;
- // FIXME: Template aliases will need to check the resulting type to make
- // sure that it's either dependent or a tag type.
+ // Alias template specializations can produce types which are not valid
+ // nested name specifiers.
+ if (!T->isDependentType() && !T->getAs<TagType>()) {
+ Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T;
+ NoteAllFoundTemplates(Template.get());
+ return true;
+ }
// Provide source-location information for the template specialization
// type.
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index dcfb7cc5214a..05c257ab8332 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -318,9 +318,13 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
TheCall->getCallee()->getLocStart());
}
- // Memset handling
- if (FnInfo->isStr("memset"))
- CheckMemsetArguments(TheCall);
+ // Memset/memcpy/memmove handling
+ if (FDecl->getLinkage() == ExternalLinkage &&
+ (!getLangOptions().CPlusPlus || FDecl->isExternC())) {
+ if (FnInfo->isStr("memset") || FnInfo->isStr("memcpy") ||
+ FnInfo->isStr("memmove"))
+ CheckMemsetcpymoveArguments(TheCall, FnInfo);
+ }
return false;
}
@@ -1797,49 +1801,59 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
//===--- CHECK: Standard memory functions ---------------------------------===//
+/// \brief Determine whether the given type is a dynamic class type (e.g.,
+/// whether it has a vtable).
+static bool isDynamicClassType(QualType T) {
+ if (CXXRecordDecl *Record = T->getAsCXXRecordDecl())
+ if (CXXRecordDecl *Definition = Record->getDefinition())
+ if (Definition->isDynamicClass())
+ return true;
+
+ return false;
+}
+
/// \brief Check for dangerous or invalid arguments to memset().
///
-/// This issues warnings on known problematic or dangerous or unspecified
-/// arguments to the standard 'memset' function call.
+/// This issues warnings on known problematic, dangerous or unspecified
+/// arguments to the standard 'memset', 'memcpy', and 'memmove' function calls.
///
/// \param Call The call expression to diagnose.
-void Sema::CheckMemsetArguments(const CallExpr *Call) {
+void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
+ const IdentifierInfo *FnName) {
// It is possible to have a non-standard definition of memset. Validate
// we have the proper number of arguments, and if not, abort further
// checking.
if (Call->getNumArgs() != 3)
return;
- const Expr *Dest = Call->getArg(0)->IgnoreParenImpCasts();
-
- // The type checking for this warning is moderately expensive, only do it
- // when enabled.
- if (getDiagnostics().getDiagnosticLevel(diag::warn_non_pod_memset,
- Dest->getExprLoc()) ==
- Diagnostic::Ignored)
- return;
-
- QualType DestTy = Dest->getType();
- if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
- QualType PointeeTy = DestPtrTy->getPointeeType();
- if (PointeeTy->isVoidType())
- return;
-
- // Check the C++11 POD definition regardless of language mode; it is more
- // relaxed than earlier definitions and we don't want spurrious warnings.
- if (PointeeTy->isCXX11PODType())
- return;
-
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::warn_non_pod_memset)
- << PointeeTy << Call->getCallee()->getSourceRange());
+ unsigned LastArg = FnName->isStr("memset")? 1 : 2;
+ for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) {
+ const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts();
+
+ QualType DestTy = Dest->getType();
+ if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
+ QualType PointeeTy = DestPtrTy->getPointeeType();
+ if (PointeeTy->isVoidType())
+ continue;
+
+ // Always complain about dynamic classes.
+ if (isDynamicClassType(PointeeTy)) {
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_dyn_class_memaccess)
+ << ArgIdx << FnName << PointeeTy
+ << Call->getCallee()->getSourceRange());
+ } else {
+ continue;
+ }
- SourceRange ArgRange = Call->getArg(0)->getSourceRange();
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::note_non_pod_memset_silence)
- << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
+ SourceRange ArgRange = Call->getArg(0)->getSourceRange();
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::note_bad_memaccess_silence)
+ << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
+ break;
+ }
}
}
@@ -2356,7 +2370,7 @@ IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
// the sign right on this one case. It would be nice if APValue
// preserved this.
assert(result.isLValue());
- return IntRange(MaxWidth, Ty->isUnsignedIntegerType());
+ return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType());
}
/// Pseudo-evaluate the given integer expression, estimating the
@@ -2530,7 +2544,8 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C);
unsigned BitWidth = BitWidthAP.getZExtValue();
- return IntRange(BitWidth, BitField->getType()->isUnsignedIntegerType());
+ return IntRange(BitWidth,
+ BitField->getType()->isUnsignedIntegerOrEnumerationType());
}
return IntRange::forValueOfType(C, E->getType());
@@ -2947,6 +2962,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (!Source->isIntegerType() || !Target->isIntegerType())
return;
+ if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
+ == Expr::NPCK_GNUNull) && Target->isIntegerType()) {
+ S.Diag(E->getExprLoc(), diag::warn_impcast_null_pointer_to_integer)
+ << E->getSourceRange() << clang::SourceRange(CC);
+ return;
+ }
+
IntRange SourceRange = GetExprRange(S.Context, E);
IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target);
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index cc8726de9df8..e328eeb0aa2b 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2658,6 +2658,16 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
case Decl::UnresolvedUsingTypename:
return CXCursor_UsingDeclaration;
+ case Decl::ObjCPropertyImpl:
+ switch (cast<ObjCPropertyImplDecl>(D)->getPropertyImplementation()) {
+ case ObjCPropertyImplDecl::Dynamic:
+ return CXCursor_ObjCDynamicDecl;
+
+ case ObjCPropertyImplDecl::Synthesize:
+ return CXCursor_ObjCSynthesizeDecl;
+ }
+ break;
+
default:
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {
@@ -3078,6 +3088,7 @@ typedef llvm::SmallPtrSet<IdentifierInfo*, 16> AddedPropertiesSet;
static void AddObjCProperties(ObjCContainerDecl *Container,
bool AllowCategories,
+ bool AllowNullaryMethods,
DeclContext *CurContext,
AddedPropertiesSet &AddedProperties,
ResultBuilder &Results) {
@@ -3092,32 +3103,75 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
Results.MaybeAddResult(Result(*P, 0), CurContext);
}
+ // Add nullary methods
+ if (AllowNullaryMethods) {
+ ASTContext &Context = Container->getASTContext();
+ for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
+ MEnd = Container->meth_end();
+ M != MEnd; ++M) {
+ if (M->getSelector().isUnarySelector())
+ if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0))
+ if (AddedProperties.insert(Name)) {
+ CodeCompletionBuilder Builder(Results.getAllocator());
+ AddResultTypeChunk(Context, *M, Builder);
+ Builder.AddTypedTextChunk(
+ Results.getAllocator().CopyString(Name->getName()));
+
+ CXAvailabilityKind Availability = CXAvailability_Available;
+ switch (M->getAvailability()) {
+ case AR_Available:
+ case AR_NotYetIntroduced:
+ Availability = CXAvailability_Available;
+ break;
+
+ case AR_Deprecated:
+ Availability = CXAvailability_Deprecated;
+ break;
+
+ case AR_Unavailable:
+ Availability = CXAvailability_NotAvailable;
+ break;
+ }
+
+ Results.MaybeAddResult(Result(Builder.TakeString(),
+ CCP_MemberDeclaration + CCD_MethodAsProperty,
+ M->isInstanceMethod()
+ ? CXCursor_ObjCInstanceMethodDecl
+ : CXCursor_ObjCClassMethodDecl,
+ Availability),
+ CurContext);
+ }
+ }
+ }
+
+
// Add properties in referenced protocols.
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
PEnd = Protocol->protocol_end();
P != PEnd; ++P)
- AddObjCProperties(*P, AllowCategories, CurContext, AddedProperties,
- Results);
+ AddObjCProperties(*P, AllowCategories, AllowNullaryMethods, CurContext,
+ AddedProperties, Results);
} else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){
if (AllowCategories) {
// Look through categories.
for (ObjCCategoryDecl *Category = IFace->getCategoryList();
Category; Category = Category->getNextClassCategory())
- AddObjCProperties(Category, AllowCategories, CurContext,
- AddedProperties, Results);
+ AddObjCProperties(Category, AllowCategories, AllowNullaryMethods,
+ CurContext, AddedProperties, Results);
}
// Look through protocols.
for (ObjCInterfaceDecl::all_protocol_iterator
I = IFace->all_referenced_protocol_begin(),
E = IFace->all_referenced_protocol_end(); I != E; ++I)
- AddObjCProperties(*I, AllowCategories, CurContext, AddedProperties,
- Results);
+ AddObjCProperties(*I, AllowCategories, AllowNullaryMethods, CurContext,
+ AddedProperties, Results);
// Look in the superclass.
if (IFace->getSuperClass())
- AddObjCProperties(IFace->getSuperClass(), AllowCategories, CurContext,
+ AddObjCProperties(IFace->getSuperClass(), AllowCategories,
+ AllowNullaryMethods, CurContext,
AddedProperties, Results);
} else if (const ObjCCategoryDecl *Category
= dyn_cast<ObjCCategoryDecl>(Container)) {
@@ -3125,8 +3179,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
PEnd = Category->protocol_end();
P != PEnd; ++P)
- AddObjCProperties(*P, AllowCategories, CurContext, AddedProperties,
- Results);
+ AddObjCProperties(*P, AllowCategories, AllowNullaryMethods, CurContext,
+ AddedProperties, Results);
}
}
@@ -3192,14 +3246,16 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
const ObjCObjectPointerType *ObjCPtr
= BaseType->getAsObjCInterfacePointerType();
assert(ObjCPtr && "Non-NULL pointer guaranteed above!");
- AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, CurContext,
+ AddObjCProperties(ObjCPtr->getInterfaceDecl(), true,
+ /*AllowNullaryMethods=*/true, CurContext,
AddedProperties, Results);
// Add properties from the protocols in a qualified interface.
for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(),
E = ObjCPtr->qual_end();
I != E; ++I)
- AddObjCProperties(*I, true, CurContext, AddedProperties, Results);
+ AddObjCProperties(*I, true, /*AllowNullaryMethods=*/true, CurContext,
+ AddedProperties, Results);
} else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
(!IsArrow && BaseType->isObjCObjectType())) {
// Objective-C instance variable access.
@@ -4109,6 +4165,8 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
Results.AddResult(CodeCompletionResult("copy"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic))
Results.AddResult(CodeCompletionResult("nonatomic"));
+ if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_atomic))
+ Results.AddResult(CodeCompletionResult("atomic"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) {
CodeCompletionBuilder Setter(Results.getAllocator());
Setter.AddTypedTextChunk("setter");
@@ -5334,11 +5392,13 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) {
Results.EnterNewScope();
if (ObjCImplementationDecl *ClassImpl
= dyn_cast<ObjCImplementationDecl>(Container))
- AddObjCProperties(ClassImpl->getClassInterface(), false, CurContext,
+ AddObjCProperties(ClassImpl->getClassInterface(), false,
+ /*AllowNullaryMethods=*/false, CurContext,
AddedProperties, Results);
else
AddObjCProperties(cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(),
- false, CurContext, AddedProperties, Results);
+ false, /*AllowNullaryMethods=*/false, CurContext,
+ AddedProperties, Results);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
@@ -5549,7 +5609,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
bool IsInstanceMethod,
QualType ReturnType,
ASTContext &Context,
- const KnownMethodsMap &KnownMethods,
+ VisitedSelectorSet &KnownSelectors,
ResultBuilder &Results) {
IdentifierInfo *PropName = Property->getIdentifier();
if (!PropName || PropName->getLength() == 0)
@@ -5595,7 +5655,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// Add the normal accessor -(type)key.
if (IsInstanceMethod &&
- !KnownMethods.count(Selectors.getNullarySelector(PropName)) &&
+ KnownSelectors.insert(Selectors.getNullarySelector(PropName)) &&
ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) {
if (ReturnType.isNull())
AddObjCPassingTypeChunk(Property->getType(), Context, Builder);
@@ -5615,7 +5675,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
Property->getType()->isBooleanType())))) {
std::string SelectorName = (llvm::Twine("is") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("BOOL");
@@ -5634,7 +5694,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
!Property->getSetterMethodDecl()) {
std::string SelectorName = (llvm::Twine("set") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5685,7 +5745,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
(ReturnType.isNull() || ReturnType->isIntegerType())) {
std::string SelectorName = (llvm::Twine("countOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSUInteger");
@@ -5708,7 +5768,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("objectIn") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("id");
@@ -5735,7 +5795,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine(Property->getName()) + "AtIndexes").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSArray *");
@@ -5760,7 +5820,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("range")
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5794,7 +5854,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get(SelectorName)
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5826,7 +5886,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("atIndexes")
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5854,7 +5914,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("removeObjectFrom") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5876,7 +5936,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("remove") + UpperKey + "AtIndexes").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5902,7 +5962,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("withObject")
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5935,7 +5995,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get(SelectorName2)
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5968,7 +6028,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
->getName() == "NSEnumerator"))) {
std::string SelectorName = (llvm::Twine("enumeratorOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSEnumerator *");
@@ -5986,7 +6046,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
(ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) {
std::string SelectorName = (llvm::Twine("memberOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("object-type");
@@ -6016,7 +6076,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("add") + UpperKey + llvm::Twine("Object")).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6038,7 +6098,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (llvm::Twine("add") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6060,7 +6120,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("remove") + UpperKey + llvm::Twine("Object")).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6082,7 +6142,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (llvm::Twine("remove") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6103,7 +6163,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (llvm::Twine("intersect") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6131,7 +6191,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("keyPathsForValuesAffecting") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSSet *");
@@ -6140,7 +6200,28 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName));
Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,
- CXCursor_ObjCInstanceMethodDecl));
+ CXCursor_ObjCClassMethodDecl));
+ }
+ }
+
+ // + (BOOL)automaticallyNotifiesObserversForKey
+ if (!IsInstanceMethod &&
+ (ReturnType.isNull() ||
+ ReturnType->isIntegerType() ||
+ ReturnType->isBooleanType())) {
+ std::string SelectorName
+ = (llvm::Twine("automaticallyNotifiesObserversOf") + UpperKey).str();
+ IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
+ if (ReturnType.isNull()) {
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddTextChunk("BOOL");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ }
+
+ Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName));
+ Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,
+ CXCursor_ObjCClassMethodDecl));
}
}
}
@@ -6271,6 +6352,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
llvm::SmallVector<ObjCContainerDecl *, 4> Containers;
Containers.push_back(SearchDecl);
+ VisitedSelectorSet KnownSelectors;
+ for (KnownMethodsMap::iterator M = KnownMethods.begin(),
+ MEnd = KnownMethods.end();
+ M != MEnd; ++M)
+ KnownSelectors.insert(M->first);
+
+
ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(SearchDecl);
if (!IFace)
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(SearchDecl))
@@ -6287,7 +6375,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
PEnd = Containers[I]->prop_end();
P != PEnd; ++P) {
AddObjCKeyValueCompletions(*P, IsInstanceMethod, ReturnType, Context,
- KnownMethods, Results);
+ KnownSelectors, Results);
}
}
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 7214988bdafc..9446c0e8c03f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -891,19 +891,19 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *,
/// Filters out lookup results that don't fall within the given scope
/// as determined by isDeclInScope.
-static void FilterLookupForScope(Sema &SemaRef, LookupResult &R,
- DeclContext *Ctx, Scope *S,
- bool ConsiderLinkage,
- bool ExplicitInstantiationOrSpecialization) {
+void Sema::FilterLookupForScope(LookupResult &R,
+ DeclContext *Ctx, Scope *S,
+ bool ConsiderLinkage,
+ bool ExplicitInstantiationOrSpecialization) {
LookupResult::Filter F = R.makeFilter();
while (F.hasNext()) {
NamedDecl *D = F.next();
- if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
+ if (isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
continue;
if (ConsiderLinkage &&
- isOutOfScopePreviousDeclaration(D, Ctx, SemaRef.Context))
+ isOutOfScopePreviousDeclaration(D, Ctx, Context))
continue;
F.erase();
@@ -938,7 +938,7 @@ static void RemoveUsingDecls(LookupResult &R) {
static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) {
// FIXME: Should check for private access too but access is set after we get
// the decl here.
- if (D->isThisDeclarationADefinition())
+ if (D->doesThisDeclarationHaveABody())
return false;
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
@@ -973,10 +973,9 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
return false;
}
- if (FD->isThisDeclarationADefinition() &&
+ if (FD->doesThisDeclarationHaveABody() &&
Context.DeclMustBeEmitted(FD))
return false;
-
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl() ||
VD->getType().isConstant(Context) ||
@@ -1506,18 +1505,21 @@ struct GNUCompatibleParamWarning {
/// getSpecialMember - get the special member enum for a method.
Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
+ if (Ctor->isDefaultConstructor())
+ return Sema::CXXDefaultConstructor;
+
if (Ctor->isCopyConstructor())
return Sema::CXXCopyConstructor;
-
- return Sema::CXXConstructor;
- }
-
- if (isa<CXXDestructorDecl>(MD))
+
+ if (Ctor->isMoveConstructor())
+ return Sema::CXXMoveConstructor;
+ } else if (isa<CXXDestructorDecl>(MD)) {
return Sema::CXXDestructor;
-
- assert(MD->isCopyAssignmentOperator() &&
- "Must have copy assignment operator");
- return Sema::CXXCopyAssignment;
+ } else if (MD->isCopyAssignmentOperator()) {
+ return Sema::CXXCopyAssignment;
+ }
+
+ return Sema::CXXInvalid;
}
/// canRedefineFunction - checks if a function can be redefined. Currently,
@@ -1525,7 +1527,7 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
/// GNU89 mode.
static bool canRedefineFunction(const FunctionDecl *FD,
const LangOptions& LangOpts) {
- return (LangOpts.GNUMode && !LangOpts.C99 && !LangOpts.CPlusPlus &&
+ return (LangOpts.GNUInline && !LangOpts.CPlusPlus &&
FD->isInlineSpecified() &&
FD->getStorageClass() == SC_Extern);
}
@@ -1728,6 +1730,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
<< New << getSpecialMember(OldMethod);
return true;
}
+ } else if (OldMethod->isExplicitlyDefaulted()) {
+ Diag(NewMethod->getLocation(),
+ diag::err_definition_of_explicitly_defaulted_member)
+ << getSpecialMember(OldMethod);
+ return true;
}
}
@@ -1907,10 +1914,6 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
if (Old->isPure())
New->setPure();
- // Merge the "deleted" flag.
- if (Old->isDeleted())
- New->setDeleted();
-
// Merge attributes from the parameters. These can mismatch with K&R
// declarations.
if (New->getNumParams() == Old->getNumParams())
@@ -1933,7 +1936,9 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
for (ObjCMethodDecl::param_iterator oi = oldMethod->param_begin(),
ni = newMethod->param_begin(), ne = newMethod->param_end();
ni != ne; ++ni, ++oi)
- mergeParamDeclAttributes(*ni, *oi, Context);
+ mergeParamDeclAttributes(*ni, *oi, Context);
+
+ CheckObjCMethodOverride(newMethod, oldMethod, true);
}
/// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and
@@ -2132,6 +2137,16 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
/// no declarator (e.g. "struct foo;") is parsed.
Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS) {
+ return ParsedFreeStandingDeclSpec(S, AS, DS,
+ MultiTemplateParamsArg(*this, 0, 0));
+}
+
+/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+/// no declarator (e.g. "struct foo;") is parsed. It also accopts template
+/// parameters to cope with template friend declarations.
+Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS,
+ MultiTemplateParamsArg TemplateParams) {
Decl *TagD = 0;
TagDecl *Tag = 0;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
@@ -2163,7 +2178,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
// whatever routines created it handled the friendship aspect.
if (TagD && !Tag)
return 0;
- return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
+ return ActOnFriendTypeDecl(S, DS, TemplateParams);
}
// Track whether we warned about the fact that there aren't any
@@ -2484,6 +2499,24 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
PrevSpec, DiagID, getLangOptions());
}
+ // Ignore const/volatile/restrict qualifiers.
+ if (DS.getTypeQualifiers()) {
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+ Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+ << Record->isUnion() << 0
+ << FixItHint::CreateRemoval(DS.getConstSpecLoc());
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
+ Diag(DS.getVolatileSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+ << Record->isUnion() << 1
+ << FixItHint::CreateRemoval(DS.getVolatileSpecLoc());
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
+ Diag(DS.getRestrictSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+ << Record->isUnion() << 2
+ << FixItHint::CreateRemoval(DS.getRestrictSpecLoc());
+
+ DS.ClearTypeQualifiers();
+ }
+
// C++ [class.union]p2:
// The member-specification of an anonymous union shall only
// define non-static data members. [Note: nested types and
@@ -2502,7 +2535,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
}
- if (CheckNontrivialField(FD))
+ // C++ [class.union]p1
+ // An object of a class with a non-trivial constructor, a non-trivial
+ // copy constructor, a non-trivial destructor, or a non-trivial copy
+ // assignment operator cannot be a member of a union, nor can an
+ // array of such objects.
+ if (!getLangOptions().CPlusPlus0x && CheckNontrivialField(FD))
Invalid = true;
} else if ((*Mem)->isImplicit()) {
// Any implicit members are fine.
@@ -2572,7 +2610,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo,
- /*BitWidth=*/0, /*Mutable=*/false);
+ /*BitWidth=*/0, /*Mutable=*/false,
+ /*HasInit=*/false);
Anon->setAccess(AS);
if (getLangOptions().CPlusPlus)
FieldCollector->Add(cast<FieldDecl>(Anon));
@@ -2662,7 +2701,8 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo,
- /*BitWidth=*/0, /*Mutable=*/false);
+ /*BitWidth=*/0, /*Mutable=*/false,
+ /*HasInit=*/false);
Anon->setImplicit();
// Add the anonymous struct object to the current context.
@@ -2829,7 +2869,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
switch (DS.getTypeSpecType()) {
case DeclSpec::TST_typename:
case DeclSpec::TST_typeofType:
- case DeclSpec::TST_decltype: {
+ case DeclSpec::TST_decltype:
+ case DeclSpec::TST_underlyingType: {
// Grab the type from the parser.
TypeSourceInfo *TSI = 0;
QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI);
@@ -2883,8 +2924,10 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
return false;
}
-Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
- return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
+Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D,
+ bool IsFunctionDefinition) {
+ return HandleDeclarator(S, D, MultiTemplateParamsArg(*this),
+ IsFunctionDefinition);
}
/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
@@ -2952,7 +2995,6 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
<< D.getCXXScopeSpec().getRange();
return 0;
}
-
bool IsDependentContext = DC->isDependentContext();
if (!IsDependentContext &&
@@ -3294,15 +3336,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewTD, D);
+ CheckTypedefForVariablyModifiedType(S, NewTD);
+
return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration);
}
-/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which
-/// declares a typedef-name, either using the 'typedef' type specifier or via
-/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'.
-NamedDecl*
-Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
- LookupResult &Previous, bool &Redeclaration) {
+void
+Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
// C99 6.7.7p2: If a typedef name specifies a variably modified type
// then it shall have block scope.
// Note that variably modified types must be fixed before merging the decl so
@@ -3333,10 +3373,18 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
}
}
}
+}
+
+/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which
+/// declares a typedef-name, either using the 'typedef' type specifier or via
+/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'.
+NamedDecl*
+Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
+ LookupResult &Previous, bool &Redeclaration) {
// Merge the decl with the existing one if appropriate. If the decl is
// in an outer scope, it isn't the same thing.
- FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false,
+ FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false,
/*ExplicitInstantiationOrSpecialization=*/false);
if (!Previous.empty()) {
Redeclaration = true;
@@ -3518,7 +3566,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool Invalid = false;
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getSourceRange().getBegin(),
+ D.getDeclSpec().getSourceRange().getBegin(),
+ D.getIdentifierLoc(),
D.getCXXScopeSpec(),
TemplateParamLists.get(),
TemplateParamLists.size(),
@@ -3540,7 +3589,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< II
<< SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc());
- isExplicitSpecialization = true;
}
}
@@ -3615,7 +3663,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
- FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(),
+ FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(),
isExplicitSpecialization);
if (!getLangOptions().CPlusPlus)
@@ -3806,8 +3854,12 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
}
if (NewVD->hasLocalStorage() && T.isObjCGCWeak()
- && !NewVD->hasAttr<BlocksAttr>())
- Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
+ && !NewVD->hasAttr<BlocksAttr>()) {
+ if (getLangOptions().getGCMode() != LangOptions::NonGC)
+ Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local);
+ else
+ Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
+ }
bool isVM = T->isVariablyModifiedType();
if (isVM || NewVD->hasAttr<CleanupAttr>() ||
@@ -4062,7 +4114,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Set the lexical context.
NewFD->setLexicalDeclContext(CurContext);
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+ FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
/*ExplicitInstantiationOrSpecialization=*/false);
} else {
isFriend = D.getDeclSpec().isFriendSpecified();
@@ -4088,24 +4140,38 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
R = CheckConstructorDeclarator(D, R, SC);
// Create the new declaration
- NewFD = CXXConstructorDecl::Create(Context,
+ CXXConstructorDecl *NewCD = CXXConstructorDecl::Create(
+ Context,
cast<CXXRecordDecl>(DC),
D.getSourceRange().getBegin(),
NameInfo, R, TInfo,
isExplicit, isInline,
/*isImplicitlyDeclared=*/false);
+
+ NewFD = NewCD;
} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
// This is a C++ destructor declaration.
if (DC->isRecord()) {
R = CheckDestructorDeclarator(D, R, SC);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- NewFD = CXXDestructorDecl::Create(Context,
- cast<CXXRecordDecl>(DC),
+ CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(Context, Record,
D.getSourceRange().getBegin(),
NameInfo, R, TInfo,
isInline,
/*isImplicitlyDeclared=*/false);
+ NewFD = NewDD;
isVirtualOkay = true;
+
+ // If the class is complete, then we now create the implicit exception
+ // specification. If the class is incomplete or dependent, we can't do
+ // it yet.
+ if (getLangOptions().CPlusPlus0x && !Record->isDependentType() &&
+ Record->getDefinition() && !Record->isBeingDefined() &&
+ R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) {
+ AdjustDestructorExceptionSpec(Record, NewDD);
+ }
+
} else {
Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
@@ -4162,11 +4228,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
isStatic = true;
// This is a C++ method declaration.
- NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
- D.getSourceRange().getBegin(),
- NameInfo, R, TInfo,
- isStatic, SCAsWritten, isInline,
- SourceLocation());
+ CXXMethodDecl *NewMD = CXXMethodDecl::Create(
+ Context, cast<CXXRecordDecl>(DC),
+ D.getSourceRange().getBegin(),
+ NameInfo, R, TInfo,
+ isStatic, SCAsWritten, isInline,
+ SourceLocation());
+ NewFD = NewMD;
isVirtualOkay = !isStatic;
} else {
@@ -4202,6 +4270,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getSourceRange().getBegin(),
+ D.getIdentifierLoc(),
D.getCXXScopeSpec(),
TemplateParamLists.get(),
TemplateParamLists.size(),
@@ -4339,7 +4408,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+ FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
@@ -4406,6 +4475,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
bool IsTypeAlias = false;
if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl());
+ else if (const TemplateSpecializationType *TST =
+ Param->getType()->getAs<TemplateSpecializationType>())
+ IsTypeAlias = TST->isTypeAlias();
Diag(Param->getLocation(), diag::err_param_typedef_of_void)
<< IsTypeAlias;
}
@@ -4452,8 +4524,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (!getLangOptions().CPlusPlus) {
// Perform semantic checking on the function declaration.
- bool isExplctSpecialization=false;
- CheckFunctionDeclaration(S, NewFD, Previous, isExplctSpecialization,
+ bool isExplicitSpecialization=false;
+ CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
Redeclaration);
assert((NewFD->isInvalidDecl() || !Redeclaration ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
@@ -4476,7 +4548,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
HasExplicitTemplateArgs = true;
- if (FunctionTemplate) {
+ if (NewFD->isInvalidDecl()) {
+ HasExplicitTemplateArgs = false;
+ } else if (FunctionTemplate) {
// Function template with explicit template arguments.
Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec)
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc);
@@ -4532,6 +4606,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
(HasExplicitTemplateArgs ? &TemplateArgs : 0),
Previous))
NewFD->setInvalidDecl();
+
+ // C++ [dcl.stc]p1:
+ // A storage-class-specifier shall not be specified in an explicit
+ // specialization (14.7.3)
+ if (SC != SC_None) {
+ Diag(NewFD->getLocation(),
+ diag::err_explicit_specialization_storage_class)
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+ }
+
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) {
if (CheckMemberSpecialization(NewFD, Previous))
NewFD->setInvalidDecl();
@@ -4647,8 +4731,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
<< D.getCXXScopeSpec().getRange();
}
}
-
-
+
+
// Handle attributes. We need to have merged decls when handling attributes
// (for example to check for conflicts, etc).
// FIXME: This needs to happen before we merge declarations. Then,
@@ -4661,7 +4745,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (Redeclaration && Previous.isSingleResult()) {
const FunctionDecl *Def;
FunctionDecl *PrevFD = dyn_cast<FunctionDecl>(Previous.getFoundDecl());
- if (PrevFD && PrevFD->hasBody(Def) && D.hasAttributes()) {
+ if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) {
Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition);
Diag(Def->getLocation(), diag::note_previous_definition);
}
@@ -5076,9 +5160,11 @@ namespace {
if (OrigDecl != ReferenceDecl) return;
LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
Sema::NotForRedeclaration);
- S.Diag(SubExpr->getLocStart(), diag::warn_uninit_self_reference_in_init)
- << Result.getLookupName() << OrigDecl->getLocation()
- << SubExpr->getSourceRange();
+ S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr,
+ S.PDiag(diag::warn_uninit_self_reference_in_init)
+ << Result.getLookupName()
+ << OrigDecl->getLocation()
+ << SubExpr->getSourceRange());
}
};
}
@@ -5553,40 +5639,53 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
return;
}
- const RecordType *Record
- = Context.getBaseElementType(Type)->getAs<RecordType>();
- if (Record && getLangOptions().CPlusPlus &&
- cast<CXXRecordDecl>(Record->getDecl())->isPOD()) {
- // C++03 [dcl.init]p9:
- // If no initializer is specified for an object, and the
- // object is of (possibly cv-qualified) non-POD class type (or
- // array thereof), the object shall be default-initialized; if
- // the object is of const-qualified type, the underlying class
- // type shall have a user-declared default
- // constructor. Otherwise, if no initializer is specified for
- // a non- static object, the object and its subobjects, if
- // any, have an indeterminate initial value); if the object
- // or any of its subobjects are of const-qualified type, the
- // program is ill-formed.
- } else {
- // Check for jumps past the implicit initializer. C++0x
- // clarifies that this applies to a "variable with automatic
- // storage duration", not a "local variable".
- if (getLangOptions().CPlusPlus && Var->hasLocalStorage())
- getCurFunction()->setHasBranchProtectedScope();
-
- InitializedEntity Entity = InitializedEntity::InitializeVariable(Var);
- InitializationKind Kind
- = InitializationKind::CreateDefault(Var->getLocation());
-
- InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
- ExprResult Init = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, 0, 0));
- if (Init.isInvalid())
- Var->setInvalidDecl();
- else if (Init.get())
- Var->setInit(MaybeCreateExprWithCleanups(Init.get()));
+ // Check for jumps past the implicit initializer. C++0x
+ // clarifies that this applies to a "variable with automatic
+ // storage duration", not a "local variable".
+ // C++0x [stmt.dcl]p3
+ // A program that jumps from a point where a variable with automatic
+ // storage duration is not in scope to a point where it is in scope is
+ // ill-formed unless the variable has scalar type, class type with a
+ // trivial default constructor and a trivial destructor, a cv-qualified
+ // version of one of these types, or an array of one of the preceding
+ // types and is declared without an initializer.
+ if (getLangOptions().CPlusPlus && Var->hasLocalStorage()) {
+ if (const RecordType *Record
+ = Context.getBaseElementType(Type)->getAs<RecordType>()) {
+ CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record->getDecl());
+ if ((!getLangOptions().CPlusPlus0x && !CXXRecord->isPOD()) ||
+ (getLangOptions().CPlusPlus0x &&
+ (!CXXRecord->hasTrivialDefaultConstructor() ||
+ !CXXRecord->hasTrivialDestructor())))
+ getCurFunction()->setHasBranchProtectedScope();
+ }
}
+
+ // C++03 [dcl.init]p9:
+ // If no initializer is specified for an object, and the
+ // object is of (possibly cv-qualified) non-POD class type (or
+ // array thereof), the object shall be default-initialized; if
+ // the object is of const-qualified type, the underlying class
+ // type shall have a user-declared default
+ // constructor. Otherwise, if no initializer is specified for
+ // a non- static object, the object and its subobjects, if
+ // any, have an indeterminate initial value); if the object
+ // or any of its subobjects are of const-qualified type, the
+ // program is ill-formed.
+ // C++0x [dcl.init]p11:
+ // If no initializer is specified for an object, the object is
+ // default-initialized; [...].
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(Var);
+ InitializationKind Kind
+ = InitializationKind::CreateDefault(Var->getLocation());
+
+ InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
+ ExprResult Init = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, 0, 0));
+ if (Init.isInvalid())
+ Var->setInvalidDecl();
+ else if (Init.get())
+ Var->setInit(MaybeCreateExprWithCleanups(Init.get()));
CheckCompleteVariableDeclaration(Var);
}
@@ -6056,7 +6155,7 @@ void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) {
// Don't complain if we're in GNU89 mode and the previous definition
// was an extern inline function.
const FunctionDecl *Definition;
- if (FD->hasBody(Definition) &&
+ if (FD->isDefined(Definition) &&
!canRedefineFunction(Definition, getLangOptions())) {
if (getLangOptions().GNUMode && Definition->isInlineSpecified() &&
Definition->getStorageClass() == SC_Extern)
@@ -6221,6 +6320,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
WP.disableCheckFallThrough();
}
+ // MSVC permits the use of pure specifier (=0) on function definition,
+ // defined at class scope, warn about this non standard construct.
+ if (getLangOptions().Microsoft && FD->isPure())
+ Diag(FD->getLocation(), diag::warn_pure_function_definition);
+
if (!FD->isInvalidDecl()) {
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(),
@@ -6499,7 +6603,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
///
/// \returns true if the new tag kind is acceptable, false otherwise.
bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
- TagTypeKind NewTag,
+ TagTypeKind NewTag, bool isDefinition,
SourceLocation NewTagLoc,
const IdentifierInfo &Name) {
// C++ [dcl.type.elab]p3:
@@ -6516,8 +6620,9 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
// struct class-key shall be used to refer to a class (clause 9)
// declared using the class or struct class-key.
TagTypeKind OldTag = Previous->getTagKind();
- if (OldTag == NewTag)
- return true;
+ if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct))
+ if (OldTag == NewTag)
+ return true;
if ((OldTag == TTK_Struct || OldTag == TTK_Class) &&
(NewTag == TTK_Struct || NewTag == TTK_Class)) {
@@ -6526,12 +6631,63 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
isTemplate = Record->getDescribedClassTemplate();
+ if (!ActiveTemplateInstantiations.empty()) {
+ // In a template instantiation, do not offer fix-its for tag mismatches
+ // since they usually mess up the template instead of fixing the problem.
+ Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
+ << (NewTag == TTK_Class) << isTemplate << &Name;
+ return true;
+ }
+
+ if (isDefinition) {
+ // On definitions, check previous tags and issue a fix-it for each
+ // one that doesn't match the current tag.
+ if (Previous->getDefinition()) {
+ // Don't suggest fix-its for redefinitions.
+ return true;
+ }
+
+ bool previousMismatch = false;
+ for (TagDecl::redecl_iterator I(Previous->redecls_begin()),
+ E(Previous->redecls_end()); I != E; ++I) {
+ if (I->getTagKind() != NewTag) {
+ if (!previousMismatch) {
+ previousMismatch = true;
+ Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch)
+ << (NewTag == TTK_Class) << isTemplate << &Name;
+ }
+ Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion)
+ << (NewTag == TTK_Class)
+ << FixItHint::CreateReplacement(I->getInnerLocStart(),
+ NewTag == TTK_Class?
+ "class" : "struct");
+ }
+ }
+ return true;
+ }
+
+ // Check for a previous definition. If current tag and definition
+ // are same type, do nothing. If no definition, but disagree with
+ // with previous tag type, give a warning, but no fix-it.
+ const TagDecl *Redecl = Previous->getDefinition() ?
+ Previous->getDefinition() : Previous;
+ if (Redecl->getTagKind() == NewTag) {
+ return true;
+ }
+
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
<< (NewTag == TTK_Class)
- << isTemplate << &Name
- << FixItHint::CreateReplacement(SourceRange(NewTagLoc),
- OldTag == TTK_Class? "class" : "struct");
- Diag(Previous->getLocation(), diag::note_previous_use);
+ << isTemplate << &Name;
+ Diag(Redecl->getLocation(), diag::note_previous_use);
+
+ // If there is a previous defintion, suggest a fix-it.
+ if (Previous->getDefinition()) {
+ Diag(NewTagLoc, diag::note_struct_class_suggestion)
+ << (Redecl->getTagKind() == TTK_Class)
+ << FixItHint::CreateReplacement(SourceRange(NewTagLoc),
+ Redecl->getTagKind() == TTK_Class? "class" : "struct");
+ }
+
return true;
}
return false;
@@ -6567,7 +6723,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (TemplateParameterLists.size() > 0 ||
(SS.isNotEmpty() && TUK != TUK_Reference)) {
if (TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
+ = MatchTemplateParametersToScopeSpecifier(KWLoc, NameLoc, SS,
TemplateParameterLists.get(),
TemplateParameterLists.size(),
TUK == TUK_Friend,
@@ -6705,6 +6861,17 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// shouldn't be diagnosing.
LookupName(Previous, S);
+ if (Previous.isAmbiguous() &&
+ (TUK == TUK_Definition || TUK == TUK_Declaration)) {
+ LookupResult::Filter F = Previous.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *ND = F.next();
+ if (ND->getDeclContext()->getRedeclContext() != SearchDC)
+ F.erase();
+ }
+ F.done();
+ }
+
// Note: there used to be some attempt at recovery here.
if (Previous.isAmbiguous())
return 0;
@@ -6846,7 +7013,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) {
// Make sure that this wasn't declared as an enum and now used as a
// struct or something similar.
- if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
+ if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind,
+ TUK == TUK_Definition, KWLoc,
+ *Name)) {
bool SafeToContinue
= (PrevTagDecl->getTagKind() != TTK_Enum &&
Kind != TTK_Enum);
@@ -6911,8 +7080,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// for the consumer of this Decl to know it doesn't own it.
// For our current ASTs this shouldn't be a problem, but will
// need to be changed with DeclGroups.
- if ((TUK == TUK_Reference && !PrevTagDecl->getFriendObjectKind()) ||
- TUK == TUK_Friend)
+ if ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() ||
+ getLangOptions().Microsoft)) || TUK == TUK_Friend)
return PrevTagDecl;
// Diagnose attempts to redefine a tag.
@@ -7154,8 +7323,12 @@ CreateNewDecl:
New->setLexicalDeclContext(CurContext);
// Mark this as a friend decl if applicable.
+ // In Microsoft mode, a friend declaration also acts as a forward
+ // declaration so we always pass true to setObjectOfFriendDecl to make
+ // the tag name visible.
if (TUK == TUK_Friend)
- New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty());
+ New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() ||
+ getLangOptions().Microsoft);
// Set the access specifier.
if (!Invalid && SearchDC->isRecord())
@@ -7341,14 +7514,13 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
return false;
}
-/// ActOnField - Each field of a struct/union/class is passed into this in order
+/// ActOnField - Each field of a C struct/union is passed into this in order
/// to create a FieldDecl object for it.
-Decl *Sema::ActOnField(Scope *S, Decl *TagD,
- SourceLocation DeclStart,
- Declarator &D, ExprTy *BitfieldWidth) {
+Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth) {
FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD),
DeclStart, D, static_cast<Expr*>(BitfieldWidth),
- AS_public);
+ /*HasInit=*/false, AS_public);
return Res;
}
@@ -7356,7 +7528,7 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD,
///
FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
SourceLocation DeclStart,
- Declarator &D, Expr *BitWidth,
+ Declarator &D, Expr *BitWidth, bool HasInit,
AccessSpecifier AS) {
IdentifierInfo *II = D.getIdentifier();
SourceLocation Loc = DeclStart;
@@ -7405,8 +7577,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
= (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
SourceLocation TSSL = D.getSourceRange().getBegin();
FieldDecl *NewFD
- = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL,
- AS, PrevDecl, &D);
+ = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit,
+ TSSL, AS, PrevDecl, &D);
if (NewFD->isInvalidDecl())
Record->setInvalidDecl();
@@ -7435,7 +7607,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
TypeSourceInfo *TInfo,
RecordDecl *Record, SourceLocation Loc,
- bool Mutable, Expr *BitWidth,
+ bool Mutable, Expr *BitWidth, bool HasInit,
SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D) {
@@ -7515,7 +7687,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
- BitWidth, Mutable);
+ BitWidth, Mutable, HasInit);
if (InvalidDecl)
NewFD->setInvalidDecl();
@@ -7535,8 +7707,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// destructor, or a non-trivial copy assignment operator
// cannot be a member of a union, nor can an array of such
// objects.
- // TODO: C++0x alters this restriction significantly.
- if (CheckNontrivialField(NewFD))
+ if (!getLangOptions().CPlusPlus0x && CheckNontrivialField(NewFD))
NewFD->setInvalidDecl();
}
}
@@ -7582,8 +7753,8 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
CXXSpecialMember member = CXXInvalid;
if (!RDecl->hasTrivialCopyConstructor())
member = CXXCopyConstructor;
- else if (!RDecl->hasTrivialConstructor())
- member = CXXConstructor;
+ else if (!RDecl->hasTrivialDefaultConstructor())
+ member = CXXDefaultConstructor;
else if (!RDecl->hasTrivialCopyAssignment())
member = CXXCopyAssignment;
else if (!RDecl->hasTrivialDestructor())
@@ -7612,7 +7783,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
case CXXInvalid:
break;
- case CXXConstructor:
+ case CXXDefaultConstructor:
if (RD->hasUserDeclaredConstructor()) {
typedef CXXRecordDecl::ctor_iterator ctor_iter;
for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){
@@ -7633,7 +7804,15 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
case CXXCopyConstructor:
if (RD->hasUserDeclaredCopyConstructor()) {
SourceLocation CtorLoc =
- RD->getCopyConstructor(Context, 0)->getLocation();
+ RD->getCopyConstructor(0)->getLocation();
+ Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+
+ case CXXMoveConstructor:
+ if (RD->hasUserDeclaredMoveConstructor()) {
+ SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation();
Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
return;
}
@@ -7649,6 +7828,14 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
}
break;
+ case CXXMoveAssignment:
+ if (RD->hasUserDeclaredMoveAssignment()) {
+ SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation();
+ Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+
case CXXDestructor:
if (RD->hasUserDeclaredDestructor()) {
SourceLocation DtorLoc = LookupDestructor(RD)->getLocation();
@@ -7686,8 +7873,8 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
bool (CXXRecordDecl::*hasTrivial)() const;
switch (member) {
- case CXXConstructor:
- hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break;
+ case CXXDefaultConstructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialDefaultConstructor; break;
case CXXCopyConstructor:
hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
case CXXCopyAssignment:
@@ -8047,6 +8234,11 @@ void Sema::ActOnFields(Scope* S,
Convs->setAccess(I, (*I)->getAccess());
if (!CXXRecord->isDependentType()) {
+ // Adjust user-defined destructor exception spec.
+ if (getLangOptions().CPlusPlus0x &&
+ CXXRecord->hasUserDeclaredDestructor())
+ AdjustDestructorExceptionSpec(CXXRecord,CXXRecord->getDestructor());
+
// Add any implicitly-declared members to this class.
AddImplicitlyDeclaredMembersToClass(CXXRecord);
@@ -8095,6 +8287,22 @@ void Sema::ActOnFields(Scope* S,
if (!Completed)
Record->completeDefinition();
+
+ // Now that the record is complete, do any delayed exception spec checks
+ // we were missing.
+ while (!DelayedDestructorExceptionSpecChecks.empty()) {
+ const CXXDestructorDecl *Dtor =
+ DelayedDestructorExceptionSpecChecks.back().first;
+ if (Dtor->getParent() != Record)
+ break;
+
+ assert(!Dtor->getParent()->isDependentType() &&
+ "Should not ever add destructors of templates into the list.");
+ CheckOverridingFunctionExceptionSpec(Dtor,
+ DelayedDestructorExceptionSpecChecks.back().second);
+ DelayedDestructorExceptionSpecChecks.pop_back();
+ }
+
} else {
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
@@ -8149,7 +8357,7 @@ static bool isRepresentableIntegerValue(ASTContext &Context,
unsigned BitWidth = Context.getIntWidth(T);
if (Value.isUnsigned() || Value.isNonNegative()) {
- if (T->isSignedIntegerType())
+ if (T->isSignedIntegerOrEnumerationType())
--BitWidth;
return Value.getActiveBits() <= BitWidth;
}
@@ -8172,8 +8380,8 @@ static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) {
};
unsigned BitWidth = Context.getTypeSize(T);
- QualType *Types = T->isSignedIntegerType()? SignedIntegralTypes
- : UnsignedIntegralTypes;
+ QualType *Types = T->isSignedIntegerOrEnumerationType()? SignedIntegralTypes
+ : UnsignedIntegralTypes;
for (unsigned I = 0; I != NumTypes; ++I)
if (Context.getTypeSize(Types[I]) > BitWidth)
return Types[I];
@@ -8307,7 +8515,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// type that is supposed to be large enough to represent the incremented
// value, then increment.
EnumVal = LastEnumConst->getInitVal();
- EnumVal.setIsSigned(EltTy->isSignedIntegerType());
+ EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType());
EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy));
++EnumVal;
@@ -8331,7 +8539,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// Make the enumerator value match the signedness and size of the
// enumerator's type.
EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy));
- EnumVal.setIsSigned(EltTy->isSignedIntegerType());
+ EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType());
}
return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
@@ -8589,7 +8797,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
} else {
NewTy = BestType;
NewWidth = BestWidth;
- NewSign = BestType->isSignedIntegerType();
+ NewSign = BestType->isSignedIntegerOrEnumerationType();
}
// Adjust the APSInt value.
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 27632a1a57c4..ce99efbd0bd2 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -111,6 +111,102 @@ namespace {
}
}
+void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
+ assert(Context && "ImplicitExceptionSpecification without an ASTContext");
+ // If we have an MSAny or unknown spec already, don't bother.
+ if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
+ return;
+
+ const FunctionProtoType *Proto
+ = Method->getType()->getAs<FunctionProtoType>();
+
+ ExceptionSpecificationType EST = Proto->getExceptionSpecType();
+
+ // If this function can throw any exceptions, make a note of that.
+ if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) {
+ ClearExceptions();
+ ComputedEST = EST;
+ return;
+ }
+
+ // FIXME: If the call to this decl is using any of its default arguments, we
+ // need to search them for potentially-throwing calls.
+
+ // If this function has a basic noexcept, it doesn't affect the outcome.
+ if (EST == EST_BasicNoexcept)
+ return;
+
+ // If we have a throw-all spec at this point, ignore the function.
+ if (ComputedEST == EST_None)
+ return;
+
+ // If we're still at noexcept(true) and there's a nothrow() callee,
+ // change to that specification.
+ if (EST == EST_DynamicNone) {
+ if (ComputedEST == EST_BasicNoexcept)
+ ComputedEST = EST_DynamicNone;
+ return;
+ }
+
+ // Check out noexcept specs.
+ if (EST == EST_ComputedNoexcept) {
+ FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(*Context);
+ assert(NR != FunctionProtoType::NR_NoNoexcept &&
+ "Must have noexcept result for EST_ComputedNoexcept.");
+ assert(NR != FunctionProtoType::NR_Dependent &&
+ "Should not generate implicit declarations for dependent cases, "
+ "and don't know how to handle them anyway.");
+
+ // noexcept(false) -> no spec on the new function
+ if (NR == FunctionProtoType::NR_Throw) {
+ ClearExceptions();
+ ComputedEST = EST_None;
+ }
+ // noexcept(true) won't change anything either.
+ return;
+ }
+
+ assert(EST == EST_Dynamic && "EST case not considered earlier.");
+ assert(ComputedEST != EST_None &&
+ "Shouldn't collect exceptions when throw-all is guaranteed.");
+ ComputedEST = EST_Dynamic;
+ // Record the exceptions in this function's exception specification.
+ for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
+ EEnd = Proto->exception_end();
+ E != EEnd; ++E)
+ if (ExceptionsSeen.insert(Context->getCanonicalType(*E)))
+ Exceptions.push_back(*E);
+}
+
+void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
+ if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
+ return;
+
+ // FIXME:
+ //
+ // C++0x [except.spec]p14:
+ // [An] implicit exception-specification specifies the type-id T if and
+ // only if T is allowed by the exception-specification of a function directly
+ // invoked by f’s implicit definition; f shall allow all exceptions if any
+ // function it directly invokes allows all exceptions, and f shall allow no
+ // exceptions if every function it directly invokes allows no exceptions.
+ //
+ // Note in particular that if an implicit exception-specification is generated
+ // for a function containing a throw-expression, that specification can still
+ // be noexcept(true).
+ //
+ // Note also that 'directly invoked' is not defined in the standard, and there
+ // is no indication that we should only consider potentially-evaluated calls.
+ //
+ // Ultimately we should implement the intent of the standard: the exception
+ // specification should be the set of exceptions which can be thrown by the
+ // implicit definition. For now, we assume that any non-nothrow expression can
+ // throw any exception.
+
+ if (E->CanThrow(*Context))
+ ComputedEST = EST_None;
+}
+
bool
Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
SourceLocation EqualLoc) {
@@ -393,6 +489,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
diag::err_param_default_argument_member_template_redecl)
<< WhichKind
<< NewParam->getDefaultArgRange();
+ } else if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(New)) {
+ CXXSpecialMember NewSM = getSpecialMember(Ctor),
+ OldSM = getSpecialMember(cast<CXXConstructorDecl>(Old));
+ if (NewSM != OldSM) {
+ Diag(NewParam->getLocation(),diag::warn_default_arg_makes_ctor_special)
+ << NewParam->getDefaultArgRange() << NewSM;
+ Diag(Old->getLocation(), diag::note_previous_declaration_special)
+ << OldSM;
+ }
}
}
}
@@ -956,14 +1061,15 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New,
/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
-/// bitfield width if there is one and 'InitExpr' specifies the initializer if
-/// any.
+/// bitfield width if there is one, 'InitExpr' specifies the initializer if
+/// one has been parsed, and 'HasDeferredInit' is true if an initializer is
+/// present but parsing it has been deferred.
Decl *
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BW, const VirtSpecifiers &VS,
- ExprTy *InitExpr, bool IsDefinition,
- bool Deleted) {
+ ExprTy *InitExpr, bool HasDeferredInit,
+ bool IsDefinition) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -978,6 +1084,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
assert(isa<CXXRecordDecl>(CurContext));
assert(!DS.isFriendSpecified());
+ assert(!Init || !HasDeferredInit);
bool isFunc = false;
if (D.isFunctionDeclarator())
@@ -1028,7 +1135,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (isInstField) {
CXXScopeSpec &SS = D.getCXXScopeSpec();
-
if (SS.isSet() && !SS.isInvalid()) {
// The user provided a superfluous scope specifier inside a class
// definition:
@@ -1050,9 +1156,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// FIXME: Check for template parameters!
// FIXME: Check that the name is an identifier!
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
- AS);
+ HasDeferredInit, AS);
assert(Member && "HandleField never returns null");
} else {
+ assert(!HasDeferredInit);
+
Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
if (!Member) {
return 0;
@@ -1123,8 +1231,14 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (Init)
AddInitializerToDecl(Member, Init, false,
DS.getTypeSpecType() == DeclSpec::TST_auto);
- if (Deleted) // FIXME: Source location is not very good.
- SetDeclDeleted(Member, D.getSourceRange().getBegin());
+ else if (DS.getTypeSpecType() == DeclSpec::TST_auto &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_static) {
+ // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static
+ // data member if a brace-or-equal-initializer is provided.
+ Diag(Loc, diag::err_auto_var_requires_init)
+ << Name << cast<ValueDecl>(Member)->getType();
+ Member->setInvalidDecl();
+ }
FinalizeDeclaration(Member);
@@ -1133,6 +1247,47 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
return Member;
}
+/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an
+/// in-class initializer for a non-static C++ class member. Such parsing
+/// is deferred until the class is complete.
+void
+Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
+ Expr *InitExpr) {
+ FieldDecl *FD = cast<FieldDecl>(D);
+
+ if (!InitExpr) {
+ FD->setInvalidDecl();
+ FD->removeInClassInitializer();
+ return;
+ }
+
+ ExprResult Init = InitExpr;
+ if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
+ // FIXME: if there is no EqualLoc, this is list-initialization.
+ Init = PerformCopyInitialization(
+ InitializedEntity::InitializeMember(FD), EqualLoc, InitExpr);
+ if (Init.isInvalid()) {
+ FD->setInvalidDecl();
+ return;
+ }
+
+ CheckImplicitConversions(Init.get(), EqualLoc);
+ }
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ Init = MaybeCreateExprWithCleanups(Init);
+ if (Init.isInvalid()) {
+ FD->setInvalidDecl();
+ return;
+ }
+
+ InitExpr = Init.release();
+
+ FD->setInClassInitializer(InitExpr);
+}
+
/// \brief Find the direct and/or virtual base specifiers that
/// correspond to the given base type, for use in base initialization
/// within a constructor.
@@ -1547,7 +1702,8 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
return true;
CXXConstructExpr *ConExpr = cast<CXXConstructExpr>(DelegationInit.get());
- CXXConstructorDecl *Constructor = ConExpr->getConstructor();
+ CXXConstructorDecl *Constructor
+ = ConExpr->getConstructor();
assert(Constructor && "Delegating constructor with no target?");
CheckImplicitConversions(DelegationInit.get(), LParenLoc);
@@ -1956,24 +2112,26 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
return false;
}
- if (FieldBaseElementType->isReferenceType()) {
- SemaRef.Diag(Constructor->getLocation(),
- diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit()
- << SemaRef.Context.getTagDeclType(Constructor->getParent())
- << 0 << Field->getDeclName();
- SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
- return true;
- }
+ if (!Field->getParent()->isUnion()) {
+ if (FieldBaseElementType->isReferenceType()) {
+ SemaRef.Diag(Constructor->getLocation(),
+ diag::err_uninitialized_member_in_ctor)
+ << (int)Constructor->isImplicit()
+ << SemaRef.Context.getTagDeclType(Constructor->getParent())
+ << 0 << Field->getDeclName();
+ SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
- if (FieldBaseElementType.isConstQualified()) {
- SemaRef.Diag(Constructor->getLocation(),
- diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit()
- << SemaRef.Context.getTagDeclType(Constructor->getParent())
- << 1 << Field->getDeclName();
- SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
- return true;
+ if (FieldBaseElementType.isConstQualified()) {
+ SemaRef.Diag(Constructor->getLocation(),
+ diag::err_uninitialized_member_in_ctor)
+ << (int)Constructor->isImplicit()
+ << SemaRef.Context.getTagDeclType(Constructor->getParent())
+ << 1 << Field->getDeclName();
+ SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
}
// Nothing to initialize.
@@ -2001,7 +2159,7 @@ struct BaseAndFieldInfo {
};
}
-static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
+static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
FieldDecl *Top, FieldDecl *Field) {
// Overwhelmingly common case: we have a direct initializer for this field.
@@ -2010,6 +2168,18 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
return false;
}
+ // C++0x [class.base.init]p8: if the entity is a non-static data member that
+ // has a brace-or-equal-initializer, the entity is initialized as specified
+ // in [dcl.init].
+ if (Field->hasInClassInitializer()) {
+ Info.AllToInit.push_back(
+ new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
+ SourceLocation(),
+ SourceLocation(), 0,
+ SourceLocation()));
+ return false;
+ }
+
if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) {
const RecordType *FieldClassType = Field->getType()->getAs<RecordType>();
assert(FieldClassType && "anonymous struct/union without record type");
@@ -2032,7 +2202,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
// field in the class is also initialized, so exit immediately.
return false;
} else if ((*FA)->isAnonymousStructOrUnion()) {
- if (CollectFieldInitializer(Info, Top, *FA))
+ if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
return true;
}
}
@@ -2047,7 +2217,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
// necessary.
for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
EA = FieldClassDecl->field_end(); FA != EA; FA++) {
- if (CollectFieldInitializer(Info, Top, *FA))
+ if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
return true;
}
}
@@ -2056,7 +2226,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
// Don't try to build an implicit initializer if there were semantic
// errors in any of the initializers (and therefore we might be
// missing some that the user actually wrote).
- if (Info.AnyErrorsInInits)
+ if (Info.AnyErrorsInInits || Field->isInvalidDecl())
return false;
CXXCtorInitializer *Init = 0;
@@ -2072,26 +2242,22 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
bool
Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
CXXCtorInitializer *Initializer) {
+ assert(Initializer->isDelegatingInitializer());
Constructor->setNumCtorInitializers(1);
CXXCtorInitializer **initializer =
new (Context) CXXCtorInitializer*[1];
memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*));
Constructor->setCtorInitializers(initializer);
- // FIXME: This doesn't catch indirect loops yet
- CXXConstructorDecl *Target = Initializer->getTargetConstructor();
- while (Target) {
- if (Target == Constructor) {
- Diag(Initializer->getSourceLocation(), diag::err_delegating_ctor_loop)
- << Constructor;
- return true;
- }
- Target = Target->getTargetConstructor();
+ if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
+ MarkDeclarationReferenced(Initializer->getSourceLocation(), Dtor);
+ DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
}
+ DelegatingCtorDecls.push_back(Constructor);
+
return false;
}
-
bool
Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
@@ -2192,7 +2358,7 @@ Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
"Incomplete array type is not valid");
continue;
}
- if (CollectFieldInitializer(Info, *Field, *Field))
+ if (CollectFieldInitializer(*this, Info, *Field, *Field))
HadError = true;
}
@@ -2468,7 +2634,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
HadError = true;
// We will treat this as being the only initializer.
}
- SetDelegatingInitializer(Constructor, *MemInits);
+ SetDelegatingInitializer(Constructor, MemInits[i]);
// Return immediately as the initializer is set.
return;
}
@@ -2805,7 +2971,7 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info,
CXXMethodDecl *MD) {
// No need to do the check on definitions, which require that
// the return/param types be complete.
- if (MD->isThisDeclarationADefinition())
+ if (MD->doesThisDeclarationHaveABody())
return;
// For safety's sake, just ignore it if we don't have type source
@@ -2871,6 +3037,9 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (RecordDecl::field_iterator F = Record->field_begin(),
FEnd = Record->field_end();
F != FEnd; ++F) {
+ if (F->hasInClassInitializer())
+ continue;
+
if (F->getType()->isReferenceType() ||
(F->getType().isConstQualified() && F->getType()->isScalarType())) {
if (!Complained) {
@@ -2937,6 +3106,953 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// instantiated (e.g. meta-functions). This doesn't apply to classes that
// have inherited constructors.
DeclareInheritedConstructors(Record);
+
+ if (!Record->isDependentType())
+ CheckExplicitlyDefaultedMethods(Record);
+}
+
+void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) {
+ for (CXXRecordDecl::method_iterator MI = Record->method_begin(),
+ ME = Record->method_end();
+ MI != ME; ++MI) {
+ if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) {
+ switch (getSpecialMember(*MI)) {
+ case CXXDefaultConstructor:
+ CheckExplicitlyDefaultedDefaultConstructor(
+ cast<CXXConstructorDecl>(*MI));
+ break;
+
+ case CXXDestructor:
+ CheckExplicitlyDefaultedDestructor(cast<CXXDestructorDecl>(*MI));
+ break;
+
+ case CXXCopyConstructor:
+ CheckExplicitlyDefaultedCopyConstructor(cast<CXXConstructorDecl>(*MI));
+ break;
+
+ case CXXCopyAssignment:
+ CheckExplicitlyDefaultedCopyAssignment(*MI);
+ break;
+
+ case CXXMoveConstructor:
+ case CXXMoveAssignment:
+ Diag(MI->getLocation(), diag::err_defaulted_move_unsupported);
+ break;
+
+ default:
+ // FIXME: Do moves once they exist
+ llvm_unreachable("non-special member explicitly defaulted!");
+ }
+ }
+ }
+
+}
+
+void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
+ assert(CD->isExplicitlyDefaulted() && CD->isDefaultConstructor());
+
+ // Whether this was the first-declared instance of the constructor.
+ // This affects whether we implicitly add an exception spec (and, eventually,
+ // constexpr). It is also ill-formed to explicitly default a constructor such
+ // that it would be deleted. (C++0x [decl.fct.def.default])
+ bool First = CD == CD->getCanonicalDecl();
+
+ bool HadError = false;
+ if (CD->getNumParams() != 0) {
+ Diag(CD->getLocation(), diag::err_defaulted_default_ctor_params)
+ << CD->getSourceRange();
+ HadError = true;
+ }
+
+ ImplicitExceptionSpecification Spec
+ = ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent());
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ if (EPI.ExceptionSpecType == EST_Delayed) {
+ // Exception specification depends on some deferred part of the class. We'll
+ // try again when the class's definition has been fully processed.
+ return;
+ }
+ const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ if (CtorType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << CXXDefaultConstructor,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ CtorType, CD->getLocation())) {
+ HadError = true;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // We know there are no parameters.
+ EPI.ExtInfo = CtorType->getExtInfo();
+ CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ }
+
+ if (HadError) {
+ CD->setInvalidDecl();
+ return;
+ }
+
+ if (ShouldDeleteDefaultConstructor(CD)) {
+ if (First) {
+ CD->setDeletedAsWritten();
+ } else {
+ Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
+ << CXXDefaultConstructor;
+ CD->setInvalidDecl();
+ }
+ }
+}
+
+void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) {
+ assert(CD->isExplicitlyDefaulted() && CD->isCopyConstructor());
+
+ // Whether this was the first-declared instance of the constructor.
+ bool First = CD == CD->getCanonicalDecl();
+
+ bool HadError = false;
+ if (CD->getNumParams() != 1) {
+ Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_params)
+ << CD->getSourceRange();
+ HadError = true;
+ }
+
+ ImplicitExceptionSpecification Spec(Context);
+ bool Const;
+ llvm::tie(Spec, Const) =
+ ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent());
+
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ // Check for parameter type matching.
+ // This is a copy ctor so we know it's a cv-qualified reference to T.
+ QualType ArgType = CtorType->getArgType(0);
+ if (ArgType->getPointeeType().isVolatileQualified()) {
+ Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_volatile_param);
+ HadError = true;
+ }
+ if (ArgType->getPointeeType().isConstQualified() && !Const) {
+ Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_const_param);
+ HadError = true;
+ }
+
+ if (CtorType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << CXXCopyConstructor,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ CtorType, CD->getLocation())) {
+ HadError = true;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // We duplicate the one parameter type.
+ EPI.ExtInfo = CtorType->getExtInfo();
+ CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ }
+
+ if (HadError) {
+ CD->setInvalidDecl();
+ return;
+ }
+
+ if (ShouldDeleteCopyConstructor(CD)) {
+ if (First) {
+ CD->setDeletedAsWritten();
+ } else {
+ Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
+ << CXXCopyConstructor;
+ CD->setInvalidDecl();
+ }
+ }
+}
+
+void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
+ assert(MD->isExplicitlyDefaulted());
+
+ // Whether this was the first-declared instance of the operator
+ bool First = MD == MD->getCanonicalDecl();
+
+ bool HadError = false;
+ if (MD->getNumParams() != 1) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_params)
+ << MD->getSourceRange();
+ HadError = true;
+ }
+
+ QualType ReturnType =
+ MD->getType()->getAs<FunctionType>()->getResultType();
+ if (!ReturnType->isLValueReferenceType() ||
+ !Context.hasSameType(
+ Context.getCanonicalType(ReturnType->getPointeeType()),
+ Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_return_type);
+ HadError = true;
+ }
+
+ ImplicitExceptionSpecification Spec(Context);
+ bool Const;
+ llvm::tie(Spec, Const) =
+ ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent());
+
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ QualType ArgType = OperType->getArgType(0);
+ if (!ArgType->isReferenceType()) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref);
+ HadError = true;
+ } else {
+ if (ArgType->getPointeeType().isVolatileQualified()) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_volatile_param);
+ HadError = true;
+ }
+ if (ArgType->getPointeeType().isConstQualified() && !Const) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_const_param);
+ HadError = true;
+ }
+ }
+
+ if (OperType->getTypeQuals()) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_quals);
+ HadError = true;
+ }
+
+ if (OperType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << CXXCopyAssignment,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ OperType, MD->getLocation())) {
+ HadError = true;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // We duplicate the one parameter type.
+ EPI.RefQualifier = OperType->getRefQualifier();
+ EPI.ExtInfo = OperType->getExtInfo();
+ MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI));
+ }
+
+ if (HadError) {
+ MD->setInvalidDecl();
+ return;
+ }
+
+ if (ShouldDeleteCopyAssignmentOperator(MD)) {
+ if (First) {
+ MD->setDeletedAsWritten();
+ } else {
+ Diag(MD->getLocation(), diag::err_out_of_line_default_deletes)
+ << CXXCopyAssignment;
+ MD->setInvalidDecl();
+ }
+ }
+}
+
+void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
+ assert(DD->isExplicitlyDefaulted());
+
+ // Whether this was the first-declared instance of the destructor.
+ bool First = DD == DD->getCanonicalDecl();
+
+ ImplicitExceptionSpecification Spec
+ = ComputeDefaultedDtorExceptionSpec(DD->getParent());
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ const FunctionProtoType *DtorType = DD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ if (DtorType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << CXXDestructor,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ DtorType, DD->getLocation())) {
+ DD->setInvalidDecl();
+ return;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // There are no parameters.
+ EPI.ExtInfo = DtorType->getExtInfo();
+ DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ }
+
+ if (ShouldDeleteDestructor(DD)) {
+ if (First) {
+ DD->setDeletedAsWritten();
+ } else {
+ Diag(DD->getLocation(), diag::err_out_of_line_default_deletes)
+ << CXXDestructor;
+ DD->setInvalidDecl();
+ }
+ }
+}
+
+bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
+ CXXRecordDecl *RD = CD->getParent();
+ assert(!RD->isDependentType() && "do deletion after instantiation");
+ if (!LangOpts.CPlusPlus0x)
+ return false;
+
+ SourceLocation Loc = CD->getLocation();
+
+ // Do access control from the constructor
+ ContextRAII CtorContext(*this, CD);
+
+ bool Union = RD->isUnion();
+ bool AllConst = true;
+
+ // We do this because we should never actually use an anonymous
+ // union's constructor.
+ if (Union && RD->isAnonymousStructOrUnion())
+ return false;
+
+ // FIXME: We should put some diagnostic logic right into this function.
+
+ // C++0x [class.ctor]/5
+ // A defaulted default constructor for class X is defined as deleted if:
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ // We'll handle this one later
+ if (BI->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- any [direct base class] has a type with a destructor that is
+ // deleted or inaccessible from the defaulted default constructor
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- any [direct base class either] has no default constructor or
+ // overload resolution as applied to [its] default constructor
+ // results in an ambiguity or in a function that is deleted or
+ // inaccessible from the defaulted default constructor
+ CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl);
+ if (!BaseDefault || BaseDefault->isDeleted())
+ return true;
+
+ if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+ BE = RD->vbases_end();
+ BI != BE; ++BI) {
+ CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- any [virtual base class] has a type with a destructor that is
+ // delete or inaccessible from the defaulted default constructor
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- any [virtual base class either] has no default constructor or
+ // overload resolution as applied to [its] default constructor
+ // results in an ambiguity or in a function that is deleted or
+ // inaccessible from the defaulted default constructor
+ CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl);
+ if (!BaseDefault || BaseDefault->isDeleted())
+ return true;
+
+ if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end();
+ FI != FE; ++FI) {
+ if (FI->isInvalidDecl())
+ continue;
+
+ QualType FieldType = Context.getBaseElementType(FI->getType());
+ CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+
+ // -- any non-static data member with no brace-or-equal-initializer is of
+ // reference type
+ if (FieldType->isReferenceType() && !FI->hasInClassInitializer())
+ return true;
+
+ // -- X is a union and all its variant members are of const-qualified type
+ // (or array thereof)
+ if (Union && !FieldType.isConstQualified())
+ AllConst = false;
+
+ if (FieldRecord) {
+ // -- X is a union-like class that has a variant member with a non-trivial
+ // default constructor
+ if (Union && !FieldRecord->hasTrivialDefaultConstructor())
+ return true;
+
+ CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
+ if (FieldDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- any non-variant non-static data member of const-qualified type (or
+ // array thereof) with no brace-or-equal-initializer does not have a
+ // user-provided default constructor
+ if (FieldType.isConstQualified() &&
+ !FI->hasInClassInitializer() &&
+ !FieldRecord->hasUserProvidedDefaultConstructor())
+ return true;
+
+ if (!Union && FieldRecord->isUnion() &&
+ FieldRecord->isAnonymousStructOrUnion()) {
+ // We're okay to reuse AllConst here since we only care about the
+ // value otherwise if we're in a union.
+ AllConst = true;
+
+ for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+ UE = FieldRecord->field_end();
+ UI != UE; ++UI) {
+ QualType UnionFieldType = Context.getBaseElementType(UI->getType());
+ CXXRecordDecl *UnionFieldRecord =
+ UnionFieldType->getAsCXXRecordDecl();
+
+ if (!UnionFieldType.isConstQualified())
+ AllConst = false;
+
+ if (UnionFieldRecord &&
+ !UnionFieldRecord->hasTrivialDefaultConstructor())
+ return true;
+ }
+
+ if (AllConst)
+ return true;
+
+ // Don't try to initialize the anonymous union
+ // This is technically non-conformant, but sanity demands it.
+ continue;
+ }
+
+ // -- any non-static data member with no brace-or-equal-initializer has
+ // class type M (or array thereof) and either M has no default
+ // constructor or overload resolution as applied to M's default
+ // constructor results in an ambiguity or in a function that is deleted
+ // or inaccessible from the defaulted default constructor.
+ if (!FI->hasInClassInitializer()) {
+ CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
+ if (!FieldDefault || FieldDefault->isDeleted())
+ return true;
+ if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+ } else if (!Union && FieldType.isConstQualified() &&
+ !FI->hasInClassInitializer()) {
+ // -- any non-variant non-static data member of const-qualified type (or
+ // array thereof) with no brace-or-equal-initializer does not have a
+ // user-provided default constructor
+ return true;
+ }
+ }
+
+ if (Union && AllConst)
+ return true;
+
+ return false;
+}
+
+bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
+ CXXRecordDecl *RD = CD->getParent();
+ assert(!RD->isDependentType() && "do deletion after instantiation");
+ if (!LangOpts.CPlusPlus0x)
+ return false;
+
+ SourceLocation Loc = CD->getLocation();
+
+ // Do access control from the constructor
+ ContextRAII CtorContext(*this, CD);
+
+ bool Union = RD->isUnion();
+
+ assert(!CD->getParamDecl(0)->getType()->getPointeeType().isNull() &&
+ "copy assignment arg has no pointee type");
+ unsigned ArgQuals =
+ CD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ?
+ Qualifiers::Const : 0;
+
+ // We do this because we should never actually use an anonymous
+ // union's constructor.
+ if (Union && RD->isAnonymousStructOrUnion())
+ return false;
+
+ // FIXME: We should put some diagnostic logic right into this function.
+
+ // C++0x [class.copy]/11
+ // A defaulted [copy] constructor for class X is defined as delete if X has:
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ // We'll handle this one later
+ if (BI->isVirtual())
+ continue;
+
+ QualType BaseType = BI->getType();
+ CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- any [direct base class] of a type with a destructor that is deleted or
+ // inaccessible from the defaulted constructor
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- a [direct base class] B that cannot be [copied] because overload
+ // resolution, as applied to B's [copy] constructor, results in an
+ // ambiguity or a function that is deleted or inaccessible from the
+ // defaulted constructor
+ CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals);
+ if (!BaseCtor || BaseCtor->isDeleted())
+ return true;
+ if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+ BE = RD->vbases_end();
+ BI != BE; ++BI) {
+ QualType BaseType = BI->getType();
+ CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- any [virtual base class] of a type with a destructor that is deleted or
+ // inaccessible from the defaulted constructor
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- a [virtual base class] B that cannot be [copied] because overload
+ // resolution, as applied to B's [copy] constructor, results in an
+ // ambiguity or a function that is deleted or inaccessible from the
+ // defaulted constructor
+ CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals);
+ if (!BaseCtor || BaseCtor->isDeleted())
+ return true;
+ if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end();
+ FI != FE; ++FI) {
+ QualType FieldType = Context.getBaseElementType(FI->getType());
+
+ // -- for a copy constructor, a non-static data member of rvalue reference
+ // type
+ if (FieldType->isRValueReferenceType())
+ return true;
+
+ CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+
+ if (FieldRecord) {
+ // This is an anonymous union
+ if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
+ // Anonymous unions inside unions do not variant members create
+ if (!Union) {
+ for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+ UE = FieldRecord->field_end();
+ UI != UE; ++UI) {
+ QualType UnionFieldType = Context.getBaseElementType(UI->getType());
+ CXXRecordDecl *UnionFieldRecord =
+ UnionFieldType->getAsCXXRecordDecl();
+
+ // -- a variant member with a non-trivial [copy] constructor and X
+ // is a union-like class
+ if (UnionFieldRecord &&
+ !UnionFieldRecord->hasTrivialCopyConstructor())
+ return true;
+ }
+ }
+
+ // Don't try to initalize an anonymous union
+ continue;
+ } else {
+ // -- a variant member with a non-trivial [copy] constructor and X is a
+ // union-like class
+ if (Union && !FieldRecord->hasTrivialCopyConstructor())
+ return true;
+
+ // -- any [non-static data member] of a type with a destructor that is
+ // deleted or inaccessible from the defaulted constructor
+ CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
+ if (FieldDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ // -- a [non-static data member of class type (or array thereof)] B that
+ // cannot be [copied] because overload resolution, as applied to B's
+ // [copy] constructor, results in an ambiguity or a function that is
+ // deleted or inaccessible from the defaulted constructor
+ CXXConstructorDecl *FieldCtor = LookupCopyConstructor(FieldRecord,
+ ArgQuals);
+ if (!FieldCtor || FieldCtor->isDeleted())
+ return true;
+ if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
+ CXXRecordDecl *RD = MD->getParent();
+ assert(!RD->isDependentType() && "do deletion after instantiation");
+ if (!LangOpts.CPlusPlus0x)
+ return false;
+
+ SourceLocation Loc = MD->getLocation();
+
+ // Do access control from the constructor
+ ContextRAII MethodContext(*this, MD);
+
+ bool Union = RD->isUnion();
+
+ bool ConstArg =
+ MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified();
+
+ // We do this because we should never actually use an anonymous
+ // union's constructor.
+ if (Union && RD->isAnonymousStructOrUnion())
+ return false;
+
+ DeclarationName OperatorName =
+ Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+ LookupResult R(*this, OperatorName, Loc, LookupOrdinaryName);
+ R.suppressDiagnostics();
+
+ // FIXME: We should put some diagnostic logic right into this function.
+
+ // C++0x [class.copy]/11
+ // A defaulted [copy] assignment operator for class X is defined as deleted
+ // if X has:
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ // We'll handle this one later
+ if (BI->isVirtual())
+ continue;
+
+ QualType BaseType = BI->getType();
+ CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- a [direct base class] B that cannot be [copied] because overload
+ // resolution, as applied to B's [copy] assignment operator, results in
+ // an ambiguity or a function that is deleted or inaccessible from the
+ // assignment operator
+
+ LookupQualifiedName(R, BaseDecl, false);
+
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = R.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
+
+ // Build a fake argument expression
+ QualType ArgType = BaseType;
+ QualType ThisType = BaseType;
+ if (ConstArg)
+ ArgType.addConst();
+ Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
+ , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
+ };
+
+ OverloadCandidateSet OCS((Loc));
+ OverloadCandidateSet::iterator Best;
+
+ AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
+
+ if (OCS.BestViableFunction(*this, Loc, Best, false) !=
+ OR_Success)
+ return true;
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+ BE = RD->vbases_end();
+ BI != BE; ++BI) {
+ QualType BaseType = BI->getType();
+ CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- a [virtual base class] B that cannot be [copied] because overload
+ // resolution, as applied to B's [copy] assignment operator, results in
+ // an ambiguity or a function that is deleted or inaccessible from the
+ // assignment operator
+
+ LookupQualifiedName(R, BaseDecl, false);
+
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = R.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
+
+ // Build a fake argument expression
+ QualType ArgType = BaseType;
+ QualType ThisType = BaseType;
+ if (ConstArg)
+ ArgType.addConst();
+ Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
+ , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
+ };
+
+ OverloadCandidateSet OCS((Loc));
+ OverloadCandidateSet::iterator Best;
+
+ AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
+
+ if (OCS.BestViableFunction(*this, Loc, Best, false) !=
+ OR_Success)
+ return true;
+ }
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end();
+ FI != FE; ++FI) {
+ QualType FieldType = Context.getBaseElementType(FI->getType());
+
+ // -- a non-static data member of reference type
+ if (FieldType->isReferenceType())
+ return true;
+
+ // -- a non-static data member of const non-class type (or array thereof)
+ if (FieldType.isConstQualified() && !FieldType->isRecordType())
+ return true;
+
+ CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+
+ if (FieldRecord) {
+ // This is an anonymous union
+ if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
+ // Anonymous unions inside unions do not variant members create
+ if (!Union) {
+ for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+ UE = FieldRecord->field_end();
+ UI != UE; ++UI) {
+ QualType UnionFieldType = Context.getBaseElementType(UI->getType());
+ CXXRecordDecl *UnionFieldRecord =
+ UnionFieldType->getAsCXXRecordDecl();
+
+ // -- a variant member with a non-trivial [copy] assignment operator
+ // and X is a union-like class
+ if (UnionFieldRecord &&
+ !UnionFieldRecord->hasTrivialCopyAssignment())
+ return true;
+ }
+ }
+
+ // Don't try to initalize an anonymous union
+ continue;
+ // -- a variant member with a non-trivial [copy] assignment operator
+ // and X is a union-like class
+ } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) {
+ return true;
+ }
+
+ LookupQualifiedName(R, FieldRecord, false);
+
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = R.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
+
+ // Build a fake argument expression
+ QualType ArgType = FieldType;
+ QualType ThisType = FieldType;
+ if (ConstArg)
+ ArgType.addConst();
+ Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
+ , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
+ };
+
+ OverloadCandidateSet OCS((Loc));
+ OverloadCandidateSet::iterator Best;
+
+ AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
+
+ if (OCS.BestViableFunction(*this, Loc, Best, false) !=
+ OR_Success)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Sema::ShouldDeleteDestructor(CXXDestructorDecl *DD) {
+ CXXRecordDecl *RD = DD->getParent();
+ assert(!RD->isDependentType() && "do deletion after instantiation");
+ if (!LangOpts.CPlusPlus0x)
+ return false;
+
+ SourceLocation Loc = DD->getLocation();
+
+ // Do access control from the destructor
+ ContextRAII CtorContext(*this, DD);
+
+ bool Union = RD->isUnion();
+
+ // We do this because we should never actually use an anonymous
+ // union's destructor.
+ if (Union && RD->isAnonymousStructOrUnion())
+ return false;
+
+ // C++0x [class.dtor]p5
+ // A defaulted destructor for a class X is defined as deleted if:
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ // We'll handle this one later
+ if (BI->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ assert(BaseDtor && "base has no destructor");
+
+ // -- any direct or virtual base class has a deleted destructor or
+ // a destructor that is inaccessible from the defaulted destructor
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+ BE = RD->vbases_end();
+ BI != BE; ++BI) {
+ CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ assert(BaseDtor && "base has no destructor");
+
+ // -- any direct or virtual base class has a deleted destructor or
+ // a destructor that is inaccessible from the defaulted destructor
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end();
+ FI != FE; ++FI) {
+ QualType FieldType = Context.getBaseElementType(FI->getType());
+ CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+ if (FieldRecord) {
+ if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
+ for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+ UE = FieldRecord->field_end();
+ UI != UE; ++UI) {
+ QualType UnionFieldType = Context.getBaseElementType(FI->getType());
+ CXXRecordDecl *UnionFieldRecord =
+ UnionFieldType->getAsCXXRecordDecl();
+
+ // -- X is a union-like class that has a variant member with a non-
+ // trivial destructor.
+ if (UnionFieldRecord && !UnionFieldRecord->hasTrivialDestructor())
+ return true;
+ }
+ // Technically we are supposed to do this next check unconditionally.
+ // But that makes absolutely no sense.
+ } else {
+ CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
+
+ // -- any of the non-static data members has class type M (or array
+ // thereof) and M has a deleted destructor or a destructor that is
+ // inaccessible from the defaulted destructor
+ if (FieldDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- X is a union-like class that has a variant member with a non-
+ // trivial destructor.
+ if (Union && !FieldDtor->isTrivial())
+ return true;
+ }
+ }
+ }
+
+ if (DD->isVirtual()) {
+ FunctionDecl *OperatorDelete = 0;
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXOperatorName(OO_Delete);
+ if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete,
+ false))
+ return true;
+ }
+
+
+ return false;
}
/// \brief Data used with FindHiddenVirtualMethod
@@ -3053,113 +4169,6 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
dyn_cast_or_null<CXXRecordDecl>(TagDecl));
}
-namespace {
- /// \brief Helper class that collects exception specifications for
- /// implicitly-declared special member functions.
- class ImplicitExceptionSpecification {
- ASTContext &Context;
- // We order exception specifications thus:
- // noexcept is the most restrictive, but is only used in C++0x.
- // throw() comes next.
- // Then a throw(collected exceptions)
- // Finally no specification.
- // throw(...) is used instead if any called function uses it.
- ExceptionSpecificationType ComputedEST;
- llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
- llvm::SmallVector<QualType, 4> Exceptions;
-
- void ClearExceptions() {
- ExceptionsSeen.clear();
- Exceptions.clear();
- }
-
- public:
- explicit ImplicitExceptionSpecification(ASTContext &Context)
- : Context(Context), ComputedEST(EST_BasicNoexcept) {
- if (!Context.getLangOptions().CPlusPlus0x)
- ComputedEST = EST_DynamicNone;
- }
-
- /// \brief Get the computed exception specification type.
- ExceptionSpecificationType getExceptionSpecType() const {
- assert(ComputedEST != EST_ComputedNoexcept &&
- "noexcept(expr) should not be a possible result");
- return ComputedEST;
- }
-
- /// \brief The number of exceptions in the exception specification.
- unsigned size() const { return Exceptions.size(); }
-
- /// \brief The set of exceptions in the exception specification.
- const QualType *data() const { return Exceptions.data(); }
-
- /// \brief Integrate another called method into the collected data.
- void CalledDecl(CXXMethodDecl *Method) {
- // If we have an MSAny spec already, don't bother.
- if (!Method || ComputedEST == EST_MSAny)
- return;
-
- const FunctionProtoType *Proto
- = Method->getType()->getAs<FunctionProtoType>();
-
- ExceptionSpecificationType EST = Proto->getExceptionSpecType();
-
- // If this function can throw any exceptions, make a note of that.
- if (EST == EST_MSAny || EST == EST_None) {
- ClearExceptions();
- ComputedEST = EST;
- return;
- }
-
- // If this function has a basic noexcept, it doesn't affect the outcome.
- if (EST == EST_BasicNoexcept)
- return;
-
- // If we have a throw-all spec at this point, ignore the function.
- if (ComputedEST == EST_None)
- return;
-
- // If we're still at noexcept(true) and there's a nothrow() callee,
- // change to that specification.
- if (EST == EST_DynamicNone) {
- if (ComputedEST == EST_BasicNoexcept)
- ComputedEST = EST_DynamicNone;
- return;
- }
-
- // Check out noexcept specs.
- if (EST == EST_ComputedNoexcept) {
- FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(Context);
- assert(NR != FunctionProtoType::NR_NoNoexcept &&
- "Must have noexcept result for EST_ComputedNoexcept.");
- assert(NR != FunctionProtoType::NR_Dependent &&
- "Should not generate implicit declarations for dependent cases, "
- "and don't know how to handle them anyway.");
-
- // noexcept(false) -> no spec on the new function
- if (NR == FunctionProtoType::NR_Throw) {
- ClearExceptions();
- ComputedEST = EST_None;
- }
- // noexcept(true) won't change anything either.
- return;
- }
-
- assert(EST == EST_Dynamic && "EST case not considered earlier.");
- assert(ComputedEST != EST_None &&
- "Shouldn't collect exceptions when throw-all is guaranteed.");
- ComputedEST = EST_Dynamic;
- // Record the exceptions in this function's exception specification.
- for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
- EEnd = Proto->exception_end();
- E != EEnd; ++E)
- if (ExceptionsSeen.insert(Context.getCanonicalType(*E)))
- Exceptions.push_back(*E);
- }
- };
-}
-
-
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
/// special functions, such as the default constructor, copy
/// constructor, or destructor, to the given C++ class (C++
@@ -3467,6 +4476,11 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>())
Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
<< DeclaratorType << isa<TypeAliasDecl>(TT->getDecl());
+ else if (const TemplateSpecializationType *TST =
+ DeclaratorType->getAs<TemplateSpecializationType>())
+ if (TST->isTypeAlias())
+ Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
+ << DeclaratorType << 1;
// C++ [class.dtor]p2:
// A destructor is used to destroy objects of its class type. A
@@ -3725,18 +4739,37 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// treated as an original-namespace-name.
//
// Since namespace names are unique in their scope, and we don't
- // look through using directives, just
- DeclContext::lookup_result R = CurContext->getRedeclContext()->lookup(II);
- NamedDecl *PrevDecl = R.first == R.second? 0 : *R.first;
-
+ // look through using directives, just look for any ordinary names.
+
+ const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member |
+ Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
+ Decl::IDNS_Namespace;
+ NamedDecl *PrevDecl = 0;
+ for (DeclContext::lookup_result R
+ = CurContext->getRedeclContext()->lookup(II);
+ R.first != R.second; ++R.first) {
+ if ((*R.first)->getIdentifierNamespace() & IDNS) {
+ PrevDecl = *R.first;
+ break;
+ }
+ }
+
if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
// This is an extended namespace definition.
if (Namespc->isInline() != OrigNS->isInline()) {
// inline-ness must match
- Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
- << Namespc->isInline();
+ if (OrigNS->isInline()) {
+ // The user probably just forgot the 'inline', so suggest that it
+ // be added back.
+ Diag(Namespc->getLocation(),
+ diag::warn_inline_namespace_reopened_noninline)
+ << FixItHint::CreateInsertion(NamespaceLoc, "inline ");
+ } else {
+ Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
+ << Namespc->isInline();
+ }
Diag(OrigNS->getLocation(), diag::note_previous_definition);
- Namespc->setInvalidDecl();
+
// Recover by ignoring the new namespace's inline status.
Namespc->setInline(OrigNS->isInline());
}
@@ -4408,6 +5441,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// Otherwise, look up the target name.
LookupResult R(*this, NameInfo, LookupOrdinaryName);
+ R.setUsingDeclaration(true);
// Unlike most lookups, we don't always want to hide tag
// declarations: tag names are visible through the using declaration
@@ -4701,9 +5735,13 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
Decl *Sema::ActOnAliasDeclaration(Scope *S,
AccessSpecifier AS,
+ MultiTemplateParamsArg TemplateParamLists,
SourceLocation UsingLoc,
UnqualifiedId &Name,
TypeResult Type) {
+ // Skip up to the relevant declaration scope.
+ while (S->getFlags() & Scope::TemplateParamScope)
+ S = S->getParent();
assert((S->getFlags() & Scope::DeclScope) &&
"got alias-declaration outside of declaration scope");
@@ -4719,8 +5757,11 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
return 0;
if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo,
- UPPC_DeclarationType))
+ UPPC_DeclarationType)) {
Invalid = true;
+ TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
+ TInfo->getTypeLoc().getBeginLoc());
+ }
LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
LookupName(Previous, S);
@@ -4745,13 +5786,93 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (Invalid)
NewTD->setInvalidDecl();
+ CheckTypedefForVariablyModifiedType(S, NewTD);
+ Invalid |= NewTD->isInvalidDecl();
+
bool Redeclaration = false;
- ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration);
+
+ NamedDecl *NewND;
+ if (TemplateParamLists.size()) {
+ TypeAliasTemplateDecl *OldDecl = 0;
+ TemplateParameterList *OldTemplateParams = 0;
+
+ if (TemplateParamLists.size() != 1) {
+ Diag(UsingLoc, diag::err_alias_template_extra_headers)
+ << SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(),
+ TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc());
+ }
+ TemplateParameterList *TemplateParams = TemplateParamLists.get()[0];
+
+ // Only consider previous declarations in the same scope.
+ FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false,
+ /*ExplicitInstantiationOrSpecialization*/false);
+ if (!Previous.empty()) {
+ Redeclaration = true;
+
+ OldDecl = Previous.getAsSingle<TypeAliasTemplateDecl>();
+ if (!OldDecl && !Invalid) {
+ Diag(UsingLoc, diag::err_redefinition_different_kind)
+ << Name.Identifier;
+
+ NamedDecl *OldD = Previous.getRepresentativeDecl();
+ if (OldD->getLocation().isValid())
+ Diag(OldD->getLocation(), diag::note_previous_definition);
+
+ Invalid = true;
+ }
+
+ if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) {
+ if (TemplateParameterListsAreEqual(TemplateParams,
+ OldDecl->getTemplateParameters(),
+ /*Complain=*/true,
+ TPL_TemplateMatch))
+ OldTemplateParams = OldDecl->getTemplateParameters();
+ else
+ Invalid = true;
+
+ TypeAliasDecl *OldTD = OldDecl->getTemplatedDecl();
+ if (!Invalid &&
+ !Context.hasSameType(OldTD->getUnderlyingType(),
+ NewTD->getUnderlyingType())) {
+ // FIXME: The C++0x standard does not clearly say this is ill-formed,
+ // but we can't reasonably accept it.
+ Diag(NewTD->getLocation(), diag::err_redefinition_different_typedef)
+ << 2 << NewTD->getUnderlyingType() << OldTD->getUnderlyingType();
+ if (OldTD->getLocation().isValid())
+ Diag(OldTD->getLocation(), diag::note_previous_definition);
+ Invalid = true;
+ }
+ }
+ }
+
+ // Merge any previous default template arguments into our parameters,
+ // and check the parameter list.
+ if (CheckTemplateParameterList(TemplateParams, OldTemplateParams,
+ TPC_TypeAliasTemplate))
+ return 0;
+
+ TypeAliasTemplateDecl *NewDecl =
+ TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc,
+ Name.Identifier, TemplateParams,
+ NewTD);
+
+ NewDecl->setAccess(AS);
+
+ if (Invalid)
+ NewDecl->setInvalidDecl();
+ else if (OldDecl)
+ NewDecl->setPreviousDeclaration(OldDecl);
+
+ NewND = NewDecl;
+ } else {
+ ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration);
+ NewND = NewTD;
+ }
if (!Redeclaration)
- PushOnScopeChains(NewTD, S);
+ PushOnScopeChains(NewND, S);
- return NewTD;
+ return NewND;
}
Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
@@ -4855,39 +5976,8 @@ namespace {
};
}
-static CXXConstructorDecl *getDefaultConstructorUnsafe(Sema &Self,
- CXXRecordDecl *D) {
- ASTContext &Context = Self.Context;
- QualType ClassType = Context.getTypeDeclType(D);
- DeclarationName ConstructorName
- = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(ClassType.getUnqualifiedType()));
-
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- // FIXME: In C++0x, a constructor template can be a default constructor.
- if (isa<FunctionTemplateDecl>(*Con))
- continue;
-
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
- if (Constructor->isDefaultConstructor())
- return Constructor;
- }
- return 0;
-}
-
-CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
- CXXRecordDecl *ClassDecl) {
- // C++ [class.ctor]p5:
- // A default constructor for a class X is a constructor of class X
- // that can be called without an argument. If there is no
- // user-declared constructor for class X, a default constructor is
- // implicitly declared. An implicitly-declared default constructor
- // is an inline public member of its class.
- assert(!ClassDecl->hasUserDeclaredConstructor() &&
- "Should not build implicit default constructor!");
-
+Sema::ImplicitExceptionSpecification
+Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
@@ -4902,10 +5992,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (!BaseClassDecl->hasDeclaredDefaultConstructor())
- ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl));
- else if (CXXConstructorDecl *Constructor
- = getDefaultConstructorUnsafe(*this, BaseClassDecl))
+ CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
+ // If this is a deleted function, add it anyway. This might be conformant
+ // with the standard. This might not. I'm not sure. It might not matter.
+ if (Constructor)
ExceptSpec.CalledDecl(Constructor);
}
}
@@ -4916,10 +6006,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
B != BEnd; ++B) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (!BaseClassDecl->hasDeclaredDefaultConstructor())
- ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl));
- else if (CXXConstructorDecl *Constructor
- = getDefaultConstructorUnsafe(*this, BaseClassDecl))
+ CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
+ // If this is a deleted function, add it anyway. This might be conformant
+ // with the standard. This might not. I'm not sure. It might not matter.
+ if (Constructor)
ExceptSpec.CalledDecl(Constructor);
}
}
@@ -4928,22 +6018,42 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
FEnd = ClassDecl->field_end();
F != FEnd; ++F) {
- if (const RecordType *RecordTy
+ if (F->hasInClassInitializer()) {
+ if (Expr *E = F->getInClassInitializer())
+ ExceptSpec.CalledExpr(E);
+ else if (!F->isInvalidDecl())
+ ExceptSpec.SetDelayed();
+ } else if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!FieldClassDecl->hasDeclaredDefaultConstructor())
- ExceptSpec.CalledDecl(
- DeclareImplicitDefaultConstructor(FieldClassDecl));
- else if (CXXConstructorDecl *Constructor
- = getDefaultConstructorUnsafe(*this, FieldClassDecl))
+ CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+ CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
+ // If this is a deleted function, add it anyway. This might be conformant
+ // with the standard. This might not. I'm not sure. It might not matter.
+ // In particular, the problem is that this function never gets called. It
+ // might just be ill-formed because this function attempts to refer to
+ // a deleted function here.
+ if (Constructor)
ExceptSpec.CalledDecl(Constructor);
}
}
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
- EPI.NumExceptions = ExceptSpec.size();
- EPI.Exceptions = ExceptSpec.data();
+ return ExceptSpec;
+}
+
+CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
+ CXXRecordDecl *ClassDecl) {
+ // C++ [class.ctor]p5:
+ // A default constructor for a class X is a constructor of class X
+ // that can be called without an argument. If there is no
+ // user-declared constructor for class X, a default constructor is
+ // implicitly declared. An implicitly-declared default constructor
+ // is an inline public member of its class.
+ assert(!ClassDecl->hasUserDeclaredConstructor() &&
+ "Should not build implicit default constructor!");
+
+ ImplicitExceptionSpecification Spec =
+ ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
// Create the actual constructor declaration.
CanQualType ClassType
@@ -4961,8 +6071,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
DefaultCon->setAccess(AS_public);
+ DefaultCon->setDefaulted();
DefaultCon->setImplicit();
- DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
+ DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
// Note that we have declared this constructor.
++ASTContext::NumImplicitDefaultConstructorsDeclared;
@@ -4970,14 +6081,18 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(DefaultCon, S, false);
ClassDecl->addDecl(DefaultCon);
+
+ if (ShouldDeleteDefaultConstructor(DefaultCon))
+ DefaultCon->setDeletedAsWritten();
return DefaultCon;
}
void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor) {
- assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
- !Constructor->isUsed(false)) &&
+ assert((Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
+ !Constructor->doesThisDeclarationHaveABody() &&
+ !Constructor->isDeleted()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
CXXRecordDecl *ClassDecl = Constructor->getParent();
@@ -4988,7 +6103,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) ||
Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXConstructor << Context.getTagDeclType(ClassDecl);
+ << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
return;
}
@@ -5004,6 +6119,59 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
}
}
+/// Get any existing defaulted default constructor for the given class. Do not
+/// implicitly define one if it does not exist.
+static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self,
+ CXXRecordDecl *D) {
+ ASTContext &Context = Self.Context;
+ QualType ClassType = Context.getTypeDeclType(D);
+ DeclarationName ConstructorName
+ = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(ClassType.getUnqualifiedType()));
+
+ DeclContext::lookup_const_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName);
+ Con != ConEnd; ++Con) {
+ // A function template cannot be defaulted.
+ if (isa<FunctionTemplateDecl>(*Con))
+ continue;
+
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+ if (Constructor->isDefaultConstructor())
+ return Constructor->isDefaulted() ? Constructor : 0;
+ }
+ return 0;
+}
+
+void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
+ if (!D) return;
+ AdjustDeclIfTemplate(D);
+
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
+ CXXConstructorDecl *CtorDecl
+ = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl);
+
+ if (!CtorDecl) return;
+
+ // Compute the exception specification for the default constructor.
+ const FunctionProtoType *CtorTy =
+ CtorDecl->getType()->castAs<FunctionProtoType>();
+ if (CtorTy->getExceptionSpecType() == EST_Delayed) {
+ ImplicitExceptionSpecification Spec =
+ ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ assert(EPI.ExceptionSpecType != EST_Delayed);
+
+ CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ }
+
+ // If the default constructor is explicitly defaulted, checking the exception
+ // specification is deferred until now.
+ if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() &&
+ !ClassDecl->isDependentType())
+ CheckExplicitlyDefaultedDefaultConstructor(CtorDecl);
+}
+
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
// We start with an initial pass over the base classes to collect those that
// inherit constructors from. If there are none, we can forgo all further
@@ -5097,7 +6265,9 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
// Build up a function type for this particular constructor.
// FIXME: The working paper does not consider that the exception spec
// for the inheriting constructor might be larger than that of the
- // source. This code doesn't yet, either.
+ // source. This code doesn't yet, either. When it does, this code will
+ // need to be delayed until after exception specifications and in-class
+ // member initializers are attached.
const Type *NewCtorType;
if (params == maxParams)
NewCtorType = BaseCtorType;
@@ -5179,12 +6349,8 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
}
}
-CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
- // C++ [class.dtor]p2:
- // If a class has no user-declared destructor, a destructor is
- // declared implicitly. An implicitly-declared destructor is an
- // inline public member of its class.
-
+Sema::ImplicitExceptionSpecification
+Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have
// an exception-specification.
@@ -5199,18 +6365,18 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
ExceptSpec.CalledDecl(
- LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
+ LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
}
-
+
// Virtual base-class destructors.
for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
BEnd = ClassDecl->vbases_end();
B != BEnd; ++B) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
ExceptSpec.CalledDecl(
- LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
+ LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
}
-
+
// Field destructors.
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
FEnd = ClassDecl->field_end();
@@ -5218,14 +6384,23 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>())
ExceptSpec.CalledDecl(
- LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
+ LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
}
+ return ExceptSpec;
+}
+
+CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
+ // C++ [class.dtor]p2:
+ // If a class has no user-declared destructor, a destructor is
+ // declared implicitly. An implicitly-declared destructor is an
+ // inline public member of its class.
+
+ ImplicitExceptionSpecification Spec =
+ ComputeDefaultedDtorExceptionSpec(ClassDecl);
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+
// Create the actual destructor declaration.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
- EPI.NumExceptions = ExceptSpec.size();
- EPI.Exceptions = ExceptSpec.data();
QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
CanQualType ClassType
@@ -5239,6 +6414,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
+ Destructor->setDefaulted();
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
@@ -5252,6 +6428,9 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
// This could be uniqued if it ever proves significant.
Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
+
+ if (ShouldDeleteDestructor(Destructor))
+ Destructor->setDeletedAsWritten();
AddOverriddenMethods(ClassDecl, Destructor);
@@ -5260,7 +6439,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXDestructorDecl *Destructor) {
- assert((Destructor->isImplicit() && !Destructor->isUsed(false)) &&
+ assert((Destructor->isDefaulted() &&
+ !Destructor->doesThisDeclarationHaveABody()) &&
"DefineImplicitDestructor - call it for implicit default dtor");
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
@@ -5293,6 +6473,35 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
}
+void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,
+ CXXDestructorDecl *destructor) {
+ // C++11 [class.dtor]p3:
+ // A declaration of a destructor that does not have an exception-
+ // specification is implicitly considered to have the same exception-
+ // specification as an implicit declaration.
+ const FunctionProtoType *dtorType = destructor->getType()->
+ getAs<FunctionProtoType>();
+ if (dtorType->hasExceptionSpec())
+ return;
+
+ ImplicitExceptionSpecification exceptSpec =
+ ComputeDefaultedDtorExceptionSpec(classDecl);
+
+ // Replace the destructor's type.
+ FunctionProtoType::ExtProtoInfo epi;
+ epi.ExceptionSpecType = exceptSpec.getExceptionSpecType();
+ epi.NumExceptions = exceptSpec.size();
+ epi.Exceptions = exceptSpec.data();
+ QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi);
+
+ destructor->setType(ty);
+
+ // FIXME: If the destructor has a body that could throw, and the newly created
+ // spec doesn't allow exceptions, we should emit a warning, because this
+ // change in behavior can break conforming C++03 programs at runtime.
+ // However, we don't have a body yet, so it needs to be done somewhere else.
+}
+
/// \brief Builds a statement that copies the given entity from \p From to
/// \c To.
///
@@ -5530,13 +6739,9 @@ static bool hasConstCopyAssignment(Sema &S, const CXXRecordDecl *CClass) {
return false;
}
-CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
- // Note: The following rules are largely analoguous to the copy
- // constructor rules. Note that virtual bases are not taken into account
- // for determining the argument type of the operator. Note also that
- // operators taking an object instead of a reference are allowed.
-
-
+std::pair<Sema::ImplicitExceptionSpecification, bool>
+Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
+ CXXRecordDecl *ClassDecl) {
// C++ [class.copy]p10:
// If the class definition does not explicitly declare a copy
// assignment operator, one is declared implicitly.
@@ -5581,11 +6786,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// have the form
//
// X& X::operator=(X&)
- QualType ArgType = Context.getTypeDeclType(ClassDecl);
- QualType RetType = Context.getLValueReferenceType(ArgType);
- if (HasConstCopyAssignment)
- ArgType = ArgType.withConst();
- ArgType = Context.getLValueReferenceType(ArgType);
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
@@ -5622,12 +6822,29 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
}
}
+ return std::make_pair(ExceptSpec, HasConstCopyAssignment);
+}
+
+CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
+ // Note: The following rules are largely analoguous to the copy
+ // constructor rules. Note that virtual bases are not taken into account
+ // for determining the argument type of the operator. Note also that
+ // operators taking an object instead of a reference are allowed.
+
+ ImplicitExceptionSpecification Spec(Context);
+ bool Const;
+ llvm::tie(Spec, Const) =
+ ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl);
+
+ QualType ArgType = Context.getTypeDeclType(ClassDecl);
+ QualType RetType = Context.getLValueReferenceType(ArgType);
+ if (Const)
+ ArgType = ArgType.withConst();
+ ArgType = Context.getLValueReferenceType(ArgType);
+
// An implicitly-declared copy assignment operator is an inline public
// member of its class.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
- EPI.NumExceptions = ExceptSpec.size();
- EPI.Exceptions = ExceptSpec.data();
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
@@ -5639,6 +6856,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
/*isInline=*/true,
SourceLocation());
CopyAssignment->setAccess(AS_public);
+ CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
@@ -5652,21 +6870,24 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// Note that we have added this copy-assignment operator.
++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
-
+
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(CopyAssignment, S, false);
ClassDecl->addDecl(CopyAssignment);
+ if (ShouldDeleteCopyAssignmentOperator(CopyAssignment))
+ CopyAssignment->setDeletedAsWritten();
+
AddOverriddenMethods(ClassDecl, CopyAssignment);
return CopyAssignment;
}
void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *CopyAssignOperator) {
- assert((CopyAssignOperator->isImplicit() &&
+ assert((CopyAssignOperator->isDefaulted() &&
CopyAssignOperator->isOverloadedOperator() &&
CopyAssignOperator->getOverloadedOperator() == OO_Equal &&
- !CopyAssignOperator->isUsed(false)) &&
+ !CopyAssignOperator->doesThisDeclarationHaveABody()) &&
"DefineImplicitCopyAssignment called for wrong function");
CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();
@@ -5956,12 +7177,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
}
-CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
- CXXRecordDecl *ClassDecl) {
- // C++ [class.copy]p4:
- // If the class definition does not explicitly declare a copy
- // constructor, one is declared implicitly.
-
+std::pair<Sema::ImplicitExceptionSpecification, bool>
+Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
// C++ [class.copy]p5:
// The implicitly-declared copy constructor for a class X will
// have the form
@@ -5969,6 +7186,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// X::X(const X&)
//
// if
+ // FIXME: It ought to be possible to store this on the record.
bool HasConstCopyConstructor = true;
// -- each direct or virtual base class B of X has a copy
@@ -5984,11 +7202,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(BaseClassDecl);
-
- HasConstCopyConstructor
- = BaseClassDecl->hasConstCopyConstructor(Context);
+ LookupCopyConstructor(BaseClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
@@ -5997,11 +7212,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
++Base) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(BaseClassDecl);
-
- HasConstCopyConstructor
- = BaseClassDecl->hasConstCopyConstructor(Context);
+ LookupCopyConstructor(BaseClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
// -- for all the nonstatic data members of X that are of a
@@ -6013,27 +7225,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
HasConstCopyConstructor && Field != FieldEnd;
++Field) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (!FieldClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(FieldClassDecl);
-
- HasConstCopyConstructor
- = FieldClassDecl->hasConstCopyConstructor(Context);
+ if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
+ LookupCopyConstructor(FieldClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
}
-
// Otherwise, the implicitly declared copy constructor will have
// the form
//
// X::X(X&)
- QualType ClassType = Context.getTypeDeclType(ClassDecl);
- QualType ArgType = ClassType;
- if (HasConstCopyConstructor)
- ArgType = ArgType.withConst();
- ArgType = Context.getLValueReferenceType(ArgType);
-
+
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
@@ -6049,11 +7250,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(BaseClassDecl);
-
- if (CXXConstructorDecl *CopyConstructor
- = BaseClassDecl->getCopyConstructor(Context, Quals))
+ if (CXXConstructorDecl *CopyConstructor =
+ LookupCopyConstructor(BaseClassDecl, Quals))
ExceptSpec.CalledDecl(CopyConstructor);
}
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
@@ -6062,11 +7260,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
++Base) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(BaseClassDecl);
-
- if (CXXConstructorDecl *CopyConstructor
- = BaseClassDecl->getCopyConstructor(Context, Quals))
+ if (CXXConstructorDecl *CopyConstructor =
+ LookupCopyConstructor(BaseClassDecl, Quals))
ExceptSpec.CalledDecl(CopyConstructor);
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
@@ -6074,29 +7269,43 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
Field != FieldEnd;
++Field) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (!FieldClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(FieldClassDecl);
-
- if (CXXConstructorDecl *CopyConstructor
- = FieldClassDecl->getCopyConstructor(Context, Quals))
- ExceptSpec.CalledDecl(CopyConstructor);
+ if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
+ if (CXXConstructorDecl *CopyConstructor =
+ LookupCopyConstructor(FieldClassDecl, Quals))
+ ExceptSpec.CalledDecl(CopyConstructor);
}
}
- // An implicitly-declared copy constructor is an inline public
- // member of its class.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
- EPI.NumExceptions = ExceptSpec.size();
- EPI.Exceptions = ExceptSpec.data();
+ return std::make_pair(ExceptSpec, HasConstCopyConstructor);
+}
+
+CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
+ CXXRecordDecl *ClassDecl) {
+ // C++ [class.copy]p4:
+ // If the class definition does not explicitly declare a copy
+ // constructor, one is declared implicitly.
+
+ ImplicitExceptionSpecification Spec(Context);
+ bool Const;
+ llvm::tie(Spec, Const) =
+ ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl);
+
+ QualType ClassType = Context.getTypeDeclType(ClassDecl);
+ QualType ArgType = ClassType;
+ if (Const)
+ ArgType = ArgType.withConst();
+ ArgType = Context.getLValueReferenceType(ArgType);
+
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+
DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ClassType));
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
+
+ // An implicitly-declared copy constructor is an inline public
+ // member of its class.
CXXConstructorDecl *CopyConstructor
= CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
Context.getFunctionType(Context.VoidTy,
@@ -6106,6 +7315,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
CopyConstructor->setAccess(AS_public);
+ CopyConstructor->setDefaulted();
CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
// Note that we have declared this constructor.
@@ -6119,19 +7329,22 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
SC_None,
SC_None, 0);
CopyConstructor->setParams(&FromParam, 1);
+
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(CopyConstructor, S, false);
ClassDecl->addDecl(CopyConstructor);
+
+ if (ShouldDeleteCopyConstructor(CopyConstructor))
+ CopyConstructor->setDeletedAsWritten();
return CopyConstructor;
}
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
- CXXConstructorDecl *CopyConstructor,
- unsigned TypeQuals) {
- assert((CopyConstructor->isImplicit() &&
- CopyConstructor->isCopyConstructor(TypeQuals) &&
- !CopyConstructor->isUsed(false)) &&
+ CXXConstructorDecl *CopyConstructor) {
+ assert((CopyConstructor->isDefaulted() &&
+ CopyConstructor->isCopyConstructor() &&
+ !CopyConstructor->doesThisDeclarationHaveABody()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
@@ -7138,7 +8351,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
bool Invalid = false;
if (TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(TagLoc, SS,
+ = MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS,
TempParamLists.get(),
TempParamLists.size(),
/*friend*/ true,
@@ -7554,7 +8767,83 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
// If the declaration wasn't the first, we delete the function anyway for
// recovery.
}
- Fn->setDeleted();
+ Fn->setDeletedAsWritten();
+}
+
+void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl);
+
+ if (MD) {
+ if (MD->getParent()->isDependentType()) {
+ MD->setDefaulted();
+ MD->setExplicitlyDefaulted();
+ return;
+ }
+
+ CXXSpecialMember Member = getSpecialMember(MD);
+ if (Member == CXXInvalid) {
+ Diag(DefaultLoc, diag::err_default_special_members);
+ return;
+ }
+
+ MD->setDefaulted();
+ MD->setExplicitlyDefaulted();
+
+ // If this definition appears within the record, do the checking when
+ // the record is complete.
+ const FunctionDecl *Primary = MD;
+ if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
+ // Find the uninstantiated declaration that actually had the '= default'
+ // on it.
+ MD->getTemplateInstantiationPattern()->isDefined(Primary);
+
+ if (Primary == Primary->getCanonicalDecl())
+ return;
+
+ switch (Member) {
+ case CXXDefaultConstructor: {
+ CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
+ CheckExplicitlyDefaultedDefaultConstructor(CD);
+ if (!CD->isInvalidDecl())
+ DefineImplicitDefaultConstructor(DefaultLoc, CD);
+ break;
+ }
+
+ case CXXCopyConstructor: {
+ CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
+ CheckExplicitlyDefaultedCopyConstructor(CD);
+ if (!CD->isInvalidDecl())
+ DefineImplicitCopyConstructor(DefaultLoc, CD);
+ break;
+ }
+
+ case CXXCopyAssignment: {
+ CheckExplicitlyDefaultedCopyAssignment(MD);
+ if (!MD->isInvalidDecl())
+ DefineImplicitCopyAssignment(DefaultLoc, MD);
+ break;
+ }
+
+ case CXXDestructor: {
+ CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD);
+ CheckExplicitlyDefaultedDestructor(DD);
+ if (!DD->isInvalidDecl())
+ DefineImplicitDestructor(DefaultLoc, DD);
+ break;
+ }
+
+ case CXXMoveConstructor:
+ case CXXMoveAssignment:
+ Diag(Dcl->getLocation(), diag::err_defaulted_move_unsupported);
+ break;
+
+ default:
+ // FIXME: Do the rest once we have move functions
+ break;
+ }
+ } else {
+ Diag(DefaultLoc, diag::err_default_special_members);
+ }
}
static void SearchForReturnInStmt(Sema &Self, Stmt *S) {
@@ -7946,3 +9235,86 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
AllToInit.data(), AllToInit.size());
}
}
+
+static
+void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
+ llvm::SmallSet<CXXConstructorDecl*, 4> &Valid,
+ llvm::SmallSet<CXXConstructorDecl*, 4> &Invalid,
+ llvm::SmallSet<CXXConstructorDecl*, 4> &Current,
+ Sema &S) {
+ llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(),
+ CE = Current.end();
+ if (Ctor->isInvalidDecl())
+ return;
+
+ const FunctionDecl *FNTarget = 0;
+ CXXConstructorDecl *Target;
+
+ // We ignore the result here since if we don't have a body, Target will be
+ // null below.
+ (void)Ctor->getTargetConstructor()->hasBody(FNTarget);
+ Target
+= const_cast<CXXConstructorDecl*>(cast_or_null<CXXConstructorDecl>(FNTarget));
+
+ CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(),
+ // Avoid dereferencing a null pointer here.
+ *TCanonical = Target ? Target->getCanonicalDecl() : 0;
+
+ if (!Current.insert(Canonical))
+ return;
+
+ // We know that beyond here, we aren't chaining into a cycle.
+ if (!Target || !Target->isDelegatingConstructor() ||
+ Target->isInvalidDecl() || Valid.count(TCanonical)) {
+ for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI)
+ Valid.insert(*CI);
+ Current.clear();
+ // We've hit a cycle.
+ } else if (TCanonical == Canonical || Invalid.count(TCanonical) ||
+ Current.count(TCanonical)) {
+ // If we haven't diagnosed this cycle yet, do so now.
+ if (!Invalid.count(TCanonical)) {
+ S.Diag((*Ctor->init_begin())->getSourceLocation(),
+ diag::warn_delegating_ctor_cycle)
+ << Ctor;
+
+ // Don't add a note for a function delegating directo to itself.
+ if (TCanonical != Canonical)
+ S.Diag(Target->getLocation(), diag::note_it_delegates_to);
+
+ CXXConstructorDecl *C = Target;
+ while (C->getCanonicalDecl() != Canonical) {
+ (void)C->getTargetConstructor()->hasBody(FNTarget);
+ assert(FNTarget && "Ctor cycle through bodiless function");
+
+ C
+ = const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget));
+ S.Diag(C->getLocation(), diag::note_which_delegates_to);
+ }
+ }
+
+ for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI)
+ Invalid.insert(*CI);
+ Current.clear();
+ } else {
+ DelegatingCycleHelper(Target, Valid, Invalid, Current, S);
+ }
+}
+
+
+void Sema::CheckDelegatingCtorCycles() {
+ llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current;
+
+ llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(),
+ CE = Current.end();
+
+ for (llvm::SmallVector<CXXConstructorDecl*, 4>::iterator
+ I = DelegatingCtorDecls.begin(),
+ E = DelegatingCtorDecls.end();
+ I != E; ++I) {
+ DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
+ }
+
+ for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI)
+ (*CI)->setInvalidDecl();
+}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 7b235bab5d9a..de9097e98b4f 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -24,6 +24,141 @@
using namespace clang;
+bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
+ const ObjCMethodDecl *Overridden,
+ bool IsImplementation) {
+ if (Overridden->hasRelatedResultType() &&
+ !NewMethod->hasRelatedResultType()) {
+ // This can only happen when the method follows a naming convention that
+ // implies a related result type, and the original (overridden) method has
+ // a suitable return type, but the new (overriding) method does not have
+ // a suitable return type.
+ QualType ResultType = NewMethod->getResultType();
+ SourceRange ResultTypeRange;
+ if (const TypeSourceInfo *ResultTypeInfo
+ = NewMethod->getResultTypeSourceInfo())
+ ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+
+ // Figure out which class this method is part of, if any.
+ ObjCInterfaceDecl *CurrentClass
+ = dyn_cast<ObjCInterfaceDecl>(NewMethod->getDeclContext());
+ if (!CurrentClass) {
+ DeclContext *DC = NewMethod->getDeclContext();
+ if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(DC))
+ CurrentClass = Cat->getClassInterface();
+ else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(DC))
+ CurrentClass = Impl->getClassInterface();
+ else if (ObjCCategoryImplDecl *CatImpl
+ = dyn_cast<ObjCCategoryImplDecl>(DC))
+ CurrentClass = CatImpl->getClassInterface();
+ }
+
+ if (CurrentClass) {
+ Diag(NewMethod->getLocation(),
+ diag::warn_related_result_type_compatibility_class)
+ << Context.getObjCInterfaceType(CurrentClass)
+ << ResultType
+ << ResultTypeRange;
+ } else {
+ Diag(NewMethod->getLocation(),
+ diag::warn_related_result_type_compatibility_protocol)
+ << ResultType
+ << ResultTypeRange;
+ }
+
+ Diag(Overridden->getLocation(), diag::note_related_result_type_overridden)
+ << Overridden->getMethodFamily();
+ }
+
+ return false;
+}
+
+
+static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
+ DeclContext *DC,
+ bool SkipCurrent = true) {
+ if (!DC)
+ return false;
+
+ if (!SkipCurrent) {
+ // Look for this method. If we find it, we're done.
+ Selector Sel = NewMethod->getSelector();
+ bool IsInstance = NewMethod->isInstanceMethod();
+ DeclContext::lookup_const_iterator Meth, MethEnd;
+ for (llvm::tie(Meth, MethEnd) = DC->lookup(Sel); Meth != MethEnd; ++Meth) {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+ if (MD && MD->isInstanceMethod() == IsInstance)
+ return S.CheckObjCMethodOverride(NewMethod, MD, false);
+ }
+ }
+
+ if (ObjCInterfaceDecl *Class = llvm::dyn_cast<ObjCInterfaceDecl>(DC)) {
+ // Look through categories.
+ for (ObjCCategoryDecl *Category = Class->getCategoryList();
+ Category; Category = Category->getNextClassCategory()) {
+ if (CheckObjCMethodOverrides(S, NewMethod, Category, false))
+ return true;
+ }
+
+ // Look through protocols.
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(),
+ IEnd = Class->protocol_end();
+ I != IEnd; ++I)
+ if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+ return true;
+
+ // Look in our superclass.
+ return CheckObjCMethodOverrides(S, NewMethod, Class->getSuperClass(),
+ false);
+ }
+
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) {
+ // Look through protocols.
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(),
+ IEnd = Category->protocol_end();
+ I != IEnd; ++I)
+ if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+ return true;
+
+ return false;
+ }
+
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) {
+ // Look through protocols.
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(),
+ IEnd = Protocol->protocol_end();
+ I != IEnd; ++I)
+ if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+ return true;
+
+ return false;
+ }
+
+ return false;
+}
+
+bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod,
+ DeclContext *DC) {
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod, Class);
+
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod, Category);
+
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol);
+
+ if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod,
+ Impl->getClassInterface());
+
+ if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod,
+ CatImpl->getClassInterface());
+
+ return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext);
+}
+
static void DiagnoseObjCImplementedDeprecations(Sema &S,
NamedDecl *ND,
SourceLocation ImplLoc,
@@ -272,23 +407,27 @@ Decl *Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
return AliasDecl;
}
-void Sema::CheckForwardProtocolDeclarationForCircularDependency(
+bool Sema::CheckForwardProtocolDeclarationForCircularDependency(
IdentifierInfo *PName,
SourceLocation &Ploc, SourceLocation PrevLoc,
const ObjCList<ObjCProtocolDecl> &PList) {
+
+ bool res = false;
for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(),
E = PList.end(); I != E; ++I) {
-
if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier(),
Ploc)) {
if (PDecl->getIdentifier() == PName) {
Diag(Ploc, diag::err_protocol_has_circular_dependency);
Diag(PrevLoc, diag::note_previous_definition);
+ res = true;
}
- CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
- PDecl->getLocation(), PDecl->getReferencedProtocols());
+ if (CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
+ PDecl->getLocation(), PDecl->getReferencedProtocols()))
+ res = true;
}
}
+ return res;
}
Decl *
@@ -300,6 +439,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList) {
+ bool err = false;
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc);
@@ -314,8 +454,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
}
ObjCList<ObjCProtocolDecl> PList;
PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
- CheckForwardProtocolDeclarationForCircularDependency(
- ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
+ err = CheckForwardProtocolDeclarationForCircularDependency(
+ ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
// Make sure the cached decl gets a valid start location.
PDecl->setLocation(AtProtoInterfaceLoc);
@@ -331,7 +471,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
}
if (AttrList)
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
- if (NumProtoRefs) {
+ if (!err && NumProtoRefs ) {
/// Check then save referenced protocols.
PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
@@ -1712,11 +1852,71 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) {
return false;
}
+/// \brief Check whether the declared result type of the given Objective-C
+/// method declaration is compatible with the method's class.
+///
+static bool
+CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
+ ObjCInterfaceDecl *CurrentClass) {
+ QualType ResultType = Method->getResultType();
+ SourceRange ResultTypeRange;
+ if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo())
+ ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+
+ // If an Objective-C method inherits its related result type, then its
+ // declared result type must be compatible with its own class type. The
+ // declared result type is compatible if:
+ if (const ObjCObjectPointerType *ResultObjectType
+ = ResultType->getAs<ObjCObjectPointerType>()) {
+ // - it is id or qualified id, or
+ if (ResultObjectType->isObjCIdType() ||
+ ResultObjectType->isObjCQualifiedIdType())
+ return false;
+
+ if (CurrentClass) {
+ if (ObjCInterfaceDecl *ResultClass
+ = ResultObjectType->getInterfaceDecl()) {
+ // - it is the same as the method's class type, or
+ if (CurrentClass == ResultClass)
+ return false;
+
+ // - it is a superclass of the method's class type
+ if (ResultClass->isSuperClassOf(CurrentClass))
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/// \brief Determine if any method in the global method pool has an inferred
+/// result type.
+static bool
+anyMethodInfersRelatedResultType(Sema &S, Selector Sel, bool IsInstance) {
+ Sema::GlobalMethodPool::iterator Pos = S.MethodPool.find(Sel);
+ if (Pos == S.MethodPool.end()) {
+ if (S.ExternalSource)
+ Pos = S.ReadMethodPool(Sel);
+ else
+ return 0;
+ }
+
+ ObjCMethodList &List = IsInstance ? Pos->second.first : Pos->second.second;
+ for (ObjCMethodList *M = &List; M; M = M->Next) {
+ if (M->Method && M->Method->hasRelatedResultType())
+ return true;
+ }
+
+ return false;
+}
+
Decl *Sema::ActOnMethodDeclaration(
Scope *S,
SourceLocation MethodLoc, SourceLocation EndLoc,
tok::TokenKind MethodType, Decl *ClassDecl,
ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
+ SourceLocation SelectorStartLoc,
Selector Sel,
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
@@ -1741,7 +1941,7 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value)
<< 0 << resultDeclType;
return 0;
- }
+ }
} else // get the type for "id".
resultDeclType = Context.getObjCIdType();
@@ -1751,9 +1951,10 @@ Decl *Sema::ActOnMethodDeclaration(
cast<DeclContext>(ClassDecl),
MethodType == tok::minus, isVariadic,
false, false,
- MethodDeclKind == tok::objc_optional ?
- ObjCMethodDecl::Optional :
- ObjCMethodDecl::Required);
+ MethodDeclKind == tok::objc_optional
+ ? ObjCMethodDecl::Optional
+ : ObjCMethodDecl::Required,
+ false);
llvm::SmallVector<ParmVarDecl*, 16> Params;
@@ -1849,6 +2050,7 @@ Decl *Sema::ActOnMethodDeclaration(
}
InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel,
MethodType == tok::minus);
+
if (ObjCMethod->hasAttrs() &&
containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
Diag(EndLoc, diag::warn_attribute_method_def);
@@ -1861,6 +2063,10 @@ Decl *Sema::ActOnMethodDeclaration(
PrevMethod = CatImpDecl->getClassMethod(Sel);
CatImpDecl->addClassMethod(ObjCMethod);
}
+
+ if (ObjCCategoryDecl *Cat = CatImpDecl->getCategoryDecl())
+ InterfaceMD = Cat->getMethod(Sel, MethodType == tok::minus);
+
if (ObjCMethod->hasAttrs() &&
containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
Diag(EndLoc, diag::warn_attribute_method_def);
@@ -1874,10 +2080,65 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
}
+ // If this Objective-C method does not have a related result type, but we
+ // are allowed to infer related result types, try to do so based on the
+ // method family.
+ ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
+ if (!CurrentClass) {
+ if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl))
+ CurrentClass = Cat->getClassInterface();
+ else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(ClassDecl))
+ CurrentClass = Impl->getClassInterface();
+ else if (ObjCCategoryImplDecl *CatImpl
+ = dyn_cast<ObjCCategoryImplDecl>(ClassDecl))
+ CurrentClass = CatImpl->getClassInterface();
+ }
+
// Merge information down from the interface declaration if we have one.
- if (InterfaceMD)
+ if (InterfaceMD) {
+ // Inherit the related result type, if we can.
+ if (InterfaceMD->hasRelatedResultType() &&
+ !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass))
+ ObjCMethod->SetRelatedResultType();
+
mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
-
+ }
+
+ if (!ObjCMethod->hasRelatedResultType() &&
+ getLangOptions().ObjCInferRelatedResultType) {
+ bool InferRelatedResultType = false;
+ switch (ObjCMethod->getMethodFamily()) {
+ case OMF_None:
+ case OMF_copy:
+ case OMF_dealloc:
+ case OMF_mutableCopy:
+ case OMF_release:
+ case OMF_retainCount:
+ break;
+
+ case OMF_alloc:
+ case OMF_new:
+ InferRelatedResultType = ObjCMethod->isClassMethod();
+ break;
+
+ case OMF_init:
+ case OMF_autorelease:
+ case OMF_retain:
+ case OMF_self:
+ InferRelatedResultType = ObjCMethod->isInstanceMethod();
+ break;
+ }
+
+ if (InferRelatedResultType &&
+ !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass))
+ ObjCMethod->SetRelatedResultType();
+
+ if (!InterfaceMD &&
+ anyMethodInfersRelatedResultType(*this, ObjCMethod->getSelector(),
+ ObjCMethod->isInstanceMethod()))
+ CheckObjCMethodOverrides(ObjCMethod, cast<DeclContext>(ClassDecl));
+ }
+
return ObjCMethod;
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index f1033dc8c2ff..7bcec315ddab 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -298,8 +298,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
// - both are non-throwing, regardless of their form,
// - both have the form noexcept(constant-expression) and the constant-
// expressions are equivalent,
- // - one exception-specification is a noexcept-specification allowing all
- // exceptions and the other is of the form throw(type-id-list), or
// - both are dynamic-exception-specifications that have the same set of
// adjusted types.
//
@@ -307,8 +305,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
// of the form throw(), noexcept, or noexcept(constant-expression) where the
// constant-expression yields true.
//
- // CWG 1073 Proposed resolution: Strike the third bullet above.
- //
// C++0x [except.spec]p4: If any declaration of a function has an exception-
// specifier that is not a noexcept-specification allowing all exceptions,
// all declarations [...] of that function shall have a compatible
@@ -320,6 +316,9 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
ExceptionSpecificationType NewEST = New->getExceptionSpecType();
+ assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&
+ "Shouldn't see unknown exception specifications here");
+
// Shortcut the case where both have no spec.
if (OldEST == EST_None && NewEST == EST_None)
return false;
@@ -506,6 +505,9 @@ bool Sema::CheckExceptionSpecSubset(
ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
+ assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&
+ "Shouldn't see unknown exception specifications here");
+
// It does not. If the subset contains everything, we've failed.
if (SubEST == EST_None || SubEST == EST_MSAny) {
Diag(SubLoc, DiagID);
@@ -701,7 +703,23 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec),
+ if (getLangOptions().CPlusPlus0x && isa<CXXDestructorDecl>(New)) {
+ // Don't check uninstantiated template destructors at all. We can only
+ // synthesize correct specs after the template is instantiated.
+ if (New->getParent()->isDependentType())
+ return false;
+ if (New->getParent()->isBeingDefined()) {
+ // The destructor might be updated once the definition is finished. So
+ // remember it and check later.
+ DelayedDestructorExceptionSpecChecks.push_back(std::make_pair(
+ cast<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(Old)));
+ return false;
+ }
+ }
+ unsigned DiagID = diag::err_override_exception_spec;
+ if (getLangOptions().Microsoft)
+ DiagID = diag::warn_override_exception_spec;
+ return CheckExceptionSpecSubset(PDiag(DiagID),
PDiag(diag::note_overridden_virtual_function),
Old->getType()->getAs<FunctionProtoType>(),
Old->getLocation(),
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 20b92b84203f..0549e9499560 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -449,18 +449,58 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start)
return Owned(E);
+ // Don't allow one to pass an Objective-C interface to a vararg.
if (E->getType()->isObjCObjectType() &&
- DiagRuntimeBehavior(E->getLocStart(), 0,
- PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
- << E->getType() << CT))
+ DiagRuntimeBehavior(E->getLocStart(), 0,
+ PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
+ << E->getType() << CT))
return ExprError();
-
- if (!E->getType()->isPODType() &&
- DiagRuntimeBehavior(E->getLocStart(), 0,
+
+ if (!E->getType()->isPODType()) {
+ // C++0x [expr.call]p7:
+ // Passing a potentially-evaluated argument of class type (Clause 9)
+ // having a non-trivial copy constructor, a non-trivial move constructor,
+ // or a non-trivial destructor, with no corresponding parameter,
+ // is conditionally-supported with implementation-defined semantics.
+ bool TrivialEnough = false;
+ if (getLangOptions().CPlusPlus0x && !E->getType()->isDependentType()) {
+ if (CXXRecordDecl *Record = E->getType()->getAsCXXRecordDecl()) {
+ if (Record->hasTrivialCopyConstructor() &&
+ Record->hasTrivialMoveConstructor() &&
+ Record->hasTrivialDestructor())
+ TrivialEnough = true;
+ }
+ }
+
+ if (TrivialEnough) {
+ // Nothing to diagnose. This is okay.
+ } else if (DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << E->getType() << CT))
- return ExprError();
+ << getLangOptions().CPlusPlus0x << E->getType()
+ << CT)) {
+ // Turn this into a trap.
+ CXXScopeSpec SS;
+ UnqualifiedId Name;
+ Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
+ E->getLocStart());
+ ExprResult TrapFn = ActOnIdExpression(TUScope, SS, Name, true, false);
+ if (TrapFn.isInvalid())
+ return ExprError();
+ ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), E->getLocStart(),
+ MultiExprArg(), E->getLocEnd());
+ if (Call.isInvalid())
+ return ExprError();
+
+ ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma,
+ Call.get(), E);
+ if (Comma.isInvalid())
+ return ExprError();
+
+ E = Comma.get();
+ }
+ }
+
return Owned(E);
}
@@ -1293,8 +1333,8 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
// We've found a member of an anonymous struct/union that is
// inside a non-anonymous struct/union, so in a well-formed
// program our base object expression is "this".
- CXXMethodDecl *method = tryCaptureCXXThis();
- if (!method) {
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ if (ThisTy.isNull()) {
Diag(loc, diag::err_invalid_member_use_in_static_method)
<< indirectField->getDeclName();
return ExprError();
@@ -1302,10 +1342,9 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
// Our base object expression is "this".
baseObjectExpr =
- new (Context) CXXThisExpr(loc, method->getThisType(Context),
- /*isImplicit=*/ true);
+ new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
baseObjectIsPointer = true;
- baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers());
+ baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
}
// Build the implicit member references to the field of the
@@ -1452,14 +1491,23 @@ enum IMAKind {
/// conservatively answer "yes", in which case some errors will simply
/// not be caught until template-instantiation.
static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
+ Scope *CurScope,
const LookupResult &R) {
assert(!R.empty() && (*R.begin())->isCXXClassMember());
DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
+
bool isStaticContext =
(!isa<CXXMethodDecl>(DC) ||
cast<CXXMethodDecl>(DC)->isStatic());
+ // C++0x [expr.prim]p4:
+ // Otherwise, if a member-declarator declares a non-static data member
+ // of a class X, the expression this is a prvalue of type "pointer to X"
+ // within the optional brace-or-equal-initializer.
+ if (CurScope->getFlags() & Scope::ThisScope)
+ isStaticContext = false;
+
if (R.isUnresolvableResult())
return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
@@ -1507,8 +1555,11 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
return IMA_Error_StaticContext;
}
- CXXRecordDecl *
- contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl();
+ CXXRecordDecl *contextClass;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+ contextClass = MD->getParent()->getCanonicalDecl();
+ else
+ contextClass = cast<CXXRecordDecl>(DC);
// [class.mfct.non-static]p3:
// ...is used in the body of a non-static member function of class X,
@@ -1986,7 +2037,7 @@ ExprResult
Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
- switch (ClassifyImplicitMemberAccess(*this, R)) {
+ switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
case IMA_Instance:
return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
@@ -2429,19 +2480,18 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
// If this is known to be an instance access, go ahead and build an
// implicit 'this' expression now.
// 'this' expression now.
- CXXMethodDecl *method = tryCaptureCXXThis();
- assert(method && "didn't correctly pre-flight capture of 'this'");
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
- QualType thisType = method->getThisType(Context);
Expr *baseExpr = 0; // null signifies implicit access
if (IsKnownInstance) {
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
- baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true);
+ baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
}
- return BuildMemberReferenceExpr(baseExpr, thisType,
+ return BuildMemberReferenceExpr(baseExpr, ThisTy,
/*OpLoc*/ SourceLocation(),
/*IsArrow*/ true,
SS,
@@ -3014,8 +3064,120 @@ ExprResult Sema::ActOnParenExpr(SourceLocation L,
return Owned(new (Context) ParenExpr(L, R, E));
}
+static bool CheckVecStepTraitOperandType(Sema &S, QualType T,
+ SourceLocation Loc,
+ SourceRange ArgRange) {
+ // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in
+ // scalar or vector data type argument..."
+ // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic
+ // type (C99 6.2.5p18) or void.
+ if (!(T->isArithmeticType() || T->isVoidType() || T->isVectorType())) {
+ S.Diag(Loc, diag::err_vecstep_non_scalar_vector_type)
+ << T << ArgRange;
+ return true;
+ }
+
+ assert((T->isVoidType() || !T->isIncompleteType()) &&
+ "Scalar types should always be complete");
+ return false;
+}
+
+static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
+ SourceLocation Loc,
+ SourceRange ArgRange,
+ UnaryExprOrTypeTrait TraitKind) {
+ // C99 6.5.3.4p1:
+ if (T->isFunctionType()) {
+ // alignof(function) is allowed as an extension.
+ if (TraitKind == UETT_SizeOf)
+ S.Diag(Loc, diag::ext_sizeof_function_type) << ArgRange;
+ return false;
+ }
+
+ // Allow sizeof(void)/alignof(void) as an extension.
+ if (T->isVoidType()) {
+ S.Diag(Loc, diag::ext_sizeof_void_type) << TraitKind << ArgRange;
+ return false;
+ }
+
+ return true;
+}
+
+static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T,
+ SourceLocation Loc,
+ SourceRange ArgRange,
+ UnaryExprOrTypeTrait TraitKind) {
+ // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
+ if (S.LangOpts.ObjCNonFragileABI && T->isObjCObjectType()) {
+ S.Diag(Loc, diag::err_sizeof_nonfragile_interface)
+ << T << (TraitKind == UETT_SizeOf)
+ << ArgRange;
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Check the constrains on expression operands to unary type expression
+/// and type traits.
+///
+/// Completes any types necessary and validates the constraints on the operand
+/// expression. The logic mostly mirrors the type-based overload, but may modify
+/// the expression as it completes the type for that expression through template
+/// instantiation, etc.
+bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op,
+ UnaryExprOrTypeTrait ExprKind) {
+ QualType ExprTy = Op->getType();
+
+ // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
+ // the result is the size of the referenced type."
+ // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+ // result shall be the alignment of the referenced type."
+ if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>())
+ ExprTy = Ref->getPointeeType();
+
+ if (ExprKind == UETT_VecStep)
+ return CheckVecStepTraitOperandType(*this, ExprTy, Op->getExprLoc(),
+ Op->getSourceRange());
+
+ // Whitelist some types as extensions
+ if (!CheckExtensionTraitOperandType(*this, ExprTy, Op->getExprLoc(),
+ Op->getSourceRange(), ExprKind))
+ return false;
+
+ if (RequireCompleteExprType(Op,
+ PDiag(diag::err_sizeof_alignof_incomplete_type)
+ << ExprKind << Op->getSourceRange(),
+ std::make_pair(SourceLocation(), PDiag(0))))
+ return true;
+
+ // Completeing the expression's type may have changed it.
+ ExprTy = Op->getType();
+ if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>())
+ ExprTy = Ref->getPointeeType();
+
+ if (CheckObjCTraitOperandConstraints(*this, ExprTy, Op->getExprLoc(),
+ Op->getSourceRange(), ExprKind))
+ return true;
+
+ return false;
+}
+
+/// \brief Check the constraints on operands to unary expression and type
+/// traits.
+///
+/// This will complete any types necessary, and validate the various constraints
+/// on those operands.
+///
/// The UsualUnaryConversions() function is *not* called by this routine.
-/// See C99 6.3.2.1p[2-4] for more details.
+/// C99 6.3.2.1p[2-4] all state:
+/// Except when it is the operand of the sizeof operator ...
+///
+/// C++ [expr.sizeof]p4
+/// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer
+/// standard conversions are not applied to the operand of sizeof.
+///
+/// This policy is followed for all of the unary trait expressions.
bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType,
SourceLocation OpLoc,
SourceRange ExprRange,
@@ -3030,55 +3192,27 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType,
if (const ReferenceType *Ref = exprType->getAs<ReferenceType>())
exprType = Ref->getPointeeType();
- // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in
- // scalar or vector data type argument..."
- // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic
- // type (C99 6.2.5p18) or void.
- if (ExprKind == UETT_VecStep) {
- if (!(exprType->isArithmeticType() || exprType->isVoidType() ||
- exprType->isVectorType())) {
- Diag(OpLoc, diag::err_vecstep_non_scalar_vector_type)
- << exprType << ExprRange;
- return true;
- }
- }
+ if (ExprKind == UETT_VecStep)
+ return CheckVecStepTraitOperandType(*this, exprType, OpLoc, ExprRange);
- // C99 6.5.3.4p1:
- if (exprType->isFunctionType()) {
- // alignof(function) is allowed as an extension.
- if (ExprKind == UETT_SizeOf)
- Diag(OpLoc, diag::ext_sizeof_function_type)
- << ExprRange;
+ // Whitelist some types as extensions
+ if (!CheckExtensionTraitOperandType(*this, exprType, OpLoc, ExprRange,
+ ExprKind))
return false;
- }
-
- // Allow sizeof(void)/alignof(void) as an extension. vec_step(void) is not
- // an extension, as void is a built-in scalar type (OpenCL 1.1 6.1.1).
- if (exprType->isVoidType()) {
- if (ExprKind != UETT_VecStep)
- Diag(OpLoc, diag::ext_sizeof_void_type)
- << ExprKind << ExprRange;
- return false;
- }
if (RequireCompleteType(OpLoc, exprType,
PDiag(diag::err_sizeof_alignof_incomplete_type)
<< ExprKind << ExprRange))
return true;
- // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
- if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) {
- Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
- << exprType << (ExprKind == UETT_SizeOf)
- << ExprRange;
+ if (CheckObjCTraitOperandConstraints(*this, exprType, OpLoc, ExprRange,
+ ExprKind))
return true;
- }
return false;
}
-static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc,
- SourceRange ExprRange) {
+static bool CheckAlignOfExpr(Sema &S, Expr *E) {
E = E->IgnoreParens();
// alignof decl is always ok.
@@ -3090,7 +3224,8 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc,
return false;
if (E->getBitField()) {
- S. Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange;
+ S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield)
+ << 1 << E->getSourceRange();
return true;
}
@@ -3100,20 +3235,17 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc,
if (isa<FieldDecl>(ME->getMemberDecl()))
return false;
- return S.CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange,
- UETT_AlignOf);
+ return S.CheckUnaryExprOrTypeTraitOperand(E, UETT_AlignOf);
}
-bool Sema::CheckVecStepExpr(Expr *E, SourceLocation OpLoc,
- SourceRange ExprRange) {
+bool Sema::CheckVecStepExpr(Expr *E) {
E = E->IgnoreParens();
// Cannot know anything else if the expression is dependent.
if (E->isTypeDependent())
return false;
- return CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange,
- UETT_VecStep);
+ return CheckUnaryExprOrTypeTraitOperand(E, UETT_VecStep);
}
/// \brief Build a sizeof or alignof expression given a type operand.
@@ -3141,35 +3273,33 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
/// operand.
ExprResult
Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
- UnaryExprOrTypeTrait ExprKind,
- SourceRange R) {
+ UnaryExprOrTypeTrait ExprKind) {
// Verify that the operand is valid.
bool isInvalid = false;
if (E->isTypeDependent()) {
// Delay type-checking for type-dependent expressions.
} else if (ExprKind == UETT_AlignOf) {
- isInvalid = CheckAlignOfExpr(*this, E, OpLoc, R);
+ isInvalid = CheckAlignOfExpr(*this, E);
} else if (ExprKind == UETT_VecStep) {
- isInvalid = CheckVecStepExpr(E, OpLoc, R);
+ isInvalid = CheckVecStepExpr(E);
} else if (E->getBitField()) { // C99 6.5.3.4p1.
- Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
+ Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0;
isInvalid = true;
} else if (E->getType()->isPlaceholderType()) {
ExprResult PE = CheckPlaceholderExpr(E);
if (PE.isInvalid()) return ExprError();
- return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind, R);
+ return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind);
} else {
- isInvalid = CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, R,
- UETT_SizeOf);
+ isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf);
}
if (isInvalid)
return ExprError();
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
- return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, E,
- Context.getSizeType(),
- OpLoc, R.getEnd()));
+ return Owned(new (Context) UnaryExprOrTypeTraitExpr(
+ ExprKind, E, Context.getSizeType(), OpLoc,
+ E->getSourceRange().getEnd()));
}
/// ActOnUnaryExprOrTypeTraitExpr - Handle @c sizeof(type) and @c sizeof @c
@@ -3189,10 +3319,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
}
Expr *ArgEx = (Expr *)TyOrEx;
- ExprResult Result
- = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind,
- ArgEx->getSourceRange());
-
+ ExprResult Result = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind);
return move(Result);
}
@@ -4211,7 +4338,11 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
- return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ QualType T = PD->getType();
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ T = getMessageSendResultType(BaseType, Getter, false, false);
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
@@ -4229,7 +4360,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
SetterSel, Context))
SMD = dyn_cast<ObjCMethodDecl>(SDecl);
- QualType PType = OMD->getSendResultType();
+ QualType PType = getMessageSendResultType(BaseType, OMD, false,
+ false);
ExprValueKind VK = VK_LValue;
if (!getLangOptions().CPlusPlus &&
@@ -4297,7 +4429,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
ExprValueKind VK = VK_LValue;
if (Getter) {
- PType = Getter->getSendResultType();
+ PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
+ false);
if (!getLangOptions().CPlusPlus &&
IsCForbiddenLValueType(Context, PType))
VK = VK_RValue;
@@ -4377,120 +4510,52 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// If the user is trying to apply -> or . to a function name, it's probably
// because they forgot parentheses to call that function.
- bool TryCall = false;
- bool Overloaded = false;
- UnresolvedSet<8> AllOverloads;
- if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr.get())) {
- AllOverloads.append(Overloads->decls_begin(), Overloads->decls_end());
- TryCall = true;
- Overloaded = true;
- } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr.get())) {
- if (FunctionDecl* Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
- AllOverloads.addDecl(Fun);
- TryCall = true;
- }
- }
-
- if (TryCall) {
- // Plunder the overload set for something that would make the member
- // expression valid.
- UnresolvedSet<4> ViableOverloads;
- bool HasViableZeroArgOverload = false;
- for (OverloadExpr::decls_iterator it = AllOverloads.begin(),
- DeclsEnd = AllOverloads.end(); it != DeclsEnd; ++it) {
- // Our overload set may include TemplateDecls, which we'll ignore for the
- // purposes of determining whether we can issue a '()' fixit.
- if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) {
- QualType ResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getPointeeType()->isRecordType())) {
- ViableOverloads.addDecl(*it);
- if (OverloadDecl->getMinRequiredArguments() == 0) {
- HasViableZeroArgOverload = true;
- }
- }
- }
- }
-
- if (!HasViableZeroArgOverload || ViableOverloads.size() != 1) {
+ QualType ZeroArgCallTy;
+ UnresolvedSet<4> Overloads;
+ if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
+ if (ZeroArgCallTy.isNull()) {
Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (AllOverloads.size() > 1) << 0
- << BaseExpr.get()->getSourceRange();
- int ViableOverloadCount = ViableOverloads.size();
- int I;
- for (I = 0; I < ViableOverloadCount; ++I) {
- // FIXME: Magic number for max shown overloads stolen from
- // OverloadCandidateSet::NoteCandidates.
- if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
- break;
- }
- Diag(ViableOverloads[I].getDecl()->getSourceRange().getBegin(),
- diag::note_member_ref_possible_intended_overload);
- }
- if (I != ViableOverloadCount) {
- Diag(BaseExpr.get()->getExprLoc(), diag::note_ovl_too_many_candidates)
- << int(ViableOverloadCount - I);
+ << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
+ UnresolvedSet<2> PlausibleOverloads;
+ for (OverloadExpr::decls_iterator It = Overloads.begin(),
+ DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
+ const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
+ QualType OverloadResultTy = OverloadDecl->getResultType();
+ if ((!IsArrow && OverloadResultTy->isRecordType()) ||
+ (IsArrow && OverloadResultTy->isPointerType() &&
+ OverloadResultTy->getPointeeType()->isRecordType()))
+ PlausibleOverloads.addDecl(It.getDecl());
}
+ NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
return ExprError();
}
- } else {
- // We don't have an expression that's convenient to get a Decl from, but we
- // can at least check if the type is "function of 0 arguments which returns
- // an acceptable type".
- const FunctionType *Fun = NULL;
- if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
- if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) {
- TryCall = true;
- }
- } else if ((Fun = BaseType->getAs<FunctionType>())) {
- TryCall = true;
- } else if (BaseType == Context.BoundMemberTy) {
- // Look for the bound-member type. If it's still overloaded,
- // give up, although we probably should have fallen into the
- // OverloadExpr case above if we actually have an overloaded
- // bound member.
- QualType fnType = Expr::findBoundMemberType(BaseExpr.get());
- if (!fnType.isNull()) {
- TryCall = true;
- Fun = fnType->castAs<FunctionType>();
- }
- }
-
- if (TryCall) {
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) {
- if (FPT->getNumArgs() == 0) {
- QualType ResultTy = Fun->getResultType();
- TryCall = (!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getPointeeType()->isRecordType());
- }
- }
+ if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
+ (IsArrow && ZeroArgCallTy->isPointerType() &&
+ ZeroArgCallTy->getPointeeType()->isRecordType())) {
+ // At this point, we know BaseExpr looks like it's potentially callable
+ // with 0 arguments, and that it returns something of a reasonable type,
+ // so we can emit a fixit and carry on pretending that BaseExpr was
+ // actually a CallExpr.
+ SourceLocation ParenInsertionLoc =
+ PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
+ << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ // FIXME: Try this before emitting the fixit, and suppress diagnostics
+ // while doing so.
+ ExprResult NewBase =
+ ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
+ MultiExprArg(*this, 0, 0),
+ ParenInsertionLoc.getFileLocWithOffset(1));
+ if (NewBase.isInvalid())
+ return ExprError();
+ BaseExpr = NewBase;
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
}
}
- if (TryCall) {
- // At this point, we know BaseExpr looks like it's potentially callable with
- // 0 arguments, and that it returns something of a reasonable type, so we
- // can emit a fixit and carry on pretending that BaseExpr was actually a
- // CallExpr.
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << int(Overloaded) << 1
- << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- ExprResult NewBase = ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
- MultiExprArg(*this, 0, 0),
- ParenInsertionLoc);
- if (NewBase.isInvalid())
- return ExprError();
- BaseExpr = NewBase;
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
-
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr.get()->getSourceRange();
@@ -4946,6 +5011,26 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0);
}
+/// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments.
+///
+/// __builtin_astype( value, dst type )
+///
+ExprResult Sema::ActOnAsTypeExpr(Expr *expr, ParsedType destty,
+ SourceLocation BuiltinLoc,
+ SourceLocation RParenLoc) {
+ ExprValueKind VK = VK_RValue;
+ ExprObjectKind OK = OK_Ordinary;
+ QualType DstTy = GetTypeFromParser(destty);
+ QualType SrcTy = expr->getType();
+ if (Context.getTypeSize(DstTy) != Context.getTypeSize(SrcTy))
+ return ExprError(Diag(BuiltinLoc,
+ diag::err_invalid_astype_of_different_size)
+ << DstTy
+ << SrcTy
+ << expr->getSourceRange());
+ return Owned(new (Context) AsTypeExpr(expr, DstTy, VK, OK, BuiltinLoc, RParenLoc));
+}
+
/// BuildResolvedCallExpr - Build a call to a resolved expression,
/// i.e. an expression not of \p OverloadTy. The expression should
/// unary-convert to an expression of function-pointer or
@@ -6118,6 +6203,150 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
return QualType();
}
+/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps
+/// ParenRange in parentheses.
+static void SuggestParentheses(Sema &Self, SourceLocation Loc,
+ const PartialDiagnostic &PD,
+ const PartialDiagnostic &FirstNote,
+ SourceRange FirstParenRange,
+ const PartialDiagnostic &SecondNote,
+ SourceRange SecondParenRange) {
+ Self.Diag(Loc, PD);
+
+ if (!FirstNote.getDiagID())
+ return;
+
+ SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd());
+ if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
+ // We can't display the parentheses, so just return.
+ return;
+ }
+
+ Self.Diag(Loc, FirstNote)
+ << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+
+ if (!SecondNote.getDiagID())
+ return;
+
+ EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
+ if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
+ // We can't display the parentheses, so just dig the
+ // warning/error and return.
+ Self.Diag(Loc, SecondNote);
+ return;
+ }
+
+ Self.Diag(Loc, SecondNote)
+ << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+}
+
+static bool IsArithmeticOp(BinaryOperatorKind Opc) {
+ return Opc >= BO_Mul && Opc <= BO_Shr;
+}
+
+/// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary
+/// expression, either using a built-in or overloaded operator,
+/// and sets *OpCode to the opcode and *RHS to the right-hand side expression.
+static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
+ Expr **RHS) {
+ E = E->IgnoreParenImpCasts();
+ E = E->IgnoreConversionOperator();
+ E = E->IgnoreParenImpCasts();
+
+ // Built-in binary operator.
+ if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) {
+ if (IsArithmeticOp(OP->getOpcode())) {
+ *Opcode = OP->getOpcode();
+ *RHS = OP->getRHS();
+ return true;
+ }
+ }
+
+ // Overloaded operator.
+ if (CXXOperatorCallExpr *Call = dyn_cast<CXXOperatorCallExpr>(E)) {
+ if (Call->getNumArgs() != 2)
+ return false;
+
+ // Make sure this is really a binary operator that is safe to pass into
+ // BinaryOperator::getOverloadedOpcode(), e.g. it's not a subscript op.
+ OverloadedOperatorKind OO = Call->getOperator();
+ if (OO < OO_Plus || OO > OO_Arrow)
+ return false;
+
+ BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO);
+ if (IsArithmeticOp(OpKind)) {
+ *Opcode = OpKind;
+ *RHS = Call->getArg(1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool IsLogicOp(BinaryOperatorKind Opc) {
+ return (Opc >= BO_LT && Opc <= BO_NE) || (Opc >= BO_LAnd && Opc <= BO_LOr);
+}
+
+/// ExprLooksBoolean - Returns true if E looks boolean, i.e. it has boolean type
+/// or is a logical expression such as (x==y) which has int type, but is
+/// commonly interpreted as boolean.
+static bool ExprLooksBoolean(Expr *E) {
+ E = E->IgnoreParenImpCasts();
+
+ if (E->getType()->isBooleanType())
+ return true;
+ if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E))
+ return IsLogicOp(OP->getOpcode());
+ if (UnaryOperator *OP = dyn_cast<UnaryOperator>(E))
+ return OP->getOpcode() == UO_LNot;
+
+ return false;
+}
+
+/// DiagnoseConditionalPrecedence - Emit a warning when a conditional operator
+/// and binary operator are mixed in a way that suggests the programmer assumed
+/// the conditional operator has higher precedence, for example:
+/// "int x = a + someBinaryCondition ? 1 : 2".
+static void DiagnoseConditionalPrecedence(Sema &Self,
+ SourceLocation OpLoc,
+ Expr *cond,
+ Expr *lhs,
+ Expr *rhs) {
+ BinaryOperatorKind CondOpcode;
+ Expr *CondRHS;
+
+ if (!IsArithmeticBinaryExpr(cond, &CondOpcode, &CondRHS))
+ return;
+ if (!ExprLooksBoolean(CondRHS))
+ return;
+
+ // The condition is an arithmetic binary expression, with a right-
+ // hand side that looks boolean, so warn.
+
+ PartialDiagnostic Warn = Self.PDiag(diag::warn_precedence_conditional)
+ << cond->getSourceRange()
+ << BinaryOperator::getOpcodeStr(CondOpcode);
+
+ PartialDiagnostic FirstNote =
+ Self.PDiag(diag::note_precedence_conditional_silence)
+ << BinaryOperator::getOpcodeStr(CondOpcode);
+
+ SourceRange FirstParenRange(cond->getLocStart(),
+ cond->getLocEnd());
+
+ PartialDiagnostic SecondNote =
+ Self.PDiag(diag::note_precedence_conditional_first);
+
+ SourceRange SecondParenRange(CondRHS->getLocStart(),
+ rhs->getLocEnd());
+
+ SuggestParentheses(Self, OpLoc, Warn, FirstNote, FirstParenRange,
+ SecondNote, SecondParenRange);
+}
+
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
/// in the case of a the GNU conditional expr extension.
ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
@@ -6162,6 +6391,9 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
RHS.isInvalid())
return ExprError();
+ DiagnoseConditionalPrecedence(*this, QuestionLoc, Cond.get(), LHS.get(),
+ RHS.get());
+
if (!commonExpr)
return Owned(new (Context) ConditionalOperator(Cond.take(), QuestionLoc,
LHS.take(), ColonLoc,
@@ -7487,7 +7719,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
// Comparison of pointers with null pointer constants and equality
// comparisons of member pointers to null pointer constants.
if (RHSIsNull &&
- ((lType->isPointerType() || lType->isNullPtrType()) ||
+ ((lType->isAnyPointerType() || lType->isNullPtrType()) ||
(!isRelational && lType->isMemberPointerType()))) {
rex = ImpCastExprToType(rex.take(), lType,
lType->isMemberPointerType()
@@ -7496,7 +7728,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
return ResultTy;
}
if (LHSIsNull &&
- ((rType->isPointerType() || rType->isNullPtrType()) ||
+ ((rType->isAnyPointerType() || rType->isNullPtrType()) ||
(!isRelational && rType->isMemberPointerType()))) {
lex = ImpCastExprToType(lex.take(), rType,
rType->isMemberPointerType()
@@ -7748,13 +7980,15 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// If the RHS can be constant folded, and if it constant folds to something
// that isn't 0 or 1 (which indicate a potential logical operation that
// happened to fold to true/false) then warn.
+ // Parens on the RHS are ignored.
Expr::EvalResult Result;
- if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects &&
- Result.Val.getInt() != 0 && Result.Val.getInt() != 1) {
- Diag(Loc, diag::warn_logical_instead_of_bitwise)
- << rex.get()->getSourceRange()
- << (Opc == BO_LAnd ? "&&" : "||")
- << (Opc == BO_LAnd ? "&" : "|");
+ if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects)
+ if ((getLangOptions().Bool && !rex.get()->getType()->isBooleanType()) ||
+ (Result.Val.getInt() != 0 && Result.Val.getInt() != 1)) {
+ Diag(Loc, diag::warn_logical_instead_of_bitwise)
+ << rex.get()->getSourceRange()
+ << (Opc == BO_LAnd ? "&&" : "||")
+ << (Opc == BO_LAnd ? "&" : "|");
}
}
@@ -8127,20 +8361,31 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
E->getObjectKind() == OK_ObjCProperty);
const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
+ QualType T = E->getType();
+ QualType ReceiverType;
+ if (PRE->isObjectReceiver())
+ ReceiverType = PRE->getBase()->getType();
+ else if (PRE->isSuperReceiver())
+ ReceiverType = PRE->getSuperReceiverType();
+ else
+ ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());
+
ExprValueKind VK = VK_RValue;
if (PRE->isImplicitProperty()) {
- if (const ObjCMethodDecl *GetterMethod =
+ if (ObjCMethodDecl *GetterMethod =
PRE->getImplicitPropertyGetter()) {
- QualType Result = GetterMethod->getResultType();
- VK = Expr::getValueKindForType(Result);
+ T = getMessageSendResultType(ReceiverType, GetterMethod,
+ PRE->isClassReceiver(),
+ PRE->isSuperReceiver());
+ VK = Expr::getValueKindForType(GetterMethod->getResultType());
}
else {
Diag(PRE->getLocation(), diag::err_getter_not_found)
<< PRE->getBase()->getType();
}
}
-
- E = ImplicitCastExpr::Create(Context, E->getType(), CK_GetObjCProperty,
+
+ E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty,
E, 0, VK);
ExprResult Result = MaybeBindToTemporary(E);
@@ -8404,7 +8649,13 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
Op = ConvResult.take();
QualType OpTy = Op->getType();
QualType Result;
-
+
+ if (isa<CXXReinterpretCastExpr>(Op)) {
+ QualType OpOrigType = Op->IgnoreParenCasts()->getType();
+ S.CheckCompatibleReinterpretCast(OpOrigType, OpTy, /*IsDereference*/true,
+ Op->getSourceRange());
+ }
+
// Note that per both C89 and C99, indirection is always legal, even if OpTy
// is an incomplete type or void. It would be possible to warn about
// dereferencing a void pointer, but it's completely well-defined, and such a
@@ -8678,45 +8929,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
CompResultTy, OpLoc));
}
-/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps
-/// ParenRange in parentheses.
-static void SuggestParentheses(Sema &Self, SourceLocation Loc,
- const PartialDiagnostic &PD,
- const PartialDiagnostic &FirstNote,
- SourceRange FirstParenRange,
- const PartialDiagnostic &SecondNote,
- SourceRange SecondParenRange) {
- Self.Diag(Loc, PD);
-
- if (!FirstNote.getDiagID())
- return;
-
- SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd());
- if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just return.
- return;
- }
-
- Self.Diag(Loc, FirstNote)
- << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
-
- if (!SecondNote.getDiagID())
- return;
-
- EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
- if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just dig the
- // warning/error and return.
- Self.Diag(Loc, SecondNote);
- return;
- }
-
- Self.Diag(Loc, SecondNote)
- << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
-}
-
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
/// operators are mixed in a way that suggests that the programmer forgot that
/// comparison operators have higher precedence. The most typical example of
@@ -9666,6 +9878,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
*Complained = false;
// Decode the result (notice that AST's are still created for extensions).
+ bool CheckInferredResultType = false;
bool isInvalid = false;
unsigned DiagKind;
FixItHint Hint;
@@ -9682,6 +9895,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case IncompatiblePointer:
MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint);
DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
+ CheckInferredResultType = DstType->isObjCObjectPointerType() &&
+ SrcType->isObjCObjectPointerType();
break;
case IncompatiblePointerSign:
DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign;
@@ -9763,6 +9978,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
Diag(Loc, DiagKind) << FirstType << SecondType << Action
<< SrcExpr->getSourceRange() << Hint;
+ if (CheckInferredResultType)
+ EmitRelatedResultTypeNote(SrcExpr);
+
if (Complained)
*Complained = true;
return isInvalid;
@@ -9914,26 +10132,25 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- unsigned TypeQuals;
- if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) {
- if (Constructor->getParent()->hasTrivialConstructor())
+ if (Constructor->isDefaulted() && Constructor->isDefaultConstructor()) {
+ if (Constructor->isTrivial())
return;
if (!Constructor->isUsed(false))
DefineImplicitDefaultConstructor(Loc, Constructor);
- } else if (Constructor->isImplicit() &&
- Constructor->isCopyConstructor(TypeQuals)) {
+ } else if (Constructor->isDefaulted() &&
+ Constructor->isCopyConstructor()) {
if (!Constructor->isUsed(false))
- DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
+ DefineImplicitCopyConstructor(Loc, Constructor);
}
MarkVTableUsed(Loc, Constructor->getParent());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
- if (Destructor->isImplicit() && !Destructor->isUsed(false))
+ if (Destructor->isDefaulted() && !Destructor->isUsed(false))
DefineImplicitDestructor(Loc, Destructor);
if (Destructor->isVirtual())
MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
- if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
+ if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
if (!MethodDecl->isUsed(false))
DefineImplicitCopyAssignment(Loc, MethodDecl);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 7f1bf596a237..2f5a890e51de 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -17,6 +17,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Scope.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -385,13 +386,14 @@ static UuidAttr *GetUuidAttrOfType(QualType QT) {
else if (QT->isArrayType())
Ty = cast<ArrayType>(QT)->getElementType().getTypePtr();
- // Loop all class definition and declaration looking for an uuid attribute.
+ // Loop all record redeclaration looking for an uuid attribute.
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- while (RD) {
- if (UuidAttr *Uuid = RD->getAttr<UuidAttr>())
+ for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
+ E = RD->redecls_end(); I != E; ++I) {
+ if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
return Uuid;
- RD = RD->getPreviousDeclaration();
}
+
return 0;
}
@@ -574,42 +576,54 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) {
return Owned(E);
}
-CXXMethodDecl *Sema::tryCaptureCXXThis() {
+QualType Sema::getAndCaptureCurrentThisType() {
// Ignore block scopes: we can capture through them.
// Ignore nested enum scopes: we'll diagnose non-constant expressions
// where they're invalid, and other uses are legitimate.
// Don't ignore nested class scopes: you can't use 'this' in a local class.
DeclContext *DC = CurContext;
+ unsigned NumBlocks = 0;
while (true) {
- if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
- else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext();
+ if (isa<BlockDecl>(DC)) {
+ DC = cast<BlockDecl>(DC)->getDeclContext();
+ ++NumBlocks;
+ } else if (isa<EnumDecl>(DC))
+ DC = cast<EnumDecl>(DC)->getDeclContext();
else break;
}
- // If we're not in an instance method, error out.
- CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC);
- if (!method || !method->isInstance())
- return 0;
+ QualType ThisTy;
+ if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) {
+ if (method && method->isInstance())
+ ThisTy = method->getThisType(Context);
+ } else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
+ // C++0x [expr.prim]p4:
+ // Otherwise, if a member-declarator declares a non-static data member
+ // of a class X, the expression this is a prvalue of type "pointer to X"
+ // within the optional brace-or-equal-initializer.
+ Scope *S = getScopeForContext(DC);
+ if (!S || S->getFlags() & Scope::ThisScope)
+ ThisTy = Context.getPointerType(Context.getRecordType(RD));
+ }
- // Mark that we're closing on 'this' in all the block scopes, if applicable.
- for (unsigned idx = FunctionScopes.size() - 1;
- isa<BlockScopeInfo>(FunctionScopes[idx]);
- --idx)
- cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
+ // Mark that we're closing on 'this' in all the block scopes we ignored.
+ if (!ThisTy.isNull())
+ for (unsigned idx = FunctionScopes.size() - 1;
+ NumBlocks; --idx, --NumBlocks)
+ cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
- return method;
+ return ThisTy;
}
-ExprResult Sema::ActOnCXXThis(SourceLocation loc) {
+ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
/// is a non-lvalue expression whose value is the address of the object for
/// which the function is called.
- CXXMethodDecl *method = tryCaptureCXXThis();
- if (!method) return Diag(loc, diag::err_invalid_this_use);
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use);
- return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context),
- /*isImplicit=*/false));
+ return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false));
}
ExprResult
@@ -950,8 +964,8 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- ArraySize = ImpCastExprToType(ArraySize, Context.getSizeType(),
- CK_IntegralCast).take();
+ // Note that we do *not* convert the argument in any way. It can
+ // be signed, larger than size_t, whatever.
}
FunctionDecl *OperatorNew = 0;
@@ -1326,11 +1340,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
DeclarationName Name, Expr** Args,
unsigned NumArgs, DeclContext *Ctx,
- bool AllowMissing, FunctionDecl *&Operator) {
+ bool AllowMissing, FunctionDecl *&Operator,
+ bool Diagnose) {
LookupResult R(*this, Name, StartLoc, LookupOrdinaryName);
LookupQualifiedName(R, Ctx);
if (R.empty()) {
- if (AllowMissing)
+ if (AllowMissing || !Diagnose)
return false;
return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
<< Name << Range;
@@ -1374,41 +1389,50 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// Watch out for variadic allocator function.
unsigned NumArgsInFnDecl = FnDecl->getNumParams();
for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) {
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
+ FnDecl->getParamDecl(i));
+
+ if (!Diagnose && !CanPerformCopyInitialization(Entity, Owned(Args[i])))
+ return true;
+
ExprResult Result
- = PerformCopyInitialization(InitializedEntity::InitializeParameter(
- Context,
- FnDecl->getParamDecl(i)),
- SourceLocation(),
- Owned(Args[i]));
+ = PerformCopyInitialization(Entity, SourceLocation(), Owned(Args[i]));
if (Result.isInvalid())
return true;
Args[i] = Result.takeAs<Expr>();
}
Operator = FnDecl;
- CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl);
+ CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl,
+ Diagnose);
return false;
}
case OR_No_Viable_Function:
- Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
- << Name << Range;
- Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
+ << Name << Range;
+ Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ }
return true;
case OR_Ambiguous:
- Diag(StartLoc, diag::err_ovl_ambiguous_call)
- << Name << Range;
- Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs);
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ovl_ambiguous_call)
+ << Name << Range;
+ Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs);
+ }
return true;
case OR_Deleted: {
- Diag(StartLoc, diag::err_ovl_deleted_call)
- << Best->Function->isDeleted()
- << Name
- << getDeletedOrUnavailableSuffix(Best->Function)
- << Range;
- Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ovl_deleted_call)
+ << Best->Function->isDeleted()
+ << Name
+ << getDeletedOrUnavailableSuffix(Best->Function)
+ << Range;
+ Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ }
return true;
}
}
@@ -1568,7 +1592,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name,
- FunctionDecl* &Operator) {
+ FunctionDecl* &Operator, bool Diagnose) {
LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName);
// Try to find operator delete/operator delete[] in class scope.
LookupQualifiedName(Found, RD);
@@ -1595,33 +1619,45 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
// There's exactly one suitable operator; pick it.
if (Matches.size() == 1) {
Operator = cast<CXXMethodDecl>(Matches[0]->getUnderlyingDecl());
+
+ if (Operator->isDeleted()) {
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_deleted_function_use);
+ Diag(Operator->getLocation(), diag::note_unavailable_here) << true;
+ }
+ return true;
+ }
+
CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(),
- Matches[0]);
+ Matches[0], Diagnose);
return false;
// We found multiple suitable operators; complain about the ambiguity.
} else if (!Matches.empty()) {
- Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found)
- << Name << RD;
-
- for (llvm::SmallVectorImpl<DeclAccessPair>::iterator
- F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F)
- Diag((*F)->getUnderlyingDecl()->getLocation(),
- diag::note_member_declared_here) << Name;
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found)
+ << Name << RD;
+
+ for (llvm::SmallVectorImpl<DeclAccessPair>::iterator
+ F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F)
+ Diag((*F)->getUnderlyingDecl()->getLocation(),
+ diag::note_member_declared_here) << Name;
+ }
return true;
}
// We did find operator delete/operator delete[] declarations, but
// none of them were suitable.
if (!Found.empty()) {
- Diag(StartLoc, diag::err_no_suitable_delete_member_function_found)
- << Name << RD;
-
- for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
- F != FEnd; ++F)
- Diag((*F)->getUnderlyingDecl()->getLocation(),
- diag::note_member_declared_here) << Name;
-
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_no_suitable_delete_member_function_found)
+ << Name << RD;
+
+ for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
+ F != FEnd; ++F)
+ Diag((*F)->getUnderlyingDecl()->getLocation(),
+ diag::note_member_declared_here) << Name;
+ }
return true;
}
@@ -1633,8 +1669,8 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
Expr* DeallocArgs[1];
DeallocArgs[0] = &Null;
if (FindAllocationOverload(StartLoc, SourceRange(), Name,
- DeallocArgs, 1, TUDecl, /*AllowMissing=*/false,
- Operator))
+ DeallocArgs, 1, TUDecl, !Diagnose,
+ Operator, Diagnose))
return true;
assert(Operator && "Did not find a deallocation function!");
@@ -1780,6 +1816,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
const_cast<CXXDestructorDecl*>(Dtor));
DiagnoseUseOfDecl(Dtor, StartLoc);
}
+
+ // C++ [expr.delete]p3:
+ // In the first alternative (delete object), if the static type of the
+ // object to be deleted is different from its dynamic type, the static
+ // type shall be a base class of the dynamic type of the object to be
+ // deleted and the static type shall have a virtual destructor or the
+ // behavior is undefined.
+ //
+ // Note: a final class cannot be derived from, no issue there
+ if (!ArrayForm && RD->isPolymorphic() && !RD->hasAttr<FinalAttr>()) {
+ CXXDestructorDecl *dtor = RD->getDestructor();
+ if (!dtor || !dtor->isVirtual())
+ Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
+ }
}
if (!OperatorDelete) {
@@ -2174,7 +2224,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Pointer_Conversion: {
if (SCS.IncompatibleObjC && Action != AA_Casting) {
// Diagnose incompatible Objective-C conversions
- if (Action == AA_Initializing)
+ if (Action == AA_Initializing || Action == AA_Assigning)
Diag(From->getSourceRange().getBegin(),
diag::ext_typecheck_convert_incompatible_pointer)
<< ToType << From->getType() << Action
@@ -2184,6 +2234,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Action
<< From->getSourceRange();
+
+ if (From->getType()->isObjCObjectPointerType() &&
+ ToType->isObjCObjectPointerType())
+ EmitRelatedResultTypeNote(From);
}
CastKind Kind = CK_Invalid;
@@ -2416,6 +2470,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
// C++0x [meta.unary.prop] Table 49 requires the following traits to be
// applied to a complete type.
case UTT_IsTrivial:
+ case UTT_IsTriviallyCopyable:
case UTT_IsStandardLayout:
case UTT_IsPOD:
case UTT_IsLiteral:
@@ -2433,7 +2488,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
case UTT_HasNothrowConstructor:
case UTT_HasNothrowCopy:
case UTT_HasTrivialAssign:
- case UTT_HasTrivialConstructor:
+ case UTT_HasTrivialDefaultConstructor:
case UTT_HasTrivialCopy:
case UTT_HasTrivialDestructor:
case UTT_HasVirtualDestructor:
@@ -2512,6 +2567,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return T.isVolatileQualified();
case UTT_IsTrivial:
return T->isTrivialType();
+ case UTT_IsTriviallyCopyable:
+ return T->isTriviallyCopyableType();
case UTT_IsStandardLayout:
return T->isStandardLayoutType();
case UTT_IsPOD:
@@ -2543,7 +2600,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
//
// 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
// 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
- case UTT_HasTrivialConstructor:
+ case UTT_HasTrivialDefaultConstructor:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
// If __is_pod (type) is true then the trait is true, else if type is
// a cv class or union type (or array thereof) with a trivial default
@@ -2552,7 +2609,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return true;
if (const RecordType *RT =
C.getBaseElementType(T)->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor();
+ return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDefaultConstructor();
return false;
case UTT_HasTrivialCopy:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -2619,7 +2676,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return true;
bool FoundAssign = false;
- bool AllNoThrow = true;
DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal);
LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc),
Sema::LookupOrdinaryName);
@@ -2631,15 +2687,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
FoundAssign = true;
const FunctionProtoType *CPT
= Operator->getType()->getAs<FunctionProtoType>();
- if (!CPT->isNothrow(Self.Context)) {
- AllNoThrow = false;
- break;
- }
+ if (CPT->getExceptionSpecType() == EST_Delayed)
+ return false;
+ if (!CPT->isNothrow(Self.Context))
+ return false;
}
}
}
- return FoundAssign && AllNoThrow;
+ return FoundAssign;
}
return false;
case UTT_HasNothrowCopy:
@@ -2656,7 +2712,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return true;
bool FoundConstructor = false;
- bool AllNoThrow = true;
unsigned FoundTQs;
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD);
@@ -2671,16 +2726,16 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
FoundConstructor = true;
const FunctionProtoType *CPT
= Constructor->getType()->getAs<FunctionProtoType>();
+ if (CPT->getExceptionSpecType() == EST_Delayed)
+ return false;
// FIXME: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
- if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) {
- AllNoThrow = false;
- break;
- }
+ if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1)
+ return false;
}
}
- return FoundConstructor && AllNoThrow;
+ return FoundConstructor;
}
return false;
case UTT_HasNothrowConstructor:
@@ -2693,7 +2748,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return true;
if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialConstructor())
+ if (RD->hasTrivialDefaultConstructor())
return true;
DeclContext::lookup_const_iterator Con, ConEnd;
@@ -2706,6 +2761,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (Constructor->isDefaultConstructor()) {
const FunctionProtoType *CPT
= Constructor->getType()->getAs<FunctionProtoType>();
+ if (CPT->getExceptionSpecType() == EST_Delayed)
+ return false;
// TODO: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
@@ -2852,7 +2909,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true);
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
InitializationSequence Init(Self, To, Kind, &FromPtr, 1);
- if (Init.getKind() == InitializationSequence::FailedSequence)
+ if (Init.Failed())
return false;
ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1));
@@ -3213,7 +3270,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
if (TTy.isAtLeastAsQualifiedAs(FTy)) {
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
- if (InitSeq.getKind() != InitializationSequence::FailedSequence) {
+ if (InitSeq) {
HaveConversion = true;
return false;
}
@@ -3238,7 +3295,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
- HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence;
+ HaveConversion = !InitSeq.Failed();
ToType = TTy;
if (InitSeq.isAmbiguous())
return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
@@ -4295,3 +4352,18 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) {
return MaybeCreateStmtWithCleanups(FullStmt);
}
+
+bool Sema::CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS,
+ UnqualifiedId &Name) {
+ DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
+ DeclarationName TargetName = TargetNameInfo.getName();
+ if (!TargetName)
+ return false;
+
+ // Do the redeclaration lookup in the current scope.
+ LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName,
+ Sema::NotForRedeclaration);
+ R.suppressDiagnostics();
+ LookupParsedName(R, getCurScope(), &SS);
+ return !R.empty();
+}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 2a262f093922..cb5c1e0d0cbe 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -119,7 +119,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
return new (Context) ObjCStringLiteral(S, Ty, AtLocs[0]);
}
-Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
+ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
TypeSourceInfo *EncodedTypeInfo,
SourceLocation RParenLoc) {
QualType EncodedType = EncodedTypeInfo->getType();
@@ -127,6 +127,12 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
if (EncodedType->isDependentType())
StrTy = Context.DependentTy;
else {
+ if (!EncodedType->getAsArrayTypeUnsafe()) // Incomplete array is handled.
+ if (RequireCompleteType(AtLoc, EncodedType,
+ PDiag(diag::err_incomplete_type_objc_at_encode)
+ << EncodedTypeInfo->getTypeLoc().getSourceRange()))
+ return ExprError();
+
std::string Str;
Context.getObjCEncodingForType(EncodedType, Str);
@@ -235,10 +241,72 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf() {
return method;
}
+QualType Sema::getMessageSendResultType(QualType ReceiverType,
+ ObjCMethodDecl *Method,
+ bool isClassMessage, bool isSuperMessage) {
+ assert(Method && "Must have a method");
+ if (!Method->hasRelatedResultType())
+ return Method->getSendResultType();
+
+ // If a method has a related return type:
+ // - if the method found is an instance method, but the message send
+ // was a class message send, T is the declared return type of the method
+ // found
+ if (Method->isInstanceMethod() && isClassMessage)
+ return Method->getSendResultType();
+
+ // - if the receiver is super, T is a pointer to the class of the
+ // enclosing method definition
+ if (isSuperMessage) {
+ if (ObjCMethodDecl *CurMethod = getCurMethodDecl())
+ if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface())
+ return Context.getObjCObjectPointerType(
+ Context.getObjCInterfaceType(Class));
+ }
+
+ // - if the receiver is the name of a class U, T is a pointer to U
+ if (ReceiverType->getAs<ObjCInterfaceType>() ||
+ ReceiverType->isObjCQualifiedInterfaceType())
+ return Context.getObjCObjectPointerType(ReceiverType);
+ // - if the receiver is of type Class or qualified Class type,
+ // T is the declared return type of the method.
+ if (ReceiverType->isObjCClassType() ||
+ ReceiverType->isObjCQualifiedClassType())
+ return Method->getSendResultType();
+
+ // - if the receiver is id, qualified id, Class, or qualified Class, T
+ // is the receiver type, otherwise
+ // - T is the type of the receiver expression.
+ return ReceiverType;
+}
+
+void Sema::EmitRelatedResultTypeNote(const Expr *E) {
+ E = E->IgnoreParenImpCasts();
+ const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E);
+ if (!MsgSend)
+ return;
+
+ const ObjCMethodDecl *Method = MsgSend->getMethodDecl();
+ if (!Method)
+ return;
+
+ if (!Method->hasRelatedResultType())
+ return;
+
+ if (Context.hasSameUnqualifiedType(Method->getResultType()
+ .getNonReferenceType(),
+ MsgSend->getType()))
+ return;
+
+ Diag(Method->getLocation(), diag::note_related_result_type_inferred)
+ << Method->isInstanceMethod() << Method->getSelector()
+ << MsgSend->getType();
+}
-bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
+ Expr **Args, unsigned NumArgs,
Selector Sel, ObjCMethodDecl *Method,
- bool isClassMessage,
+ bool isClassMessage, bool isSuperMessage,
SourceLocation lbrac, SourceLocation rbrac,
QualType &ReturnType, ExprValueKind &VK) {
if (!Method) {
@@ -262,7 +330,8 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
return false;
}
- ReturnType = Method->getSendResultType();
+ ReturnType = getMessageSendResultType(ReceiverType, Method, isClassMessage,
+ isSuperMessage);
VK = Expr::getValueKindForType(Method->getResultType());
unsigned NumNamedArgs = Sel.getNumArgs();
@@ -450,9 +519,12 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
ResTy = ResTy.getNonLValueExprType(Context);
Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
- if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
- ResTy = Getter->getResultType();
-
+ if (Getter &&
+ (Getter->hasRelatedResultType()
+ || DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)))
+ ResTy = getMessageSendResultType(QualType(OPT, 0), Getter, false,
+ Super);
+
if (Super)
return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
VK_LValue, OK_ObjCProperty,
@@ -470,14 +542,18 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
+
+ QualType T = PD->getType();
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ T = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
if (Super)
- return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
SuperLoc, SuperType));
else
- return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
@@ -534,7 +610,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (Getter || Setter) {
QualType PType;
if (Getter)
- PType = Getter->getSendResultType();
+ PType = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
else {
ParmVarDecl *ArgDecl = *Setter->param_begin();
PType = ArgDecl->getType();
@@ -608,10 +684,14 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
IdentifierInfo *receiverNamePtr = &receiverName;
ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr,
receiverNameLoc);
+
+ bool IsSuper = false;
if (IFace == 0) {
// If the "receiver" is 'super' in a method, handle it as an expression-like
// property reference.
if (receiverNamePtr->isStr("super")) {
+ IsSuper = true;
+
if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) {
if (CurMethod->isInstanceMethod()) {
QualType T =
@@ -680,7 +760,9 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
ExprValueKind VK = VK_LValue;
if (Getter) {
- PType = Getter->getSendResultType();
+ PType = getMessageSendResultType(Context.getObjCInterfaceType(IFace),
+ Getter, true,
+ receiverNamePtr->isStr("super"));
if (!getLangOptions().CPlusPlus &&
!PType.hasQualifiers() && PType->isVoidType())
VK = VK_RValue;
@@ -693,6 +775,13 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
+ if (IsSuper)
+ return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
+ PType, VK, OK,
+ propertyNameLoc,
+ receiverNameLoc,
+ Context.getObjCInterfaceType(IFace)));
+
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
PType, VK, OK,
propertyNameLoc,
@@ -949,8 +1038,9 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
unsigned NumArgs = ArgsIn.size();
Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
- if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true,
- LBracLoc, RBracLoc, ReturnType, VK))
+ if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, true,
+ SuperLoc.isValid(), LBracLoc, RBracLoc,
+ ReturnType, VK))
return ExprError();
if (Method && !Method->getResultType()->isVoidType() &&
@@ -1232,7 +1322,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
ExprValueKind VK = VK_RValue;
bool ClassMessage = (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType());
- if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, ClassMessage,
+ if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method,
+ ClassMessage, SuperLoc.isValid(),
LBracLoc, RBracLoc, ReturnType, VK))
return ExprError();
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index ca3fd6dfcb45..a33f5d0b2f3e 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -296,8 +296,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
// Do nothing
} else if (Init < NumInits) {
ILE->setInit(Init, MemberInit.takeAs<Expr>());
- } else if (InitSeq.getKind()
- == InitializationSequence::ConstructorInitialization) {
+ } else if (InitSeq.isConstructorInitialization()) {
// Value-initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
@@ -418,8 +417,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
return;
}
- if (InitSeq.getKind()
- == InitializationSequence::ConstructorInitialization) {
+ if (InitSeq.isConstructorInitialization()) {
// Value-initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
@@ -2137,7 +2135,7 @@ bool InitializationSequence::isDirectReferenceBinding() const {
}
bool InitializationSequence::isAmbiguous() const {
- if (getKind() != FailedSequence)
+ if (!Failed())
return false;
switch (getFailureKind()) {
@@ -2310,7 +2308,7 @@ void InitializationSequence::AddArrayInitStep(QualType T) {
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
OverloadingResult Result) {
- SequenceKind = FailedSequence;
+ setSequenceKind(FailedSequence);
this->Failure = Failure;
this->FailedOverloadResult = Result;
}
@@ -2331,7 +2329,6 @@ static void TryListInitialization(Sema &S,
// well-formed. When we actually "perform" list initialization, we'll
// do all of the necessary checking. C++0x initializer lists will
// force us to perform more checking here.
- Sequence.setSequenceKind(InitializationSequence::ListInitialization);
QualType DestType = Entity.getType();
@@ -2800,7 +2797,6 @@ static void TryStringLiteralInitialization(Sema &S,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence) {
- Sequence.setSequenceKind(InitializationSequence::StringInit);
Sequence.AddStringInitStep(Entity.getType());
}
@@ -2813,8 +2809,6 @@ static void TryConstructorInitialization(Sema &S,
Expr **Args, unsigned NumArgs,
QualType DestType,
InitializationSequence &Sequence) {
- Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
-
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
@@ -2947,7 +2941,6 @@ static void TryValueInitialization(Sema &S,
}
Sequence.AddZeroInitializationStep(Entity.getType());
- Sequence.setSequenceKind(InitializationSequence::ZeroInitialization);
}
/// \brief Attempt default initialization (C++ [dcl.init]p6).
@@ -2973,7 +2966,6 @@ static void TryDefaultInitialization(Sema &S,
}
// - otherwise, no initialization is performed.
- Sequence.setSequenceKind(InitializationSequence::NoInitialization);
// If a program calls for the default initialization of an object of
// a const-qualified type T, T shall be a class type with a user-provided
@@ -2990,8 +2982,6 @@ static void TryUserDefinedConversion(Sema &S,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence) {
- Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion);
-
QualType DestType = Entity.getType();
assert(!DestType->isReferenceType() && "References are handled elsewhere");
QualType SourceType = Initializer->getType();
@@ -3176,6 +3166,9 @@ InitializationSequence::InitializationSequence(Sema &S,
return;
}
+ // Almost everything is a normal sequence.
+ setSequenceKind(NormalSequence);
+
for (unsigned I = 0; I != NumArgs; ++I)
if (Args[I]->getObjectKind() == OK_ObjCProperty) {
ExprResult Result = S.ConvertPropertyForRValue(Args[I]);
@@ -3252,7 +3245,6 @@ InitializationSequence::InitializationSequence(Sema &S,
else if (Initializer->HasSideEffects(S.Context))
SetFailed(FK_NonConstantArrayInit);
else {
- setSequenceKind(ArrayInit);
AddArrayInitStep(DestType);
}
} else if (DestAT->getElementType()->isAnyCharacterType())
@@ -3265,7 +3257,6 @@ InitializationSequence::InitializationSequence(Sema &S,
// Handle initialization in C
if (!S.getLangOptions().CPlusPlus) {
- setSequenceKind(CAssignment);
AddCAssignmentStep(DestType);
return;
}
@@ -3325,8 +3316,6 @@ InitializationSequence::InitializationSequence(Sema &S,
else
SetFailed(InitializationSequence::FK_ConversionFailed);
}
- else
- setSequenceKind(StandardConversion);
}
InitializationSequence::~InitializationSequence() {
@@ -3650,13 +3639,13 @@ InitializationSequence::Perform(Sema &S,
const InitializationKind &Kind,
MultiExprArg Args,
QualType *ResultType) {
- if (SequenceKind == FailedSequence) {
+ if (Failed()) {
unsigned NumArgs = Args.size();
Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs);
return ExprError();
}
- if (SequenceKind == DependentSequence) {
+ if (getKind() == DependentSequence) {
// If the declaration is a non-dependent, incomplete array type
// that has an initializer, then its type will be completed once
// the initializer is instantiated.
@@ -3710,7 +3699,8 @@ InitializationSequence::Perform(Sema &S,
SourceLocation()));
}
- if (SequenceKind == NoInitialization)
+ // No steps means no initialization.
+ if (Steps.empty())
return S.Owned((Expr *)0);
QualType DestType = Entity.getType().getNonReferenceType();
@@ -3723,8 +3713,6 @@ InitializationSequence::Perform(Sema &S,
ExprResult CurInit = S.Owned((Expr *)0);
- assert(!Steps.empty() && "Cannot have an empty initialization sequence");
-
// For initialization steps that start with a single initializer,
// grab the only argument out the Args and place it into the "current"
// initializer.
@@ -4019,8 +4007,9 @@ InitializationSequence::Perform(Sema &S,
// the definition for completely trivial constructors.
CXXRecordDecl *ClassDecl = Constructor->getParent();
assert(ClassDecl && "No parent class for constructor.");
- if (Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
- ClassDecl->hasTrivialConstructor() && !Constructor->isUsed(false))
+ if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
+ ClassDecl->hasTrivialDefaultConstructor() &&
+ !Constructor->isUsed(false))
S.DefineImplicitDefaultConstructor(Loc, Constructor);
}
@@ -4060,8 +4049,7 @@ InitializationSequence::Perform(Sema &S,
ConstructKind = Entity.getBaseSpecifier()->isVirtual() ?
CXXConstructExpr::CK_VirtualBase :
CXXConstructExpr::CK_NonVirtualBase;
- }
- if (Entity.getKind() == InitializedEntity::EK_Delegating) {
+ } else if (Entity.getKind() == InitializedEntity::EK_Delegating) {
ConstructKind = CXXConstructExpr::CK_Delegating;
}
@@ -4216,7 +4204,7 @@ bool InitializationSequence::Diagnose(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr **Args, unsigned NumArgs) {
- if (SequenceKind != FailedSequence)
+ if (!Failed())
return false;
QualType DestType = Entity.getType();
@@ -4334,6 +4322,9 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->isLValue()
<< Args[0]->getType()
<< Args[0]->getSourceRange();
+ if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
+ Args[0]->getType()->isObjCObjectPointerType())
+ S.EmitRelatedResultTypeNote(Args[0]);
break;
case FK_ConversionFailed: {
@@ -4344,6 +4335,9 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->isLValue()
<< FromType
<< Args[0]->getSourceRange();
+ if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
+ Args[0]->getType()->isObjCObjectPointerType())
+ S.EmitRelatedResultTypeNote(Args[0]);
break;
}
@@ -4587,48 +4581,16 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
}
case DependentSequence:
- OS << "Dependent sequence: ";
+ OS << "Dependent sequence\n";
return;
- case UserDefinedConversion:
- OS << "User-defined conversion sequence: ";
- break;
-
- case ConstructorInitialization:
- OS << "Constructor initialization sequence: ";
+ case NormalSequence:
+ OS << "Normal sequence: ";
break;
case ReferenceBinding:
OS << "Reference binding: ";
break;
-
- case ListInitialization:
- OS << "List initialization: ";
- break;
-
- case ZeroInitialization:
- OS << "Zero initialization\n";
- return;
-
- case NoInitialization:
- OS << "No initialization\n";
- return;
-
- case StandardConversion:
- OS << "Standard conversion: ";
- break;
-
- case CAssignment:
- OS << "C assignment: ";
- break;
-
- case StringInit:
- OS << "String initialization: ";
- break;
-
- case ArrayInit:
- OS << "Array initialization: ";
- break;
}
for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) {
@@ -4723,6 +4685,21 @@ void InitializationSequence::dump() const {
//===----------------------------------------------------------------------===//
// Initialization helper functions
//===----------------------------------------------------------------------===//
+bool
+Sema::CanPerformCopyInitialization(const InitializedEntity &Entity,
+ ExprResult Init) {
+ if (Init.isInvalid())
+ return false;
+
+ Expr *InitE = Init.get();
+ assert(InitE && "No initialization expression");
+
+ InitializationKind Kind = InitializationKind::CreateCopy(SourceLocation(),
+ SourceLocation());
+ InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
+ return !Seq.Failed();
+}
+
ExprResult
Sema::PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 309c7712d4cc..92ade1efcf01 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -14,6 +14,7 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Overload.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
@@ -534,7 +535,7 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
return;
// If the default constructor has not yet been declared, do so now.
- if (!Class->hasDeclaredDefaultConstructor())
+ if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
// If the copy constructor has not yet been declared, do so now.
@@ -581,7 +582,7 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
if (Record->getDefinition() &&
CanDeclareSpecialMemberFunction(S.Context, Record)) {
- if (!Record->hasDeclaredDefaultConstructor())
+ if (Record->needsImplicitDefaultConstructor())
S.DeclareImplicitDefaultConstructor(
const_cast<CXXRecordDecl *>(Record));
if (!Record->hasDeclaredCopyConstructor())
@@ -2136,11 +2137,200 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
}
}
+Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
+ CXXSpecialMember SM,
+ bool ConstArg,
+ bool VolatileArg,
+ bool RValueThis,
+ bool ConstThis,
+ bool VolatileThis) {
+ D = D->getDefinition();
+ assert((D && !D->isBeingDefined()) &&
+ "doing special member lookup into record that isn't fully complete");
+ if (RValueThis || ConstThis || VolatileThis)
+ assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) &&
+ "constructors and destructors always have unqualified lvalue this");
+ if (ConstArg || VolatileArg)
+ assert((SM != CXXDefaultConstructor && SM != CXXDestructor) &&
+ "parameter-less special members can't have qualified arguments");
+
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(D);
+ ID.AddInteger(SM);
+ ID.AddInteger(ConstArg);
+ ID.AddInteger(VolatileArg);
+ ID.AddInteger(RValueThis);
+ ID.AddInteger(ConstThis);
+ ID.AddInteger(VolatileThis);
+
+ void *InsertPoint;
+ SpecialMemberOverloadResult *Result =
+ SpecialMemberCache.FindNodeOrInsertPos(ID, InsertPoint);
+
+ // This was already cached
+ if (Result)
+ return Result;
+
+ Result = BumpAlloc.Allocate<SpecialMemberOverloadResult>();
+ Result = new (Result) SpecialMemberOverloadResult(ID);
+ SpecialMemberCache.InsertNode(Result, InsertPoint);
+
+ if (SM == CXXDestructor) {
+ if (!D->hasDeclaredDestructor())
+ DeclareImplicitDestructor(D);
+ CXXDestructorDecl *DD = D->getDestructor();
+ assert(DD && "record without a destructor");
+ Result->setMethod(DD);
+ Result->setSuccess(DD->isDeleted());
+ Result->setConstParamMatch(false);
+ return Result;
+ }
+
+ // Prepare for overload resolution. Here we construct a synthetic argument
+ // if necessary and make sure that implicit functions are declared.
+ CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(D));
+ DeclarationName Name;
+ Expr *Arg = 0;
+ unsigned NumArgs;
+
+ if (SM == CXXDefaultConstructor) {
+ Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
+ NumArgs = 0;
+ if (D->needsImplicitDefaultConstructor())
+ DeclareImplicitDefaultConstructor(D);
+ } else {
+ if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
+ Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
+ if (!D->hasDeclaredCopyConstructor())
+ DeclareImplicitCopyConstructor(D);
+ // TODO: Move constructors
+ } else {
+ Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+ if (!D->hasDeclaredCopyAssignment())
+ DeclareImplicitCopyAssignment(D);
+ // TODO: Move assignment
+ }
+
+ QualType ArgType = CanTy;
+ if (ConstArg)
+ ArgType.addConst();
+ if (VolatileArg)
+ ArgType.addVolatile();
+
+ // This isn't /really/ specified by the standard, but it's implied
+ // we should be working from an RValue in the case of move to ensure
+ // that we prefer to bind to rvalue references, and an LValue in the
+ // case of copy to ensure we don't bind to rvalue references.
+ // Possibly an XValue is actually correct in the case of move, but
+ // there is no semantic difference for class types in this restricted
+ // case.
+ ExprValueKind VK;
+ if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
+ VK = VK_LValue;
+ else
+ VK = VK_RValue;
+
+ NumArgs = 1;
+ Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType, VK);
+ }
+
+ // Create the object argument
+ QualType ThisTy = CanTy;
+ if (ConstThis)
+ ThisTy.addConst();
+ if (VolatileThis)
+ ThisTy.addVolatile();
+ Expr::Classification ObjectClassification =
+ (new (Context) OpaqueValueExpr(SourceLocation(), ThisTy,
+ RValueThis ? VK_RValue : VK_LValue))->
+ Classify(Context);
+
+ // Now we perform lookup on the name we computed earlier and do overload
+ // resolution. Lookup is only performed directly into the class since there
+ // will always be a (possibly implicit) declaration to shadow any others.
+ OverloadCandidateSet OCS((SourceLocation()));
+ DeclContext::lookup_iterator I, E;
+ Result->setConstParamMatch(false);
+
+ llvm::tie(I, E) = D->lookup(Name);
+ assert((I != E) &&
+ "lookup for a constructor or assignment operator was empty");
+ for ( ; I != E; ++I) {
+ if ((*I)->isInvalidDecl())
+ continue;
+
+ if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) {
+ AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg, NumArgs,
+ OCS, true);
+
+ // Here we're looking for a const parameter to speed up creation of
+ // implicit copy methods.
+ if ((SM == CXXCopyAssignment && M->isCopyAssignmentOperator()) ||
+ (SM == CXXCopyConstructor &&
+ cast<CXXConstructorDecl>(M)->isCopyConstructor())) {
+ QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0);
+ if (ArgType->getPointeeType().isConstQualified())
+ Result->setConstParamMatch(true);
+ }
+ } else {
+ FunctionTemplateDecl *Tmpl = cast<FunctionTemplateDecl>(*I);
+ AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
+ 0, &Arg, NumArgs, OCS, true);
+ }
+ }
+
+ OverloadCandidateSet::iterator Best;
+ switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) {
+ case OR_Success:
+ Result->setMethod(cast<CXXMethodDecl>(Best->Function));
+ Result->setSuccess(true);
+ break;
+
+ case OR_Deleted:
+ Result->setMethod(cast<CXXMethodDecl>(Best->Function));
+ Result->setSuccess(false);
+ break;
+
+ case OR_Ambiguous:
+ case OR_No_Viable_Function:
+ Result->setMethod(0);
+ Result->setSuccess(false);
+ break;
+ }
+
+ return Result;
+}
+
+/// \brief Look up the default constructor for the given class.
+CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) {
+ SpecialMemberOverloadResult *Result =
+ LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false,
+ false, false);
+
+ return cast_or_null<CXXConstructorDecl>(Result->getMethod());
+}
+
+/// \brief Look up the copy constructor for the given class.
+CXXConstructorDecl *Sema::LookupCopyConstructor(CXXRecordDecl *Class,
+ unsigned Quals,
+ bool *ConstParamMatch) {
+ assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
+ "non-const, non-volatile qualifiers for copy ctor arg");
+ SpecialMemberOverloadResult *Result =
+ LookupSpecialMember(Class, CXXCopyConstructor, Quals & Qualifiers::Const,
+ Quals & Qualifiers::Volatile, false, false, false);
+
+ if (ConstParamMatch)
+ *ConstParamMatch = Result->hasConstParamMatch();
+
+ return cast_or_null<CXXConstructorDecl>(Result->getMethod());
+}
+
/// \brief Look up the constructors for the given class.
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
- // If the copy constructor has not yet been declared, do so now.
+ // If the implicit constructors have not yet been declared, do so now.
if (CanDeclareSpecialMemberFunction(Context, Class)) {
- if (!Class->hasDeclaredDefaultConstructor())
+ if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
if (!Class->hasDeclaredCopyConstructor())
DeclareImplicitCopyConstructor(Class);
@@ -2158,12 +2348,9 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
///
/// \returns The destructor for this class.
CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
- // If the destructor has not yet been declared, do so now.
- if (CanDeclareSpecialMemberFunction(Context, Class) &&
- !Class->hasDeclaredDestructor())
- DeclareImplicitDestructor(Class);
-
- return Class->getDestructor();
+ return cast<CXXDestructorDecl>(LookupSpecialMember(Class, CXXDestructor,
+ false, false, false,
+ false, false)->getMethod());
}
void ADLResult::insert(NamedDecl *New) {
@@ -2410,8 +2597,8 @@ VisibleDeclsRecord::ShadowMapEntry::end() {
if (DeclOrVector.isNull())
return 0;
- if (DeclOrVector.dyn_cast<NamedDecl *>())
- return &reinterpret_cast<NamedDecl*&>(DeclOrVector) + 1;
+ if (DeclOrVector.is<NamedDecl *>())
+ return DeclOrVector.getAddrOf<NamedDecl *>() + 1;
return DeclOrVector.get<DeclVector *>()->end();
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 3f3ed0e1f902..4bba6f8877bf 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1628,6 +1628,15 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
return true;
}
+ // MSVC allows implicit function to void* type conversion.
+ if (getLangOptions().Microsoft && FromPointeeType->isFunctionType() &&
+ ToPointeeType->isVoidType()) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
// When we're overloading in C, we allow a special kind of pointer
// conversion for compatible-but-not-identical pointee types.
if (!getLangOptions().CPlusPlus &&
@@ -2197,6 +2206,13 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
Qualifiers FromQuals = FromType.getQualifiers();
Qualifiers ToQuals = ToType.getQualifiers();
+ // Allow addition/removal of GC attributes but not changing GC attributes.
+ if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
+ (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
+ FromQuals.removeObjCGCAttr();
+ ToQuals.removeObjCGCAttr();
+ }
+
// -- for every j > 0, if const is in cv 1,j then const is in cv
// 2,j, and similarly for volatile.
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
@@ -2507,12 +2523,10 @@ compareStandardConversionSubsets(ASTContext &Context,
// the identity conversion sequence is considered to be a subsequence of
// any non-identity conversion sequence
- if (SCS1.ReferenceBinding == SCS2.ReferenceBinding) {
- if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion())
- return ImplicitConversionSequence::Better;
- else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion())
- return ImplicitConversionSequence::Worse;
- }
+ if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion())
+ return ImplicitConversionSequence::Better;
+ else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion())
+ return ImplicitConversionSequence::Worse;
if (SCS1.Second != SCS2.Second) {
if (SCS1.Second == ICK_Identity)
@@ -4689,6 +4703,10 @@ class BuiltinCandidateTypeSet {
/// were present in the candidate set.
bool HasArithmeticOrEnumeralTypes;
+ /// \brief A flag indicating whether the nullptr type was present in the
+ /// candidate set.
+ bool HasNullPtrType;
+
/// Sema - The semantic analysis instance where we are building the
/// candidate type set.
Sema &SemaRef;
@@ -4707,6 +4725,7 @@ public:
BuiltinCandidateTypeSet(Sema &SemaRef)
: HasNonRecordTypes(false),
HasArithmeticOrEnumeralTypes(false),
+ HasNullPtrType(false),
SemaRef(SemaRef),
Context(SemaRef.Context) { }
@@ -4739,6 +4758,7 @@ public:
bool hasNonRecordTypes() { return HasNonRecordTypes; }
bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; }
+ bool hasNullPtrType() const { return HasNullPtrType; }
};
/// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to
@@ -4899,6 +4919,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
// extension.
HasArithmeticOrEnumeralTypes = true;
VectorTypes.insert(Ty);
+ } else if (Ty->isNullPtrType()) {
+ HasNullPtrType = true;
} else if (AllowUserConversions && TyRec) {
// No conversion functions in incomplete types.
if (SemaRef.RequireCompleteType(Loc, Ty, 0))
@@ -5358,8 +5380,8 @@ public:
// C++ [over.built]p15:
//
- // For every pointer or enumeration type T, there exist
- // candidate operator functions of the form
+ // For every T, where T is an enumeration type, a pointer type, or
+ // std::nullptr_t, there exist candidate operator functions of the form
//
// bool operator<(T, T);
// bool operator>(T, T);
@@ -5444,6 +5466,17 @@ public:
S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2,
CandidateSet);
}
+
+ if (CandidateTypes[ArgIdx].hasNullPtrType()) {
+ CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy);
+ if (AddedTypes.insert(NullPtrTy) &&
+ !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy,
+ NullPtrTy))) {
+ QualType ParamTypes[2] = { NullPtrTy, NullPtrTy };
+ S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2,
+ CandidateSet);
+ }
+ }
}
}
@@ -6401,7 +6434,9 @@ enum OverloadCandidateKind {
oc_constructor_template,
oc_implicit_default_constructor,
oc_implicit_copy_constructor,
+ oc_implicit_move_constructor,
oc_implicit_copy_assignment,
+ oc_implicit_move_assignment,
oc_implicit_inherited_constructor
};
@@ -6423,8 +6458,15 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
if (Ctor->getInheritedConstructor())
return oc_implicit_inherited_constructor;
- return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor
- : oc_implicit_default_constructor;
+ if (Ctor->isDefaultConstructor())
+ return oc_implicit_default_constructor;
+
+ if (Ctor->isMoveConstructor())
+ return oc_implicit_move_constructor;
+
+ assert(Ctor->isCopyConstructor() &&
+ "unexpected sort of implicit constructor");
+ return oc_implicit_copy_constructor;
}
if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) {
@@ -6433,6 +6475,9 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
if (!Meth->isImplicit())
return isTemplate ? oc_method_template : oc_method;
+ if (Meth->isMoveAssignmentOperator())
+ return oc_implicit_move_assignment;
+
assert(Meth->isCopyAssignmentOperator()
&& "implicit method is not copy assignment operator?");
return oc_implicit_copy_assignment;
@@ -6676,6 +6721,15 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned MinParams = Fn->getMinRequiredArguments();
+ // With invalid overloaded operators, it's possible that we think we
+ // have an arity mismatch when it fact it looks like we have the
+ // right number of arguments, because only overloaded operators have
+ // the weird behavior of overloading member and non-member functions.
+ // Just don't report anything.
+ if (Fn->isInvalidDecl() &&
+ Fn->getDeclName().getNameKind() == DeclarationName::CXXOperatorName)
+ return;
+
// at least / at most / exactly
unsigned mode, modeCount;
if (NumFormalArgs < MinParams) {
@@ -7772,6 +7826,111 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
ULE->isStdAssociatedNamespace());
}
+/// Attempt to recover from an ill-formed use of a non-dependent name in a
+/// template, where the non-dependent name was declared after the template
+/// was defined. This is common in code written for a compilers which do not
+/// correctly implement two-stage name lookup.
+///
+/// Returns true if a viable candidate was found and a diagnostic was issued.
+static bool
+DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
+ const CXXScopeSpec &SS, LookupResult &R,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
+ Expr **Args, unsigned NumArgs) {
+ if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty())
+ return false;
+
+ for (DeclContext *DC = SemaRef.CurContext; DC; DC = DC->getParent()) {
+ SemaRef.LookupQualifiedName(R, DC);
+
+ if (!R.empty()) {
+ R.suppressDiagnostics();
+
+ if (isa<CXXRecordDecl>(DC)) {
+ // Don't diagnose names we find in classes; we get much better
+ // diagnostics for these from DiagnoseEmptyLookup.
+ R.clear();
+ return false;
+ }
+
+ OverloadCandidateSet Candidates(FnLoc);
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ AddOverloadedCallCandidate(SemaRef, I.getPair(),
+ ExplicitTemplateArgs, Args, NumArgs,
+ Candidates, false);
+
+ OverloadCandidateSet::iterator Best;
+ if (Candidates.BestViableFunction(SemaRef, FnLoc, Best) != OR_Success)
+ // No viable functions. Don't bother the user with notes for functions
+ // which don't work and shouldn't be found anyway.
+ return false;
+
+ // Find the namespaces where ADL would have looked, and suggest
+ // declaring the function there instead.
+ Sema::AssociatedNamespaceSet AssociatedNamespaces;
+ Sema::AssociatedClassSet AssociatedClasses;
+ SemaRef.FindAssociatedClassesAndNamespaces(Args, NumArgs,
+ AssociatedNamespaces,
+ AssociatedClasses);
+ // Never suggest declaring a function within namespace 'std'.
+ Sema::AssociatedNamespaceSet SuggestedNamespaces;
+ if (DeclContext *Std = SemaRef.getStdNamespace()) {
+ for (Sema::AssociatedNamespaceSet::iterator
+ it = AssociatedNamespaces.begin(),
+ end = AssociatedNamespaces.end(); it != end; ++it) {
+ if (!Std->Encloses(*it))
+ SuggestedNamespaces.insert(*it);
+ }
+ } else {
+ // Lacking the 'std::' namespace, use all of the associated namespaces.
+ SuggestedNamespaces = AssociatedNamespaces;
+ }
+
+ SemaRef.Diag(R.getNameLoc(), diag::err_not_found_by_two_phase_lookup)
+ << R.getLookupName();
+ if (SuggestedNamespaces.empty()) {
+ SemaRef.Diag(Best->Function->getLocation(),
+ diag::note_not_found_by_two_phase_lookup)
+ << R.getLookupName() << 0;
+ } else if (SuggestedNamespaces.size() == 1) {
+ SemaRef.Diag(Best->Function->getLocation(),
+ diag::note_not_found_by_two_phase_lookup)
+ << R.getLookupName() << 1 << *SuggestedNamespaces.begin();
+ } else {
+ // FIXME: It would be useful to list the associated namespaces here,
+ // but the diagnostics infrastructure doesn't provide a way to produce
+ // a localized representation of a list of items.
+ SemaRef.Diag(Best->Function->getLocation(),
+ diag::note_not_found_by_two_phase_lookup)
+ << R.getLookupName() << 2;
+ }
+
+ // Try to recover by calling this function.
+ return true;
+ }
+
+ R.clear();
+ }
+
+ return false;
+}
+
+/// Attempt to recover from ill-formed use of a non-dependent operator in a
+/// template, where the non-dependent operator was declared after the template
+/// was defined.
+///
+/// Returns true if a viable candidate was found and a diagnostic was issued.
+static bool
+DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
+ SourceLocation OpLoc,
+ Expr **Args, unsigned NumArgs) {
+ DeclarationName OpName =
+ SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
+ LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName);
+ return DiagnoseTwoPhaseLookup(SemaRef, OpLoc, CXXScopeSpec(), R,
+ /*ExplicitTemplateArgs=*/0, Args, NumArgs);
+}
+
/// Attempts to recover from a call where no functions were found.
///
/// Returns true if new candidates were found.
@@ -7780,13 +7939,14 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool EmptyLookup) {
CXXScopeSpec SS;
SS.Adopt(ULE->getQualifierLoc());
TemplateArgumentListInfo TABuffer;
- const TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
+ TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
if (ULE->hasExplicitTemplateArgs()) {
ULE->copyTemplateArgumentsInto(TABuffer);
ExplicitTemplateArgs = &TABuffer;
@@ -7794,7 +7954,10 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
- if (SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression))
+ if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
+ ExplicitTemplateArgs, Args, NumArgs) &&
+ (!EmptyLookup ||
+ SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression)))
return ExprError();
assert(!R.empty() && "lookup results empty despite recovery");
@@ -7814,7 +7977,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
return ExprError();
// This shouldn't cause an infinite loop because we're giving it
- // an expression with non-empty lookup results, which should never
+ // an expression with viable lookup results, which should never
// end up here.
return SemaRef.ActOnCallExpr(/*Scope*/ 0, NewFn.take(), LParenLoc,
MultiExprArg(Args, NumArgs), RParenLoc);
@@ -7860,11 +8023,11 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet);
// If we found nothing, try to recover.
- // AddRecoveryCallCandidates diagnoses the error itself, so we just
- // bailout out if it fails.
+ // BuildRecoveryCallExpr diagnoses the error itself, so we just bail
+ // out if it fails.
if (CandidateSet.empty())
return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs,
- RParenLoc);
+ RParenLoc, /*EmptyLookup=*/true);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) {
@@ -7879,12 +8042,21 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
ExecConfig);
}
- case OR_No_Viable_Function:
+ case OR_No_Viable_Function: {
+ // Try to recover by looking for viable functions which the user might
+ // have meant to call.
+ ExprResult Recovery = BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc,
+ Args, NumArgs, RParenLoc,
+ /*EmptyLookup=*/false);
+ if (!Recovery.isInvalid())
+ return Recovery;
+
Diag(Fn->getSourceRange().getBegin(),
diag::err_ovl_no_viable_function_in_call)
<< ULE->getName() << Fn->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
break;
+ }
case OR_Ambiguous:
Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call)
@@ -8073,6 +8245,13 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
}
case OR_No_Viable_Function:
+ // This is an erroneous use of an operator which can be overloaded by
+ // a non-member function. Check for non-member operators which were
+ // defined too late to be candidates.
+ if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, NumArgs))
+ // FIXME: Recover by calling the found function.
+ return ExprError();
+
// No viable function; fall through to handling this as a
// built-in operator, which will produce an error message for us.
break;
@@ -8354,6 +8533,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
} else {
+ // This is an erroneous use of an operator which can be overloaded by
+ // a non-member function. Check for non-member operators which were
+ // defined too late to be candidates.
+ if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, 2))
+ // FIXME: Recover by calling the found function.
+ return ExprError();
+
// No viable function; try to create a built-in operation, which will
// produce an error. Then, show the non-viable candidates.
Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
@@ -8772,6 +8958,19 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
if (CheckFunctionCall(Method, TheCall))
return ExprError();
+ if ((isa<CXXConstructorDecl>(CurContext) ||
+ isa<CXXDestructorDecl>(CurContext)) &&
+ TheCall->getMethodDecl()->isPure()) {
+ const CXXMethodDecl *MD = TheCall->getMethodDecl();
+
+ if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts()))
+ Diag(MemExpr->getLocStart(),
+ diag::warn_call_to_pure_virtual_member_function_from_ctor_dtor)
+ << MD->getDeclName() << isa<CXXDestructorDecl>(CurContext)
+ << MD->getParent()->getDeclName();
+
+ Diag(MD->getLocStart(), diag::note_previous_decl) << MD->getDeclName();
+ }
return MaybeBindToTemporary(TheCall);
}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 65cea7a69d61..d7c0a543eede 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -501,7 +501,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
unsigned CondWidth
= HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion);
- bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerType();
+ bool CondIsSigned
+ = CondTypeBeforePromotion->isSignedIntegerOrEnumerationType();
// Accumulate all of the case values in a vector so that we can sort them
// and detect duplicates. This vector contains the APInt for the case after
@@ -723,7 +724,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// If switch has default case, then ignore it.
if (!CaseListIsErroneous && !HasConstantCond && ET) {
const EnumDecl *ED = ET->getDecl();
- typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
+ typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64>
+ EnumValsTy;
EnumValsTy EnumVals;
// Gather all enum values, set their type and sort them,
@@ -1252,7 +1254,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
ExprResult BoundExpr;
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT))
BoundExpr = Owned(IntegerLiteral::Create(Context, CAT->getSize(),
- Context.IntTy, RangeLoc));
+ Context.getPointerDiffType(),
+ RangeLoc));
else if (const VariableArrayType *VAT =
dyn_cast<VariableArrayType>(UnqAT))
BoundExpr = VAT->getSizeExpr();
@@ -1455,7 +1458,10 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
/// \param E The expression being returned from the function or block, or
/// being thrown.
///
-/// \param AllowFunctionParameter
+/// \param AllowFunctionParameter Whether we allow function parameters to
+/// be considered NRVO candidates. C++ prohibits this for NRVO itself, but
+/// we re-use this logic to determine whether we should try to move as part of
+/// a return or throw (which does allow function parameters).
///
/// \returns The NRVO candidate variable, if the return statement may use the
/// NRVO, or NULL if there is no such candidate.
@@ -1525,12 +1531,11 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
// parameter of the selected constructor is not an rvalue reference
// to the object's type (possibly cv-qualified), overload resolution
// is performed again, considering the object as an lvalue.
- if (Seq.getKind() != InitializationSequence::FailedSequence) {
+ if (Seq) {
for (InitializationSequence::step_iterator Step = Seq.step_begin(),
StepEnd = Seq.step_end();
Step != StepEnd; ++Step) {
- if (Step->Kind
- != InitializationSequence::SK_ConstructorInitialization)
+ if (Step->Kind != InitializationSequence::SK_ConstructorInitialization)
continue;
CXXConstructorDecl *Constructor
@@ -1583,14 +1588,18 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (Result.isInvalid())
return StmtError();
RetValExp = Result.take();
- CurBlock->ReturnType = RetValExp->getType();
- if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
- // We have to remove a 'const' added to copied-in variable which was
- // part of the implementation spec. and not the actual qualifier for
- // the variable.
- if (CDRE->isConstQualAdded())
- CurBlock->ReturnType.removeLocalConst(); // FIXME: local???
- }
+
+ if (!RetValExp->isTypeDependent()) {
+ CurBlock->ReturnType = RetValExp->getType();
+ if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
+ // We have to remove a 'const' added to copied-in variable which was
+ // part of the implementation spec. and not the actual qualifier for
+ // the variable.
+ if (CDRE->isConstQualAdded())
+ CurBlock->ReturnType.removeLocalConst(); // FIXME: local???
+ }
+ } else
+ CurBlock->ReturnType = Context.DependentTy;
} else
CurBlock->ReturnType = Context.VoidTy;
}
@@ -1607,13 +1616,17 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// compatibility to worry about here.
ReturnStmt *Result = 0;
if (CurBlock->ReturnType->isVoidType()) {
- if (RetValExp) {
+ if (RetValExp && !RetValExp->isTypeDependent() &&
+ (!getLangOptions().CPlusPlus || !RetValExp->getType()->isVoidType())) {
Diag(ReturnLoc, diag::err_return_block_has_expr);
RetValExp = 0;
}
Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
} else if (!RetValExp) {
- return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
+ if (!CurBlock->ReturnType->isDependentType())
+ return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
+
+ Result = new (Context) ReturnStmt(ReturnLoc, 0, 0);
} else {
const VarDecl *NRVOCandidate = 0;
@@ -1652,7 +1665,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// If we need to check for the named return value optimization, save the
// return statement in our scope for later processing.
- if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
+ if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
!CurContext->isDependentContext())
FunctionScopes.back()->Returns.push_back(Result);
@@ -1661,44 +1674,62 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
StmtResult
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
+ // Check for unexpanded parameter packs.
+ if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
+ return StmtError();
+
if (getCurBlock())
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
QualType FnRetType;
+ QualType DeclaredRetType;
if (const FunctionDecl *FD = getCurFunctionDecl()) {
FnRetType = FD->getResultType();
+ DeclaredRetType = FnRetType;
if (FD->hasAttr<NoReturnAttr>() ||
FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
<< getCurFunctionOrMethodDecl()->getDeclName();
- } else if (ObjCMethodDecl *MD = getCurMethodDecl())
- FnRetType = MD->getResultType();
- else // If we don't have a function/method context, bail.
+ } else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
+ DeclaredRetType = MD->getResultType();
+ if (MD->hasRelatedResultType() && MD->getClassInterface()) {
+ // In the implementation of a method with a related return type, the
+ // type used to type-check the validity of return statements within the
+ // method body is a pointer to the type of the class being implemented.
+ FnRetType = Context.getObjCInterfaceType(MD->getClassInterface());
+ FnRetType = Context.getObjCObjectPointerType(FnRetType);
+ } else {
+ FnRetType = DeclaredRetType;
+ }
+ } else // If we don't have a function/method context, bail.
return StmtError();
ReturnStmt *Result = 0;
if (FnRetType->isVoidType()) {
- if (RetValExp && !RetValExp->isTypeDependent()) {
- // C99 6.8.6.4p1 (ext_ since GCC warns)
- unsigned D = diag::ext_return_has_expr;
- if (RetValExp->getType()->isVoidType())
- D = diag::ext_return_has_void_expr;
- else {
- ExprResult Result = Owned(RetValExp);
- Result = IgnoredValueConversions(Result.take());
- if (Result.isInvalid())
- return StmtError();
- RetValExp = Result.take();
- RetValExp = ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid).take();
- }
+ if (RetValExp) {
+ if (!RetValExp->isTypeDependent()) {
+ // C99 6.8.6.4p1 (ext_ since GCC warns)
+ unsigned D = diag::ext_return_has_expr;
+ if (RetValExp->getType()->isVoidType())
+ D = diag::ext_return_has_void_expr;
+ else {
+ ExprResult Result = Owned(RetValExp);
+ Result = IgnoredValueConversions(Result.take());
+ if (Result.isInvalid())
+ return StmtError();
+ RetValExp = Result.take();
+ RetValExp = ImpCastExprToType(RetValExp,
+ Context.VoidTy, CK_ToVoid).take();
+ }
- // return (some void expression); is legal in C++.
- if (D != diag::ext_return_has_void_expr ||
- !getLangOptions().CPlusPlus) {
- NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
- Diag(ReturnLoc, D)
- << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl)
- << RetValExp->getSourceRange();
+ // return (some void expression); is legal in C++.
+ if (D != diag::ext_return_has_void_expr ||
+ !getLangOptions().CPlusPlus) {
+ NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
+ Diag(ReturnLoc, D)
+ << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl)
+ << RetValExp->getSourceRange();
+ }
}
CheckImplicitConversions(RetValExp, ReturnLoc);
@@ -1730,7 +1761,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
FnRetType,
- NRVOCandidate != 0);
+ NRVOCandidate != 0);
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
FnRetType, RetValExp);
if (Res.isInvalid()) {
@@ -1744,6 +1775,17 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
if (RetValExp) {
+ // If we type-checked an Objective-C method's return type based
+ // on a related return type, we may need to adjust the return
+ // type again. Do so now.
+ if (DeclaredRetType != FnRetType) {
+ ExprResult result = PerformImplicitConversion(RetValExp,
+ DeclaredRetType,
+ AA_Returning);
+ if (result.isInvalid()) return StmtError();
+ RetValExp = result.take();
+ }
+
CheckImplicitConversions(RetValExp, ReturnLoc);
RetValExp = MaybeCreateExprWithCleanups(RetValExp);
}
@@ -2015,7 +2057,9 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (InputDomain == AD_Int && OutputDomain == AD_Int &&
!isOperandMentioned(InputOpNo, Pieces) &&
InputExpr->isEvaluatable(Context)) {
- InputExpr = ImpCastExprToType(InputExpr, OutTy, CK_IntegralCast).take();
+ CastKind castKind =
+ (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
+ InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take();
Exprs[InputOpNo] = InputExpr;
NS->setInputExpr(i, InputExpr);
continue;
@@ -2251,7 +2295,9 @@ Sema::ActOnSEHExceptBlock(SourceLocation Loc,
assert(FilterExpr && Block);
if(!FilterExpr->getType()->isIntegerType()) {
- return StmtError(Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FilterExpr->getType());
+ return StmtError(Diag(FilterExpr->getExprLoc(),
+ diag::err_filter_expression_integral)
+ << FilterExpr->getType());
}
return Owned(SEHExceptStmt::Create(Context,Loc,FilterExpr,Block));
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ef0912485b66..5d4caacd8124 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -92,11 +92,9 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
// ambiguity in certain cases (for example, if it is found in more than
// one base class). If all of the injected-class-names that are found
// refer to specializations of the same class template, and if the name
- // is followed by a template-argument-list, the reference refers to the
- // class template itself and not a specialization thereof, and is not
+ // is used as a template-name, the reference refers to the class
+ // template itself and not a specialization thereof, and is not
// ambiguous.
- //
- // FIXME: Will we eventually have to do the same for alias templates?
if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl))
if (!ClassTemplates.insert(ClassTmpl)) {
filter.erase();
@@ -199,7 +197,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
// We'll do this lookup again later.
R.suppressDiagnostics();
} else {
- assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD));
+ assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
+ isa<TypeAliasTemplateDecl>(TD));
TemplateKind = TNK_Type_template;
}
}
@@ -603,8 +602,10 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
T->isPointerType() ||
// -- reference to object or reference to function,
T->isReferenceType() ||
- // -- pointer to member.
+ // -- pointer to member,
T->isMemberPointerType() ||
+ // -- std::nullptr_t.
+ T->isNullPtrType() ||
// If T is a dependent type, we can't do the check now, so we
// assume that it is well-formed.
T->isDependentType())
@@ -919,7 +920,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// the class-key shall agree in kind with the original class
// template declaration (7.1.5.3).
RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
- if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) {
+ if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind,
+ TUK == TUK_Definition, KWLoc, *Name)) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
<< FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName());
@@ -1062,6 +1064,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
SourceRange DefArgRange) {
switch (TPC) {
case Sema::TPC_ClassTemplate:
+ case Sema::TPC_TypeAliasTemplate:
return false;
case Sema::TPC_FunctionTemplate:
@@ -1187,9 +1190,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
bool MissingDefaultArg = false;
// C++0x [temp.param]p11:
- // If a template parameter of a primary class template is a template
- // parameter pack, it shall be the last template parameter.
- if (SawParameterPack && TPC == TPC_ClassTemplate) {
+ // If a template parameter of a primary class template or alias template
+ // is a template parameter pack, it shall be the last template parameter.
+ if (SawParameterPack &&
+ (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
Diag(ParameterPackLoc,
diag::err_template_param_pack_must_be_last_template_parameter);
Invalid = true;
@@ -1429,19 +1433,41 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
}
return super::VisitDeclRefExpr(E);
}
+
+ bool TraverseInjectedClassNameType(const InjectedClassNameType *T) {
+ return TraverseType(T->getInjectedSpecializationType());
+ }
};
}
-/// Determines whether a template-id depends on the given parameter
+/// Determines whether a given type depends on the given parameter
/// list.
static bool
-DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
- TemplateParameterList *Params) {
+DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) {
DependencyChecker Checker(Params);
- Checker.TraverseType(QualType(TemplateId, 0));
+ Checker.TraverseType(T);
return Checker.Match;
}
+// Find the source range corresponding to the named type in the given
+// nested-name-specifier, if any.
+static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
+ QualType T,
+ const CXXScopeSpec &SS) {
+ NestedNameSpecifierLoc NNSLoc(SS.getScopeRep(), SS.location_data());
+ while (NestedNameSpecifier *NNS = NNSLoc.getNestedNameSpecifier()) {
+ if (const Type *CurType = NNS->getAsType()) {
+ if (Context.hasSameUnqualifiedType(T, QualType(CurType, 0)))
+ return NNSLoc.getTypeLoc().getSourceRange();
+ } else
+ break;
+
+ NNSLoc = NNSLoc.getPrefix();
+ }
+
+ return SourceRange();
+}
+
/// \brief Match the given template parameter lists to the given scope
/// specifier, returning the template parameter list that applies to the
/// name.
@@ -1449,6 +1475,8 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
/// \param DeclStartLoc the start of the declaration that has a scope
/// specifier or a template parameter list.
///
+/// \param DeclLoc The location of the declaration itself.
+///
/// \param SS the scope specifier that will be matched to the given template
/// parameter lists. This scope specifier precedes a qualified name that is
/// being declared.
@@ -1473,6 +1501,7 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
/// itself a template).
TemplateParameterList *
Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
+ SourceLocation DeclLoc,
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
unsigned NumParamLists,
@@ -1480,138 +1509,268 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
bool &IsExplicitSpecialization,
bool &Invalid) {
IsExplicitSpecialization = false;
-
- // Find the template-ids that occur within the nested-name-specifier. These
- // template-ids will match up with the template parameter lists.
- llvm::SmallVector<const TemplateSpecializationType *, 4>
- TemplateIdsInSpecifier;
- llvm::SmallVector<ClassTemplateSpecializationDecl *, 4>
- ExplicitSpecializationsInSpecifier;
- for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
- NNS; NNS = NNS->getPrefix()) {
- const Type *T = NNS->getAsType();
- if (!T) break;
-
- // C++0x [temp.expl.spec]p17:
- // A member or a member template may be nested within many
- // enclosing class templates. In an explicit specialization for
- // such a member, the member declaration shall be preceded by a
- // template<> for each enclosing class template that is
- // explicitly specialized.
- //
- // Following the existing practice of GNU and EDG, we allow a typedef of a
- // template specialization type.
- while (const TypedefType *TT = dyn_cast<TypedefType>(T))
- T = TT->getDecl()->getUnderlyingType().getTypePtr();
-
- if (const TemplateSpecializationType *SpecType
- = dyn_cast<TemplateSpecializationType>(T)) {
- TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl();
- if (!Template)
- continue; // FIXME: should this be an error? probably...
-
- if (const RecordType *Record = SpecType->getAs<RecordType>()) {
- ClassTemplateSpecializationDecl *SpecDecl
- = cast<ClassTemplateSpecializationDecl>(Record->getDecl());
- // If the nested name specifier refers to an explicit specialization,
- // we don't need a template<> header.
- if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) {
- ExplicitSpecializationsInSpecifier.push_back(SpecDecl);
- continue;
+ Invalid = false;
+
+ // The sequence of nested types to which we will match up the template
+ // parameter lists. We first build this list by starting with the type named
+ // by the nested-name-specifier and walking out until we run out of types.
+ llvm::SmallVector<QualType, 4> NestedTypes;
+ QualType T;
+ if (SS.getScopeRep()) {
+ if (CXXRecordDecl *Record
+ = dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS, true)))
+ T = Context.getTypeDeclType(Record);
+ else
+ T = QualType(SS.getScopeRep()->getAsType(), 0);
+ }
+
+ // If we found an explicit specialization that prevents us from needing
+ // 'template<>' headers, this will be set to the location of that
+ // explicit specialization.
+ SourceLocation ExplicitSpecLoc;
+
+ while (!T.isNull()) {
+ NestedTypes.push_back(T);
+
+ // Retrieve the parent of a record type.
+ if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) {
+ // If this type is an explicit specialization, we're done.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
+ if (!isa<ClassTemplatePartialSpecializationDecl>(Spec) &&
+ Spec->getSpecializationKind() == TSK_ExplicitSpecialization) {
+ ExplicitSpecLoc = Spec->getLocation();
+ break;
}
+ } else if (Record->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization) {
+ ExplicitSpecLoc = Record->getLocation();
+ break;
+ }
+
+ if (TypeDecl *Parent = dyn_cast<TypeDecl>(Record->getParent()))
+ T = Context.getTypeDeclType(Parent);
+ else
+ T = QualType();
+ continue;
+ }
+
+ if (const TemplateSpecializationType *TST
+ = T->getAs<TemplateSpecializationType>()) {
+ if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) {
+ if (TypeDecl *Parent = dyn_cast<TypeDecl>(Template->getDeclContext()))
+ T = Context.getTypeDeclType(Parent);
+ else
+ T = QualType();
+ continue;
}
-
- TemplateIdsInSpecifier.push_back(SpecType);
}
- }
-
- // Reverse the list of template-ids in the scope specifier, so that we can
- // more easily match up the template-ids and the template parameter lists.
- std::reverse(TemplateIdsInSpecifier.begin(), TemplateIdsInSpecifier.end());
-
- SourceLocation FirstTemplateLoc = DeclStartLoc;
- if (NumParamLists)
- FirstTemplateLoc = ParamLists[0]->getTemplateLoc();
-
- // Match the template-ids found in the specifier to the template parameter
- // lists.
- unsigned ParamIdx = 0, TemplateIdx = 0;
- for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size();
- TemplateIdx != NumTemplateIds; ++TemplateIdx) {
- const TemplateSpecializationType *TemplateId
- = TemplateIdsInSpecifier[TemplateIdx];
- bool DependentTemplateId = TemplateId->isDependentType();
-
- // In friend declarations we can have template-ids which don't
- // depend on the corresponding template parameter lists. But
- // assume that empty parameter lists are supposed to match this
- // template-id.
- if (IsFriend && ParamIdx < NumParamLists && ParamLists[ParamIdx]->size()) {
- if (!DependentTemplateId ||
- !DependsOnTemplateParameters(TemplateId, ParamLists[ParamIdx]))
- continue;
+
+ // Look one step prior in a dependent template specialization type.
+ if (const DependentTemplateSpecializationType *DependentTST
+ = T->getAs<DependentTemplateSpecializationType>()) {
+ if (NestedNameSpecifier *NNS = DependentTST->getQualifier())
+ T = QualType(NNS->getAsType(), 0);
+ else
+ T = QualType();
+ continue;
+ }
+
+ // Look one step prior in a dependent name type.
+ if (const DependentNameType *DependentName = T->getAs<DependentNameType>()){
+ if (NestedNameSpecifier *NNS = DependentName->getQualifier())
+ T = QualType(NNS->getAsType(), 0);
+ else
+ T = QualType();
+ continue;
+ }
+
+ // Retrieve the parent of an enumeration type.
+ if (const EnumType *EnumT = T->getAs<EnumType>()) {
+ // FIXME: Forward-declared enums require a TSK_ExplicitSpecialization
+ // check here.
+ EnumDecl *Enum = EnumT->getDecl();
+
+ // Get to the parent type.
+ if (TypeDecl *Parent = dyn_cast<TypeDecl>(Enum->getParent()))
+ T = Context.getTypeDeclType(Parent);
+ else
+ T = QualType();
+ continue;
}
- if (ParamIdx >= NumParamLists) {
- // We have a template-id without a corresponding template parameter
- // list.
+ T = QualType();
+ }
+ // Reverse the nested types list, since we want to traverse from the outermost
+ // to the innermost while checking template-parameter-lists.
+ std::reverse(NestedTypes.begin(), NestedTypes.end());
+
+ // C++0x [temp.expl.spec]p17:
+ // A member or a member template may be nested within many
+ // enclosing class templates. In an explicit specialization for
+ // such a member, the member declaration shall be preceded by a
+ // template<> for each enclosing class template that is
+ // explicitly specialized.
+ bool SawNonEmptyTemplateParameterList = false;
+ unsigned ParamIdx = 0;
+ for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes;
+ ++TypeIdx) {
+ T = NestedTypes[TypeIdx];
+
+ // Whether we expect a 'template<>' header.
+ bool NeedEmptyTemplateHeader = false;
- // ...which is fine if this is a friend declaration.
- if (IsFriend) {
- IsExplicitSpecialization = true;
- break;
+ // Whether we expect a template header with parameters.
+ bool NeedNonemptyTemplateHeader = false;
+
+ // For a dependent type, the set of template parameters that we
+ // expect to see.
+ TemplateParameterList *ExpectedTemplateParams = 0;
+
+ // C++0x [temp.expl.spec]p15:
+ // A member or a member template may be nested within many enclosing
+ // class templates. In an explicit specialization for such a member, the
+ // member declaration shall be preceded by a template<> for each
+ // enclosing class template that is explicitly specialized.
+ if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) {
+ if (ClassTemplatePartialSpecializationDecl *Partial
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
+ ExpectedTemplateParams = Partial->getTemplateParameters();
+ NeedNonemptyTemplateHeader = true;
+ } else if (Record->isDependentType()) {
+ if (Record->getDescribedClassTemplate()) {
+ ExpectedTemplateParams = Record->getDescribedClassTemplate()
+ ->getTemplateParameters();
+ NeedNonemptyTemplateHeader = true;
+ }
+ } else if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
+ // C++0x [temp.expl.spec]p4:
+ // Members of an explicitly specialized class template are defined
+ // in the same manner as members of normal classes, and not using
+ // the template<> syntax.
+ if (Spec->getSpecializationKind() != TSK_ExplicitSpecialization)
+ NeedEmptyTemplateHeader = true;
+ else
+ continue;
+ } else if (Record->getTemplateSpecializationKind()) {
+ if (Record->getTemplateSpecializationKind()
+ != TSK_ExplicitSpecialization &&
+ TypeIdx == NumTypes - 1)
+ IsExplicitSpecialization = true;
+
+ continue;
}
-
- if (DependentTemplateId) {
- // FIXME: the location information here isn't great.
- Diag(SS.getRange().getBegin(),
- diag::err_template_spec_needs_template_parameters)
- << QualType(TemplateId, 0)
- << SS.getRange();
- Invalid = true;
- } else {
- Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header)
- << SS.getRange()
- << FixItHint::CreateInsertion(FirstTemplateLoc, "template<> ");
- IsExplicitSpecialization = true;
+ } else if (const TemplateSpecializationType *TST
+ = T->getAs<TemplateSpecializationType>()) {
+ if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) {
+ ExpectedTemplateParams = Template->getTemplateParameters();
+ NeedNonemptyTemplateHeader = true;
}
- return 0;
+ } else if (T->getAs<DependentTemplateSpecializationType>()) {
+ // FIXME: We actually could/should check the template arguments here
+ // against the corresponding template parameter list.
+ NeedNonemptyTemplateHeader = false;
+ }
+
+ // C++ [temp.expl.spec]p16:
+ // In an explicit specialization declaration for a member of a class
+ // template or a member template that ap- pears in namespace scope, the
+ // member template and some of its enclosing class templates may remain
+ // unspecialized, except that the declaration shall not explicitly
+ // specialize a class member template if its en- closing class templates
+ // are not explicitly specialized as well.
+ if (ParamIdx < NumParamLists) {
+ if (ParamLists[ParamIdx]->size() == 0) {
+ if (SawNonEmptyTemplateParameterList) {
+ Diag(DeclLoc, diag::err_specialize_member_of_template)
+ << ParamLists[ParamIdx]->getSourceRange();
+ Invalid = true;
+ IsExplicitSpecialization = false;
+ return 0;
+ }
+ } else
+ SawNonEmptyTemplateParameterList = true;
}
-
- // Check the template parameter list against its corresponding template-id.
- if (DependentTemplateId) {
- TemplateParameterList *ExpectedTemplateParams = 0;
-
- // Are there cases in (e.g.) friends where this won't match?
- if (const InjectedClassNameType *Injected
- = TemplateId->getAs<InjectedClassNameType>()) {
- CXXRecordDecl *Record = Injected->getDecl();
- if (ClassTemplatePartialSpecializationDecl *Partial =
- dyn_cast<ClassTemplatePartialSpecializationDecl>(Record))
- ExpectedTemplateParams = Partial->getTemplateParameters();
+
+ if (NeedEmptyTemplateHeader) {
+ // If we're on the last of the types, and we need a 'template<>' header
+ // here, then it's an explicit specialization.
+ if (TypeIdx == NumTypes - 1)
+ IsExplicitSpecialization = true;
+
+ if (ParamIdx < NumParamLists) {
+ if (ParamLists[ParamIdx]->size() > 0) {
+ // The header has template parameters when it shouldn't. Complain.
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
+ diag::err_template_param_list_matches_nontemplate)
+ << T
+ << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
+ ParamLists[ParamIdx]->getRAngleLoc())
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
+ Invalid = true;
+ return 0;
+ }
+
+ // Consume this template header.
+ ++ParamIdx;
+ continue;
+ }
+
+ if (!IsFriend) {
+ // We don't have a template header, but we should.
+ SourceLocation ExpectedTemplateLoc;
+ if (NumParamLists > 0)
+ ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
else
- ExpectedTemplateParams = Record->getDescribedClassTemplate()
- ->getTemplateParameters();
- }
+ ExpectedTemplateLoc = DeclStartLoc;
- if (ExpectedTemplateParams)
- TemplateParameterListsAreEqual(ParamLists[ParamIdx],
- ExpectedTemplateParams,
- true, TPL_TemplateMatch);
-
- CheckTemplateParameterList(ParamLists[ParamIdx], 0,
- TPC_ClassTemplateMember);
- } else if (ParamLists[ParamIdx]->size() > 0)
- Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- diag::err_template_param_list_matches_nontemplate)
- << TemplateId
- << ParamLists[ParamIdx]->getSourceRange();
- else
- IsExplicitSpecialization = true;
+ Diag(DeclLoc, diag::err_template_spec_needs_header)
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS)
+ << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
+ }
+
+ continue;
+ }
+
+ if (NeedNonemptyTemplateHeader) {
+ // In friend declarations we can have template-ids which don't
+ // depend on the corresponding template parameter lists. But
+ // assume that empty parameter lists are supposed to match this
+ // template-id.
+ if (IsFriend && T->isDependentType()) {
+ if (ParamIdx < NumParamLists &&
+ DependsOnTemplateParameters(T, ParamLists[ParamIdx]))
+ ExpectedTemplateParams = 0;
+ else
+ continue;
+ }
- ++ParamIdx;
+ if (ParamIdx < NumParamLists) {
+ // Check the template parameter list, if we can.
+ if (ExpectedTemplateParams &&
+ !TemplateParameterListsAreEqual(ParamLists[ParamIdx],
+ ExpectedTemplateParams,
+ true, TPL_TemplateMatch))
+ Invalid = true;
+
+ if (!Invalid &&
+ CheckTemplateParameterList(ParamLists[ParamIdx], 0,
+ TPC_ClassTemplateMember))
+ Invalid = true;
+
+ ++ParamIdx;
+ continue;
+ }
+
+ Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
+ << T
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
+ Invalid = true;
+ continue;
+ }
}
-
+
// If there were at least as many template-ids as there were template
// parameter lists, then there are no template parameter lists remaining for
// the declaration itself.
@@ -1619,32 +1778,53 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
return 0;
// If there were too many template parameter lists, complain about that now.
- if (ParamIdx != NumParamLists - 1) {
- while (ParamIdx < NumParamLists - 1) {
- bool isExplicitSpecHeader = ParamLists[ParamIdx]->size() == 0;
- Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- isExplicitSpecHeader? diag::warn_template_spec_extra_headers
- : diag::err_template_spec_extra_headers)
- << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
- ParamLists[ParamIdx]->getRAngleLoc());
-
- if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) {
- Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(),
- diag::note_explicit_template_spec_does_not_need_header)
- << ExplicitSpecializationsInSpecifier.back();
- ExplicitSpecializationsInSpecifier.pop_back();
- }
-
- // We have a template parameter list with no corresponding scope, which
- // means that the resulting template declaration can't be instantiated
- // properly (we'll end up with dependent nodes when we shouldn't).
- if (!isExplicitSpecHeader)
- Invalid = true;
-
- ++ParamIdx;
+ if (ParamIdx < NumParamLists - 1) {
+ bool HasAnyExplicitSpecHeader = false;
+ bool AllExplicitSpecHeaders = true;
+ for (unsigned I = ParamIdx; I != NumParamLists - 1; ++I) {
+ if (ParamLists[I]->size() == 0)
+ HasAnyExplicitSpecHeader = true;
+ else
+ AllExplicitSpecHeaders = false;
}
+
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
+ AllExplicitSpecHeaders? diag::warn_template_spec_extra_headers
+ : diag::err_template_spec_extra_headers)
+ << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
+ ParamLists[NumParamLists - 2]->getRAngleLoc());
+
+ // If there was a specialization somewhere, such that 'template<>' is
+ // not required, and there were any 'template<>' headers, note where the
+ // specialization occurred.
+ if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader)
+ Diag(ExplicitSpecLoc,
+ diag::note_explicit_template_spec_does_not_need_header)
+ << NestedTypes.back();
+
+ // We have a template parameter list with no corresponding scope, which
+ // means that the resulting template declaration can't be instantiated
+ // properly (we'll end up with dependent nodes when we shouldn't).
+ if (!AllExplicitSpecHeaders)
+ Invalid = true;
}
+ // C++ [temp.expl.spec]p16:
+ // In an explicit specialization declaration for a member of a class
+ // template or a member template that ap- pears in namespace scope, the
+ // member template and some of its enclosing class templates may remain
+ // unspecialized, except that the declaration shall not explicitly
+ // specialize a class member template if its en- closing class templates
+ // are not explicitly specialized as well.
+ if (ParamLists[NumParamLists - 1]->size() == 0 &&
+ SawNonEmptyTemplateParameterList) {
+ Diag(DeclLoc, diag::err_specialize_member_of_template)
+ << ParamLists[ParamIdx]->getSourceRange();
+ Invalid = true;
+ IsExplicitSpecialization = false;
+ return 0;
+ }
+
// Return the last template parameter list, which corresponds to the
// entity being declared.
return ParamLists[NumParamLists - 1];
@@ -1655,7 +1835,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
Diag(Template->getLocation(), diag::note_template_declared_here)
<< (isa<FunctionTemplateDecl>(Template)? 0
: isa<ClassTemplateDecl>(Template)? 1
- : 2)
+ : isa<TypeAliasTemplateDecl>(Template)? 2
+ : 3)
<< Template->getDeclName();
return;
}
@@ -1675,13 +1856,24 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
+ DependentTemplateName *DTN = Name.getAsDependentTemplateName();
+ if (DTN && DTN->isIdentifier())
+ // When building a template-id where the template-name is dependent,
+ // assume the template is a type template. Either our assumption is
+ // correct, or the code is ill-formed and will be diagnosed when the
+ // dependent name is substituted.
+ return Context.getDependentTemplateSpecializationType(ETK_None,
+ DTN->getQualifier(),
+ DTN->getIdentifier(),
+ TemplateArgs);
+
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template || isa<FunctionTemplateDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
return Context.getTemplateSpecializationType(Name, TemplateArgs);
-
+
Diag(TemplateLoc, diag::err_template_id_not_a_type)
<< Name;
NoteAllFoundTemplates(Name);
@@ -1700,9 +1892,32 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
QualType CanonType;
- if (Name.isDependent() ||
- TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs)) {
+ if (TypeAliasTemplateDecl *AliasTemplate
+ = dyn_cast<TypeAliasTemplateDecl>(Template)) {
+ // Find the canonical type for this type alias template specialization.
+ TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
+ if (Pattern->isInvalidDecl())
+ return QualType();
+
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
+ Converted.data(), Converted.size());
+
+ // Only substitute for the innermost template argument list.
+ MultiLevelTemplateArgumentList TemplateArgLists;
+ TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth();
+ for (unsigned I = 0; I < Depth; ++I)
+ TemplateArgLists.addOuterTemplateArguments(0, 0);
+
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template);
+ CanonType = SubstType(Pattern->getUnderlyingType(),
+ TemplateArgLists, AliasTemplate->getLocation(),
+ AliasTemplate->getDeclName());
+ if (CanonType.isNull())
+ return QualType();
+ } else if (Name.isDependent() ||
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs)) {
// This class template specialization is a dependent
// type. Therefore, its canonical type is another class template
// specialization type that contains all of the converted
@@ -1894,6 +2109,16 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
}
+
+ if (TypeAliasTemplateDecl *TAT =
+ dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) {
+ // C++0x [dcl.type.elab]p2:
+ // If the identifier resolves to a typedef-name or the simple-template-id
+ // resolves to an alias template specialization, the
+ // elaborated-type-specifier is ill-formed.
+ Diag(TemplateLoc, diag::err_tag_reference_non_tag) << 4;
+ Diag(TAT->getLocation(), diag::note_declared_at);
+ }
QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
if (Result.isNull())
@@ -1906,7 +2131,8 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
IdentifierInfo *Id = D->getIdentifier();
assert(Id && "templated class must have an identifier");
- if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) {
+ if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition,
+ TagLoc, *Id)) {
Diag(TagLoc, diag::err_use_with_wrong_tag)
<< Result
<< FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName());
@@ -2485,7 +2711,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
}
// We have a template argument that actually does refer to a class
- // template, template alias, or template template parameter, and
+ // template, alias template, or template template parameter, and
// therefore cannot be a non-type template argument.
Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr)
<< Arg.getSourceRange();
@@ -2562,7 +2788,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Type:
// We have a template template parameter but the template
// argument does not refer to a template.
- Diag(Arg.getLocation(), diag::err_template_arg_must_be_template);
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_template)
+ << getLangOptions().CPlusPlus0x;
return true;
case TemplateArgument::Declaration:
@@ -2631,9 +2858,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
unsigned ArgIdx = 0;
LocalInstantiationScope InstScope(*this, true);
while (Param != ParamEnd) {
- if (ArgIdx > NumArgs && PartialTemplateArgs)
- break;
-
if (ArgIdx < NumArgs) {
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
@@ -2674,11 +2898,31 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
continue;
}
+ // If we're checking a partial template argument list, we're done.
+ if (PartialTemplateArgs) {
+ if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty())
+ Converted.push_back(TemplateArgument::CreatePackCopy(Context,
+ ArgumentPack.data(),
+ ArgumentPack.size()));
+
+ return Invalid;
+ }
+
// If we have a template parameter pack with no more corresponding
// arguments, just break out now and we'll fill in the argument pack below.
if ((*Param)->isTemplateParameterPack())
break;
+ // If our template is a template template parameter that hasn't acquired
+ // its proper context yet (e.g., because we're using the template template
+ // parameter in the signature of a function template, before we've built
+ // the function template itself), don't attempt substitution of default
+ // template arguments at this point: we don't have enough context to
+ // do it properly.
+ if (isTemplateTemplateParameter &&
+ Template->getDeclContext()->isTranslationUnit())
+ break;
+
// We have a default template argument that we will use.
TemplateArgumentLoc Arg;
@@ -2689,7 +2933,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// the default argument.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
if (!TTP->hasDefaultArgument()) {
- assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+ assert(Invalid && "Missing default argument");
break;
}
@@ -2707,7 +2951,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (!NTTP->hasDefaultArgument()) {
- assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+ assert(Invalid && "Missing default argument");
break;
}
@@ -2726,7 +2970,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
= cast<TemplateTemplateParmDecl>(*Param);
if (!TempParm->hasDefaultArgument()) {
- assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+ assert(Invalid && "Missing default argument");
break;
}
@@ -2772,9 +3016,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// in arguments for non-template parameter packs.
if ((*Param)->isTemplateParameterPack()) {
- if (PartialTemplateArgs && ArgumentPack.empty()) {
- Converted.push_back(TemplateArgument());
- } else if (ArgumentPack.empty())
+ if (ArgumentPack.empty())
Converted.push_back(TemplateArgument(0, 0));
else {
Converted.push_back(TemplateArgument::CreatePackCopy(Context,
@@ -2918,6 +3160,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) {
return false;
}
+bool UnnamedLocalNoLinkageFinder::VisitUnaryTransformType(
+ const UnaryTransformType*) {
+ return false;
+}
+
bool UnnamedLocalNoLinkageFinder::VisitAutoType(const AutoType *T) {
return Visit(T->getDeducedType());
}
@@ -3501,32 +3748,49 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
}
+ // 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 Owned(Arg);
+ }
+
QualType IntegerType = Context.getCanonicalType(ParamType);
if (const EnumType *Enum = IntegerType->getAs<EnumType>())
IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType());
- if (!Arg->isValueDependent()) {
+ if (ParamType->isBooleanType()) {
+ // Value must be zero or one.
+ Value = Value != 0;
+ unsigned AllowedBits = Context.getTypeSize(IntegerType);
+ if (Value.getBitWidth() != AllowedBits)
+ Value = Value.extOrTrunc(AllowedBits);
+ Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType());
+ } else {
llvm::APSInt OldValue = Value;
-
+
// Coerce the template argument's value to the value it will have
// based on the template parameter's type.
unsigned AllowedBits = Context.getTypeSize(IntegerType);
if (Value.getBitWidth() != AllowedBits)
Value = Value.extOrTrunc(AllowedBits);
- Value.setIsSigned(IntegerType->isSignedIntegerType());
-
+ Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType());
+
// Complain if an unsigned parameter received a negative value.
- if (IntegerType->isUnsignedIntegerType()
- && (OldValue.isSigned() && OldValue.isNegative())) {
+ if (IntegerType->isUnsignedIntegerOrEnumerationType()
+ && (OldValue.isSigned() && OldValue.isNegative())) {
Diag(Arg->getSourceRange().getBegin(), diag::warn_template_arg_negative)
<< OldValue.toString(10) << Value.toString(10) << Param->getType()
<< Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
}
-
+
// Complain if we overflowed the template parameter's type.
unsigned RequiredBits;
- if (IntegerType->isUnsignedIntegerType())
+ if (IntegerType->isUnsignedIntegerOrEnumerationType())
RequiredBits = OldValue.getActiveBits();
else if (OldValue.isUnsigned())
RequiredBits = OldValue.getActiveBits() + 1;
@@ -3541,16 +3805,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
}
- // 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 Owned(Arg);
- }
-
Converted = TemplateArgument(Value,
ParamType->isEnumeralType() ? ParamType
: IntegerType);
@@ -3563,10 +3817,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// from a template argument of type std::nullptr_t to a non-type
// template parameter of type pointer to object, pointer to
// function, or pointer-to-member, respectively.
- if (ArgType->isNullPtrType() &&
- (ParamType->isPointerType() || ParamType->isMemberPointerType())) {
- Converted = TemplateArgument((NamedDecl *)0);
- return Owned(Arg);
+ if (ArgType->isNullPtrType()) {
+ if (ParamType->isPointerType() || ParamType->isMemberPointerType()) {
+ Converted = TemplateArgument((NamedDecl *)0);
+ return Owned(Arg);
+ }
+
+ if (ParamType->isNullPtrType()) {
+ llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true);
+ Converted = TemplateArgument(Zero, Context.NullPtrTy);
+ return Owned(Arg);
+ }
}
// Handle pointer-to-function, reference-to-function, and
@@ -3715,9 +3976,10 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
return false;
}
- // C++ [temp.arg.template]p1:
+ // C++0x [temp.arg.template]p1:
// A template-argument for a template template-parameter shall be
- // the name of a class template, expressed as id-expression. Only
+ // the name of a class template or an alias template, expressed as an
+ // id-expression. When the template-argument names a class template, only
// primary class templates are considered when matching the
// template template argument with the corresponding parameter;
// partial specializations are not considered even if their
@@ -3727,7 +3989,8 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
// will happen when we are dealing with, e.g., class template
// partial specializations.
if (!isa<ClassTemplateDecl>(Template) &&
- !isa<TemplateTemplateParmDecl>(Template)) {
+ !isa<TemplateTemplateParmDecl>(Template) &&
+ !isa<TypeAliasTemplateDecl>(Template)) {
assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
Diag(Arg.getLocation(), diag::err_template_arg_not_class_template);
@@ -3858,6 +4121,9 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
Arg.getAsIntegral()->getBoolValue(),
T, Loc));
+ if (T->isNullPtrType())
+ return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc));
+
// If this is an enum type that we're instantiating, we need to use an integer
// type the same size as the enumerator. We don't want to build an
// IntegerLiteral with enum type.
@@ -4044,7 +4310,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
// C++0x [temp.arg.template]p3:
// A template-argument matches a template template-parameter (call it P)
// when each of the template parameters in the template-parameter-list of
- // the template-argument's corresponding class template or template alias
+ // the template-argument's corresponding class template or alias template
// (call it A) matches the corresponding template parameter in the
// template-parameter-list of P. [...]
TemplateParameterList::iterator NewParm = New->begin();
@@ -4442,7 +4708,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// friend declarations.
bool Invalid = false;
TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
+ = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc,
+ TemplateNameLoc,
+ SS,
(TemplateParameterList**)TemplateParameterLists.get(),
TemplateParameterLists.size(),
TUK == TUK_Friend,
@@ -4509,7 +4777,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!");
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
- Kind, KWLoc,
+ Kind, TUK == TUK_Definition, KWLoc,
*ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
@@ -5180,7 +5448,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
SpecInfo->getPointOfInstantiation(),
HasNoEffect))
return true;
-
+
// Mark the prior declaration as an explicit specialization, so that later
// clients know that this is an explicit specialization.
if (!isFriend) {
@@ -5200,7 +5468,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
TemplArgs, /*InsertPos=*/0,
SpecInfo->getTemplateSpecializationKind(),
TemplArgsAsWritten);
-
+ FD->setStorageClass(Specialization->getStorageClass());
+
// The "previous declaration" for this function template specialization is
// the prior function template specialization.
Previous.clear();
@@ -5479,7 +5748,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
assert(Kind != TTK_Enum &&
"Invalid enum tag in class template explicit instantiation!");
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
- Kind, KWLoc,
+ Kind, /*isDefinition*/false, KWLoc,
*ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
@@ -5801,11 +6070,20 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (R.isNull())
return true;
+ // C++ [dcl.stc]p1:
+ // A storage-class-specifier shall not be specified in [...] an explicit
+ // instantiation (14.7.2) directive.
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
- // Cannot explicitly instantiate a typedef.
Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef)
<< Name;
return true;
+ } else if (D.getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_unspecified) {
+ // Complain about then remove the storage class specifier.
+ Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_storage_class)
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
}
// C++0x [temp.explicit]p1:
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 235af049cf84..7d0ce8b2e71d 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2314,7 +2314,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
FunctionTemplate->getLocation(),
FunctionTemplate->getSourceRange().getEnd(),
0, Builder,
- CTAK_Deduced)) {
+ CTAK_Specified)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
// FIXME: These template arguments are temporary. Free them!
@@ -2500,6 +2500,12 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
if (ParamRefType) {
QualType PointeeType = ParamRefType->getPointeeType();
+ // If the argument has incomplete array type, try to complete it's type.
+ if (ArgType->isIncompleteArrayType() &&
+ !S.RequireCompleteExprType(Arg, S.PDiag(),
+ std::make_pair(SourceLocation(), S.PDiag())))
+ ArgType = Arg->getType();
+
// [C++0x] If P is an rvalue reference to a cv-unqualified
// template parameter and the argument is an lvalue, the type
// "lvalue reference to A" is used in place of A for type
@@ -2507,7 +2513,9 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
if (isa<RValueReferenceType>(ParamType)) {
if (!PointeeType.getQualifiers() &&
isa<TemplateTypeParmType>(PointeeType) &&
- Arg->Classify(S.Context).isLValue())
+ Arg->Classify(S.Context).isLValue() &&
+ Arg->getType() != S.Context.OverloadTy &&
+ Arg->getType() != S.Context.BoundMemberTy)
ArgType = S.Context.getLValueReferenceType(ArgType);
}
@@ -3884,6 +3892,13 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
OnlyDeduced, Depth, Used);
break;
+ case Type::UnaryTransform:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<UnaryTransformType>(T)->getUnderlyingType(),
+ OnlyDeduced, Depth, Used);
+ break;
+
case Type::PackExpansion:
MarkUsedTemplateParameters(SemaRef,
cast<PackExpansionType>(T)->getPattern(),
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 92ba095cd6c8..3c1964175b10 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -13,6 +13,7 @@
#include "clang/Sema/SemaInternal.h"
#include "TreeTransform.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
@@ -58,9 +59,13 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
Result.addOuterTemplateArguments(Innermost);
DeclContext *Ctx = dyn_cast<DeclContext>(D);
- if (!Ctx)
+ if (!Ctx) {
Ctx = D->getDeclContext();
-
+
+ assert((!D->isTemplateParameter() || !Ctx->isTranslationUnit()) &&
+ "Template parameter doesn't have its context yet!");
+ }
+
while (!Ctx->isFileContext()) {
// Add template arguments from a class template instantiation.
if (ClassTemplateSpecializationDecl *Spec
@@ -446,10 +451,15 @@ void Sema::PrintInstantiationStack() {
Diags.Report(Active->PointOfInstantiation, DiagID)
<< Function
<< Active->InstantiationRange;
- } else {
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
Diags.Report(Active->PointOfInstantiation,
diag::note_template_static_data_member_def_here)
- << cast<VarDecl>(D)
+ << VD
+ << Active->InstantiationRange;
+ } else {
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_template_type_alias_instantiation_here)
+ << cast<TypeAliasTemplateDecl>(D)
<< Active->InstantiationRange;
}
break;
@@ -918,7 +928,8 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc,
// like it's likely to produce a lot of spurious errors.
if (Keyword != ETK_None && Keyword != ETK_Typename) {
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
- if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, TagLocation, *Id)) {
+ if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, /*isDefinition*/false,
+ TagLocation, *Id)) {
SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
<< Id
<< FixItHint::CreateReplacement(SourceRange(TagLocation),
@@ -968,8 +979,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
}
TemplateName Template = Arg.getAsTemplate();
- assert(!Template.isNull() && Template.getAsTemplateDecl() &&
- "Wrong kind of template template argument");
+ assert(!Template.isNull() && "Null template template argument");
// We don't ever want to substitute for a qualified template name, since
// the qualifier is handled separately. So, look through the qualified
@@ -1384,6 +1394,12 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) {
ParmVarDecl *P = FP.getArg(I);
+ // The parameter's type as written might be dependent even if the
+ // decayed type was not dependent.
+ if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo())
+ if (TSInfo->getType()->isDependentType())
+ return true;
+
// TODO: currently we always rebuild expressions. When we
// properly get lazier about this, we should use the same
// logic to avoid rebuilding prototypes here.
@@ -1729,6 +1745,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
llvm::SmallVector<Decl*, 4> Fields;
+ llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4>
+ FieldsWithMemberInitializers;
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
MemberEnd = Pattern->decls_end();
Member != MemberEnd; ++Member) {
@@ -1751,9 +1769,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Decl *NewMember = Instantiator.Visit(*Member);
if (NewMember) {
- if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) {
Fields.push_back(Field);
- else if (NewMember->isInvalidDecl())
+ FieldDecl *OldField = cast<FieldDecl>(*Member);
+ if (OldField->getInClassInitializer())
+ FieldsWithMemberInitializers.push_back(std::make_pair(OldField,
+ Field));
+ } else if (NewMember->isInvalidDecl())
Invalid = true;
} else {
// FIXME: Eventually, a NULL return will mean that one of the
@@ -1767,6 +1789,43 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Fields.data(), Fields.size(), SourceLocation(), SourceLocation(),
0);
CheckCompletedCXXClass(Instantiation);
+
+ // Attach any in-class member initializers now the class is complete.
+ for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) {
+ FieldDecl *OldField = FieldsWithMemberInitializers[I].first;
+ FieldDecl *NewField = FieldsWithMemberInitializers[I].second;
+ Expr *OldInit = OldField->getInClassInitializer();
+ ExprResult NewInit = SubstExpr(OldInit, TemplateArgs);
+
+ // If the initialization is no longer dependent, check it now.
+ if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent())
+ && !NewField->getType()->isDependentType()
+ && !NewInit.get()->isTypeDependent()) {
+ // FIXME: handle list-initialization
+ SourceLocation EqualLoc = NewField->getLocation();
+ NewInit = PerformCopyInitialization(
+ InitializedEntity::InitializeMember(NewField), EqualLoc,
+ NewInit.release());
+
+ if (!NewInit.isInvalid()) {
+ CheckImplicitConversions(NewInit.get(), EqualLoc);
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ NewInit = MaybeCreateExprWithCleanups(NewInit);
+ }
+ }
+
+ if (NewInit.isInvalid())
+ NewField->setInvalidDecl();
+ else
+ NewField->setInClassInitializer(NewInit.release());
+ }
+
+ if (!FieldsWithMemberInitializers.empty())
+ ActOnFinishDelayedMemberInitializers(Instantiation);
+
if (Instantiation->isInvalidDecl())
Invalid = true;
else {
@@ -2009,7 +2068,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
SuppressNew)
continue;
- if (Function->hasBody())
+ if (Function->isDefined())
continue;
if (TSK == TSK_ExplicitInstantiationDefinition) {
@@ -2019,7 +2078,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
// specialization and is only an explicit instantiation definition
// of members whose definition is visible at the point of
// instantiation.
- if (!Pattern->hasBody())
+ if (!Pattern->isDefined())
continue;
Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 6e11ef5bbc5f..e78aa2991e74 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -128,8 +128,8 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
return Inst;
}
-Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D,
- bool IsTypeAlias) {
+Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
+ bool IsTypeAlias) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI->getType()->isDependentType() ||
@@ -178,17 +178,62 @@ Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D,
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
Typedef->setAccess(D->getAccess());
- Owner->addDecl(Typedef);
return Typedef;
}
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
- return VisitTypedefNameDecl(D, /*IsTypeAlias=*/false);
+ Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false);
+ Owner->addDecl(Typedef);
+ return Typedef;
}
Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) {
- return VisitTypedefNameDecl(D, /*IsTypeAlias=*/true);
+ Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true);
+ Owner->addDecl(Typedef);
+ return Typedef;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ // Create a local instantiation scope for this type alias template, which
+ // will contain the instantiations of the template parameters.
+ LocalInstantiationScope Scope(SemaRef);
+
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return 0;
+
+ TypeAliasDecl *Pattern = D->getTemplatedDecl();
+
+ TypeAliasTemplateDecl *PrevAliasTemplate = 0;
+ if (Pattern->getPreviousDeclaration()) {
+ DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
+ if (Found.first != Found.second) {
+ PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first);
+ }
+ }
+
+ TypeAliasDecl *AliasInst = cast_or_null<TypeAliasDecl>(
+ InstantiateTypedefNameDecl(Pattern, /*IsTypeAlias=*/true));
+ if (!AliasInst)
+ return 0;
+
+ TypeAliasTemplateDecl *Inst
+ = TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getDeclName(), InstParams, AliasInst);
+ if (PrevAliasTemplate)
+ Inst->setPreviousDeclaration(PrevAliasTemplate);
+
+ Inst->setAccess(D->getAccess());
+
+ if (!PrevAliasTemplate)
+ Inst->setInstantiatedFromMemberTemplate(D);
+
+ Owner->addDecl(Inst);
+
+ return Inst;
}
/// \brief Instantiate an initializer, breaking it into separate
@@ -432,6 +477,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
D->getLocation(),
D->isMutable(),
BitWidth,
+ D->hasInClassInitializer(),
D->getTypeSpecStartLoc(),
D->getAccess(),
0);
@@ -1171,7 +1217,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
D->isThisDeclarationADefinition()) {
// Check for a function body.
const FunctionDecl *Definition = 0;
- if (Function->hasBody(Definition) &&
+ if (Function->isDefined(Definition) &&
Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
<< Function->getDeclName();
@@ -1203,7 +1249,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
default:
if (const FunctionDecl *RPattern
= R->getTemplateInstantiationPattern())
- if (RPattern->hasBody(RPattern)) {
+ if (RPattern->isDefined(RPattern)) {
SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
<< Function->getDeclName();
SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
@@ -1219,6 +1265,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
PrincipalDecl->setNonMemberOperator();
+ assert(!D->isDefaulted() && "only methods should be defaulted");
return Function;
}
@@ -1451,7 +1498,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
else
Owner->addDecl(DeclToAdd);
}
-
+
+ if (D->isExplicitlyDefaulted()) {
+ SemaRef.SetDeclDefaulted(Method, Method->getLocation());
+ } else {
+ assert(!D->isDefaulted() &&
+ "should not implicitly default uninstantiated function");
+ }
+
return Method;
}
@@ -2079,8 +2133,8 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
bool
TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *Tmpl) {
- if (Tmpl->isDeleted())
- New->setDeleted();
+ if (Tmpl->isDeletedAsWritten())
+ New->setDeletedAsWritten();
// If we are performing substituting explicitly-specified template arguments
// or deduced template arguments into a function template and we reach this
@@ -2186,6 +2240,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
}
Expr *NoexceptExpr = 0;
if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
if (E.isUsable())
NoexceptExpr = E.take();
@@ -2255,7 +2310,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive,
bool DefinitionRequired) {
- if (Function->isInvalidDecl() || Function->hasBody())
+ if (Function->isInvalidDecl() || Function->isDefined())
return;
// Never instantiate an explicit specialization.
@@ -2264,12 +2319,19 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern();
- Stmt *Pattern = 0;
- if (PatternDecl)
- Pattern = PatternDecl->getBody(PatternDecl);
+ assert(PatternDecl && "instantiating a non-template");
+
+ Stmt *Pattern = PatternDecl->getBody(PatternDecl);
+ assert(PatternDecl && "template definition is not a template");
+ if (!Pattern) {
+ // Try to find a defaulted definition
+ PatternDecl->isDefined(PatternDecl);
+ }
+ assert(PatternDecl && "template definition is not a template");
// Postpone late parsed template instantiations.
- if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) {
+ if (PatternDecl->isLateTemplateParsed() &&
+ !LateTemplateParser) {
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
return;
@@ -2277,13 +2339,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Call the LateTemplateParser callback if there a need to late parse
// a templated function definition.
- if (!Pattern && PatternDecl && PatternDecl->isLateTemplateParsed() &&
+ if (!Pattern && PatternDecl->isLateTemplateParsed() &&
LateTemplateParser) {
LateTemplateParser(OpaqueParser, PatternDecl);
Pattern = PatternDecl->getBody(PatternDecl);
}
- if (!Pattern) {
+ if (!Pattern && !PatternDecl->isDefaulted()) {
if (DefinitionRequired) {
if (Function->getPrimaryTemplate())
Diag(PointOfInstantiation,
@@ -2378,21 +2440,27 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
- // If this is a constructor, instantiate the member initializers.
- if (const CXXConstructorDecl *Ctor =
- dyn_cast<CXXConstructorDecl>(PatternDecl)) {
- InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,
- TemplateArgs);
- }
+ if (PatternDecl->isDefaulted()) {
+ ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);
- // Instantiate the function body.
- StmtResult Body = SubstStmt(Pattern, TemplateArgs);
+ SetDeclDefaulted(Function, PatternDecl->getLocation());
+ } else {
+ // If this is a constructor, instantiate the member initializers.
+ if (const CXXConstructorDecl *Ctor =
+ dyn_cast<CXXConstructorDecl>(PatternDecl)) {
+ InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,
+ TemplateArgs);
+ }
- if (Body.isInvalid())
- Function->setInvalidDecl();
-
- ActOnFinishFunctionBody(Function, Body.get(),
- /*IsInstantiation=*/true);
+ // Instantiate the function body.
+ StmtResult Body = SubstStmt(Pattern, TemplateArgs);
+
+ if (Body.isInvalid())
+ Function->setInvalidDecl();
+
+ ActOnFinishFunctionBody(Function, Body.get(),
+ /*IsInstantiation=*/true);
+ }
PerformDependentDiagnostics(PatternDecl, TemplateArgs);
@@ -2415,9 +2483,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
PerformPendingInstantiations();
// Restore the set of pending vtables.
+ assert(VTableUses.empty() &&
+ "VTableUses should be empty before it is discarded.");
VTableUses.swap(SavedVTableUses);
// Restore the set of pending implicit instantiations.
+ assert(PendingInstantiations.empty() &&
+ "PendingInstantiations should be empty before it is discarded.");
PendingInstantiations.swap(SavedPendingInstantiations);
}
}
@@ -2484,6 +2556,10 @@ void Sema::InstantiateStaticDataMemberDefinition(
== TSK_ExplicitInstantiationDeclaration)
return;
+ // If we already have a definition, we're done.
+ if (Var->getDefinition())
+ return;
+
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
if (Inst)
return;
@@ -2491,9 +2567,12 @@ void Sema::InstantiateStaticDataMemberDefinition(
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
+ llvm::SmallVector<VTableUse, 16> SavedVTableUses;
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
- if (Recursive)
+ if (Recursive) {
+ VTableUses.swap(SavedVTableUses);
PendingInstantiations.swap(SavedPendingInstantiations);
+ }
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
@@ -2515,11 +2594,23 @@ void Sema::InstantiateStaticDataMemberDefinition(
}
if (Recursive) {
+ // Define any newly required vtables.
+ DefineUsedVTables();
+
// Instantiate any pending implicit instantiations found during the
// instantiation of this template.
PerformPendingInstantiations();
+ // Restore the set of pending vtables.
+ assert(VTableUses.empty() &&
+ "VTableUses should be empty before it is discarded, "
+ "while instantiating static data member.");
+ VTableUses.swap(SavedVTableUses);
+
// Restore the set of pending implicit instantiations.
+ assert(PendingInstantiations.empty() &&
+ "PendingInstantiations should be empty before it is discarded, "
+ "while instantiating static data member.");
PendingInstantiations.swap(SavedPendingInstantiations);
}
}
@@ -3115,10 +3206,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
-///
-/// \returns true if anything was instantiated.
-bool Sema::PerformPendingInstantiations(bool LocalOnly) {
- bool InstantiatedAnything = false;
+void Sema::PerformPendingInstantiations(bool LocalOnly) {
while (!PendingLocalImplicitInstantiations.empty() ||
(!LocalOnly && !PendingInstantiations.empty())) {
PendingImplicitInstantiation Inst;
@@ -3139,7 +3227,6 @@ bool Sema::PerformPendingInstantiations(bool LocalOnly) {
TSK_ExplicitInstantiationDefinition;
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
DefinitionRequired);
- InstantiatedAnything = true;
continue;
}
@@ -3176,10 +3263,7 @@ bool Sema::PerformPendingInstantiations(bool LocalOnly) {
TSK_ExplicitInstantiationDefinition;
InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true,
DefinitionRequired);
- InstantiatedAnything = true;
}
-
- return InstantiatedAnything;
}
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 096d353bccc3..86d3bc170909 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -617,7 +617,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
switch (DS.getTypeSpecType()) {
case TST_typename:
- case TST_typeofType: {
+ case TST_typeofType:
+ case TST_underlyingType: {
QualType T = DS.getRepAsType().get();
if (!T.isNull() && T->containsUnexpandedParameterPack())
return true;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 00ac1d63dbe7..5fd8afa6acf4 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/Template.h"
#include "clang/Basic/OpenCL.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -836,6 +837,18 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) {
}
break;
}
+ case DeclSpec::TST_underlyingType:
+ Result = S.GetTypeFromParser(DS.getRepAsType());
+ assert(!Result.isNull() && "Didn't get a type for __underlying_type?");
+ Result = S.BuildUnaryTransformType(Result,
+ UnaryTransformType::EnumUnderlyingType,
+ DS.getTypeSpecTypeLoc());
+ if (Result.isNull()) {
+ Result = Context.IntTy;
+ declarator.setInvalidType(true);
+ }
+ break;
+
case DeclSpec::TST_auto: {
// TypeQuals handled by caller.
Result = Context.getAutoType(QualType());
@@ -1048,6 +1061,9 @@ QualType Sema::BuildPointerType(QualType T,
QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
SourceLocation Loc,
DeclarationName Entity) {
+ assert(Context.getCanonicalType(T) != Context.OverloadTy &&
+ "Unresolved overloaded function type");
+
// C++0x [dcl.ref]p6:
// If a typedef (7.1.3), a type template-parameter (14.3.1), or a
// decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a
@@ -1464,41 +1480,37 @@ static void DiagnoseIgnoredQualifiers(unsigned Quals,
FixItHint VolatileFixIt;
FixItHint RestrictFixIt;
+ const SourceManager &SM = S.getSourceManager();
+
// FIXME: The locations here are set kind of arbitrarily. It'd be nicer to
// find a range and grow it to encompass all the qualifiers, regardless of
// the order in which they textually appear.
if (Quals & Qualifiers::Const) {
ConstFixIt = FixItHint::CreateRemoval(ConstQualLoc);
- Loc = ConstQualLoc;
- ++NumQuals;
QualStr = "const";
+ ++NumQuals;
+ if (!Loc.isValid() || SM.isBeforeInTranslationUnit(ConstQualLoc, Loc))
+ Loc = ConstQualLoc;
}
if (Quals & Qualifiers::Volatile) {
VolatileFixIt = FixItHint::CreateRemoval(VolatileQualLoc);
- if (NumQuals == 0) {
- Loc = VolatileQualLoc;
- QualStr = "volatile";
- } else {
- QualStr += " volatile";
- }
+ QualStr += (NumQuals == 0 ? "volatile" : " volatile");
++NumQuals;
+ if (!Loc.isValid() || SM.isBeforeInTranslationUnit(VolatileQualLoc, Loc))
+ Loc = VolatileQualLoc;
}
if (Quals & Qualifiers::Restrict) {
RestrictFixIt = FixItHint::CreateRemoval(RestrictQualLoc);
- if (NumQuals == 0) {
- Loc = RestrictQualLoc;
- QualStr = "restrict";
- } else {
- QualStr += " restrict";
- }
+ QualStr += (NumQuals == 0 ? "restrict" : " restrict");
++NumQuals;
+ if (!Loc.isValid() || SM.isBeforeInTranslationUnit(RestrictQualLoc, Loc))
+ Loc = RestrictQualLoc;
}
assert(NumQuals > 0 && "No known qualifiers?");
S.Diag(Loc, diag::warn_qual_return_type)
- << QualStr << NumQuals
- << ConstFixIt << VolatileFixIt << RestrictFixIt;
+ << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt;
}
/// GetTypeForDeclarator - Convert the type for the specified
@@ -1581,6 +1593,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
Error = 0; // Function prototype
break;
case Declarator::MemberContext:
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
+ break;
switch (cast<TagDecl>(CurContext)->getTagKind()) {
case TTK_Enum: assert(0 && "unhandled tag kind"); break;
case TTK_Struct: Error = 1; /* Struct member */ break;
@@ -1601,6 +1615,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
Error = 7; // Template type argument
break;
case Declarator::AliasDeclContext:
+ case Declarator::AliasTemplateContext:
Error = 9; // Type alias
break;
case Declarator::TypeNameContext:
@@ -1659,7 +1674,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Does this declaration declare a typedef-name?
bool IsTypedefName =
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef ||
- D.getContext() == Declarator::AliasDeclContext;
+ D.getContext() == Declarator::AliasDeclContext ||
+ D.getContext() == Declarator::AliasTemplateContext;
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
@@ -1839,7 +1855,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// anyway.
if (IsTypedefName && FTI.getExceptionSpecType())
Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef)
- << (D.getContext() == Declarator::AliasDeclContext);
+ << (D.getContext() == Declarator::AliasDeclContext ||
+ D.getContext() == Declarator::AliasTemplateContext);
if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) {
// Simple void foo(), where the incoming T is the result type.
@@ -2204,6 +2221,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here?
case Declarator::TypeNameContext:
case Declarator::AliasDeclContext:
+ case Declarator::AliasTemplateContext:
case Declarator::MemberContext:
case Declarator::BlockContext:
case Declarator::ForContext:
@@ -2367,6 +2385,16 @@ namespace {
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
TL.setUnderlyingTInfo(TInfo);
}
+ void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ // FIXME: This holds only because we only have one unary transform.
+ assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);
+ TL.setKWLoc(DS.getTypeSpecTypeLoc());
+ TL.setParensRange(DS.getTypeofParensRange());
+ assert(DS.getRepAsType());
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+ TL.setUnderlyingTInfo(TInfo);
+ }
void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
// By default, use the source location of the type specifier.
TL.setBuiltinLoc(DS.getTypeSpecTypeLoc());
@@ -2640,13 +2668,17 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
CheckExtraCXXDefaultArguments(D);
// C++0x [dcl.type]p3:
- // A type-specifier-seq shall not define a class or enumeration
- // unless it appears in the type-id of an alias-declaration
- // (7.1.3).
- if (OwnedTag && OwnedTag->isDefinition() &&
- D.getContext() != Declarator::AliasDeclContext)
- Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
- << Context.getTypeDeclType(OwnedTag);
+ // A type-specifier-seq shall not define a class or enumeration unless
+ // it appears in the type-id of an alias-declaration (7.1.3) that is not
+ // the declaration of a template-declaration.
+ if (OwnedTag && OwnedTag->isDefinition()) {
+ if (D.getContext() == Declarator::AliasTemplateContext)
+ Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template)
+ << Context.getTypeDeclType(OwnedTag);
+ else if (D.getContext() != Declarator::AliasDeclContext)
+ Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
+ << Context.getTypeDeclType(OwnedTag);
+ }
}
return CreateParsedType(T, TInfo);
@@ -3213,6 +3245,82 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
} while ((attrs = next));
}
+/// \brief Ensure that the type of the given expression is complete.
+///
+/// This routine checks whether the expression \p E has a complete type. If the
+/// expression refers to an instantiable construct, that instantiation is
+/// performed as needed to complete its type. Furthermore
+/// Sema::RequireCompleteType is called for the expression's type (or in the
+/// case of a reference type, the referred-to type).
+///
+/// \param E The expression whose type is required to be complete.
+/// \param PD The partial diagnostic that will be printed out if the type cannot
+/// be completed.
+///
+/// \returns \c true if the type of \p E is incomplete and diagnosed, \c false
+/// otherwise.
+bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
+ std::pair<SourceLocation,
+ PartialDiagnostic> Note) {
+ QualType T = E->getType();
+
+ // Fast path the case where the type is already complete.
+ if (!T->isIncompleteType())
+ return false;
+
+ // Incomplete array types may be completed by the initializer attached to
+ // their definitions. For static data members of class templates we need to
+ // instantiate the definition to get this initializer and complete the type.
+ if (T->isIncompleteArrayType()) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (Var->isStaticDataMember() &&
+ Var->getInstantiatedFromStaticDataMember()) {
+
+ MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
+ assert(MSInfo && "Missing member specialization information?");
+ if (MSInfo->getTemplateSpecializationKind()
+ != TSK_ExplicitSpecialization) {
+ // If we don't already have a point of instantiation, this is it.
+ if (MSInfo->getPointOfInstantiation().isInvalid()) {
+ MSInfo->setPointOfInstantiation(E->getLocStart());
+
+ // This is a modification of an existing AST node. Notify
+ // listeners.
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->StaticDataMemberInstantiated(Var);
+ }
+
+ InstantiateStaticDataMemberDefinition(E->getExprLoc(), Var);
+
+ // Update the type to the newly instantiated definition's type both
+ // here and within the expression.
+ if (VarDecl *Def = Var->getDefinition()) {
+ DRE->setDecl(Def);
+ T = Def->getType();
+ DRE->setType(T);
+ E->setType(T);
+ }
+ }
+
+ // We still go on to try to complete the type independently, as it
+ // may also require instantiations or diagnostics if it remains
+ // incomplete.
+ }
+ }
+ }
+ }
+
+ // FIXME: Are there other cases which require instantiating something other
+ // than the type to complete the type of an expression?
+
+ // Look through reference types and complete the referred type.
+ if (const ReferenceType *Ref = T->getAs<ReferenceType>())
+ T = Ref->getPointeeType();
+
+ return RequireCompleteType(E->getExprLoc(), T, PD, Note);
+}
+
/// @brief Ensure that the type T is a complete type.
///
/// This routine checks whether the type @p T is complete in any
@@ -3363,3 +3471,27 @@ QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) {
return Context.getDecltypeType(E);
}
+
+QualType Sema::BuildUnaryTransformType(QualType BaseType,
+ UnaryTransformType::UTTKind UKind,
+ SourceLocation Loc) {
+ switch (UKind) {
+ case UnaryTransformType::EnumUnderlyingType:
+ if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) {
+ Diag(Loc, diag::err_only_enums_have_underlying_types);
+ return QualType();
+ } else {
+ QualType Underlying = BaseType;
+ if (!BaseType->isDependentType()) {
+ EnumDecl *ED = BaseType->getAs<EnumType>()->getDecl();
+ assert(ED && "EnumType has no EnumDecl");
+ DiagnoseUseOfDecl(ED, Loc);
+ Underlying = ED->getIntegerType();
+ }
+ assert(!Underlying.isNull());
+ return Context.getUnaryTransformType(BaseType, Underlying,
+ UnaryTransformType::EnumUnderlyingType);
+ }
+ }
+ llvm_unreachable("unknown unary transform type");
+}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 2a71e14265a8..ff2e46a9026b 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -21,6 +21,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -701,6 +702,11 @@ public:
/// By default, builds a new TypeOfType with the given underlying type.
QualType RebuildTypeOfType(QualType Underlying);
+ /// \brief Build a new unary transform type.
+ QualType RebuildUnaryTransformType(QualType BaseType,
+ UnaryTransformType::UTTKind UKind,
+ SourceLocation Loc);
+
/// \brief Build a new C++0x decltype type.
///
/// By default, performs semantic analysis when building the decltype type.
@@ -855,7 +861,7 @@ public:
case LookupResult::Found:
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue: {
- NamedDecl *SomeDecl = Result.getRepresentativeDecl();
+ NamedDecl *SomeDecl = Result.getRepresentativeDecl();
unsigned Kind = 0;
if (isa<TypedefDecl>(SomeDecl)) Kind = 1;
else if (isa<TypeAliasDecl>(SomeDecl)) Kind = 2;
@@ -863,7 +869,7 @@ public:
SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind;
SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at);
break;
- }
+ }
default:
// FIXME: Would be nice to highlight just the source range.
SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope)
@@ -873,7 +879,8 @@ public:
return QualType();
}
- if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, IdLoc, *Id)) {
+ if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, /*isDefinition*/false,
+ IdLoc, *Id)) {
SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id;
SemaRef.Diag(Tag->getLocation(), diag::note_previous_use);
return QualType();
@@ -1372,7 +1379,7 @@ public:
UnaryExprOrTypeTrait ExprKind,
SourceRange R) {
ExprResult Result
- = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind, R);
+ = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind);
if (Result.isInvalid())
return ExprError();
@@ -2567,9 +2574,13 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
Q.getLocalEndLoc());
break;
}
-
- SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
- << TL.getType() << SS.getRange();
+ // If the nested-name-specifier is an invalid type def, don't emit an
+ // error because a previous error should have already been emitted.
+ TypedefTypeLoc* TTL = dyn_cast<TypedefTypeLoc>(&TL);
+ if (!TTL || !TTL->getTypedefNameDecl()->isInvalidDecl()) {
+ SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
+ << TL.getType() << SS.getRange();
+ }
return NestedNameSpecifierLoc();
}
}
@@ -4154,6 +4165,29 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
}
template<typename Derived>
+QualType TreeTransform<Derived>::TransformUnaryTransformType(
+ TypeLocBuilder &TLB,
+ UnaryTransformTypeLoc TL) {
+ QualType Result = TL.getType();
+ if (Result->isDependentType()) {
+ const UnaryTransformType *T = TL.getTypePtr();
+ QualType NewBase =
+ getDerived().TransformType(TL.getUnderlyingTInfo())->getType();
+ Result = getDerived().RebuildUnaryTransformType(NewBase,
+ T->getUTTKind(),
+ TL.getKWLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ UnaryTransformTypeLoc NewTL = TLB.push<UnaryTransformTypeLoc>(Result);
+ NewTL.setKWLoc(TL.getKWLoc());
+ NewTL.setParensRange(TL.getParensRange());
+ NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo());
+ return Result;
+}
+
+template<typename Derived>
QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
AutoTypeLoc TL) {
const AutoType *T = TL.getTypePtr();
@@ -4389,6 +4423,23 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
NewTemplateArgs);
if (!Result.isNull()) {
+ // Specializations of template template parameters are represented as
+ // TemplateSpecializationTypes, and substitution of type alias templates
+ // within a dependent context can transform them into
+ // DependentTemplateSpecializationTypes.
+ if (isa<DependentTemplateSpecializationType>(Result)) {
+ DependentTemplateSpecializationTypeLoc NewTL
+ = TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getTemplateNameLoc());
+ NewTL.setQualifierLoc(NestedNameSpecifierLoc());
+ NewTL.setNameLoc(TL.getTemplateNameLoc());
+ NewTL.setLAngleLoc(TL.getLAngleLoc());
+ NewTL.setRAngleLoc(TL.getRAngleLoc());
+ for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i)
+ NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo());
+ return Result;
+ }
+
TemplateSpecializationTypeLoc NewTL
= TLB.push<TemplateSpecializationTypeLoc>(Result);
NewTL.setTemplateNameLoc(TL.getTemplateNameLoc());
@@ -4478,6 +4529,23 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
if (NamedT.isNull())
return QualType();
+ // C++0x [dcl.type.elab]p2:
+ // If the identifier resolves to a typedef-name or the simple-template-id
+ // resolves to an alias template specialization, the
+ // elaborated-type-specifier is ill-formed.
+ if (T->getKeyword() != ETK_None && T->getKeyword() != ETK_Typename) {
+ if (const TemplateSpecializationType *TST =
+ NamedT->getAs<TemplateSpecializationType>()) {
+ TemplateName Template = TST->getTemplateName();
+ if (TypeAliasTemplateDecl *TAT =
+ dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) {
+ SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(),
+ diag::err_tag_reference_non_tag) << 4;
+ SemaRef.Diag(TAT->getLocation(), diag::note_declared_at);
+ }
+ }
+ }
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
QualifierLoc != TL.getQualifierLoc() ||
@@ -6629,8 +6697,12 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
DeclContext *DC = getSema().getFunctionLevelDeclContext();
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC);
- QualType T = MD->getThisType(getSema().Context);
+ QualType T;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+ T = MD->getThisType(getSema().Context);
+ else
+ T = getSema().Context.getPointerType(
+ getSema().Context.getRecordType(cast<CXXRecordDecl>(DC)));
if (!getDerived().AlwaysRebuild() && T == E->getType())
return SemaRef.Owned(E);
@@ -7449,6 +7521,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) {
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
ExprResult SubExpr = getDerived().TransformExpr(E->getOperand());
if (SubExpr.isInvalid())
return ExprError();
@@ -7700,6 +7773,11 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
BlockScopeInfo *blockScope = SemaRef.getCurBlock();
blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic());
+ // We built a new blockScopeInfo in call to ActOnBlockStart
+ // in above, CapturesCXXThis need be set here from the block
+ // expression.
+ blockScope->CapturesCXXThis = oldBlock->capturesCXXThis();
+
llvm::SmallVector<ParmVarDecl*, 4> params;
llvm::SmallVector<QualType, 4> paramTypes;
@@ -7759,22 +7837,21 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
#ifndef NDEBUG
// In builds with assertions, make sure that we captured everything we
// captured before.
+ if (!SemaRef.getDiagnostics().hasErrorOccurred()) {
+ for (BlockDecl::capture_iterator i = oldBlock->capture_begin(),
+ e = oldBlock->capture_end(); i != e; ++i) {
+ VarDecl *oldCapture = i->getVariable();
+
+ // Ignore parameter packs.
+ if (isa<ParmVarDecl>(oldCapture) &&
+ cast<ParmVarDecl>(oldCapture)->isParameterPack())
+ continue;
- if (oldBlock->capturesCXXThis()) assert(blockScope->CapturesCXXThis);
-
- for (BlockDecl::capture_iterator i = oldBlock->capture_begin(),
- e = oldBlock->capture_end(); i != e; ++i) {
- VarDecl *oldCapture = i->getVariable();
-
- // Ignore parameter packs.
- if (isa<ParmVarDecl>(oldCapture) &&
- cast<ParmVarDecl>(oldCapture)->isParameterPack())
- continue;
-
- VarDecl *newCapture =
- cast<VarDecl>(getDerived().TransformDecl(E->getCaretLocation(),
- oldCapture));
- assert(blockScope->CaptureMap.count(newCapture));
+ VarDecl *newCapture =
+ cast<VarDecl>(getDerived().TransformDecl(E->getCaretLocation(),
+ oldCapture));
+ assert(blockScope->CaptureMap.count(newCapture));
+ }
}
#endif
@@ -7805,6 +7882,13 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
ND, NameInfo, 0);
}
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) {
+ assert(false && "Cannot transform asType expressions yet");
+ return SemaRef.Owned(E);
+}
+
//===----------------------------------------------------------------------===//
// Type reconstruction
//===----------------------------------------------------------------------===//
@@ -8010,6 +8094,13 @@ QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E,
}
template<typename Derived>
+QualType TreeTransform<Derived>::RebuildUnaryTransformType(QualType BaseType,
+ UnaryTransformType::UTTKind UKind,
+ SourceLocation Loc) {
+ return SemaRef.BuildUnaryTransformType(BaseType, UKind, Loc);
+}
+
+template<typename Derived>
QualType TreeTransform<Derived>::RebuildTemplateSpecializationType(
TemplateName Template,
SourceLocation TemplateNameLoc,
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index d2e41a96c946..8fb20d22b7de 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -92,6 +92,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_IMPORTANT(AppleKext, diag::warn_pch_apple_kext);
PARSE_LANGOPT_IMPORTANT(ObjCDefaultSynthProperties,
diag::warn_pch_objc_auto_properties);
+ PARSE_LANGOPT_BENIGN(ObjCInferRelatedResultType)
PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings,
diag::warn_pch_no_constant_cfstrings);
PARSE_LANGOPT_BENIGN(PascalStrings);
@@ -1697,7 +1698,8 @@ namespace {
using namespace clang::io;
HeaderFileInfo HFI;
unsigned Flags = *d++;
- HFI.isImport = (Flags >> 3) & 0x01;
+ HFI.isImport = (Flags >> 4) & 0x01;
+ HFI.isPragmaOnce = (Flags >> 3) & 0x01;
HFI.DirInfo = (Flags >> 1) & 0x03;
HFI.Resolved = Flags & 0x01;
HFI.NumIncludes = ReadUnalignedLE16(d);
@@ -1841,6 +1843,22 @@ MacroDefinition *ASTReader::getMacroDefinition(MacroID ID) {
return MacroDefinitionsLoaded[ID - 1];
}
+const FileEntry *ASTReader::getFileEntry(llvm::StringRef filenameStrRef) {
+ std::string Filename = filenameStrRef;
+ MaybeAddSystemRootToFilename(Filename);
+ const FileEntry *File = FileMgr.getFile(Filename);
+ if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() &&
+ OriginalDir != CurrentDir) {
+ std::string resolved = resolveFileRelativeToOriginalDir(Filename,
+ OriginalDir,
+ CurrentDir);
+ if (!resolved.empty())
+ File = FileMgr.getFile(resolved);
+ }
+
+ return File;
+}
+
/// \brief If we are loading a relocatable PCH file, and the filename is
/// not an absolute path, add the system root to the beginning of the file
/// name.
@@ -2113,15 +2131,6 @@ ASTReader::ReadASTBlock(PerFileData &F) {
TotalVisibleDeclContexts += Record[3];
break;
- case TENTATIVE_DEFINITIONS:
- // Optimization for the first block.
- if (TentativeDefinitions.empty())
- TentativeDefinitions.swap(Record);
- else
- TentativeDefinitions.insert(TentativeDefinitions.end(),
- Record.begin(), Record.end());
- break;
-
case UNUSED_FILESCOPED_DECLS:
// Optimization for the first block.
if (UnusedFileScopedDecls.empty())
@@ -2131,6 +2140,15 @@ ASTReader::ReadASTBlock(PerFileData &F) {
Record.begin(), Record.end());
break;
+ case DELEGATING_CTORS:
+ // Optimization for the first block.
+ if (DelegatingCtorDecls.empty())
+ DelegatingCtorDecls.swap(Record);
+ else
+ DelegatingCtorDecls.insert(DelegatingCtorDecls.end(),
+ Record.begin(), Record.end());
+ break;
+
case WEAK_UNDECLARED_IDENTIFIERS:
// Later blocks overwrite earlier ones.
WeakUndeclaredIdentifiers.swap(Record);
@@ -2176,6 +2194,11 @@ ASTReader::ReadASTBlock(PerFileData &F) {
F.LocalSLocSize = Record[1];
break;
+ case FILE_SOURCE_LOCATION_OFFSETS:
+ F.SLocFileOffsets = (const uint32_t *)BlobStart;
+ F.LocalNumSLocFileEntries = Record[0];
+ break;
+
case SOURCE_LOCATION_PRELOADS:
if (PreloadSLocEntries.empty())
PreloadSLocEntries.swap(Record);
@@ -2236,6 +2259,10 @@ ASTReader::ReadASTBlock(PerFileData &F) {
MaybeAddSystemRootToFilename(OriginalFileName);
break;
+ case ORIGINAL_FILE_ID:
+ OriginalFileID = FileID::get(Record[0]);
+ break;
+
case ORIGINAL_PCH_DIR:
// The primary AST will be the last to get here, so it will be the one
// that's used.
@@ -2330,6 +2357,15 @@ ASTReader::ReadASTBlock(PerFileData &F) {
// Later tables overwrite earlier ones.
OpenCLExtensions.swap(Record);
break;
+
+ case TENTATIVE_DEFINITIONS:
+ // Optimization for the first block.
+ if (TentativeDefinitions.empty())
+ TentativeDefinitions.swap(Record);
+ else
+ TentativeDefinitions.insert(TentativeDefinitions.end(),
+ Record.begin(), Record.end());
+ break;
}
First = false;
}
@@ -2337,6 +2373,75 @@ ASTReader::ReadASTBlock(PerFileData &F) {
return Failure;
}
+ASTReader::ASTReadResult ASTReader::validateFileEntries() {
+ for (unsigned CI = 0, CN = Chain.size(); CI != CN; ++CI) {
+ PerFileData *F = Chain[CI];
+ llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
+
+ for (unsigned i = 0, e = F->LocalNumSLocFileEntries; i != e; ++i) {
+ SLocEntryCursor.JumpToBit(F->SLocFileOffsets[i]);
+ unsigned Code = SLocEntryCursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK ||
+ Code == llvm::bitc::ENTER_SUBBLOCK ||
+ Code == llvm::bitc::DEFINE_ABBREV) {
+ Error("incorrectly-formatted source location entry in AST file");
+ return Failure;
+ }
+
+ RecordData Record;
+ const char *BlobStart;
+ unsigned BlobLen;
+ switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default:
+ Error("incorrectly-formatted source location entry in AST file");
+ return Failure;
+
+ case SM_SLOC_FILE_ENTRY: {
+ llvm::StringRef Filename(BlobStart, BlobLen);
+ const FileEntry *File = getFileEntry(Filename);
+
+ if (File == 0) {
+ std::string ErrorStr = "could not find file '";
+ ErrorStr += Filename;
+ ErrorStr += "' referenced by AST file";
+ Error(ErrorStr.c_str());
+ return IgnorePCH;
+ }
+
+ if (Record.size() < 6) {
+ Error("source location entry is incorrect");
+ return Failure;
+ }
+
+ // The stat info from the FileEntry came from the cached stat
+ // info of the PCH, so we cannot trust it.
+ struct stat StatBuf;
+ if (::stat(File->getName(), &StatBuf) != 0) {
+ StatBuf.st_size = File->getSize();
+ StatBuf.st_mtime = File->getModificationTime();
+ }
+
+ if (((off_t)Record[4] != StatBuf.st_size
+#if !defined(LLVM_ON_WIN32)
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ || (time_t)Record[5] != StatBuf.st_mtime
+#endif
+ )) {
+ Error(diag::err_fe_pch_file_modified, Filename);
+ return IgnorePCH;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ return Success;
+}
+
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ASTFileType Type) {
switch(ReadASTCore(FileName, Type)) {
@@ -2347,6 +2452,14 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
// Here comes stuff that we only do once the entire chain is loaded.
+ if (!DisableValidation) {
+ switch(validateFileEntries()) {
+ case Failure: return Failure;
+ case IgnorePCH: return IgnorePCH;
+ case Success: break;
+ }
+ }
+
// Allocate space for loaded slocentries, identifiers, decls and types.
unsigned TotalNumIdentifiers = 0, TotalNumTypes = 0, TotalNumDecls = 0,
TotalNumPreallocatedPreprocessingEntities = 0, TotalNumMacroDefs = 0,
@@ -2372,7 +2485,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
PP->getHeaderSearchInfo().SetExternalLookup(this);
if (TotalNumPreallocatedPreprocessingEntities > 0) {
if (!PP->getPreprocessingRecord())
- PP->createPreprocessingRecord();
+ PP->createPreprocessingRecord(true);
PP->getPreprocessingRecord()->SetExternalSource(*this,
TotalNumPreallocatedPreprocessingEntities);
}
@@ -2441,12 +2554,15 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
// the source manager to the file source file from which the preamble was
// built. This is the only valid way to use a precompiled preamble.
if (Type == Preamble) {
- SourceLocation Loc
- = SourceMgr.getLocation(FileMgr.getFile(getOriginalSourceFile()), 1, 1);
- if (Loc.isValid()) {
- std::pair<FileID, unsigned> Decomposed = SourceMgr.getDecomposedLoc(Loc);
- SourceMgr.SetPreambleFileID(Decomposed.first);
+ if (OriginalFileID.isInvalid()) {
+ SourceLocation Loc
+ = SourceMgr.getLocation(FileMgr.getFile(getOriginalSourceFile()), 1, 1);
+ if (Loc.isValid())
+ OriginalFileID = SourceMgr.getDecomposedLoc(Loc).first;
}
+
+ if (!OriginalFileID.isInvalid())
+ SourceMgr.SetPreambleFileID(OriginalFileID);
}
return Success;
@@ -2571,7 +2687,7 @@ void ASTReader::setPreprocessor(Preprocessor &pp) {
TotalNum += Chain[I]->NumPreallocatedPreprocessingEntities;
if (TotalNum) {
if (!PP->getPreprocessingRecord())
- PP->createPreprocessingRecord();
+ PP->createPreprocessingRecord(true);
PP->getPreprocessingRecord()->SetExternalSource(*this, TotalNum);
}
}
@@ -2819,6 +2935,7 @@ bool ASTReader::ParseLanguageOptions(
PARSE_LANGOPT(ObjCNonFragileABI2);
PARSE_LANGOPT(AppleKext);
PARSE_LANGOPT(ObjCDefaultSynthProperties);
+ PARSE_LANGOPT(ObjCInferRelatedResultType);
PARSE_LANGOPT(NoConstantCFStrings);
PARSE_LANGOPT(PascalStrings);
PARSE_LANGOPT(WritableStrings);
@@ -3182,6 +3299,13 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
case TYPE_DECLTYPE:
return Context->getDecltypeType(ReadExpr(*Loc.F));
+ case TYPE_UNARY_TRANSFORM: {
+ QualType BaseType = GetType(Record[0]);
+ QualType UnderlyingType = GetType(Record[1]);
+ UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2];
+ return Context->getUnaryTransformType(BaseType, UnderlyingType, UKind);
+ }
+
case TYPE_AUTO:
return Context->getAutoType(GetType(Record[0]));
@@ -3356,14 +3480,14 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
llvm::SmallVector<TemplateArgument, 8> Args;
ReadTemplateArgumentList(Args, *Loc.F, Record, Idx);
- QualType Canon = GetType(Record[Idx++]);
+ QualType Underlying = GetType(Record[Idx++]);
QualType T;
- if (Canon.isNull())
+ if (Underlying.isNull())
T = Context->getCanonicalTemplateSpecializationType(Name, Args.data(),
Args.size());
else
T = Context->getTemplateSpecializationType(Name, Args.data(),
- Args.size(), Canon);
+ Args.size(), Underlying);
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
return T;
}
@@ -3498,6 +3622,12 @@ void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
+void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ TL.setKWLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
+}
void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
@@ -4099,6 +4229,13 @@ void ASTReader::InitializeSema(Sema &S) {
SemaObj->UnusedFileScopedDecls.push_back(D);
}
+ // If there were any delegating constructors, add them to Sema's list
+ for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) {
+ CXXConstructorDecl *D
+ = cast<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I]));
+ SemaObj->DelegatingCtorDecls.push_back(D);
+ }
+
// If there were any locally-scoped external declarations,
// deserialize them and add them to Sema's table of locally-scoped
// external declarations.
@@ -4710,18 +4847,28 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record,
bool IsBaseVirtual = false;
FieldDecl *Member = 0;
IndirectFieldDecl *IndirectMember = 0;
+ CXXConstructorDecl *Target = 0;
- bool IsBaseInitializer = Record[Idx++];
- if (IsBaseInitializer) {
+ CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
+ switch (Type) {
+ case CTOR_INITIALIZER_BASE:
BaseClassInfo = GetTypeSourceInfo(F, Record, Idx);
IsBaseVirtual = Record[Idx++];
- } else {
- bool IsIndirectMemberInitializer = Record[Idx++];
- if (IsIndirectMemberInitializer)
- IndirectMember = cast<IndirectFieldDecl>(GetDecl(Record[Idx++]));
- else
- Member = cast<FieldDecl>(GetDecl(Record[Idx++]));
+ break;
+
+ case CTOR_INITIALIZER_DELEGATING:
+ Target = cast<CXXConstructorDecl>(GetDecl(Record[Idx++]));
+ break;
+
+ case CTOR_INITIALIZER_MEMBER:
+ Member = cast<FieldDecl>(GetDecl(Record[Idx++]));
+ break;
+
+ case CTOR_INITIALIZER_INDIRECT_MEMBER:
+ IndirectMember = cast<IndirectFieldDecl>(GetDecl(Record[Idx++]));
+ break;
}
+
SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
Expr *Init = ReadExpr(F);
SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
@@ -4739,10 +4886,13 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record,
}
CXXCtorInitializer *BOMInit;
- if (IsBaseInitializer) {
+ if (Type == CTOR_INITIALIZER_BASE) {
BOMInit = new (C) CXXCtorInitializer(C, BaseClassInfo, IsBaseVirtual,
LParenLoc, Init, RParenLoc,
MemberOrEllipsisLoc);
+ } else if (Type == CTOR_INITIALIZER_DELEGATING) {
+ BOMInit = new (C) CXXCtorInitializer(C, MemberOrEllipsisLoc, LParenLoc,
+ Target, Init, RParenLoc);
} else if (IsWritten) {
if (Member)
BOMInit = new (C) CXXCtorInitializer(C, Member, MemberOrEllipsisLoc,
@@ -5050,7 +5200,8 @@ ASTReader::~ASTReader() {
}
ASTReader::PerFileData::PerFileData(ASTFileType Ty)
- : Type(Ty), SizeInBits(0), LocalNumSLocEntries(0), SLocOffsets(0), LocalSLocSize(0),
+ : Type(Ty), SizeInBits(0), LocalNumSLocEntries(0), SLocOffsets(0),
+ SLocFileOffsets(0), LocalSLocSize(0),
LocalNumIdentifiers(0), IdentifierOffsets(0), IdentifierTableData(0),
IdentifierLookupTable(0), LocalNumMacroDefinitions(0),
MacroDefinitionOffsets(0),
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 3a825de6e6d8..fab2069bc5f4 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -125,6 +125,7 @@ namespace clang {
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
@@ -173,6 +174,18 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() {
void ASTDeclReader::Visit(Decl *D) {
DeclVisitor<ASTDeclReader, void>::Visit(D);
+ if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (DD->DeclInfo) {
+ DeclaratorDecl::ExtInfo *Info =
+ DD->DeclInfo.get<DeclaratorDecl::ExtInfo *>();
+ Info->TInfo =
+ GetTypeSourceInfo(Record, Idx);
+ }
+ else {
+ DD->DeclInfo = GetTypeSourceInfo(Record, Idx);
+ }
+ }
+
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
// if we have a fully initialized TypeDecl, we can safely read its type now.
TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
@@ -307,10 +320,8 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
DeclaratorDecl::ExtInfo *Info
= new (*Reader.getContext()) DeclaratorDecl::ExtInfo();
ReadQualifierInfo(*Info, Record, Idx);
- Info->TInfo = GetTypeSourceInfo(Record, Idx);
DD->DeclInfo = Info;
- } else
- DD->DeclInfo = GetTypeSourceInfo(Record, Idx);
+ }
}
void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
@@ -428,6 +439,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->HasWrittenPrototype = Record[Idx++];
FD->IsDeleted = Record[Idx++];
FD->IsTrivial = Record[Idx++];
+ FD->IsDefaulted = Record[Idx++];
+ FD->IsExplicitlyDefaulted = Record[Idx++];
FD->HasImplicitReturnZero = Record[Idx++];
FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
@@ -455,6 +468,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
MD->setDefined(Record[Idx++]);
MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ MD->SetRelatedResultType(Record[Idx++]);
MD->setNumSelectorArgs(unsigned(Record[Idx++]));
MD->setResultType(Reader.GetType(Record[Idx++]));
MD->setResultTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
@@ -663,8 +677,11 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
VisitDeclaratorDecl(FD);
FD->setMutable(Record[Idx++]);
- if (Record[Idx++])
+ int BitWidthOrInitializer = Record[Idx++];
+ if (BitWidthOrInitializer == 1)
FD->setBitWidth(Reader.ReadExpr(F));
+ else if (BitWidthOrInitializer == 2)
+ FD->setInClassInitializer(Reader.ReadExpr(F));
if (!FD->getDeclName()) {
FieldDecl *Tmpl = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
if (Tmpl)
@@ -857,7 +874,8 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasPrivateFields = Record[Idx++];
Data.HasProtectedFields = Record[Idx++];
Data.HasPublicFields = Record[Idx++];
- Data.HasTrivialConstructor = Record[Idx++];
+ Data.HasMutableFields = Record[Idx++];
+ Data.HasTrivialDefaultConstructor = Record[Idx++];
Data.HasConstExprNonCopyMoveConstructor = Record[Idx++];
Data.HasTrivialCopyConstructor = Record[Idx++];
Data.HasTrivialMoveConstructor = Record[Idx++];
@@ -866,6 +884,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasTrivialDestructor = Record[Idx++];
Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
Data.ComputedVisibleConversions = Record[Idx++];
+ Data.UserProvidedDefaultConstructor = Record[Idx++];
Data.DeclaredDefaultConstructor = Record[Idx++];
Data.DeclaredCopyConstructor = Record[Idx++];
Data.DeclaredCopyAssignment = Record[Idx++];
@@ -1266,6 +1285,10 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
D->ParameterPack = Record[Idx++];
}
+void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+}
+
void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
VisitDecl(D);
D->AssertExpr = Reader.ReadExpr(F);
@@ -1380,7 +1403,7 @@ static bool isConsumerInterestedIn(Decl *D) {
return Var->isFileVarDecl() &&
Var->isThisDeclarationADefinition() == VarDecl::Definition;
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
- return Func->isThisDeclarationADefinition();
+ return Func->doesThisDeclarationHaveABody();
return isa<ObjCProtocolDecl>(D) || isa<ObjCImplementationDecl>(D);
}
@@ -1572,6 +1595,9 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0,
false, 0, 0);
break;
+ case DECL_TYPE_ALIAS_TEMPLATE:
+ D = TypeAliasTemplateDecl::Create(*Context, Decl::EmptyShell());
+ break;
case DECL_STATIC_ASSERT:
D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0,
SourceLocation());
@@ -1626,7 +1652,7 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
break;
case DECL_FIELD:
D = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, 0, false);
+ QualType(), 0, 0, false, false);
break;
case DECL_INDIRECTFIELD:
D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 918db7e367c6..f3f67a76c4d4 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -189,7 +189,7 @@ namespace clang {
void VisitOpaqueValueExpr(OpaqueValueExpr *E);
// CUDA Expressions
- void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
+ void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
};
}
@@ -2000,6 +2000,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
case EXPR_CUDA_KERNEL_CALL:
S = new (Context) CUDAKernelCallExpr(*Context, Empty);
break;
+
+ case EXPR_ASTYPE:
+ S = new (Context) AsTypeExpr(Empty);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 6d44fb63e5a2..ba9032e0d33e 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -223,6 +223,13 @@ void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
Code = TYPE_DECLTYPE;
}
+void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {
+ Writer.AddTypeRef(T->getBaseType(), Record);
+ Writer.AddTypeRef(T->getUnderlyingType(), Record);
+ Record.push_back(T->getUTTKind());
+ Code = TYPE_UNARY_TRANSFORM;
+}
+
void ASTTypeWriter::VisitAutoType(const AutoType *T) {
Writer.AddTypeRef(T->getDeducedType(), Record);
Code = TYPE_AUTO;
@@ -277,7 +284,8 @@ ASTTypeWriter::VisitTemplateSpecializationType(
for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end();
ArgI != ArgE; ++ArgI)
Writer.AddTemplateArgument(*ArgI, Record);
- Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
+ Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() :
+ T->isCanonicalUnqualified() ? QualType()
: T->getCanonicalTypeInternal(),
Record);
Code = TYPE_TEMPLATE_SPECIALIZATION;
@@ -493,6 +501,12 @@ void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
+void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKWLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
+}
void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
@@ -726,6 +740,7 @@ void ASTWriter::WriteBlockInfoBlock() {
// AST Top-Level Block.
BLOCK(AST_BLOCK);
RECORD(ORIGINAL_FILE_NAME);
+ RECORD(ORIGINAL_FILE_ID);
RECORD(TYPE_OFFSET);
RECORD(DECL_OFFSET);
RECORD(LANGUAGE_OPTIONS);
@@ -764,6 +779,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(HEADER_SEARCH_TABLE);
RECORD(FP_PRAGMA_OPTIONS);
RECORD(OPENCL_EXTENSIONS);
+ RECORD(DELEGATING_CTORS);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -873,13 +889,14 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_INDIRECTFIELD);
RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK);
+ // Statements and Exprs can occur in the Decls and Types block.
+ AddStmtsExprs(Stream, Record);
+
BLOCK(PREPROCESSOR_DETAIL_BLOCK);
RECORD(PPD_MACRO_INSTANTIATION);
RECORD(PPD_MACRO_DEFINITION);
RECORD(PPD_INCLUSION_DIRECTIVE);
- // Statements and Exprs can occur in the Decls and Types block.
- AddStmtsExprs(Stream, Record);
#undef RECORD
#undef BLOCK
Stream.ExitBlock();
@@ -951,7 +968,7 @@ void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot,
const std::string &BlobStr = Chain ? Chain->getFileName() : Target.getTriple().getTriple();
Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, BlobStr);
- // Original file name
+ // Original file name and file ID
SourceManager &SM = Context.getSourceManager();
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
@@ -969,6 +986,10 @@ void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot,
RecordData Record;
Record.push_back(ORIGINAL_FILE_NAME);
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
+
+ Record.clear();
+ Record.push_back(SM.getMainFileID().getOpaqueValue());
+ Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
}
// Original PCH directory
@@ -1029,6 +1050,7 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.AppleKext); // Apple's kernel extensions ABI
Record.push_back(LangOpts.ObjCDefaultSynthProperties); // Objective-C auto-synthesized
// properties enabled.
+ Record.push_back(LangOpts.ObjCInferRelatedResultType);
Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled..
Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
@@ -1280,7 +1302,8 @@ namespace {
using namespace clang::io;
uint64_t Start = Out.tell(); (void)Start;
- unsigned char Flags = (Data.isImport << 3)
+ unsigned char Flags = (Data.isImport << 4)
+ | (Data.isPragmaOnce << 3)
| (Data.DirInfo << 1)
| Data.Resolved;
Emit8(Out, (uint8_t)Flags);
@@ -1428,6 +1451,9 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Write out the source location entry table. We skip the first
// entry, which is always the same dummy entry.
std::vector<uint32_t> SLocEntryOffsets;
+ // Write out the offsets of only source location file entries.
+ // We will go through them in ASTReader::validateFileEntries().
+ std::vector<uint32_t> SLocFileEntryOffsets;
RecordData PreloadSLocs;
unsigned BaseSLocID = Chain ? Chain->getTotalNumSLocs() : 0;
SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1 - BaseSLocID);
@@ -1442,9 +1468,10 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Figure out which record code to use.
unsigned Code;
if (SLoc->isFile()) {
- if (SLoc->getFile().getContentCache()->OrigEntry)
+ if (SLoc->getFile().getContentCache()->OrigEntry) {
Code = SM_SLOC_FILE_ENTRY;
- else
+ SLocFileEntryOffsets.push_back(Stream.GetCurrentBitNo());
+ } else
Code = SM_SLOC_BUFFER_ENTRY;
} else
Code = SM_SLOC_INSTANTIATION_ENTRY;
@@ -1544,6 +1571,18 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.push_back(SourceMgr.getNextOffset() - BaseOffset);
Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets));
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(FILE_SOURCE_LOCATION_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
+ unsigned SLocFileOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Record.clear();
+ Record.push_back(FILE_SOURCE_LOCATION_OFFSETS);
+ Record.push_back(SLocFileEntryOffsets.size());
+ Stream.EmitRecordWithBlob(SLocFileOffsetsAbbrev, Record,
+ data(SLocFileEntryOffsets));
+
// Write the source location entry preloads array, telling the AST
// reader which source locations entries it should load eagerly.
Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs);
@@ -2663,8 +2702,15 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
NextSelectorID(FirstSelectorID), FirstMacroID(1), NextMacroID(FirstMacroID),
CollectedStmts(&StmtsToEmit),
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
- NumVisibleDeclContexts(0), FirstCXXBaseSpecifiersID(1),
- NextCXXBaseSpecifiersID(1)
+ NumVisibleDeclContexts(0),
+ FirstCXXBaseSpecifiersID(1), NextCXXBaseSpecifiersID(1),
+ DeclParmVarAbbrev(0), DeclContextLexicalAbbrev(0),
+ DeclContextVisibleLookupAbbrev(0), UpdateVisibleAbbrev(0),
+ DeclRefExprAbbrev(0), CharacterLiteralAbbrev(0),
+ DeclRecordAbbrev(0), IntegerLiteralAbbrev(0),
+ DeclTypedefAbbrev(0),
+ DeclVarAbbrev(0), DeclFieldAbbrev(0),
+ DeclEnumAbbrev(0), DeclObjCIvarAbbrev(0)
{
}
@@ -2722,6 +2768,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
for (unsigned i=0, e = SemaRef.UnusedFileScopedDecls.size(); i !=e; ++i)
AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls);
+ RecordData DelegatingCtorDecls;
+ for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i)
+ AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls);
+
RecordData WeakUndeclaredIdentifiers;
if (!SemaRef.WeakUndeclaredIdentifiers.empty()) {
WeakUndeclaredIdentifiers.push_back(
@@ -2826,7 +2876,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Keep writing types and declarations until all types and
// declarations have been written.
- Stream.EnterSubblock(DECLTYPES_BLOCK_ID, 3);
+ Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
WriteDeclsBlockAbbrevs();
while (!DeclTypesToEmit.empty()) {
DeclOrType DOT = DeclTypesToEmit.front();
@@ -2896,6 +2946,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Write the record containing CUDA-specific declaration references.
if (!CUDASpecialDeclRefs.empty())
Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs);
+
+ // Write the delegating constructors.
+ if (!DelegatingCtorDecls.empty())
+ Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
// Some simple statistics
Record.clear();
@@ -2970,6 +3024,14 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls);
}
+ // Build a record containing all of the delegating constructor decls in this
+ // file.
+ RecordData DelegatingCtorDecls;
+ for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i) {
+ if (SemaRef.DelegatingCtorDecls[i]->getPCHLevel() == 0)
+ AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls);
+ }
+
// We write the entire table, overwriting the tables from the chain.
RecordData WeakUndeclaredIdentifiers;
if (!SemaRef.WeakUndeclaredIdentifiers.empty()) {
@@ -3044,7 +3106,7 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs);
}
- Stream.EnterSubblock(DECLTYPES_BLOCK_ID, 3);
+ Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
WriteDeclsBlockAbbrevs();
for (DeclsToRewriteTy::iterator
I = DeclsToRewrite.begin(), E = DeclsToRewrite.end(); I != E; ++I)
@@ -3127,6 +3189,10 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Write the record containing declaration references of Sema.
if (!SemaDeclRefs.empty())
Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);
+
+ // Write the delegating constructors.
+ if (!DelegatingCtorDecls.empty())
+ Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
// Write the updates to DeclContexts.
for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator
@@ -3152,7 +3218,7 @@ void ASTWriter::WriteDeclUpdatesBlocks() {
return;
RecordData OffsetsRecord;
- Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, 3);
+ Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
for (DeclUpdateMap::iterator
I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) {
const Decl *D = I->first;
@@ -3743,16 +3809,19 @@ void ASTWriter::AddCXXCtorInitializers(
for (unsigned i=0; i != NumCtorInitializers; ++i) {
const CXXCtorInitializer *Init = CtorInitializers[i];
- Record.push_back(Init->isBaseInitializer());
if (Init->isBaseInitializer()) {
+ Record.push_back(CTOR_INITIALIZER_BASE);
AddTypeSourceInfo(Init->getBaseClassInfo(), Record);
Record.push_back(Init->isBaseVirtual());
+ } else if (Init->isDelegatingInitializer()) {
+ Record.push_back(CTOR_INITIALIZER_DELEGATING);
+ AddDeclRef(Init->getTargetConstructor(), Record);
+ } else if (Init->isMemberInitializer()){
+ Record.push_back(CTOR_INITIALIZER_MEMBER);
+ AddDeclRef(Init->getMember(), Record);
} else {
- Record.push_back(Init->isIndirectMemberInitializer());
- if (Init->isIndirectMemberInitializer())
- AddDeclRef(Init->getIndirectMember(), Record);
- else
- AddDeclRef(Init->getMember(), Record);
+ Record.push_back(CTOR_INITIALIZER_INDIRECT_MEMBER);
+ AddDeclRef(Init->getIndirectMember(), Record);
}
AddSourceLocation(Init->getMemberLocation(), Record);
@@ -3787,7 +3856,8 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasPrivateFields);
Record.push_back(Data.HasProtectedFields);
Record.push_back(Data.HasPublicFields);
- Record.push_back(Data.HasTrivialConstructor);
+ Record.push_back(Data.HasMutableFields);
+ Record.push_back(Data.HasTrivialDefaultConstructor);
Record.push_back(Data.HasConstExprNonCopyMoveConstructor);
Record.push_back(Data.HasTrivialCopyConstructor);
Record.push_back(Data.HasTrivialMoveConstructor);
@@ -3796,6 +3866,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasTrivialDestructor);
Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
Record.push_back(Data.ComputedVisibleConversions);
+ Record.push_back(Data.UserProvidedDefaultConstructor);
Record.push_back(Data.DeclaredDefaultConstructor);
Record.push_back(Data.DeclaredCopyConstructor);
Record.push_back(Data.DeclaredCopyAssignment);
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 1ca00a32f820..7c24088c65ba 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -86,6 +86,7 @@ namespace clang {
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
@@ -123,12 +124,19 @@ namespace clang {
void ASTDeclWriter::Visit(Decl *D) {
DeclVisitor<ASTDeclWriter>::Visit(D);
+ // Source locations require array (variable-length) abbreviations. The
+ // abbreviation infrastructure requires that arrays are encoded last, so
+ // we handle it here in the case of those classes derived from DeclaratorDecl
+ if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)){
+ Writer.AddTypeSourceInfo(DD->getTypeSourceInfo(), Record);
+ }
+
// Handle FunctionDecl's body here and write it after all other Stmts/Exprs
// have been written. We want it last because we will not read it back when
// retrieving it from the AST, we'll just lazily set the offset.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- Record.push_back(FD->isThisDeclarationADefinition());
- if (FD->isThisDeclarationADefinition())
+ Record.push_back(FD->doesThisDeclarationHaveABody());
+ if (FD->doesThisDeclarationHaveABody())
Writer.AddStmt(FD->getBody());
}
}
@@ -168,6 +176,18 @@ void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) {
void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
VisitTypeDecl(D);
Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ D->getPCHLevel() == 0 &&
+ D->RedeclLink.getNext() == D &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getAccess() == AS_none &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier)
+ AbbrevToUse = Writer.getDeclTypedefAbbrev();
+
Code = serialization::DECL_TYPEDEF;
}
@@ -204,6 +224,21 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
Record.push_back(D->isScopedUsingClassTag());
Record.push_back(D->isFixed());
Writer.AddDeclRef(D->getInstantiatedFromMemberEnum(), Record);
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ D->getPCHLevel() == 0 &&
+ !D->hasExtInfo() &&
+ D->RedeclLink.getNext() == D &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getAccess() == AS_none &&
+ !CXXRecordDecl::classofKind(D->getKind()) &&
+ !D->getIntegerTypeSourceInfo() &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier)
+ AbbrevToUse = Writer.getDeclEnumAbbrev();
+
Code = serialization::DECL_ENUM;
}
@@ -212,6 +247,20 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
Record.push_back(D->hasFlexibleArrayMember());
Record.push_back(D->isAnonymousStructOrUnion());
Record.push_back(D->hasObjectMember());
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ D->getPCHLevel() == 0 &&
+ !D->hasExtInfo() &&
+ D->RedeclLink.getNext() == D &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getAccess() == AS_none &&
+ !CXXRecordDecl::classofKind(D->getKind()) &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier)
+ AbbrevToUse = Writer.getDeclRecordAbbrev();
+
Code = serialization::DECL_RECORD;
}
@@ -226,6 +275,7 @@ void ASTDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
if (D->getInitExpr())
Writer.AddStmt(D->getInitExpr());
Writer.AddAPSInt(D->getInitVal(), Record);
+
Code = serialization::DECL_ENUM_CONSTANT;
}
@@ -235,7 +285,6 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
Record.push_back(D->hasExtInfo());
if (D->hasExtInfo())
Writer.AddQualifierInfo(*D->getExtInfo(), Record);
- Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
}
void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
@@ -321,8 +370,10 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(D->isPure());
Record.push_back(D->hasInheritedPrototype());
Record.push_back(D->hasWrittenPrototype());
- Record.push_back(D->isDeleted());
+ Record.push_back(D->isDeletedAsWritten());
Record.push_back(D->isTrivial());
+ Record.push_back(D->isDefaulted());
+ Record.push_back(D->isExplicitlyDefaulted());
Record.push_back(D->hasImplicitReturnZero());
Writer.AddSourceLocation(D->getLocEnd(), Record);
@@ -353,6 +404,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Record.push_back(D->getImplementationControl());
// FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
Record.push_back(D->getObjCDeclQualifier());
+ Record.push_back(D->hasRelatedResultType());
Record.push_back(D->getNumSelectorArgs());
Writer.AddTypeRef(D->getResultType(), Record);
Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record);
@@ -413,6 +465,18 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
// FIXME: stable encoding for @public/@private/@protected/@package
Record.push_back(D->getAccessControl());
Record.push_back(D->getSynthesize());
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getPCHLevel() == 0 &&
+ !D->getBitWidth() &&
+ !D->hasExtInfo() &&
+ D->getDeclName())
+ AbbrevToUse = Writer.getDeclObjCIvarAbbrev();
+
Code = serialization::DECL_OBJC_IVAR;
}
@@ -535,11 +599,28 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
VisitDeclaratorDecl(D);
Record.push_back(D->isMutable());
- Record.push_back(D->getBitWidth()? 1 : 0);
+ Record.push_back(D->getBitWidth()? 1 : D->hasInClassInitializer() ? 2 : 0);
if (D->getBitWidth())
Writer.AddStmt(D->getBitWidth());
+ else if (D->hasInClassInitializer())
+ Writer.AddStmt(D->getInClassInitializer());
if (!D->getDeclName())
Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record);
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getPCHLevel() == 0 &&
+ !D->getBitWidth() &&
+ !D->hasInClassInitializer() &&
+ !D->hasExtInfo() &&
+ !ObjCIvarDecl::classofKind(D->getKind()) &&
+ !ObjCAtDefsFieldDecl::classofKind(D->getKind()) &&
+ D->getDeclName())
+ AbbrevToUse = Writer.getDeclFieldAbbrev();
+
Code = serialization::DECL_FIELD;
}
@@ -577,6 +658,22 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record);
}
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getAccess() == AS_none &&
+ D->getPCHLevel() == 0 &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier &&
+ !D->hasExtInfo() &&
+ D->RedeclLink.getNext() == D &&
+ !D->hasCXXDirectInitializer() &&
+ D->getInit() == 0 &&
+ !ParmVarDecl::classofKind(D->getKind()) &&
+ !SpecInfo)
+ AbbrevToUse = Writer.getDeclVarAbbrev();
+
Code = serialization::DECL_VAR;
}
@@ -601,8 +698,8 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
// If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here
// we dynamically check for the properties that we optimize for, but don't
// know are true of all PARM_VAR_DECLs.
- if (!D->getTypeSourceInfo() &&
- !D->hasAttrs() &&
+ if (!D->hasAttrs() &&
+ !D->hasExtInfo() &&
!D->isImplicit() &&
!D->isUsed(false) &&
D->getAccess() == AS_none &&
@@ -615,7 +712,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
!D->hasInheritedDefaultArg() &&
D->getInit() == 0 &&
!D->hasUninstantiatedDefaultArg()) // No default expr.
- AbbrevToUse = Writer.getParmVarDeclAbbrev();
+ AbbrevToUse = Writer.getDeclParmVarAbbrev();
// Check things we know are true of *every* PARM_VAR_DECL, which is more than
// just us assuming it.
@@ -1081,6 +1178,11 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
}
+void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+ Code = serialization::DECL_TYPE_ALIAS_TEMPLATE;
+}
+
void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
VisitDecl(D);
Writer.AddStmt(D->getAssertExpr());
@@ -1141,10 +1243,161 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
void ASTWriter::WriteDeclsBlockAbbrevs() {
using namespace llvm;
- // Abbreviation for DECL_PARM_VAR.
- BitCodeAbbrev *Abv = new BitCodeAbbrev();
- Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR));
+ BitCodeAbbrev *Abv;
+
+ // Abbreviation for DECL_FIELD
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ // FieldDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
+ Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclFieldAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_OBJC_IVAR
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_OBJC_IVAR));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ // FieldDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
+ Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth
+ // ObjC Ivar
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclObjCIvarAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_ENUM
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // TypeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ // TagDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isDefinition
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl
+ // EnumDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddTypeRef
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IntegerType
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getPromotionType
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getNumPositiveBits
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getNumNegativeBits
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScoped
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScopedUsingClassTag
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isFixed
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InstantiatedMembEnum
+ // DC
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
+ DeclEnumAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_RECORD
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // TypeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ // TagDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isDefinition
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl
+ // RecordDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasObjectMember
+ // DC
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
+ DeclRecordAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_PARM_VAR
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR));
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1156,7 +1409,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
-
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1165,7 +1417,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// DeclaratorDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
- Abv->Add(BitCodeAbbrevOp(serialization::PREDEF_TYPE_NULL_ID)); // InfoType
// VarDecl
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
@@ -1185,8 +1436,128 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // KNRPromoted
Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg
Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclParmVarAbbrev = Stream.EmitAbbrev(Abv);
- ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv);
+ // Abbreviation for DECL_TYPEDEF
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // TypeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
+ // TypedefDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclTypedefAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_VAR
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_VAR));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ // VarDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClassAsWritten
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isThreadSpecified
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclVarAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for EXPR_DECL_REF
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_DECL_REF));
+ //Stmt
+ //Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ //DeclRefExpr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HasQualifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ DeclRefExprAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for EXPR_INTEGER_LITERAL
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_INTEGER_LITERAL));
+ //Stmt
+ //Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ //Integer Literal
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(32)); // Bit Width
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Value
+ IntegerLiteralAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for EXPR_CHARACTER_LITERAL
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CHARACTER_LITERAL));
+ //Stmt
+ //Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ //Character Literal
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsWide
+ CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv);
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_LEXICAL));
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index bd5889ad9299..00e240494645 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -30,6 +30,7 @@ namespace clang {
public:
serialization::StmtCode Code;
+ unsigned AbbrevToUse;
ASTStmtWriter(ASTWriter &Writer, ASTWriter::RecordData &Record)
: Writer(Writer), Record(Record) { }
@@ -164,6 +165,8 @@ namespace clang {
// CUDA Expressions
void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
+
+ void VisitAsTypeExpr(AsTypeExpr *E);
};
}
@@ -392,6 +395,14 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
Record.push_back(NumTemplateArgs);
}
+ DeclarationName::NameKind nk = (E->getDecl()->getDeclName().getNameKind());
+
+ if ((!E->hasExplicitTemplateArgs()) && (!E->hasQualifier()) &&
+ (E->getDecl() == E->getFoundDecl()) &&
+ nk == DeclarationName::Identifier) {
+ AbbrevToUse = Writer.getDeclRefExprAbbrev();
+ }
+
if (E->hasQualifier())
Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
@@ -411,6 +422,11 @@ void ASTStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) {
VisitExpr(E);
Writer.AddSourceLocation(E->getLocation(), Record);
Writer.AddAPInt(E->getValue(), Record);
+
+ if (E->getValue().getBitWidth() == 32) {
+ AbbrevToUse = Writer.getIntegerLiteralAbbrev();
+ }
+
Code = serialization::EXPR_INTEGER_LITERAL;
}
@@ -449,6 +465,9 @@ void ASTStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) {
Record.push_back(E->getValue());
Writer.AddSourceLocation(E->getLocation(), Record);
Record.push_back(E->isWide());
+
+ AbbrevToUse = Writer.getCharacterLiteralAbbrev();
+
Code = serialization::EXPR_CHARACTER_LITERAL;
}
@@ -1416,6 +1435,15 @@ void ASTStmtWriter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
}
//===----------------------------------------------------------------------===//
+// OpenCL Expressions and Statements.
+//===----------------------------------------------------------------------===//
+void ASTStmtWriter::VisitAsTypeExpr(AsTypeExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSrcExpr());
+ Code = serialization::EXPR_ASTYPE;
+}
+
+//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
@@ -1460,6 +1488,7 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
CollectedStmts = &SubStmts;
Writer.Code = serialization::STMT_NULL_PTR;
+ Writer.AbbrevToUse = 0;
Writer.Visit(S);
#ifndef NDEBUG
@@ -1481,7 +1510,7 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
while (!SubStmts.empty())
WriteSubStmt(SubStmts.pop_back_val());
- Stream.EmitRecord(Writer.Code, Record);
+ Stream.EmitRecord(Writer.Code, Record, Writer.AbbrevToUse);
}
/// \brief Flush all of the statements that have been added to the
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index a6a256a87bcf..f2f5c1ed44e9 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -42,6 +42,7 @@ public:
bool wantsRegionChangeUpdate(const GRState *state) const;
const GRState *checkRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *,
const MemRegion * const *Begin,
const MemRegion * const *End) const;
@@ -77,6 +78,7 @@ public:
void evalStrcmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrncmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const;
+ void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
bool isBounded = false, bool ignoreCase = false) const;
@@ -711,16 +713,13 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// If the size is zero, there won't be any actual memory access, so
// just bind the return value to the destination buffer and return.
if (stateZeroSize) {
+ stateZeroSize = stateZeroSize->BindExpr(CE, destVal);
C.addTransition(stateZeroSize);
- if (IsMempcpy)
- state->BindExpr(CE, destVal);
- else
- state->BindExpr(CE, sizeVal);
- return;
}
// If the size can be nonzero, we have to check the other arguments.
if (stateNonZeroSize) {
+ state = stateNonZeroSize;
// Ensure the destination is not null. If it is NULL there will be a
// NULL pointer dereference.
@@ -737,42 +736,55 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
if (!state)
return;
- // Ensure the buffers do not overlap.
- state = stateNonZeroSize;
+ // Ensure the accesses are valid and that the buffers do not overlap.
state = CheckBufferAccess(C, state, Size, Dest, Source,
/* FirstIsDst = */ true);
if (Restricted)
state = CheckOverlap(C, state, Size, Dest, Source);
- if (state) {
-
- // If this is mempcpy, get the byte after the last byte copied and
- // bind the expr.
- if (IsMempcpy) {
- loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal);
-
- // Get the length to copy.
- SVal lenVal = state->getSVal(Size);
- NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&lenVal);
-
+ if (!state)
+ return;
+
+ // If this is mempcpy, get the byte after the last byte copied and
+ // bind the expr.
+ if (IsMempcpy) {
+ loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal);
+ assert(destRegVal && "Destination should be a known MemRegionVal here");
+
+ // Get the length to copy.
+ NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&sizeVal);
+
+ if (lenValNonLoc) {
// Get the byte after the last byte copied.
SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
*destRegVal,
*lenValNonLoc,
Dest->getType());
-
+
// The byte after the last byte copied is the return value.
state = state->BindExpr(CE, lastElement);
+ } else {
+ // If we don't know how much we copied, we can at least
+ // conjure a return value for later.
+ unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ SVal result =
+ C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
+ state = state->BindExpr(CE, result);
}
- // Invalidate the destination.
- // FIXME: Even if we can't perfectly model the copy, we should see if we
- // can use LazyCompoundVals to copy the source values into the destination.
- // This would probably remove any existing bindings past the end of the
- // copied region, but that's still an improvement over blank invalidation.
- state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest));
- C.addTransition(state);
+ } else {
+ // All other copies return the destination buffer.
+ // (Well, bcopy() has a void return type, but this won't hurt.)
+ state = state->BindExpr(CE, destVal);
}
+
+ // Invalidate the destination.
+ // FIXME: Even if we can't perfectly model the copy, we should see if we
+ // can use LazyCompoundVals to copy the source values into the destination.
+ // This would probably remove any existing bindings past the end of the
+ // copied region, but that's still an improvement over blank invalidation.
+ state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest));
+ C.addTransition(state);
}
}
@@ -782,7 +794,7 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
const GRState *state = C.getState();
- state = state->BindExpr(CE, state->getSVal(Dest));
+
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true);
}
@@ -800,7 +812,7 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
const GRState *state = C.getState();
- state = state->BindExpr(CE, state->getSVal(Dest));
+
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1));
}
@@ -953,7 +965,7 @@ void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
}
void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
- // char *strcpy(char *restrict dst, const char *restrict src);
+ // char *strncpy(char *restrict dst, const char *restrict src, size_t n);
evalStrcpyCommon(C, CE,
/* returnEnd = */ false,
/* isBounded = */ true,
@@ -1128,6 +1140,12 @@ void CStringChecker::evalStrcasecmp(CheckerContext &C,
evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true);
}
+void CStringChecker::evalStrncasecmp(CheckerContext &C,
+ const CallExpr *CE) const {
+ //int strncasecmp(const char *restrict s1, const char *restrict s2, size_t n);
+ evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ true);
+}
+
void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
bool isBounded, bool ignoreCase) const {
const GRState *state = C.getState();
@@ -1181,31 +1199,17 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
return;
llvm::APSInt lenInt(CI->getValue());
- // Compare using the bounds provided like strncmp() does.
- if (ignoreCase) {
- // TODO Implement compare_lower(RHS, n) in LLVM StringRef.
- // result = s1StrRef.compare_lower(s2StrRef,
- // (size_t)lenInt.getLimitedValue());
+ // Create substrings of each to compare the prefix.
+ s1StrRef = s1StrRef.substr(0, (size_t)lenInt.getLimitedValue());
+ s2StrRef = s2StrRef.substr(0, (size_t)lenInt.getLimitedValue());
+ }
- // For now, give up.
- return;
- } else {
- // Create substrings of each to compare the prefix.
- llvm::StringRef s1SubStr =
- s1StrRef.substr(0, (size_t)lenInt.getLimitedValue());
- llvm::StringRef s2SubStr =
- s2StrRef.substr(0, (size_t)lenInt.getLimitedValue());
-
- // Compare the substrings.
- result = s1SubStr.compare(s2SubStr);
- }
+ if (ignoreCase) {
+ // Compare string 1 to string 2 the same way strcasecmp() does.
+ result = s1StrRef.compare_lower(s2StrRef);
} else {
// Compare string 1 to string 2 the same way strcmp() does.
- if (ignoreCase) {
- result = s1StrRef.compare_lower(s2StrRef);
- } else {
- result = s1StrRef.compare(s2StrRef);
- }
+ result = s1StrRef.compare(s2StrRef);
}
// Build the SVal of the comparison to bind the return value.
@@ -1243,11 +1247,11 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
.Cases("memcpy", "__memcpy_chk", &CStringChecker::evalMemcpy)
- .Case("mempcpy", &CStringChecker::evalMempcpy)
+ .Cases("mempcpy", "__mempcpy_chk", &CStringChecker::evalMempcpy)
.Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
.Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
.Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)
- .Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
+ //.Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
.Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy)
.Cases("strcat", "__strcat_chk", &CStringChecker::evalStrcat)
.Cases("strncat", "__strncat_chk", &CStringChecker::evalStrncat)
@@ -1256,6 +1260,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
.Case("strcmp", &CStringChecker::evalStrcmp)
.Case("strncmp", &CStringChecker::evalStrncmp)
.Case("strcasecmp", &CStringChecker::evalStrcasecmp)
+ .Case("strncasecmp", &CStringChecker::evalStrncasecmp)
.Case("bcopy", &CStringChecker::evalBcopy)
.Default(NULL);
@@ -1311,6 +1316,7 @@ bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) const {
const GRState *
CStringChecker::checkRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *,
const MemRegion * const *Begin,
const MemRegion * const *End) const {
CStringLength::EntryMap Entries = state->get<CStringLength>();
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 63a591729944..a51d8e0d19ae 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -97,7 +97,7 @@ public:
void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
AnalysisManager &mgr,
BugReporter &BR) const {
- if (!D->isThisDeclarationADefinition())
+ if (!D->doesThisDeclarationHaveABody())
return;
if (!D->getResultType()->isVoidType())
return;
diff --git a/lib/StaticAnalyzer/Core/BasicStore.cpp b/lib/StaticAnalyzer/Core/BasicStore.cpp
index 4faa84ca2660..7c9f45a474c1 100644
--- a/lib/StaticAnalyzer/Core/BasicStore.cpp
+++ b/lib/StaticAnalyzer/Core/BasicStore.cpp
@@ -49,11 +49,11 @@ public:
SVal Retrieve(Store store, Loc loc, QualType T = QualType());
StoreRef invalidateRegion(Store store, const MemRegion *R, const Expr *E,
- unsigned Count, InvalidatedSymbols *IS);
+ unsigned Count, InvalidatedSymbols &IS);
StoreRef invalidateRegions(Store store, const MemRegion * const *Begin,
const MemRegion * const *End, const Expr *E,
- unsigned Count, InvalidatedSymbols *IS,
+ unsigned Count, InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions);
@@ -538,7 +538,7 @@ StoreRef BasicStoreManager::invalidateRegions(Store store,
const MemRegion * const *I,
const MemRegion * const *End,
const Expr *E, unsigned Count,
- InvalidatedSymbols *IS,
+ InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions) {
StoreRef newStore(store, *this);
@@ -587,18 +587,16 @@ StoreRef BasicStoreManager::invalidateRegion(Store store,
const MemRegion *R,
const Expr *E,
unsigned Count,
- InvalidatedSymbols *IS) {
+ InvalidatedSymbols &IS) {
R = R->StripCasts();
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
return StoreRef(store, *this);
- if (IS) {
- BindingsTy B = GetBindings(store);
- if (BindingsTy::data_type *Val = B.lookup(R)) {
- if (SymbolRef Sym = Val->getAsSymbol())
- IS->insert(Sym);
- }
+ BindingsTy B = GetBindings(store);
+ if (BindingsTy::data_type *Val = B.lookup(R)) {
+ if (SymbolRef Sym = Val->getAsSymbol())
+ IS.insert(Sym);
}
QualType T = cast<TypedRegion>(R)->getValueType();
diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index ae8a04ce439f..0ed4ff143171 100644
--- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -101,7 +101,8 @@ const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth,
const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) {
unsigned bits = Ctx.getTypeSize(T);
- llvm::APSInt V(bits, T->isUnsignedIntegerType() || Loc::isLocType(T));
+ llvm::APSInt V(bits,
+ T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T));
V = X;
return getValue(V);
}
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index d9b1ce825cea..0512e2f08d04 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -930,6 +930,13 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
S = getPersistentStopSummary();
break;
}
+ // For C++ methods, generate an implicit "stop" summary as well. We
+ // can relax this once we have a clear policy for C++ methods and
+ // ownership attributes.
+ if (isa<CXXMethodDecl>(FD)) {
+ S = getPersistentStopSummary();
+ break;
+ }
// [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the
// function's type.
@@ -1111,15 +1118,11 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
RetainSummary*
RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl* FD,
StringRef FName) {
-
if (FName.find("Create") != StringRef::npos ||
FName.find("Copy") != StringRef::npos)
return getCFSummaryCreateRule(FD);
- if (FName.find("Get") != StringRef::npos)
- return getCFSummaryGetRule(FD);
-
- return getDefaultSummary();
+ return getCFSummaryGetRule(FD);
}
RetainSummary*
@@ -1233,6 +1236,9 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
if (FD->getAttr<CFReturnsRetainedAttr>()) {
Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
}
+ else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
+ Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+ }
}
}
@@ -1758,6 +1764,15 @@ public:
StmtNodeBuilder& Builder,
const ReturnStmt* S,
ExplodedNode* Pred);
+
+ void evalReturnWithRetEffect(ExplodedNodeSet& Dst,
+ ExprEngine& Engine,
+ StmtNodeBuilder& Builder,
+ const ReturnStmt* S,
+ ExplodedNode* Pred,
+ RetEffect RE, RefVal X,
+ SymbolRef Sym, const GRState *state);
+
// Assumptions.
@@ -2075,7 +2090,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
if (CurrV.isOwned()) {
- os << "+1 retain count (owning reference).";
+ os << "+1 retain count";
if (static_cast<CFRefBug&>(getBugType()).getTF().isGCEnabled()) {
assert(CurrV.getObjKind() == RetEffect::CF);
@@ -2085,7 +2100,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
else {
assert (CurrV.isNotOwned());
- os << "+0 retain count (non-owning reference).";
+ os << "+0 retain count";
}
PathDiagnosticLocation Pos(S, BRC.getSourceManager());
@@ -2217,11 +2232,11 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
case RefVal::ReturnedOwned:
os << "Object returned to caller as an owning reference (single retain "
- "count transferred to caller).";
+ "count transferred to caller)";
break;
case RefVal::ReturnedNotOwned:
- os << "Object returned to caller with a +0 (non-owning) retain count.";
+ os << "Object returned to caller with a +0 retain count";
break;
default:
@@ -2354,12 +2369,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
llvm::tie(AllocNode, FirstBinding) =
GetAllocationSite(BRC.getStateManager(), EndN, Sym);
- // Get the allocate site.
- assert(AllocNode);
- const Stmt* FirstStmt = cast<PostStmt>(AllocNode->getLocation()).getStmt();
-
SourceManager& SMgr = BRC.getSourceManager();
- unsigned AllocLine =SMgr.getInstantiationLineNumber(FirstStmt->getLocStart());
// Compute an actual location for the leak. Sometimes a leak doesn't
// occur at an actual statement (e.g., transition between blocks; end
@@ -2392,10 +2402,14 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
- os << "Object allocated on line " << AllocLine;
+ os << "Object leaked: ";
- if (FirstBinding)
- os << " and stored into '" << FirstBinding->getString() << '\'';
+ if (FirstBinding) {
+ os << "object allocated and stored into '"
+ << FirstBinding->getString() << '\'';
+ }
+ else
+ os << "allocated object";
// Get the retain count.
const RefVal* RV = EndN->getState()->get<RefBindings>(Sym);
@@ -2404,12 +2418,22 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
// FIXME: Per comments in rdar://6320065, "create" only applies to CF
// ojbects. Only "copy", "alloc", "retain" and "new" transfer ownership
// to the caller for NS objects.
- ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
- os << " is returned from a method whose name ('"
- << MD.getSelector().getAsString()
- << "') does not contain 'copy' or otherwise starts with"
- " 'new' or 'alloc'. This violates the naming convention rules given"
- " in the Memory Management Guide for Cocoa (object leaked)";
+ const Decl *D = &EndN->getCodeDecl();
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ os << " is returned from a method whose name ('"
+ << MD->getSelector().getAsString()
+ << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'."
+ " This violates the naming convention rules "
+ " given in the Memory Management Guide for Cocoa";
+ }
+ else {
+ const FunctionDecl *FD = cast<FunctionDecl>(D);
+ os << " is return from a function whose name ('"
+ << FD->getNameAsString()
+ << "') does not contain 'Copy' or 'Create'. This violates the naming"
+ " convention rules given the Memory Management Guide for Core "
+ " Foundation";
+ }
}
else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
@@ -2421,7 +2445,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
}
else
os << " is not referenced later in this execution path and has a retain "
- "count of +" << RV->getCount() << " (object leaked)";
+ "count of +" << RV->getCount();
return new PathDiagnosticEventPiece(L, os.str());
}
@@ -2494,6 +2518,23 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
return RetTy;
}
+
+// HACK: Symbols that have ref-count state that are referenced directly
+// (not as structure or array elements, or via bindings) by an argument
+// should not have their ref-count state stripped after we have
+// done an invalidation pass.
+//
+// FIXME: This is a global to currently share between CFRefCount and
+// RetainReleaseChecker. Eventually all functionality in CFRefCount should
+// be migrated to RetainReleaseChecker, and we can make this a non-global.
+llvm::DenseSet<SymbolRef> WhitelistedSymbols;
+namespace {
+struct ResetWhiteList {
+ ResetWhiteList() {}
+ ~ResetWhiteList() { WhitelistedSymbols.clear(); }
+};
+}
+
void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
ExprEngine& Eng,
StmtNodeBuilder& Builder,
@@ -2510,12 +2551,9 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
SymbolRef ErrorSym = 0;
llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate;
-
- // HACK: Symbols that have ref-count state that are referenced directly
- // (not as structure or array elements, or via bindings) by an argument
- // should not have their ref-count state stripped after we have
- // done an invalidation pass.
- llvm::DenseSet<SymbolRef> WhitelistedSymbols;
+
+ // Use RAII to make sure the whitelist is properly cleared.
+ ResetWhiteList resetWhiteList;
// Invalidate all instance variables of the receiver of a message.
// FIXME: We should be able to do better with inter-procedural analysis.
@@ -2624,20 +2662,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
// NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
// global variables.
- state = state->invalidateRegions(RegionsToInvalidate.data(),
- RegionsToInvalidate.data() +
- RegionsToInvalidate.size(),
- Ex, Count, &IS,
- /* invalidateGlobals = */ true);
-
- for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
- E = IS.end(); I!=E; ++I) {
- SymbolRef sym = *I;
- if (WhitelistedSymbols.count(sym))
- continue;
- // Remove any existing reference-count binding.
- state = state->remove<RefBindings>(*I);
- }
+ // NOTE: RetainReleaseChecker handles the actual invalidation of symbols.
+ state =
+ state->invalidateRegions(RegionsToInvalidate.data(),
+ RegionsToInvalidate.data() +
+ RegionsToInvalidate.size(),
+ Ex, Count, &IS,
+ /* invalidateGlobals = */
+ Eng.doesInvalidateGlobals(callOrMsg));
// Evaluate the effect on the message receiver.
if (!ErrorRange.isValid() && Receiver) {
@@ -2946,30 +2978,50 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst,
assert(T);
X = *T;
+ // Consult the summary of the enclosing method.
+ Decl const *CD = &Pred->getCodeDecl();
+
+ if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
+ const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
+ return evalReturnWithRetEffect(Dst, Eng, Builder, S,
+ Pred, Summ.getRetEffect(), X,
+ Sym, state);
+ }
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
+ if (!isa<CXXMethodDecl>(FD))
+ if (const RetainSummary *Summ = Summaries.getSummary(FD))
+ return evalReturnWithRetEffect(Dst, Eng, Builder, S,
+ Pred, Summ->getRetEffect(), X,
+ Sym, state);
+ }
+}
+
+void CFRefCount::evalReturnWithRetEffect(ExplodedNodeSet &Dst,
+ ExprEngine &Eng,
+ StmtNodeBuilder &Builder,
+ const ReturnStmt *S,
+ ExplodedNode *Pred,
+ RetEffect RE, RefVal X,
+ SymbolRef Sym, const GRState *state) {
// Any leaks or other errors?
if (X.isReturnedOwned() && X.getCount() == 0) {
- Decl const *CD = &Pred->getCodeDecl();
- if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
- const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
- RetEffect RE = Summ.getRetEffect();
+ if (RE.getKind() != RetEffect::NoRet) {
bool hasError = false;
-
- if (RE.getKind() != RetEffect::NoRet) {
- if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) {
- // Things are more complicated with garbage collection. If the
- // returned object is suppose to be an Objective-C object, we have
- // a leak (as the caller expects a GC'ed object) because no
- // method should return ownership unless it returns a CF object.
- hasError = true;
- X = X ^ RefVal::ErrorGCLeakReturned;
- }
- else if (!RE.isOwned()) {
- // Either we are using GC and the returned object is a CF type
- // or we aren't using GC. In either case, we expect that the
- // enclosing method is expected to return ownership.
- hasError = true;
- X = X ^ RefVal::ErrorLeakReturned;
- }
+ if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) {
+ // Things are more complicated with garbage collection. If the
+ // returned object is suppose to be an Objective-C object, we have
+ // a leak (as the caller expects a GC'ed object) because no
+ // method should return ownership unless it returns a CF object.
+ hasError = true;
+ X = X ^ RefVal::ErrorGCLeakReturned;
+ }
+ else if (!RE.isOwned()) {
+ // Either we are using GC and the returned object is a CF type
+ // or we aren't using GC. In either case, we expect that the
+ // enclosing method is expected to return ownership.
+ hasError = true;
+ X = X ^ RefVal::ErrorLeakReturned;
}
if (hasError) {
@@ -2987,26 +3039,24 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst,
}
}
}
+ return;
}
- else if (X.isReturnedNotOwned()) {
- Decl const *CD = &Pred->getCodeDecl();
- if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
- const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
- if (Summ.getRetEffect().isOwned()) {
- // Trying to return a not owned object to a caller expecting an
- // owned object.
-
- static int ReturnNotOwnedForOwnedTag = 0;
- state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned);
- if (ExplodedNode *N =
- Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
- &ReturnNotOwnedForOwnedTag),
- state, Pred)) {
- CFRefReport *report =
- new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned),
- *this, N, Sym);
- BR->EmitReport(report);
- }
+
+ if (X.isReturnedNotOwned()) {
+ if (RE.isOwned()) {
+ // Trying to return a not owned object to a caller expecting an
+ // owned object.
+
+ static int ReturnNotOwnedForOwnedTag = 0;
+ state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned);
+ if (ExplodedNode *N =
+ Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
+ &ReturnNotOwnedForOwnedTag),
+ state, Pred)) {
+ CFRefReport *report =
+ new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned),
+ *this, N, Sym);
+ BR->EmitReport(report);
}
}
}
@@ -3418,12 +3468,43 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
namespace {
class RetainReleaseChecker
- : public Checker< check::PostStmt<BlockExpr> > {
+ : public Checker< check::PostStmt<BlockExpr>, check::RegionChanges > {
public:
+ bool wantsRegionUpdate;
+
+ RetainReleaseChecker() : wantsRegionUpdate(true) {}
+
+
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
+ const GRState *checkRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ const MemRegion * const *begin,
+ const MemRegion * const *end) const;
+
+ bool wantsRegionChangeUpdate(const GRState *state) const {
+ return wantsRegionUpdate;
+ }
};
} // end anonymous namespace
+const GRState *
+RetainReleaseChecker::checkRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ const MemRegion * const *begin,
+ const MemRegion * const *end) const {
+ if (!invalidated)
+ return state;
+
+ for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
+ E = invalidated->end(); I!=E; ++I) {
+ SymbolRef sym = *I;
+ if (WhitelistedSymbols.count(sym))
+ continue;
+ // Remove any existing reference-count binding.
+ state = state->remove<RefBindings>(sym);
+ }
+ return state;
+}
void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE,
CheckerContext &C) const {
diff --git a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
index 54cbca08b981..ef7bc2016cdf 100644
--- a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
@@ -132,7 +132,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
assert(CD);
#if 0
- if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
+ if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
// FIXME: invalidate the object.
return;
#endif
@@ -246,7 +246,7 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
const Stmt *S,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- if (!(DD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
+ if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
return;
// Create the context for 'this' region.
const StackFrameContext *SFC = AMgr.getStackFrame(DD,
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 4a2549091cb4..ba7c384e5c36 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -345,6 +345,7 @@ bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) {
/// \brief Run checkers for region changes.
const GRState *
CheckerManager::runCheckersForRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
const MemRegion * const *Begin,
const MemRegion * const *End) {
for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
@@ -352,7 +353,7 @@ CheckerManager::runCheckersForRegionChanges(const GRState *state,
// bail out.
if (!state)
return NULL;
- state = RegionChangesCheckers[i].CheckFn(state, Begin, End);
+ state = RegionChangesCheckers[i].CheckFn(state, invalidated, Begin, End);
}
return state;
}
@@ -415,6 +416,15 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
}
}
+/// \brief Run checkers for the entire Translation Unit.
+void CheckerManager::runCheckersOnEndOfTranslationUnit(
+ const TranslationUnitDecl *TU,
+ AnalysisManager &mgr,
+ BugReporter &BR) {
+ for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e; ++i)
+ EndOfTranslationUnitCheckers[i](TU, mgr, BR);
+}
+
//===----------------------------------------------------------------------===//
// Internal registration functions for AST traversing.
//===----------------------------------------------------------------------===//
@@ -494,6 +504,11 @@ void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
EvalCallCheckers.push_back(checkfn);
}
+void CheckerManager::_registerForEndOfTranslationUnit(
+ CheckEndOfTranslationUnit checkfn) {
+ EndOfTranslationUnitCheckers.push_back(checkfn);
+}
+
//===----------------------------------------------------------------------===//
// Implementation details.
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index a00f9dc10b68..48f126bfd863 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -39,6 +39,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
}
for (;;) {
+ if (const Expr *Ex = dyn_cast<Expr>(E))
+ E = Ex->IgnoreParens();
+
switch (E->getStmtClass()) {
case Stmt::AddrLabelExprClass:
return svalBuilder.makeLoc(cast<AddrLabelExpr>(E));
@@ -48,13 +51,10 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
continue;
}
case Stmt::ParenExprClass:
- // ParenExprs are no-ops.
- E = cast<ParenExpr>(E)->getSubExpr();
- continue;
case Stmt::GenericSelectionExprClass:
- // GenericSelectionExprs are no-ops.
- E = cast<GenericSelectionExpr>(E)->getResultExpr();
- continue;
+ llvm_unreachable("ParenExprs and GenericSelectionExprs should "
+ "have been handled by IgnoreParens()");
+ return UnknownVal();
case Stmt::CharacterLiteralClass: {
const CharacterLiteral* C = cast<CharacterLiteral>(E);
return svalBuilder.makeIntVal(C->getValue(), C->getType());
@@ -77,21 +77,6 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
// For special C0xx nullptr case, make a null pointer SVal.
case Stmt::CXXNullPtrLiteralExprClass:
return svalBuilder.makeNull();
- case Stmt::ImplicitCastExprClass:
- case Stmt::CXXFunctionalCastExprClass:
- case Stmt::CStyleCastExprClass: {
- // We blast through no-op casts to get the descendant
- // subexpression that has a value.
- const CastExpr* C = cast<CastExpr>(E);
- QualType CT = C->getType();
- if (CT->isVoidType())
- return UnknownVal();
- if (C->getCastKind() == CK_NoOp) {
- E = C->getSubExpr();
- continue;
- }
- break;
- }
case Stmt::ExprWithCleanupsClass:
E = cast<ExprWithCleanups>(E)->getSubExpr();
continue;
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 657420d06f06..aed39eb0cec6 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -156,6 +156,27 @@ const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) {
return state;
}
+bool
+ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const
+{
+ if (callOrMessage.isFunctionCall() && !callOrMessage.isCXXCall()) {
+ SVal calleeV = callOrMessage.getFunctionCallee();
+ if (const FunctionTextRegion *codeR =
+ llvm::dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) {
+
+ const FunctionDecl *fd = codeR->getDecl();
+ if (const IdentifierInfo *ii = fd->getIdentifier()) {
+ llvm::StringRef fname = ii->getName();
+ if (fname == "strlen")
+ return false;
+ }
+ }
+ }
+
+ // The conservative answer: invalidates globals.
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
@@ -179,9 +200,11 @@ bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) {
const GRState *
ExprEngine::processRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End) {
- return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
+ const StoreManager::InvalidatedSymbols *invalidated,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End) {
+ return getCheckerManager().runCheckersForRegionChanges(state, invalidated,
+ Begin, End);
}
void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
@@ -516,6 +539,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::VAArgExprClass:
case Stmt::CUDAKernelCallExprClass:
case Stmt::OpaqueValueExprClass:
+ case Stmt::AsTypeExprClass:
// Fall through.
// Cases we intentionally don't evaluate, since they don't need
@@ -2462,7 +2486,7 @@ void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE,
const APSInt &IV = Res.Val.getInt();
assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
assert(OOE->getType()->isIntegerType());
- assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
+ assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType());
SVal X = svalBuilder.makeIntVal(IV);
MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X));
return;
@@ -2701,7 +2725,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
if (U->isLValue())
state = state->BindExpr(U, loc);
else
- state = state->BindExpr(U, V2);
+ state = state->BindExpr(U, U->isPostfix() ? V2 : Result);
// Perform the store.
evalStore(Dst, NULL, U, *I2, state, loc, Result);
diff --git a/lib/StaticAnalyzer/Core/FlatStore.cpp b/lib/StaticAnalyzer/Core/FlatStore.cpp
index 7bdca6b7f17d..ca867aebded4 100644
--- a/lib/StaticAnalyzer/Core/FlatStore.cpp
+++ b/lib/StaticAnalyzer/Core/FlatStore.cpp
@@ -59,7 +59,7 @@ public:
StoreRef invalidateRegions(Store store, const MemRegion * const *I,
const MemRegion * const *E, const Expr *Ex,
- unsigned Count, InvalidatedSymbols *IS,
+ unsigned Count, InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions);
@@ -175,7 +175,7 @@ StoreRef FlatStoreManager::invalidateRegions(Store store,
const MemRegion * const *I,
const MemRegion * const *E,
const Expr *Ex, unsigned Count,
- InvalidatedSymbols *IS,
+ InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions) {
assert(false && "Not implemented");
diff --git a/lib/StaticAnalyzer/Core/GRState.cpp b/lib/StaticAnalyzer/Core/GRState.cpp
index 7b216775b8e6..0f6ff1ef588c 100644
--- a/lib/StaticAnalyzer/Core/GRState.cpp
+++ b/lib/StaticAnalyzer/Core/GRState.cpp
@@ -141,6 +141,20 @@ const GRState *GRState::invalidateRegions(const MemRegion * const *Begin,
const Expr *E, unsigned Count,
StoreManager::InvalidatedSymbols *IS,
bool invalidateGlobals) const {
+ if (!IS) {
+ StoreManager::InvalidatedSymbols invalidated;
+ return invalidateRegionsImpl(Begin, End, E, Count,
+ invalidated, invalidateGlobals);
+ }
+ return invalidateRegionsImpl(Begin, End, E, Count, *IS, invalidateGlobals);
+}
+
+const GRState *
+GRState::invalidateRegionsImpl(const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ StoreManager::InvalidatedSymbols &IS,
+ bool invalidateGlobals) const {
GRStateManager &Mgr = getStateManager();
SubEngine* Eng = Mgr.getOwningEngine();
@@ -150,7 +164,7 @@ const GRState *GRState::invalidateRegions(const MemRegion * const *Begin,
= Mgr.StoreMgr->invalidateRegions(getStore(), Begin, End, E, Count, IS,
invalidateGlobals, &Regions);
const GRState *newState = makeWithStore(newStore);
- return Eng->processRegionChanges(newState,
+ return Eng->processRegionChanges(newState, &IS,
&Regions.front(),
&Regions.back()+1);
}
diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index c005819c9c96..c00060047498 100644
--- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
@@ -141,6 +141,13 @@ SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const {
return UnknownVal();
}
+SVal CallOrObjCMessage::getFunctionCallee() const {
+ assert(isFunctionCall());
+ assert(!isCXXCall());
+ const Expr *callee = CallE->getCallee()->IgnoreParenCasts();
+ return State->getSVal(callee);
+}
+
SVal CallOrObjCMessage::getCXXCallee() const {
assert(isCXXCall());
const Expr *callee =
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 4522f976e648..d0d8f601f071 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -240,7 +240,7 @@ public:
const MemRegion * const *Begin,
const MemRegion * const *End,
const Expr *E, unsigned Count,
- InvalidatedSymbols *IS,
+ InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions);
@@ -586,14 +586,14 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker>
{
const Expr *Ex;
unsigned Count;
- StoreManager::InvalidatedSymbols *IS;
+ StoreManager::InvalidatedSymbols &IS;
StoreManager::InvalidatedRegions *Regions;
public:
invalidateRegionsWorker(RegionStoreManager &rm,
GRStateManager &stateMgr,
RegionBindings b,
const Expr *ex, unsigned count,
- StoreManager::InvalidatedSymbols *is,
+ StoreManager::InvalidatedSymbols &is,
StoreManager::InvalidatedRegions *r,
bool includeGlobals)
: ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
@@ -609,9 +609,8 @@ private:
void invalidateRegionsWorker::VisitBinding(SVal V) {
// A symbol? Mark it touched by the invalidation.
- if (IS)
- if (SymbolRef Sym = V.getAsSymbol())
- IS->insert(Sym);
+ if (SymbolRef Sym = V.getAsSymbol())
+ IS.insert(Sym);
if (const MemRegion *R = V.getAsRegion()) {
AddToWorkList(R);
@@ -648,11 +647,9 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
}
void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
- if (IS) {
- // Symbolic region? Mark that symbol touched by the invalidation.
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
- IS->insert(SR->getSymbol());
- }
+ // Symbolic region? Mark that symbol touched by the invalidation.
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
+ IS.insert(SR->getSymbol());
// BlockDataRegion? If so, invalidate captured variables that are passed
// by reference.
@@ -724,7 +721,7 @@ StoreRef RegionStoreManager::invalidateRegions(Store store,
const MemRegion * const *I,
const MemRegion * const *E,
const Expr *Ex, unsigned Count,
- InvalidatedSymbols *IS,
+ InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions) {
invalidateRegionsWorker W(*this, StateMgr,
@@ -1066,6 +1063,11 @@ SVal RegionStoreManager::RetrieveElement(Store store,
// return *y;
// FIXME: This is a hack, and doesn't do anything really intelligent yet.
const RegionRawOffset &O = R->getAsArrayOffset();
+
+ // If we cannot reason about the offset, return an unknown value.
+ if (!O.getRegion())
+ return UnknownVal();
+
if (const TypedRegion *baseR = dyn_cast_or_null<TypedRegion>(O.getRegion())) {
QualType baseT = baseR->getValueType();
if (baseT->isScalarType()) {
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 1ee694ef8a13..20762e07dd22 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -262,7 +262,8 @@ const GRState *SimpleConstraintManager::assumeSymRel(const GRState *state,
QualType T = Sym->getType(Ctx);
assert(T->isIntegerType() || Loc::isLocType(T));
unsigned bitwidth = Ctx.getTypeSize(T);
- bool isSymUnsigned = T->isUnsignedIntegerType() || Loc::isLocType(T);
+ bool isSymUnsigned
+ = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
// Convert the adjustment.
Adjustment.setIsUnsigned(isSymUnsigned);
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 5d802511510a..197442b1574f 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -97,7 +97,8 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
return UnknownVal();
llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
- i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::isLocType(castTy));
+ i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() ||
+ Loc::isLocType(castTy));
i = i.extOrTrunc(Context.getTypeSize(castTy));
if (isLocType)
@@ -129,7 +130,8 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
return makeLocAsInteger(val, BitWidth);
llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
- i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::isLocType(castTy));
+ i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() ||
+ Loc::isLocType(castTy));
i = i.extOrTrunc(BitWidth);
return makeIntVal(i);
}
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index fe6e1fd6bbd2..b8dbb545041e 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -200,18 +200,20 @@ void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
}
break;
}
-
+
+ case Decl::ObjCCategoryImpl:
case Decl::ObjCImplementation: {
- ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I);
+ ObjCImplDecl* ID = cast<ObjCImplDecl>(*I);
HandleCode(ID);
- for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(),
+ for (ObjCContainerDecl::method_iterator MI = ID->meth_begin(),
ME = ID->meth_end(); MI != ME; ++MI) {
checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR);
if ((*MI)->isThisDeclarationADefinition()) {
if (!Opts.AnalyzeSpecificFunction.empty() &&
- Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString())
+ Opts.AnalyzeSpecificFunction !=
+ (*MI)->getSelector().getAsString())
break;
DisplayFunction(*MI);
HandleCode(*MI);
@@ -232,6 +234,9 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
HandleDeclContext(C, TU);
+ // After all decls handled, run checkers on the entire TranslationUnit.
+ checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
+
// Explicitly destroy the PathDiagnosticClient. This will flush its output.
// FIXME: This should be replaced with something that doesn't rely on
// side-effects in PathDiagnosticClient's destructor. This is required when
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
deleted file mode 100644
index f52cf6c8917f..000000000000
--- a/lib/Tooling/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-SET(LLVM_USED_LIBS clangBasic clangFrontend clangAST)
-
-add_clang_library(clangTooling
- JsonCompileCommandLineDatabase.cpp
- Tooling.cpp
- )
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.cpp b/lib/Tooling/JsonCompileCommandLineDatabase.cpp
deleted file mode 100644
index 7f027cfbead4..000000000000
--- a/lib/Tooling/JsonCompileCommandLineDatabase.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-//===--- JsonCompileCommandLineDatabase.cpp - Simple JSON database --------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements reading a compile command line database, as written
-// out for example by CMake.
-//
-//===----------------------------------------------------------------------===//
-
-#include "JsonCompileCommandLineDatabase.h"
-#include "llvm/ADT/Twine.h"
-
-namespace clang {
-namespace tooling {
-
-namespace {
-
-// A parser for JSON escaped strings of command line arguments with \-escaping
-// for quoted arguments (see the documentation of UnescapeJsonCommandLine(...)).
-class CommandLineArgumentParser {
- public:
- CommandLineArgumentParser(llvm::StringRef CommandLine)
- : Input(CommandLine), Position(Input.begin()-1) {}
-
- std::vector<std::string> Parse() {
- bool HasMoreInput = true;
- while (HasMoreInput && NextNonWhitespace()) {
- std::string Argument;
- HasMoreInput = ParseStringInto(Argument);
- CommandLine.push_back(Argument);
- }
- return CommandLine;
- }
-
- private:
- // All private methods return true if there is more input available.
-
- bool ParseStringInto(std::string &String) {
- do {
- if (*Position == '"') {
- if (!ParseQuotedStringInto(String)) return false;
- } else {
- if (!ParseFreeStringInto(String)) return false;
- }
- } while (*Position != ' ');
- return true;
- }
-
- bool ParseQuotedStringInto(std::string &String) {
- if (!Next()) return false;
- while (*Position != '"') {
- if (!SkipEscapeCharacter()) return false;
- String.push_back(*Position);
- if (!Next()) return false;
- }
- return Next();
- }
-
- bool ParseFreeStringInto(std::string &String) {
- do {
- if (!SkipEscapeCharacter()) return false;
- String.push_back(*Position);
- if (!Next()) return false;
- } while (*Position != ' ' && *Position != '"');
- return true;
- }
-
- bool SkipEscapeCharacter() {
- if (*Position == '\\') {
- return Next();
- }
- return true;
- }
-
- bool NextNonWhitespace() {
- do {
- if (!Next()) return false;
- } while (*Position == ' ');
- return true;
- }
-
- bool Next() {
- ++Position;
- if (Position == Input.end()) return false;
- // Remove the JSON escaping first. This is done unconditionally.
- if (*Position == '\\') ++Position;
- return Position != Input.end();
- }
-
- const llvm::StringRef Input;
- llvm::StringRef::iterator Position;
- std::vector<std::string> CommandLine;
-};
-
-} // end namespace
-
-std::vector<std::string> UnescapeJsonCommandLine(
- llvm::StringRef JsonEscapedCommandLine) {
- CommandLineArgumentParser parser(JsonEscapedCommandLine);
- return parser.Parse();
-}
-
-JsonCompileCommandLineParser::JsonCompileCommandLineParser(
- const llvm::StringRef Input, CompileCommandHandler *CommandHandler)
- : Input(Input), Position(Input.begin()-1), CommandHandler(CommandHandler) {}
-
-bool JsonCompileCommandLineParser::Parse() {
- NextNonWhitespace();
- return ParseTranslationUnits();
-}
-
-std::string JsonCompileCommandLineParser::GetErrorMessage() const {
- return ErrorMessage;
-}
-
-bool JsonCompileCommandLineParser::ParseTranslationUnits() {
- if (!ConsumeOrError('[', "at start of compile command file")) return false;
- if (!ParseTranslationUnit(/*First=*/true)) return false;
- while (Consume(',')) {
- if (!ParseTranslationUnit(/*First=*/false)) return false;
- }
- if (!ConsumeOrError(']', "at end of array")) return false;
- if (CommandHandler != NULL) {
- CommandHandler->EndTranslationUnits();
- }
- return true;
-}
-
-bool JsonCompileCommandLineParser::ParseTranslationUnit(bool First) {
- if (First) {
- if (!Consume('{')) return true;
- } else {
- if (!ConsumeOrError('{', "at start of object")) return false;
- }
- if (!Consume('}')) {
- if (!ParseObjectKeyValuePairs()) return false;
- if (!ConsumeOrError('}', "at end of object")) return false;
- }
- if (CommandHandler != NULL) {
- CommandHandler->EndTranslationUnit();
- }
- return true;
-}
-
-bool JsonCompileCommandLineParser::ParseObjectKeyValuePairs() {
- do {
- llvm::StringRef Key;
- if (!ParseString(Key)) return false;
- if (!ConsumeOrError(':', "between name and value")) return false;
- llvm::StringRef Value;
- if (!ParseString(Value)) return false;
- if (CommandHandler != NULL) {
- CommandHandler->HandleKeyValue(Key, Value);
- }
- } while (Consume(','));
- return true;
-}
-
-bool JsonCompileCommandLineParser::ParseString(llvm::StringRef &String) {
- if (!ConsumeOrError('"', "at start of string")) return false;
- llvm::StringRef::iterator First = Position;
- llvm::StringRef::iterator Last = Position;
- while (!Consume('"')) {
- Consume('\\');
- ++Position;
- // We need to store Position, as Consume will change Last before leaving
- // the loop.
- Last = Position;
- }
- String = llvm::StringRef(First, Last - First);
- return true;
-}
-
-bool JsonCompileCommandLineParser::Consume(char C) {
- if (Position == Input.end()) return false;
- if (*Position != C) return false;
- NextNonWhitespace();
- return true;
-}
-
-bool JsonCompileCommandLineParser::ConsumeOrError(
- char C, llvm::StringRef Message) {
- if (!Consume(C)) {
- SetExpectError(C, Message);
- return false;
- }
- return true;
-}
-
-void JsonCompileCommandLineParser::SetExpectError(
- char C, llvm::StringRef Message) {
- ErrorMessage = (llvm::Twine("'") + llvm::StringRef(&C, 1) +
- "' expected " + Message + ".").str();
-}
-
-void JsonCompileCommandLineParser::NextNonWhitespace() {
- do {
- ++Position;
- } while (IsWhitespace());
-}
-
-bool JsonCompileCommandLineParser::IsWhitespace() {
- if (Position == Input.end()) return false;
- return (*Position == ' ' || *Position == '\t' ||
- *Position == '\n' || *Position == '\r');
-}
-
-} // end namespace tooling
-} // end namespace clang
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.h b/lib/Tooling/JsonCompileCommandLineDatabase.h
deleted file mode 100644
index 9e776d60010d..000000000000
--- a/lib/Tooling/JsonCompileCommandLineDatabase.h
+++ /dev/null
@@ -1,107 +0,0 @@
-//===--- JsonCompileCommandLineDatabase - Simple JSON database --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements reading a compile command line database, as written
-// out for example by CMake. It only supports the subset of the JSON standard
-// that is needed to parse the CMake output.
-// See http://www.json.org/ for the full standard.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
-#define LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
-
-#include "llvm/ADT/StringRef.h"
-#include <string>
-#include <vector>
-
-namespace clang {
-namespace tooling {
-
-/// \brief Converts a JSON escaped command line to a vector of arguments.
-///
-/// \param JsonEscapedCommandLine The escaped command line as a string. This
-/// is assumed to be escaped as a JSON string (e.g. " and \ are escaped).
-/// In addition, any arguments containing spaces are assumed to be \-escaped
-///
-/// For example, the input (|| denoting non C-escaped strings):
-/// |./call a \"b \\\" c \\\\ \" d|
-/// would yield:
-/// [ |./call|, |a|, |b " c \ |, |d| ].
-std::vector<std::string> UnescapeJsonCommandLine(
- llvm::StringRef JsonEscapedCommandLine);
-
-/// \brief Interface for users of the JsonCompileCommandLineParser.
-class CompileCommandHandler {
- public:
- virtual ~CompileCommandHandler() {}
-
- /// \brief Called after all translation units are parsed.
- virtual void EndTranslationUnits() {}
-
- /// \brief Called at the end of a single translation unit.
- virtual void EndTranslationUnit() {}
-
- /// \brief Called for every (Key, Value) pair in a translation unit
- /// description.
- virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {}
-};
-
-/// \brief A JSON parser that supports the subset of JSON needed to parse
-/// JSON compile command line databases as written out by CMake.
-///
-/// The supported subset describes a list of compile command lines for
-/// each processed translation unit. The translation units are stored in a
-/// JSON array, where each translation unit is described by a JSON object
-/// containing (Key, Value) pairs for the working directory the compile command
-/// line was executed from, the main C/C++ input file of the translation unit
-/// and the actual compile command line, for example:
-/// [
-/// {
-/// "file":"/file.cpp",
-/// "directory":"/",
-/// "command":"/cc /file.cpp"
-/// }
-/// ]
-class JsonCompileCommandLineParser {
- public:
- /// \brief Create a parser on 'Input', calling 'CommandHandler' to handle the
- /// parsed constructs. 'CommandHandler' may be NULL in order to just check
- /// the validity of 'Input'.
- JsonCompileCommandLineParser(const llvm::StringRef Input,
- CompileCommandHandler *CommandHandler);
-
- /// \brief Parses the specified input. Returns true if no parsing errors were
- /// foudn.
- bool Parse();
-
- /// \brief Returns an error message if Parse() returned false previously.
- std::string GetErrorMessage() const;
-
- private:
- bool ParseTranslationUnits();
- bool ParseTranslationUnit(bool First);
- bool ParseObjectKeyValuePairs();
- bool ParseString(llvm::StringRef &String);
- bool Consume(char C);
- bool ConsumeOrError(char C, llvm::StringRef Message);
- void NextNonWhitespace();
- bool IsWhitespace();
- void SetExpectError(char C, llvm::StringRef Message);
-
- const llvm::StringRef Input;
- llvm::StringRef::iterator Position;
- std::string ErrorMessage;
- CompileCommandHandler * const CommandHandler;
-};
-
-} // end namespace tooling
-} // end namespace clang
-
-#endif // LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
diff --git a/lib/Tooling/Makefile b/lib/Tooling/Makefile
deleted file mode 100644
index 501a00c3f4f4..000000000000
--- a/lib/Tooling/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- clang/lib/Tooling/Makefile ---------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-CLANG_LEVEL := ../..
-LIBRARYNAME := clangTooling
-
-include $(CLANG_LEVEL)/Makefile
-
-
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
deleted file mode 100644
index c1714a9be715..000000000000
--- a/lib/Tooling/Tooling.cpp
+++ /dev/null
@@ -1,322 +0,0 @@
-//===--- Tooling.cpp - Running clang standalone tools --------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements functions to run clang tools standalone instead
-// of running them as a plugin.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include "clang/Basic/DiagnosticIDs.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/Tool.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendAction.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "JsonCompileCommandLineDatabase.h"
-#include <map>
-#include <cstdio>
-
-namespace clang {
-namespace tooling {
-
-namespace {
-
-// Checks that the input conforms to the argv[] convention as in
-// main(). Namely:
-// - it must contain at least a program path,
-// - argv[0], ..., and argv[argc - 1] mustn't be NULL, and
-// - argv[argc] must be NULL.
-void ValidateArgv(int argc, char* argv[]) {
- if (argc < 1) {
- fprintf(stderr, "ERROR: argc is %d. It must be >= 1.\n", argc);
- abort();
- }
-
- for (int i = 0; i < argc; ++i) {
- if (argv[i] == NULL) {
- fprintf(stderr, "ERROR: argv[%d] is NULL.\n", i);
- abort();
- }
- }
-
- if (argv[argc] != NULL) {
- fprintf(stderr, "ERROR: argv[argc] isn't NULL.\n");
- abort();
- }
-}
-
-} // end namespace
-
-// FIXME: This file contains structural duplication with other parts of the
-// code that sets up a compiler to run tools on it, and we should refactor
-// it to be based on the same framework.
-
-static clang::Diagnostic* NewTextDiagnostics() {
- llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
- new clang::DiagnosticIDs());
- clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(
- llvm::errs(), clang::DiagnosticOptions());
- return new clang::Diagnostic(DiagIDs, DiagClient);
-}
-
-// Exists solely for the purpose of lookup of the main executable.
-static int StaticSymbol;
-
-/// \brief Builds a clang driver initialized for running clang tools.
-static clang::driver::Driver* NewDriver(clang::Diagnostic* Diagnostics,
- const char* BinaryName) {
- // This just needs to be some symbol in the binary.
- void* const SymbolAddr = &StaticSymbol;
- const llvm::sys::Path ExePath =
- llvm::sys::Path::GetMainExecutable(BinaryName, SymbolAddr);
-
- const std::string DefaultOutputName = "a.out";
- clang::driver::Driver* CompilerDriver = new clang::driver::Driver(
- ExePath.str(), llvm::sys::getHostTriple(),
- DefaultOutputName, false, false, *Diagnostics);
- CompilerDriver->setTitle("clang_based_tool");
- return CompilerDriver;
-}
-
-/// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs.
-/// Returns NULL on error.
-static const clang::driver::ArgStringList* GetCC1Arguments(
- clang::Diagnostic* Diagnostics, clang::driver::Compilation* Compilation) {
- // We expect to get back exactly one Command job, if we didn't something
- // failed. Extract that job from the Compilation.
- const clang::driver::JobList &Jobs = Compilation->getJobs();
- if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
- llvm::SmallString<256> error_msg;
- llvm::raw_svector_ostream error_stream(error_msg);
- Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true);
- Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
- << error_stream.str();
- return NULL;
- }
-
- // The one job we find should be to invoke clang again.
- const clang::driver::Command *Cmd =
- cast<clang::driver::Command>(*Jobs.begin());
- if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
- Diagnostics->Report(clang::diag::err_fe_expected_clang_command);
- return NULL;
- }
-
- return &Cmd->getArguments();
-}
-
-/// \brief Returns a clang build invocation initialized from the CC1 flags.
-static clang::CompilerInvocation* NewInvocation(
- clang::Diagnostic* Diagnostics,
- const clang::driver::ArgStringList& CC1Args) {
- clang::CompilerInvocation* Invocation = new clang::CompilerInvocation;
- clang::CompilerInvocation::CreateFromArgs(
- *Invocation, CC1Args.data(), CC1Args.data() + CC1Args.size(),
- *Diagnostics);
- Invocation->getFrontendOpts().DisableFree = false;
- return Invocation;
-}
-
-/// \brief Runs the specified clang tool action and returns whether it executed
-/// successfully.
-static bool RunInvocation(const char* BinaryName,
- clang::driver::Compilation* Compilation,
- clang::CompilerInvocation* Invocation,
- const clang::driver::ArgStringList& CC1Args,
- clang::FrontendAction* ToolAction) {
- llvm::OwningPtr<clang::FrontendAction> ScopedToolAction(ToolAction);
- // Show the invocation, with -v.
- if (Invocation->getHeaderSearchOpts().Verbose) {
- llvm::errs() << "clang Invocation:\n";
- Compilation->PrintJob(llvm::errs(), Compilation->getJobs(), "\n", true);
- llvm::errs() << "\n";
- }
-
- // Create a compiler instance to handle the actual work.
- clang::CompilerInstance Compiler;
- Compiler.setInvocation(Invocation);
-
- // Create the compilers actual diagnostics engine.
- Compiler.createDiagnostics(CC1Args.size(),
- const_cast<char**>(CC1Args.data()));
- if (!Compiler.hasDiagnostics())
- return false;
-
- // Infer the builtin include path if unspecified.
- if (Compiler.getHeaderSearchOpts().UseBuiltinIncludes &&
- Compiler.getHeaderSearchOpts().ResourceDir.empty()) {
- // This just needs to be some symbol in the binary.
- void* const SymbolAddr = &StaticSymbol;
- Compiler.getHeaderSearchOpts().ResourceDir =
- clang::CompilerInvocation::GetResourcesPath(BinaryName, SymbolAddr);
- }
-
- const bool Success = Compiler.ExecuteAction(*ToolAction);
- return Success;
-}
-
-/// \brief Converts a string vector representing a Command line into a C
-/// string vector representing the Argv (including the trailing NULL).
-std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command) {
- std::vector<char*> Result(Command->size() + 1);
- for (std::vector<char*>::size_type I = 0; I < Command->size(); ++I) {
- Result[I] = const_cast<char*>((*Command)[I].c_str());
- }
- Result[Command->size()] = NULL;
- return Result;
-}
-
-bool RunToolWithFlags(
- clang::FrontendAction* ToolAction, int Args, char* Argv[]) {
- ValidateArgv(Args, Argv);
- const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
- const llvm::OwningPtr<clang::driver::Driver> Driver(
- NewDriver(Diagnostics.get(), Argv[0]));
- const llvm::OwningPtr<clang::driver::Compilation> Compilation(
- Driver->BuildCompilation(llvm::ArrayRef<const char*>(Argv, Args)));
- const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments(
- Diagnostics.get(), Compilation.get());
- if (CC1Args == NULL) {
- return false;
- }
- llvm::OwningPtr<clang::CompilerInvocation> Invocation(
- NewInvocation(Diagnostics.get(), *CC1Args));
- return RunInvocation(Argv[0], Compilation.get(), Invocation.take(),
- *CC1Args, ToolAction);
-}
-
-/// \brief Runs 'ToolAction' on the code specified by 'FileContents'.
-///
-/// \param FileContents A mapping from file name to source code. For each
-/// entry a virtual file mapping will be created when running the tool.
-bool RunToolWithFlagsOnCode(
- const std::vector<std::string>& CommandLine,
- const std::map<std::string, std::string>& FileContents,
- clang::FrontendAction* ToolAction) {
- const std::vector<char*> Argv = CommandLineToArgv(&CommandLine);
- const char* const BinaryName = Argv[0];
-
- const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
- const llvm::OwningPtr<clang::driver::Driver> Driver(
- NewDriver(Diagnostics.get(), BinaryName));
-
- // Since the Input is only virtual, don't check whether it exists.
- Driver->setCheckInputsExist(false);
-
- const llvm::OwningPtr<clang::driver::Compilation> Compilation(
- Driver->BuildCompilation(llvm::ArrayRef<const char*>(&Argv[0],
- Argv.size() - 1)));
- const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments(
- Diagnostics.get(), Compilation.get());
- if (CC1Args == NULL) {
- return false;
- }
- llvm::OwningPtr<clang::CompilerInvocation> Invocation(
- NewInvocation(Diagnostics.get(), *CC1Args));
-
- for (std::map<std::string, std::string>::const_iterator
- It = FileContents.begin(), End = FileContents.end();
- It != End; ++It) {
- // Inject the code as the given file name into the preprocessor options.
- const llvm::MemoryBuffer* Input =
- llvm::MemoryBuffer::getMemBuffer(It->second.c_str());
- Invocation->getPreprocessorOpts().addRemappedFile(It->first.c_str(), Input);
- }
-
- return RunInvocation(BinaryName, Compilation.get(),
- Invocation.take(), *CC1Args, ToolAction);
-}
-
-bool RunSyntaxOnlyToolOnCode(
- clang::FrontendAction *ToolAction, llvm::StringRef Code) {
- const char* const FileName = "input.cc";
- const char* const CommandLine[] = {
- "clang-tool", "-fsyntax-only", FileName
- };
- std::map<std::string, std::string> FileContents;
- FileContents[FileName] = Code;
- return RunToolWithFlagsOnCode(
- std::vector<std::string>(
- CommandLine,
- CommandLine + sizeof(CommandLine)/sizeof(CommandLine[0])),
- FileContents, ToolAction);
-}
-
-namespace {
-
-// A CompileCommandHandler implementation that finds compile commands for a
-// specific input file.
-//
-// FIXME: Implement early exit when JsonCompileCommandLineParser supports it.
-class FindHandler : public clang::tooling::CompileCommandHandler {
- public:
- explicit FindHandler(llvm::StringRef File)
- : FileToMatch(File), FoundMatchingCommand(false) {}
-
- virtual void EndTranslationUnits() {
- if (!FoundMatchingCommand && ErrorMessage.empty()) {
- ErrorMessage = "ERROR: No matching command found.";
- }
- }
-
- virtual void EndTranslationUnit() {
- if (File == FileToMatch) {
- FoundMatchingCommand = true;
- MatchingCommand.Directory = Directory;
- MatchingCommand.CommandLine = UnescapeJsonCommandLine(Command);
- }
- }
-
- virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {
- if (Key == "directory") { Directory = Value; }
- else if (Key == "file") { File = Value; }
- else if (Key == "command") { Command = Value; }
- else {
- ErrorMessage = (llvm::Twine("Unknown key: \"") + Key + "\"").str();
- }
- }
-
- const llvm::StringRef FileToMatch;
- bool FoundMatchingCommand;
- CompileCommand MatchingCommand;
- std::string ErrorMessage;
-
- llvm::StringRef Directory;
- llvm::StringRef File;
- llvm::StringRef Command;
-};
-
-} // end namespace
-
-CompileCommand FindCompileArgsInJsonDatabase(
- llvm::StringRef FileName, llvm::StringRef JsonDatabase,
- std::string &ErrorMessage) {
- FindHandler find_handler(FileName);
- JsonCompileCommandLineParser parser(JsonDatabase, &find_handler);
- if (!parser.Parse()) {
- ErrorMessage = parser.GetErrorMessage();
- return CompileCommand();
- }
- return find_handler.MatchingCommand;
-}
-
-} // end namespace tooling
-} // end namespace clang
-